aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--LICENSE2
-rw-r--r--NEWS112
-rw-r--r--bpkg/bpkg.cli5
-rw-r--r--bpkg/bpkg.cxx142
-rw-r--r--bpkg/bpkg.hxx35
-rw-r--r--bpkg/buildfile64
-rw-r--r--bpkg/common.cli55
-rw-r--r--bpkg/database.cxx1
-rw-r--r--bpkg/database.hxx38
-rw-r--r--bpkg/diagnostics.cxx4
-rw-r--r--bpkg/diagnostics.hxx31
-rw-r--r--bpkg/fetch-git.cxx160
-rw-r--r--bpkg/fetch-pkg.cxx76
-rw-r--r--bpkg/fetch.cxx456
-rw-r--r--bpkg/fetch.hxx56
-rw-r--r--bpkg/manifest-utility.cxx31
-rw-r--r--bpkg/manifest-utility.hxx19
-rw-r--r--bpkg/options-types.hxx13
-rw-r--r--bpkg/package-query.cxx232
-rw-r--r--bpkg/package-query.hxx73
-rw-r--r--bpkg/package-skeleton.cxx423
-rw-r--r--bpkg/package-skeleton.hxx81
-rw-r--r--bpkg/package.cxx122
-rw-r--r--bpkg/package.hxx323
-rw-r--r--bpkg/package.xml128
-rw-r--r--bpkg/pkg-bindist.cli908
-rw-r--r--bpkg/pkg-bindist.cxx689
-rw-r--r--bpkg/pkg-bindist.hxx27
-rw-r--r--bpkg/pkg-build-collect.cxx5074
-rw-r--r--bpkg/pkg-build-collect.hxx894
-rw-r--r--bpkg/pkg-build.cli168
-rw-r--r--bpkg/pkg-build.cxx4699
-rw-r--r--bpkg/pkg-checkout.cxx48
-rw-r--r--bpkg/pkg-command.cxx46
-rw-r--r--bpkg/pkg-configure.cxx734
-rw-r--r--bpkg/pkg-configure.hxx144
-rw-r--r--bpkg/pkg-disfigure.cxx8
-rw-r--r--bpkg/pkg-drop.cli7
-rw-r--r--bpkg/pkg-drop.cxx53
-rw-r--r--bpkg/pkg-fetch.cxx101
-rw-r--r--bpkg/pkg-fetch.hxx2
-rw-r--r--bpkg/pkg-install.hxx1
-rw-r--r--bpkg/pkg-purge.cxx5
-rw-r--r--bpkg/pkg-status.cli2
-rw-r--r--bpkg/pkg-uninstall.hxx1
-rw-r--r--bpkg/pkg-unpack.cxx80
-rw-r--r--bpkg/pkg-unpack.hxx6
-rw-r--r--bpkg/pkg-update.hxx1
-rw-r--r--bpkg/pkg-verify.cxx2
-rw-r--r--bpkg/pkg-verify.hxx4
-rw-r--r--bpkg/rep-create.cxx14
-rw-r--r--bpkg/rep-fetch.cxx274
-rw-r--r--bpkg/rep-mask.cxx368
-rw-r--r--bpkg/rep-mask.hxx73
-rw-r--r--bpkg/rep-remove.cxx107
-rw-r--r--bpkg/repository-types.cli4
-rw-r--r--bpkg/satisfaction.cxx20
-rw-r--r--bpkg/satisfaction.hxx9
-rw-r--r--bpkg/system-package-manager-archive.cxx794
-rw-r--r--bpkg/system-package-manager-archive.hxx55
-rw-r--r--bpkg/system-package-manager-debian.cxx3616
-rw-r--r--bpkg/system-package-manager-debian.hxx271
-rw-r--r--bpkg/system-package-manager-debian.test.cxx386
-rw-r--r--bpkg/system-package-manager-debian.test.testscript1177
-rw-r--r--bpkg/system-package-manager-fedora.cxx4560
-rw-r--r--bpkg/system-package-manager-fedora.hxx372
-rw-r--r--bpkg/system-package-manager-fedora.test.cxx431
-rw-r--r--bpkg/system-package-manager-fedora.test.testscript1410
-rw-r--r--bpkg/system-package-manager.cxx904
-rw-r--r--bpkg/system-package-manager.hxx463
-rw-r--r--bpkg/system-package-manager.test.cxx160
-rw-r--r--bpkg/system-package-manager.test.hxx112
-rw-r--r--bpkg/system-package-manager.test.testscript158
-rw-r--r--bpkg/system-repository.cxx8
-rw-r--r--bpkg/system-repository.hxx17
-rw-r--r--bpkg/types-parsers.cxx79
-rw-r--r--bpkg/types-parsers.hxx23
-rw-r--r--bpkg/types.hxx15
-rw-r--r--bpkg/utility.cxx68
-rw-r--r--bpkg/utility.hxx43
-rw-r--r--bpkg/utility.txx145
-rw-r--r--build/root.build7
-rwxr-xr-xdoc/cli.sh27
-rw-r--r--doc/manual.cli952
-rw-r--r--manifest18
-rw-r--r--tests/build/root.build5
-rw-r--r--tests/common.testscript4
-rw-r--r--tests/common/compatibility/t15/libbar-1.0.0.tar.gzbin0 -> 442 bytes
-rw-r--r--tests/common/compatibility/t15/libbaz-1.0.0.tar.gzbin0 -> 442 bytes
-rw-r--r--tests/common/compatibility/t15/libbiz-1.0.0.tar.gzbin0 -> 422 bytes
-rw-r--r--tests/common/compatibility/t15/libfoo-1.0.0.tar.gzbin0 -> 423 bytes
-rw-r--r--tests/common/compatibility/t15/repositories.manifest1
-rw-r--r--tests/common/dependency-alternatives/t11a/bax-0.1.0.tar.gzbin0 -> 423 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/bax-1.0.0.tar.gzbin435 -> 494 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/biz-0.1.0.tar.gzbin0 -> 416 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/box-0.2.0.tar.gzbin0 -> 396 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/bus-0.1.0.tar.gzbin0 -> 478 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/fex-0.1.0.tar.gzbin0 -> 440 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/foo-1.0.0.tar.gzbin456 -> 485 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/fox-1.0.0.tar.gzbin399 -> 461 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/fux-0.1.0.tar.gzbin0 -> 443 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/fux-0.1.1.tar.gzbin0 -> 443 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/fux-0.2.0.tar.gzbin0 -> 486 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/fux-1.0.0.tar.gzbin419 -> 429 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/libbiz-0.1.0.tar.gzbin0 -> 401 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/libbiz-1.0.0.tar.gzbin0 -> 409 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/libfoo-1.0.0.tar.gzbin480 -> 488 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/tex-1.0.0.tar.gzbin461 -> 492 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/tez-0.1.0.tar.gzbin0 -> 465 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/tiz-1.0.0.tar.gzbin464 -> 496 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/tuz-1.0.0.tar.gzbin0 -> 440 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/tvz-0.1.0.tar.gzbin0 -> 475 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/tvz-1.0.0.tar.gzbin0 -> 451 bytes
-rw-r--r--tests/common/dependency-alternatives/t13a/box-1.0.0.tar.gzbin0 -> 505 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/bax-0.1.0.tar.gzbin0 -> 437 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/bax-1.0.0.tar.gzbin0 -> 446 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/bix-0.1.0.tar.gzbin0 -> 350 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/bix-1.0.0.tar.gzbin0 -> 438 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/box-1.0.0.tar.gzbin460 -> 479 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/bux-1.0.0.tar.gzbin0 -> 359 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/dax-1.0.0.tar.gzbin0 -> 470 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/dix-0.1.0.tar.gzbin0 -> 348 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/dix-1.0.0.tar.gzbin0 -> 395 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/dox-1.0.0.tar.gzbin0 -> 351 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/dux-1.0.0.tar.gzbin0 -> 353 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/foz-1.0.0.tar.gzbin0 -> 353 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/fuz-1.0.0.tar.gzbin0 -> 412 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/libbar-1.0.0.tar.gzbin350 -> 411 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/libbaz-1.0.0.tar.gzbin360 -> 416 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/libbaz-1.1.0.tar.gzbin360 -> 415 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/libfoo-1.0.0.tar.gzbin0 -> 407 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/libfoo-2.0.0.tar.gzbin0 -> 406 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/libfox-1.0.0.tar.gzbin0 -> 398 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/tax-1.0.0.tar.gzbin0 -> 373 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/tex-1.0.0.tar.gzbin0 -> 470 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/tix-1.0.0.tar.gzbin0 -> 425 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/tox-1.0.0.tar.gzbin0 -> 504 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/tpx-1.0.0.tar.gzbin0 -> 496 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/tux-1.0.0.tar.gzbin0 -> 431 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/tvx-1.0.0.tar.gzbin0 -> 482 bytes
-rw-r--r--tests/common/dependency-alternatives/t8a/twx-1.0.0.tar.gzbin0 -> 431 bytes
-rw-r--r--tests/common/git/README2
-rw-r--r--tests/common/git/state0/libbar.tarbin194560 -> 194560 bytes
-rw-r--r--tests/common/git/state0/libfoo.tarbin481280 -> 491520 bytes
-rw-r--r--tests/common/git/state0/libfox.tarbin266240 -> 276480 bytes
-rw-r--r--tests/common/git/state0/links.tarbin296960 -> 296960 bytes
-rw-r--r--tests/common/git/state0/style-basic.tarbin81920 -> 81920 bytes
-rw-r--r--tests/common/git/state0/style.tarbin153600 -> 153600 bytes
-rw-r--r--tests/common/git/state1/libbaz.tarbin71680 -> 71680 bytes
-rw-r--r--tests/common/git/state1/libfoo.tarbin552960 -> 552960 bytes
-rw-r--r--tests/common/git/state1/libfox.tarbin266240 -> 276480 bytes
-rw-r--r--tests/common/git/state1/style-basic.tarbin81920 -> 81920 bytes
-rw-r--r--tests/common/git/state1/style.tarbin153600 -> 163840 bytes
-rw-r--r--tests/common/linked/t7a/foo-1.0.0.tar.gzbin384 -> 476 bytes
-rw-r--r--tests/common/linked/t7a/libbar-1.0.0.tar.gzbin371 -> 459 bytes
-rw-r--r--tests/common/linked/t7a/libbaz-1.0.0.tar.gzbin410 -> 466 bytes
-rw-r--r--tests/common/linked/t7a/libbiz-1.0.0.tar.gzbin384 -> 431 bytes
-rw-r--r--tests/common/linked/t7a/libbox-1.0.0.tar.gzbin373 -> 459 bytes
-rw-r--r--tests/common/linked/t7a/libbuild2-bar-1.0.0.tar.gzbin349 -> 406 bytes
-rw-r--r--tests/common/linked/t7a/libbuild2-foo-1.0.0.tar.gzbin371 -> 433 bytes
-rw-r--r--tests/common/linked/t7a/libbuz-1.0.0.tar.gzbin378 -> 414 bytes
-rw-r--r--tests/common/linked/t7a/libfax-1.0.0.tar.gzbin349 -> 409 bytes
-rw-r--r--tests/common/linked/t7a/libfix-1.0.0.tar.gzbin379 -> 424 bytes
-rw-r--r--tests/common/linked/t7b/foo-1.1.0.tar.gzbin361 -> 438 bytes
-rw-r--r--tests/common/linked/t7b/libbar-1.1.0.tar.gzbin374 -> 457 bytes
-rw-r--r--tests/common/linked/t7b/libbaz-1.1.0.tar.gzbin355 -> 413 bytes
-rw-r--r--tests/common/linked/t7b/libbox-1.1.0.tar.gzbin371 -> 444 bytes
-rw-r--r--tests/common/satisfy/libbar-0.1.0.tar.gzbin0 -> 406 bytes
-rw-r--r--tests/common/satisfy/libbar-1.0.0.tar.gzbin356 -> 418 bytes
-rw-r--r--tests/common/satisfy/libbar-1.1.0.tar.gzbin368 -> 445 bytes
-rw-r--r--tests/common/satisfy/libbar-1.2.0.tar.gzbin348 -> 485 bytes
-rw-r--r--tests/common/satisfy/libbar-2.1.0.tar.gzbin0 -> 414 bytes
-rw-r--r--tests/common/satisfy/libbax-1.0.0.tar.gzbin0 -> 347 bytes
-rw-r--r--tests/common/satisfy/libbax-2.0.0.tar.gzbin0 -> 350 bytes
-rw-r--r--tests/common/satisfy/libbaz-1.1.0.tar.gzbin363 -> 400 bytes
-rw-r--r--tests/common/satisfy/libbaz-1.2.0.tar.gzbin0 -> 386 bytes
-rw-r--r--tests/common/satisfy/libbaz-2.0.0.tar.gzbin0 -> 388 bytes
-rw-r--r--tests/common/satisfy/libbaz-2.1.0.tar.gzbin0 -> 385 bytes
-rw-r--r--tests/common/satisfy/libbix-1.0.0.tar.gzbin0 -> 360 bytes
-rw-r--r--tests/common/satisfy/libbix-2.0.0.tar.gzbin0 -> 363 bytes
-rw-r--r--tests/common/satisfy/libbox-1.0.0.tar.gzbin0 -> 361 bytes
-rw-r--r--tests/common/satisfy/libbox-1.2.0.tar.gzbin0 -> 421 bytes
-rw-r--r--tests/common/satisfy/libbox-2.0.0.tar.gzbin0 -> 367 bytes
-rw-r--r--tests/common/satisfy/libbux-1.0.0.tar.gzbin0 -> 351 bytes
-rw-r--r--tests/common/satisfy/libfix-1.0.0.tar.gzbin0 -> 364 bytes
-rw-r--r--tests/common/satisfy/libfoo-0.1.0.tar.gzbin0 -> 355 bytes
-rw-r--r--tests/common/satisfy/libfoo-1.0.0.tar.gzbin369 -> 423 bytes
-rw-r--r--tests/common/satisfy/libfoo-1.1.0+1.tar.gzbin353 -> 349 bytes
-rw-r--r--tests/common/satisfy/libfoo-1.1.0+2.tar.gzbin0 -> 348 bytes
-rw-r--r--tests/common/satisfy/libfoo-1.1.0+3.tar.gzbin0 -> 347 bytes
-rw-r--r--tests/common/satisfy/libfoo-1.1.0.tar.gzbin349 -> 400 bytes
-rw-r--r--tests/common/satisfy/libfoo-1.1.1.tar.gzbin0 -> 404 bytes
-rw-r--r--tests/common/satisfy/libfoo-2.0.0.tar.gzbin0 -> 368 bytes
-rw-r--r--tests/common/satisfy/libfoo-3.0.0.tar.gzbin0 -> 416 bytes
-rw-r--r--tests/common/satisfy/libfox-1.1.0.tar.gzbin0 -> 370 bytes
-rw-r--r--tests/common/satisfy/libfox-2.0.0.tar.gzbin0 -> 367 bytes
-rw-r--r--tests/common/satisfy/libfox-2.1.0.tar.gzbin0 -> 374 bytes
-rw-r--r--tests/common/satisfy/libfox-3.0.0.tar.gzbin0 -> 379 bytes
-rw-r--r--tests/common/satisfy/t10/libbar-baz-1.0.0.tar.gzbin0 -> 399 bytes
-rw-r--r--tests/common/satisfy/t10/libbar-foo-1.0.0.tar.gzbin0 -> 401 bytes
-rw-r--r--tests/common/satisfy/t10/libbar-tests-1.0.0.tar.gzbin0 -> 632 bytes
-rw-r--r--tests/common/satisfy/t10/libfoo-tests-1.0.0.tar.gzbin413 -> 492 bytes
l---------tests/common/satisfy/t14a/libfoo-1.0.0.tar.gz1
l---------tests/common/satisfy/t14a/repositories.manifest1
l---------tests/common/satisfy/t14b/libfoo-1.1.0.tar.gz1
l---------tests/common/satisfy/t14b/repositories.manifest1
l---------tests/common/satisfy/t14c/libfoo-1.1.0+1.tar.gz1
l---------tests/common/satisfy/t14c/repositories.manifest1
l---------tests/common/satisfy/t14d/libfoo-1.1.0+2.tar.gz1
l---------tests/common/satisfy/t14d/repositories.manifest1
l---------tests/common/satisfy/t14e/libfoo-1.1.0+3.tar.gz1
l---------tests/common/satisfy/t14e/repositories.manifest1
l---------tests/common/satisfy/t14f/libfoo-1.1.1.tar.gz1
l---------tests/common/satisfy/t14f/repositories.manifest1
l---------tests/common/satisfy/t14i/libfoo-1.2.0.tar.gz1
l---------tests/common/satisfy/t14i/repositories.manifest1
l---------tests/common/satisfy/t2/libfoo-0.1.0.tar.gz1
l---------tests/common/satisfy/t4f/libbar-1.2.0.tar.gz1
l---------tests/common/satisfy/t4f/libbar-2.1.0.tar.gz1
l---------tests/common/satisfy/t4f/libbax-1.0.0.tar.gz1
l---------tests/common/satisfy/t4f/libbax-2.0.0.tar.gz1
l---------tests/common/satisfy/t4f/libbix-1.0.0.tar.gz1
l---------tests/common/satisfy/t4f/libbix-2.0.0.tar.gz1
l---------tests/common/satisfy/t4f/libbox-1.0.0.tar.gz1
l---------tests/common/satisfy/t4f/libbox-2.0.0.tar.gz1
l---------tests/common/satisfy/t4f/libbux-1.0.0.tar.gz1
l---------tests/common/satisfy/t4f/libfix-1.0.0.tar.gz1
l---------tests/common/satisfy/t4f/libfoo-2.0.0.tar.gz1
l---------tests/common/satisfy/t4f/libfox-1.1.0.tar.gz1
l---------tests/common/satisfy/t4f/libfox-2.0.0.tar.gz1
-rw-r--r--tests/common/satisfy/t4f/repositories.manifest1
l---------tests/common/satisfy/t4i/libbar-0.1.0.tar.gz1
l---------tests/common/satisfy/t4i/libbaz-2.0.0.tar.gz1
-rw-r--r--tests/common/satisfy/t4i/repositories.manifest1
l---------tests/common/satisfy/t4j/libbar-0.1.0.tar.gz1
l---------tests/common/satisfy/t4j/libbar-1.2.0.tar.gz1
l---------tests/common/satisfy/t4j/libbaz-1.2.0.tar.gz1
l---------tests/common/satisfy/t4j/libbaz-2.1.0.tar.gz1
l---------tests/common/satisfy/t4j/libfix-1.0.0.tar.gz1
l---------tests/common/satisfy/t4j/libfoo-3.0.0.tar.gz1
l---------tests/common/satisfy/t4j/libfox-0.0.1.tar.gz1
l---------tests/common/satisfy/t4j/libfox-2.1.0.tar.gz1
l---------tests/common/satisfy/t4j/libfox-3.0.0.tar.gz1
-rw-r--r--tests/common/satisfy/t4j/repositories.manifest1
-rw-r--r--tests/common/satisfy/t4k/libbar-1.0.0.tar.gzbin0 -> 364 bytes
-rw-r--r--tests/common/satisfy/t4k/libbaz-1.0.0.tar.gzbin0 -> 355 bytes
-rw-r--r--tests/common/satisfy/t4k/libfax-1.0.0.tar.gzbin0 -> 365 bytes
-rw-r--r--tests/common/satisfy/t4k/libfax-2.0.0.tar.gzbin0 -> 364 bytes
-rw-r--r--tests/common/satisfy/t4k/libfaz-1.0.0.tar.gzbin0 -> 360 bytes
-rw-r--r--tests/common/satisfy/t4k/libfaz-2.0.0.tar.gzbin0 -> 360 bytes
-rw-r--r--tests/common/satisfy/t4k/libfex-1.0.0.tar.gzbin0 -> 362 bytes
-rw-r--r--tests/common/satisfy/t4k/libfex-2.0.0.tar.gzbin0 -> 360 bytes
-rw-r--r--tests/common/satisfy/t4k/libfix-1.0.0.tar.gzbin0 -> 360 bytes
-rw-r--r--tests/common/satisfy/t4k/libfix-2.0.0.tar.gzbin0 -> 361 bytes
-rw-r--r--tests/common/satisfy/t4k/libfoo-1.0.0.tar.gzbin0 -> 359 bytes
-rw-r--r--tests/common/satisfy/t4k/libfoo-2.0.0.tar.gzbin0 -> 360 bytes
-rw-r--r--tests/common/satisfy/t4k/libfox-1.0.0.tar.gzbin0 -> 361 bytes
-rw-r--r--tests/common/satisfy/t4k/libfox-1.2.0.tar.gzbin0 -> 376 bytes
-rw-r--r--tests/common/satisfy/t4k/libfox-2.0.0.tar.gzbin0 -> 362 bytes
-rw-r--r--tests/common/satisfy/t4k/libfux-1.0.0.tar.gzbin0 -> 371 bytes
-rw-r--r--tests/common/satisfy/t4k/libfux-2.0.0.tar.gzbin0 -> 371 bytes
-rw-r--r--tests/common/satisfy/t4k/libfuz-1.0.0.tar.gzbin0 -> 349 bytes
-rw-r--r--tests/common/satisfy/t4k/libfuz-2.0.0.tar.gzbin0 -> 348 bytes
-rw-r--r--tests/common/satisfy/t4k/repositories.manifest1
l---------tests/common/satisfy/t5/libbox-1.2.0.tar.gz1
-rw-r--r--tests/config.testscript3
-rw-r--r--tests/pkg-build.testscript19261
l---------tests/pkg-build/libbar-0.0.3.tar.gz1
l---------tests/pkg-build/libbar-1.1.0.tar.gz1
l---------tests/pkg-build/libbar-1.2.0.tar.gz1
l---------tests/pkg-build/t14a1
l---------tests/pkg-build/t14b1
l---------tests/pkg-build/t14c1
l---------tests/pkg-build/t14d1
l---------tests/pkg-build/t14e1
l---------tests/pkg-build/t14f1
l---------tests/pkg-build/t14i1
l---------tests/pkg-build/t151
l---------tests/pkg-build/t4f1
l---------tests/pkg-build/t4i1
l---------tests/pkg-build/t4j1
l---------tests/pkg-build/t4k1
-rw-r--r--tests/pkg-checkout.testscript19
-rw-r--r--tests/pkg-configure.testscript10
-rw-r--r--tests/pkg-drop.testscript11
-rw-r--r--tests/pkg-fetch.testscript9
-rw-r--r--tests/pkg-system.testscript46
-rw-r--r--tests/pkg-verify.testscript28
l---------tests/pkg-verify/libbaz-1.0.0.tar.gz1
-rw-r--r--tests/remote-git.testscript4
-rw-r--r--tests/rep-fetch-git-refname.testscript4
-rw-r--r--tests/rep-fetch.testscript11
-rw-r--r--tests/rep-info.testscript68
l---------tests/rep-info/t151
295 files changed, 48249 insertions, 4830 deletions
diff --git a/.gitignore b/.gitignore
index c3de2e7..5046596 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,10 +5,16 @@
*.d
*.t
*.i
+*.i.*
*.ii
+*.ii.*
*.o
*.obj
+*.gcm
+*.pcm
+*.ifc
*.so
+*.dylib
*.dll
*.a
*.lib
diff --git a/LICENSE b/LICENSE
index 26fcce7..5a25163 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2014-2022 the build2 authors (see the AUTHORS and LEGAL files).
+Copyright (c) 2014-2024 the build2 authors (see the AUTHORS and LEGAL files).
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/NEWS b/NEWS
index 1c8eb35..24f2673 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,115 @@
+Version 0.16.0
+
+ * System package manager query/installation support for Debian and Fedora
+ (and alike).
+
+ The pkg-build command will now query (unless --sys-no-query is specified)
+ the system package manager on Debian (and alike, such as Ubuntu) and
+ Fedora (and alike, such as RHEL) for versions of packages that are
+ specified as coming from the system (the sys: scheme). For example, if
+ running the following command on one of these distributions:
+
+ bpkg build hello ?sys:libsqlite3
+
+ Then pkg-build will query the system package manager for the installed
+ version of libsqlite3 and fail if none is present.
+
+ Additionally, if --sys-install is specified, pkg-build will attempt to
+ install such packages if not present but available from the system package
+ repository.
+
+ Other relevant options include --sys-yes, --sys-no-fetch, --sys-no-stub,
+ and --sys-sudo. See bpkg-pkg-build(1) for details.
+
+ See also the `*-{name, version, to-downstream-version}` package manifest
+ values in the manual for details on the bpkg to distribution package name
+ and version mapping.
+
+ * Binary distribution package generation support for Debian and Fedora (and
+ alike).
+
+ The new pkg-bindist command can be used to automatically generate binary
+ distribution packages from bpkg packages for Debian (and alike, such as
+ Ubuntu), Fedora (and alike, such as RHEL), and for other operating systems
+ as installation archives. For Debian and Fedora, dependencies can be
+ satisfied with system packages, bpkg packages, or bundled. See
+ bpkg-pkg-bindist(1) for details.
+
+ * Package build configuration support (*-build-config manifest values).
+
+ A package can now customize in its manifest the build configuration used
+ by automated build bots. This includes specifying configuration variable
+ values, forcing specific versions of dependencies, satisfying dependencies
+ with system packages, and enabling/disabling build bot steps. For example:
+
+ # Test with extras enabled.
+ #
+ extras-build-config: config.libfoo.extra=true
+
+ # Test with system-installed libsqlite3.
+ #
+ system-builds: sys
+ system-build-config: ?sys:libsqlite3
+
+ # Enable Debian binary distribution generation and upload.
+ #
+ bindist-debian-builds: bindist
+ bindist-debian-build-include: linux_debian*-**
+ bindist-debian-build-include: linux_ubuntu*-**
+ bindist-debian-build-exclude: **
+ bindist-debian-build-config:
+ \
+ +bpkg.bindist.debian:
+ +bbot.bindist.upload:
+ \
+
+ See the `*-build-config` package manifest values in the manual for
+ details.
+
+ * New package-description and package-description-{file,type} package
+ manifest values.
+
+ Compared to the description* values, these can be used to provide a bpkg
+ package-specific description, such as the recommended usage, configuration
+ variables, etc. See the `description`, `package-description` package
+ manifest values in the manual for details.
+
+ * New changes-type package manifest value and type auto-detection, similar
+ to description.
+
+ See the `changes` package manifest value in the manual for details.
+
+ * New --deorphan pkg-build option.
+
+ This option can be used to replace orphaned packages (packages that no
+ longer have the corresponding package available in the repository it came
+ from) with the closest available package versions that satisfy all the
+ constraints.
+
+ * New --mask-repository* pkg-build options.
+
+ These options allow pretending for the duration of the pkg-build command
+ execution that the specified repository was removed as if by performing
+ the rep-remove command.
+
+ * New --dependent-exit pkg-drop option.
+
+ This option causes the pkg-drop command to silently exit with the
+ specified error code if attempting to drop dependent packages.
+
+ * New --git-capabilities common option to override auto-detected git
+ capabilities.
+
+ We now also assume the git repository protocol is smart if the HTTP
+ response code is 401 (requires authentication).
+
+ * curl is now used instead of wget as the default fetch program.
+
+ We used to prefer wget 1.16 because it has --show-progress which results
+ in nicer progress. But experience shows that wget is quite unreliable plus
+ with bdep always using curl, it would be strange to use both curl and wget
+ (and expecting the user to setup proxy, authentication, etc., for both).
+
Version 0.15.0
* New dependency declaration features:
diff --git a/bpkg/bpkg.cli b/bpkg/bpkg.cli
index 17ac927..6edea97 100644
--- a/bpkg/bpkg.cli
+++ b/bpkg/bpkg.cli
@@ -257,6 +257,11 @@ namespace bpkg
"\l{bpkg-pkg-clean(1)} \- clean package"
}
+ bool pkg-bindist|bindist
+ {
+ "\l{bpkg-pkg-bindist(1)} \- generate binary distribution package"
+ }
+
bool pkg-verify
{
"\l{bpkg-pkg-verify(1)} \- verify package archive"
diff --git a/bpkg/bpkg.cxx b/bpkg/bpkg.cxx
index 2a9fb6d..b5eaf7d 100644
--- a/bpkg/bpkg.cxx
+++ b/bpkg/bpkg.cxx
@@ -1,7 +1,11 @@
// file : bpkg/bpkg.cxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
+#include <bpkg/bpkg.hxx>
+
#include <limits>
+#include <cstdlib> // getenv()
+#include <cstring> // strcmp()
#include <iostream>
#include <exception> // set_terminate(), terminate_handler
#include <type_traits> // enable_if, is_base_of
@@ -13,9 +17,6 @@
#include <libbuild2/types.hxx>
#include <libbuild2/utility.hxx>
#include <libbuild2/module.hxx>
-#include <libbuild2/context.hxx>
-#include <libbuild2/scheduler.hxx>
-#include <libbuild2/file-cache.hxx>
#include <libbuild2/b-options.hxx>
#include <libbuild2/b-cmdline.hxx>
@@ -32,6 +33,9 @@
#include <libbuild2/cxx/init.hxx>
#include <libbuild2/version/init.hxx>
+#include <libbuild2/bash/init.hxx>
+#include <libbuild2/cli/init.hxx>
+
#include <bpkg/types.hxx>
#include <bpkg/utility.hxx>
@@ -47,6 +51,7 @@
#include <bpkg/cfg-link.hxx>
#include <bpkg/cfg-unlink.hxx>
+#include <bpkg/pkg-bindist.hxx>
#include <bpkg/pkg-build.hxx>
#include <bpkg/pkg-checkout.hxx>
#include <bpkg/pkg-clean.hxx>
@@ -106,8 +111,6 @@ namespace bpkg
static const char* build2_argv0;
- // Use build2_sched.started() to check if already initialized.
- //
void
build2_init (const common_options& co)
{
@@ -155,26 +158,39 @@ namespace bpkg
if (bo.help () || bo.version ())
fail << "--help or --version specified with --build-option";
+
+ // Make sure someone didn't specify a non-global override with
+ // --build-option, which messes our global/package-specific config
+ // variable split.
+ //
+ for (const string& v: bc.cmd_vars)
+ {
+ if (v[0] != '!')
+ fail << "non-global configuration variable '" << v
+ << "' specified with --build-option";
+ }
}
build2_cmd_vars = move (bc.cmd_vars);
init_diag (bc.verbosity,
bo.silent (),
- (bc.progress ? bc.progress :
- co.progress () ? optional<bool> (true) :
- co.no_progress () ? optional<bool> (false) : nullopt),
+ (bc.progress ? bc.progress :
+ co.progress () ? optional<bool> (true) :
+ co.no_progress () ? optional<bool> (false) : nullopt),
+ (bc.diag_color ? bc.diag_color :
+ co.diag_color () ? optional<bool> (true) :
+ co.no_diag_color () ? optional<bool> (false) : nullopt),
bo.no_line (),
bo.no_column (),
- bpkg::stderr_term);
+ bpkg::stderr_term.has_value ());
- // Note that we pretend to be in the serial-stop mode even though we may
- // build build system modules in parallel in order to get better
- // diagnostics for the common case.
+ // Also note that we now use this in pkg_configure(), but serial-stop
+ // is good for it as well.
//
init (&build2_terminate,
build2_argv0,
- true /* serial_stop */,
+ false /* serial_stop */,
bc.mtime_check,
bc.config_sub,
bc.config_guess);
@@ -191,6 +207,9 @@ namespace bpkg
load_builtin_module (&build2::version::build2_version_load);
load_builtin_module (&build2::in::build2_in_load);
+ load_builtin_module (&build2::bash::build2_bash_load);
+ load_builtin_module (&build2::cli::build2_cli_load);
+
// Note that while all we need is serial execution (all we do is load),
// in the process we may need to update some build system modules (while
// we only support built-in and standard pre-installed modules here, we
@@ -200,6 +219,10 @@ namespace bpkg
// serial execution, which is relatively cheap. The module building
// logic will then re-tune it to parallel if and when necessary.
//
+ // Note that we now also use this in pkg_configure() where we re-tune
+ // the scheduler (it may already have been initialized as part of the
+ // package skeleton work).
+ //
build2_sched.startup (1 /* max_active */,
1 /* init_active */,
bc.max_jobs,
@@ -212,7 +235,7 @@ namespace bpkg
}
catch (const build2::failed&)
{
- throw failed (); // Assume the diagnostics has already been issued.
+ throw bpkg::failed (); // Assume the diagnostics has already been issued.
}
}
@@ -441,8 +464,25 @@ init (const common_options& co,
{
optional<dir_path> extra;
if (o.default_options_specified ())
+ {
extra = o.default_options ();
+ // Note that load_default_options() expects absolute and normalized
+ // directory.
+ //
+ try
+ {
+ if (extra->relative ())
+ extra->complete ();
+
+ extra->normalize ();
+ }
+ catch (const invalid_path& e)
+ {
+ fail << "invalid --default-options value " << e.path;
+ }
+ }
+
default_options<O> dos (
load_default_options<O, cli::argv_file_scanner, cli::unknown_mode> (
nullopt /* sys_dir */,
@@ -465,31 +505,48 @@ init (const common_options& co,
// Verify common options.
//
- // Also merge the --progress/--no-progress options, overriding a less
- // specific flag with a more specific.
+ // Also merge the --*/--no-* options, overriding a less specific flag with
+ // a more specific.
+ //
//
- optional<bool> progress;
- auto merge_progress = [&progress]
- (const O& o,
- const default_options_entry<O>* e = nullptr)
+ optional<bool> progress, diag_color;
+ auto merge_no = [&progress, &diag_color] (
+ const O& o,
+ const default_options_entry<O>* e = nullptr)
{
- if (o.progress () && o.no_progress ())
{
- diag_record dr;
- (e != nullptr ? dr << fail (e->file) : dr << fail)
+ if (o.progress () && o.no_progress ())
+ {
+ diag_record dr;
+ (e != nullptr ? dr << fail (e->file) : dr << fail)
<< "both --progress and --no-progress specified";
+ }
+
+ if (o.progress ())
+ progress = true;
+ else if (o.no_progress ())
+ progress = false;
}
- if (o.progress ())
- progress = true;
- else if (o.no_progress ())
- progress = false;
+ {
+ if (o.diag_color () && o.no_diag_color ())
+ {
+ diag_record dr;
+ (e != nullptr ? dr << fail (e->file) : dr << fail)
+ << "both --diag-color and --no-diag-color specified";
+ }
+
+ if (o.diag_color ())
+ diag_color = true;
+ else if (o.no_diag_color ())
+ diag_color = false;
+ }
};
for (const default_options_entry<O>& e: dos)
- merge_progress (e.options, &e);
+ merge_no (e.options, &e);
- merge_progress (o);
+ merge_no (o);
o = merge_options (dos, o);
@@ -498,6 +555,12 @@ init (const common_options& co,
o.progress (*progress);
o.no_progress (!*progress);
}
+
+ if (diag_color)
+ {
+ o.diag_color (*diag_color);
+ o.no_diag_color (!*diag_color);
+ }
}
catch (const invalid_argument& e)
{
@@ -544,7 +607,24 @@ try
default_terminate = set_terminate (custom_terminate);
- stderr_term = fdterm (stderr_fd ());
+ if (fdterm (stderr_fd ()))
+ {
+ stderr_term = std::getenv ("TERM");
+
+ stderr_term_color =
+#ifdef _WIN32
+ // For now we disable color on Windows since it's unclear if/where/how
+ // it is supported. Maybe one day someone will figure this out.
+ //
+ false
+#else
+ // This test was lifted from GCC (Emacs shell sets TERM=dumb).
+ //
+ *stderr_term != nullptr && strcmp (*stderr_term, "dumb") != 0
+#endif
+ ;
+ }
+
exec_dir = path (argv[0]).directory ();
build2_argv0 = argv[0];
@@ -566,6 +646,7 @@ try
cout << "bpkg " << BPKG_VERSION_ID << endl
<< "libbpkg " << LIBBPKG_VERSION_ID << endl
<< "libbutl " << LIBBUTL_VERSION_ID << endl
+ << "host " << host_triplet << endl
<< "Copyright (c) " << BPKG_COPYRIGHT << "." << endl
<< "This is free software released under the MIT license." << endl;
return 0;
@@ -704,6 +785,7 @@ try
// These commands need the '--' separator to be kept in args.
//
+ PKG_COMMAND (bindist, true, true);
PKG_COMMAND (build, true, false);
PKG_COMMAND (clean, true, true);
PKG_COMMAND (configure, true, true);
diff --git a/bpkg/bpkg.hxx b/bpkg/bpkg.hxx
new file mode 100644
index 0000000..1ebbf85
--- /dev/null
+++ b/bpkg/bpkg.hxx
@@ -0,0 +1,35 @@
+// file : bpkg/bpkg.hxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BPKG_BPKG_HXX
+#define BPKG_BPKG_HXX
+
+// Embedded build system driver.
+//
+#include <libbuild2/context.hxx>
+#include <libbuild2/scheduler.hxx>
+#include <libbuild2/file-cache.hxx>
+
+#include <bpkg/types.hxx>
+#include <bpkg/utility.hxx>
+
+#include <bpkg/common-options.hxx>
+
+namespace bpkg
+{
+ // These are initialized by build2_init().
+ //
+ extern strings build2_cmd_vars;
+ extern build2::scheduler build2_sched;
+ extern build2::global_mutexes build2_mutexes;
+ extern build2::file_cache build2_fcache;
+
+ // Use build2_sched.started() to check if already initialized. Note that the
+ // scheduler is pre-tuned for serial execution.
+ //
+ //
+ void
+ build2_init (const common_options&);
+}
+
+#endif // BPKG_BPKG_HXX
diff --git a/bpkg/buildfile b/bpkg/buildfile
index cc9e7b5..0ba60dc 100644
--- a/bpkg/buildfile
+++ b/bpkg/buildfile
@@ -12,7 +12,7 @@ import libs = build2%lib{build2}
# NOTE: see also module loading in bpkg.cxx if adding anything here.
#
-for m: bin c cc cxx in version
+for m: bash bin c cc cli cxx in version
import libs += build2%lib{build2-$m}
import libs += libbpkg%lib{bpkg}
@@ -34,6 +34,7 @@ cfg-unlink-options \
common-options \
configuration-options \
help-options \
+pkg-bindist-options \
pkg-build-options \
pkg-checkout-options \
pkg-clean-options \
@@ -97,8 +98,13 @@ for t: cxx{**.test...}
# Build options.
#
-obj{utility}: cxx.poptions += -DBPKG_EXE_PREFIX='"'$bin.exe.prefix'"' \
--DBPKG_EXE_SUFFIX='"'$bin.exe.suffix'"'
+
+#cxx.poptions += -DBPKG_OUTPROC_CONFIGURE
+
+obj{utility}: cxx.poptions += \
+"-DBPKG_EXE_PREFIX=\"$bin.exe.prefix\"" \
+"-DBPKG_EXE_SUFFIX=\"$bin.exe.suffix\"" \
+"-DBPKG_HOST_TRIPLET=\"$cxx.target\""
# Pass the copyright notice extracted from the LICENSE file.
#
@@ -107,7 +113,7 @@ copyright = $process.run_regex( \
'Copyright \(c\) (.+) \(see the AUTHORS and LEGAL files\)\.', \
'\1')
-obj{bpkg}: cxx.poptions += -DBPKG_COPYRIGHT=\"$copyright\"
+obj{bpkg}: cxx.poptions += "-DBPKG_COPYRIGHT=\"$copyright\""
# Disable "unknown pragma" warnings.
#
@@ -125,10 +131,34 @@ switch $cxx.class
if ($cxx.id == 'msvc' && $cxx.version.major == 19 && $cxx.version.minor < 10)
cxx.coptions += /wd4503
-# Make sure backtrace includes function names.
+# Similar option to the build system driver.
#
-if ($cxx.target.class == 'linux')
- cxx.loptions += -rdynamic
+switch $cxx.target.class
+{
+ case 'linux'
+ {
+ # Make sure backtrace includes function names.
+ #
+ if ($cc.stdlib == 'glibc')
+ cxx.loptions += -rdynamic
+
+ # Make sure we use RPATH and not RUNPATH since the latter messes up
+ # dlopen().
+ #
+ cxx.loptions += -Wl,--disable-new-dtags
+ }
+ case 'windows'
+ {
+ # Adjust stack size (affects all threads).
+ #
+ # 8M 4M
+ stack_size = ($cxx.target.cpu == "x86_64" ? 8388608 : 4194304)
+
+ cxx.loptions += ($cxx.target.system == 'win32-msvc' \
+ ? "/STACK:$stack_size" \
+ : "-Wl,--stack,$stack_size")
+ }
+}
# Generated options parser.
#
@@ -146,6 +176,7 @@ if $cli.configured
# pkg-* command.
#
+ cli.cxx{pkg-bindist-options}: cli{pkg-bindist}
cli.cxx{pkg-build-options}: cli{pkg-build}
cli.cxx{pkg-checkout-options}: cli{pkg-checkout}
cli.cxx{pkg-clean-options}: cli{pkg-clean}
@@ -187,25 +218,36 @@ if $cli.configured
# Option length must be the same to get commands/topics/options aligned.
#
+ # Need global --suppress-undocumented because of few undocumented options
+ # in common.cli.
+ #
+ #
cli.options += --std c++11 -I $src_root --include-with-brackets \
--include-prefix bpkg --guard-prefix BPKG \
--cxx-prologue "#include <bpkg/types-parsers.hxx>" --cli-namespace bpkg::cli \
--generate-vector-scanner --generate-file-scanner --generate-group-scanner \
--keep-separator --generate-specifier --generate-parse --generate-merge \
--page-usage 'bpkg::print_$name$_' --ansi-color --ascii-tree \
---include-base-last --option-length 24
+--include-base-last --suppress-undocumented --option-length 25
# Both --*-usage options.
#
cli.cxx{common-options}: cli.options += --short-usage --long-usage \
--generate-modifier
- cli.cxx{bpkg-options}: cli.options += --short-usage --suppress-undocumented
+ cli.cxx{bpkg-options}: cli.options += --short-usage
cli.options += --long-usage # All other pages -- long usage.
- cli.cxx{pkg-build-options}: cli.options += --class-doc \
-bpkg::pkg_build_pkg_options=exclude-base --generate-modifier
+ cli.cxx{pkg-build-options}: cli.options += --generate-modifier \
+--class-doc bpkg::pkg_build_pkg_options=exclude-base
+
+ cli.cxx{pkg-bindist-options}: cli.options += \
+--class-doc bpkg::pkg_bindist_common_options=exclude-base \
+--class-doc bpkg::pkg_bindist_debian_options=exclude-base \
+--class-doc bpkg::pkg_bindist_fedora_options=exclude-base \
+--class-doc bpkg::pkg_bindist_archive_options=exclude-base \
+--omit-link-check --link-regex '%#.+%%'
# Avoid generating CLI runtime and empty inline file for help topics.
#
diff --git a/bpkg/common.cli b/bpkg/common.cli
index d62633a..c7d28bc 100644
--- a/bpkg/common.cli
+++ b/bpkg/common.cli
@@ -98,9 +98,6 @@ namespace bpkg
\cb{test}, etc."
}
- // In the future we may also have --structured-result, similar to the
- // build system.
- //
bool --no-result
{
"Don't print informational messages about the outcome of performing
@@ -109,6 +106,18 @@ namespace bpkg
instead, unless suppressed with \cb{--no-progress}."
}
+ string --structured-result
+ {
+ "<fmt>",
+ "Write the result of performing a command in a structured form. In
+ this mode, instead of printing to \cb{stderr} informational messages
+ about the outcome of performing a command or some of its parts,
+ \cb{bpkg} writes to \cb{stdout} a machine-readable result description
+ in the specified format. Not all commands support producing structured
+ result and valid <fmt> values are command-specific. Consult the command
+ documentation for details."
+ }
+
// When it comes to external programs (such as curl, git, etc), if stderr
// is not a terminal, the logic is actually tri-state: With --no-progress
// we suppress any progress. With --progress we request full progress.
@@ -134,6 +143,18 @@ namespace bpkg
network transfers, building, etc."
}
+ bool --diag-color
+ {
+ "Use color in diagnostics. If printing to a terminal the color is used
+ by default provided the terminal is not dumb. Use \cb{--no-diag-color}
+ to suppress."
+ }
+
+ bool --no-diag-color
+ {
+ "Don't use color in diagnostics."
+ }
+
path --build
{
"<path>",
@@ -167,8 +188,7 @@ namespace bpkg
If the fetch program is not specified, then \cb{bpkg} will try to
discover if one of the above programs is available and use that.
- Currently, \cb{bpkg} has the following preference order: \cb{wget}
- 1.16 or higher (supports \cb{--show-progress}), \cb{curl},
+ Currently, \cb{bpkg} has the following preference order: \cb{curl},
\cb{wget}, and \cb{fetch}."
}
@@ -180,6 +200,13 @@ namespace bpkg
specify multiple fetch options."
}
+ // Undocumented equivalents to bdep's --curl* options. We "merge" them
+ // into --fetch/--fetch-option in an ad hoc manner (see fetch.cxx for
+ // details).
+ //
+ path --curl;
+ strings --curl-option;
+
size_t --fetch-timeout
{
"<sec>",
@@ -363,6 +390,24 @@ namespace bpkg
"Assume the answer to all authentication prompts is \cb{no}."
}
+ git_capabilities_map --git-capabilities
+ {
+ "<up>=<pc>",
+ "Protocol capabilities (<pc>) for a \cb{git} repository URL prefix
+ (<up>). Valid values for the capabilities are \cb{dumb} (no shallow
+ clone support), \cb{smart} (support for shallow clone, but not for
+ fetching unadvertised commits), \cb{unadv} (support for shallow clone
+ and for fetching unadvertised commits). For example:
+
+ \
+ bpkg build https://example.org/foo.git#master \
+ --git-capabilities https://example.org=smart
+ \
+
+ See \l{bpkg-repository-types(1)} for details on the \cb{git} protocol
+ capabilities."
+ }
+
string --pager // String to allow empty value.
{
"<path>",
diff --git a/bpkg/database.cxx b/bpkg/database.cxx
index 6b135fc..65e3af8 100644
--- a/bpkg/database.cxx
+++ b/bpkg/database.cxx
@@ -349,7 +349,6 @@ namespace bpkg
else
config_orig = config;
-
string = '[' + config_orig.representation () + ']';
try
diff --git a/bpkg/database.hxx b/bpkg/database.hxx
index cfd2645..035ff60 100644
--- a/bpkg/database.hxx
+++ b/bpkg/database.hxx
@@ -158,6 +158,9 @@ namespace bpkg
// Move-constructible but not move-assignable.
//
+ // Note: noexcept is not specified since
+ // odb::sqlite::database(odb::sqlite::database&&) can throw.
+ //
database (database&&);
database& operator= (database&&) = delete;
@@ -501,8 +504,9 @@ namespace bpkg
linked_databases implicit_links_;
};
- // NOTE: remember to update config_package comparison operators and
- // compare_lazy_ptr if changing the database comparison operators.
+ // NOTE: remember to update package_key and package_version_key comparison
+ // operators and compare_lazy_ptr if changing the database comparison
+ // operators.
//
// Note that here we use the database address as the database identity since
// we don't suppose two database instances for the same configuration to
@@ -534,7 +538,7 @@ namespace bpkg
inline ostream&
operator<< (ostream& os, const database& db)
{
- const string& s (const_cast<database&> (db).string);
+ const string& s (db.string);
if (!s.empty ())
os << ' ' << s;
@@ -714,9 +718,10 @@ namespace bpkg
public small_vector<pair<reference_wrapper<database>, V>, 16>
{
public:
- using value_type = pair<reference_wrapper<database>, V>;
- using base_type = small_vector<value_type, 16>;
- using iterator = typename base_type::iterator;
+ using value_type = pair<reference_wrapper<database>, V>;
+ using base_type = small_vector<value_type, 16>;
+ using iterator = typename base_type::iterator;
+ using const_iterator = typename base_type::const_iterator;
using base_type::begin;
using base_type::end;
@@ -731,6 +736,16 @@ namespace bpkg
});
}
+ const_iterator
+ find (database& db) const
+ {
+ return find_if (begin (), end (),
+ [&db] (const value_type& i) -> bool
+ {
+ return i.first == db;
+ });
+ }
+
pair<iterator, bool>
insert (database& db, V&& v)
{
@@ -740,6 +755,17 @@ namespace bpkg
return make_pair (base_type::emplace (end (), db, move (v)), true);
}
+
+ V&
+ operator[] (database& db)
+ {
+ iterator i (find (db));
+
+ if (i == end ())
+ i = base_type::emplace (end (), db, V ());
+
+ return i->second;
+ }
};
}
diff --git a/bpkg/diagnostics.cxx b/bpkg/diagnostics.cxx
index ef87cab..cf096d1 100644
--- a/bpkg/diagnostics.cxx
+++ b/bpkg/diagnostics.cxx
@@ -103,7 +103,7 @@ namespace bpkg
void trace_mark_base::
execute (odb::connection&, const char* stmt)
{
- if (verb >= 5)
+ if (verb >= 6)
static_cast<trace_mark&> (*this) << stmt;
}
@@ -129,7 +129,7 @@ namespace bpkg
const basic_mark error ("error");
const basic_mark warn ("warning");
const basic_mark info ("info");
- const basic_mark text (nullptr);
+ const basic_mark text (nullptr, nullptr, nullptr, nullptr); // No frame.
const fail_mark fail ("error");
const fail_end endf;
}
diff --git a/bpkg/diagnostics.hxx b/bpkg/diagnostics.hxx
index e8d9f0a..a01d90c 100644
--- a/bpkg/diagnostics.hxx
+++ b/bpkg/diagnostics.hxx
@@ -118,9 +118,37 @@ namespace bpkg
//
using butl::diag_stream;
using butl::diag_epilogue;
+ using butl::diag_frame;
// Diagnostic facility, project specifics.
//
+
+ // Note: diag frames are not applied to text/trace diagnostics.
+ //
+ template <typename F>
+ struct diag_frame_impl: diag_frame
+ {
+ explicit
+ diag_frame_impl (F f): diag_frame (&thunk), func_ (move (f)) {}
+
+ private:
+ static void
+ thunk (const diag_frame& f, const butl::diag_record& r)
+ {
+ static_cast<const diag_frame_impl&> (f).func_ (
+ const_cast<diag_record&> (static_cast<const diag_record&> (r)));
+ }
+
+ const F func_;
+ };
+
+ template <typename F>
+ inline diag_frame_impl<F>
+ make_diag_frame (F f)
+ {
+ return diag_frame_impl<F> (move (f));
+ }
+
struct simple_prologue_base
{
explicit
@@ -184,7 +212,7 @@ namespace bpkg
basic_mark_base (const char* type,
const char* name = nullptr,
const void* data = nullptr,
- diag_epilogue* epilogue = nullptr)
+ diag_epilogue* epilogue = &diag_frame::apply)
: type_ (type), name_ (name), data_ (data), epilogue_ (epilogue) {}
simple_prologue
@@ -288,6 +316,7 @@ namespace bpkg
data,
[](const diag_record& r, butl::diag_writer* w)
{
+ diag_frame::apply (r);
r.flush (w);
throw failed ();
}) {}
diff --git a/bpkg/fetch-git.cxx b/bpkg/fetch-git.cxx
index 79567e6..d2c30a1 100644
--- a/bpkg/fetch-git.cxx
+++ b/bpkg/fetch-git.cxx
@@ -285,20 +285,7 @@ namespace bpkg
try
{
- ifdstream is (move (pipe.in), fdstream_mode::skip, ifdstream::badbit);
-
- // We could probably write something like this, instead:
- //
- // *diag_stream << is.rdbuf () << flush;
- //
- // However, it would never throw and we could potentially miss the
- // reading failure, unless we decide to additionally mess with the
- // diagnostics stream exception mask.
- //
- for (string l; !eof (getline (is, l)); )
- *diag_stream << l << endl;
-
- is.close ();
+ dump_stderr (move (pipe.in));
// Fall through.
}
@@ -549,7 +536,11 @@ namespace bpkg
// For HTTP(S) sense the protocol type by sending the first HTTP request of
// the fetch operation handshake and analyzing the first line of the
// response. Fail if connecting to the server failed, the response code
- // differs from 200, or reading the response body failed.
+ // differs from 200 and 401, or reading the response body failed. If the
+ // response code is 401 (requires authentication), then consider protocol as
+ // smart. The thinking here is that a git repository with support for
+ // authentication is likely one of the hosting places (like git{hub,lab})
+ // and is unlikely to be dumb.
//
// Note that, as a side-effect, this function checks the HTTP(S) server
// availability and so must be called prior to any git command that involves
@@ -565,21 +556,16 @@ namespace bpkg
// URLs, if possible. That's why the function requires the git version
// parameter.
//
- enum class capabilities
- {
- dumb, // No shallow clone support.
- smart, // Support for shallow clone, but not for unadvertised refs fetch.
- unadv // Support for shallow clone and for unadvertised refs fetch.
- };
+ using capabilities = git_protocol_capabilities;
static capabilities
sense_capabilities (const common_options& co,
- repository_url url,
+ const repository_url& repo_url,
const semantic_version& git_ver)
{
- assert (url.path);
+ assert (repo_url.path);
- switch (url.scheme)
+ switch (repo_url.scheme)
{
case repository_protocol::git:
case repository_protocol::ssh:
@@ -588,6 +574,9 @@ namespace bpkg
case repository_protocol::https: break; // Ask the server (see below).
}
+ // Craft the URL for sensing the capabilities.
+ //
+ repository_url url (repo_url);
path& up (*url.path);
if (!up.to_directory ())
@@ -601,19 +590,94 @@ namespace bpkg
url.query = "service=git-upload-pack";
string u (url.string ());
- process pr (start_fetch (co,
- u,
- path () /* out */,
- "git/" + git_ver.string ()));
+
+ // Start fetching, also trying to retrieve the HTTP status code.
+ //
+ // We unset failbit to properly handle an empty response (no refs) from
+ // the dumb server.
+ //
+ ifdstream is (ifdstream::badbit);
+
+ pair<process, uint16_t> ps (
+ start_fetch_http (co,
+ u,
+ is /* out */,
+ fdstream_mode::skip | fdstream_mode::binary,
+ stderr_mode::redirect_quiet,
+ "git/" + git_ver.string ()));
+
+ process& pr (ps.first);
+
+ // If the fetch program stderr is redirected, then read it out and pass
+ // through.
+ //
+ auto dump_stderr = [&pr] ()
+ {
+ if (pr.in_efd != nullfd)
+ try
+ {
+ bpkg::dump_stderr (move (pr.in_efd));
+ }
+ catch (const io_error&)
+ {
+ // Not much we can do here.
+ }
+ };
try
{
- // We unset failbit to properly handle an empty response (no refs) from
- // the dumb server.
+ // If authentication is required (HTTP status code is 401), then
+ // consider the protocol as smart. Drop the diagnostics if that's the
+ // case and dump it otherwise.
+ //
+ if (ps.second == 401)
+ {
+ if (verb >= 2)
+ {
+ info << "smart git protocol assumed for repository " << repo_url
+ << " due to authentication requirement" <<
+ info << "use --git-capabilities to override or suppress this "
+ << "diagnostics";
+ }
+
+ // Note that we don't care about the process exit code here and just
+ // silently wait for the process completion in the process object
+ // destructor. We, however, close the stream (reading out the
+ // content), so that the process won't get blocked writing to it.
+ //
+ // Also note that we drop the potentially redirected process stderr
+ // stream content. We even don't read it out, since we assume it fully
+ // fits into the pipe buffer.
+ //
+ is.close ();
+
+ return capabilities::smart;
+ }
+
+ // Fail on any other HTTP error (e.g., 404). In the case of a success
+ // code other than 200 (e.g. 204 (No Content)) just let the capabilities
+ // detection to take its course.
//
- ifdstream is (move (pr.in_ofd),
- fdstream_mode::skip | fdstream_mode::binary,
- ifdstream::badbit);
+ if (ps.second != 0 && (ps.second < 200 || ps.second >= 300))
+ {
+ // Note that we don't care about the process exit code here (see above
+ // for the reasoning).
+ //
+ is.close ();
+
+ // Dump the potentially redirected process stderr stream content since
+ // it may be helpful to the user.
+ //
+ // Note, however, that we don't know if it really contains the error
+ // description since the fetch program may even exit successfully (see
+ // start_fetch_http() for details). Thus, we additionally print the
+ // HTTP status code in the diagnostics.
+ //
+ dump_stderr ();
+
+ fail << "unable to fetch " << url <<
+ info << "HTTP status code " << ps.second << endg;
+ }
string l;
getline (is, l); // Is empty if no refs returned by the dumb server.
@@ -667,6 +731,8 @@ namespace bpkg
is.close ();
+ dump_stderr ();
+
if (pr.wait ())
return r;
@@ -674,6 +740,8 @@ namespace bpkg
}
catch (const io_error&)
{
+ dump_stderr ();
+
if (pr.wait ())
fail << "unable to read fetched " << url << endg;
@@ -1084,7 +1152,25 @@ namespace bpkg
// the first call, and so git version get assigned (and checked).
//
if (!cap)
- cap = sense_capabilities (co, url (), git_ver);
+ {
+ const repository_url& u (url ());
+
+ // Check if the protocol capabilities are overridden for this
+ // repository.
+ //
+ const git_capabilities_map& gcs (co.git_capabilities ());
+
+ if (!gcs.empty () && u.scheme != repository_protocol::file)
+ {
+ auto i (gcs.find_sup (u.string ()));
+
+ if (i != gcs.end ())
+ cap = i->second;
+ }
+
+ if (!cap)
+ cap = sense_capabilities (co, u, git_ver);
+ }
return *cap;
};
@@ -2606,6 +2692,9 @@ namespace bpkg
void
git_verify_symlinks (const common_options& co, const dir_path& dir)
{
+ if ((verb && !co.no_progress ()) || co.progress ())
+ text << "verifying symlinks...";
+
verify_symlinks (co, dir, dir_path () /* prefix */);
}
@@ -2917,6 +3006,9 @@ namespace bpkg
bool revert,
bool ie)
{
+ if (!revert && ((verb && !co.no_progress ()) || co.progress ()))
+ text << "fixing up symlinks...";
+
try
{
optional<bool> r (
diff --git a/bpkg/fetch-pkg.cxx b/bpkg/fetch-pkg.cxx
index ca4767f..721e4b8 100644
--- a/bpkg/fetch-pkg.cxx
+++ b/bpkg/fetch-pkg.cxx
@@ -97,20 +97,80 @@ namespace bpkg
if (exists (df))
fail << "file " << df << " already exists";
+ // Currently we only expect fetching a package archive via the HTTP(S)
+ // protocol.
+ //
+ switch (u.scheme)
+ {
+ case repository_protocol::git:
+ case repository_protocol::ssh:
+ case repository_protocol::file: assert (false);
+ case repository_protocol::http:
+ case repository_protocol::https: break;
+ }
+
auto_rmfile arm (df);
- process pr (start_fetch (o,
- u.string (),
- df,
- string () /* user_agent */,
- o.pkg_proxy ()));
- if (!pr.wait ())
+ // Note that a package file may not be present in the repository due to
+ // outdated repository information. Thus, while fetching the file we also
+ // try to retrieve the HTTP status code. If the HTTP status code is
+ // retrieved and is 404 (not found) or the fetch program doesn't support
+ // its retrieval and fails, then we also advise the user to re-fetch the
+ // repositories.
+ //
+ pair<process, uint16_t> ps (
+ start_fetch_http (o,
+ u.string (),
+ df,
+ string () /* user_agent */,
+ o.pkg_proxy ()));
+
+ process& pr (ps.first);
+ uint16_t sc (ps.second);
+
+ // Fail if the fetch process didn't exit normally with 0 code or the HTTP
+ // status code is retrieved and differs from 200.
+ //
+ // Note that the diagnostics may potentially look as follows:
+ //
+ // foo-1.0.0.tar.gz:
+ // ###################################################### 100.0%
+ // error: unable to fetch package https://example.org/1/foo-1.0.0.tar.gz
+ // info: repository metadata could be stale
+ // info: run 'bpkg rep-fetch' (or equivalent) to update
+ //
+ // It's a bit unfortunate that the 100% progress indicator can be shown
+ // for a potential HTTP error and it doesn't seem that we can easily fix
+ // that. Note, however, that this situation is not very common and
+ // probably that's fine.
+ //
+ if (!pr.wait () || (sc != 0 && sc != 200))
{
// While it is reasonable to assuming the child process issued
// diagnostics, some may not mention the URL.
//
- fail << "unable to fetch " << u <<
- info << "re-run with -v for more information";
+ diag_record dr (fail);
+ dr << "unable to fetch package " << u;
+
+ // Print the HTTP status code in the diagnostics on the request failure,
+ // unless it cannot be retrieved or is 404. Note that the fetch program
+ // may even exit successfully on such a failure (see start_fetch_http()
+ // for details) and issue no diagnostics at all.
+ //
+ if (sc != 0 && sc != 200 && sc != 404)
+ dr << info << "HTTP status code " << sc;
+
+ // If not found, advise the user to re-fetch the repositories. Note that
+ // if the status code cannot be retrieved, we assume it could be 404 and
+ // advise.
+ //
+ if (sc == 404 || sc == 0)
+ {
+ dr << info << "repository metadata could be stale" <<
+ info << "run 'bpkg rep-fetch' (or equivalent) to update";
+ }
+ else if (verb < 2)
+ dr << info << "re-run with -v for more information";
}
arm.cancel ();
diff --git a/bpkg/fetch.cxx b/bpkg/fetch.cxx
index 5ecddbb..5b59d42 100644
--- a/bpkg/fetch.cxx
+++ b/bpkg/fetch.cxx
@@ -3,9 +3,12 @@
#include <bpkg/fetch.hxx>
+#include <libbutl/curl.hxx>
+
#include <bpkg/diagnostics.hxx>
using namespace std;
+using namespace butl;
namespace bpkg
{
@@ -84,13 +87,21 @@ namespace bpkg
}
}
- static process
+ // Note that there is no easy way to retrieve the HTTP status code for wget
+ // (there is no reliable way to redirect the status line/headers to stdout)
+ // and thus we always return 0. Due to the status code unavailability there
+ // is no need to redirect stderr and thus we ignore the stderr mode.
+ //
+ static pair<process, uint16_t>
start_wget (const path& prog,
const optional<size_t>& timeout,
bool progress,
bool no_progress,
+ stderr_mode,
const strings& ops,
const string& url,
+ ifdstream* out_is,
+ fdstream_mode out_ism,
const path& out,
const string& user_agent,
const string& http_proxy)
@@ -108,8 +119,8 @@ namespace bpkg
};
// Wget 1.16 introduced the --show-progress option which in the quiet mode
- // shows a nice and tidy progress bar (if only it also showed errors, then
- // it would have been perfect).
+ // (-q) shows a nice and tidy progress bar (if only it also showed errors,
+ // then it would have been perfect).
//
bool has_show_progress (wget_major > 1 ||
(wget_major == 1 && wget_minor >= 16));
@@ -222,12 +233,19 @@ namespace bpkg
// just the file name (rather than the whole path) in the progress
// report. Process exceptions must be handled by the caller.
//
- return fo
- ? process (pp, args.data (),
- 0, 1, 2,
- out.directory ().string ().c_str (),
- env.vars)
- : process (pp, args.data (), 0, -1, 2, nullptr /* cwd */, env.vars);
+ process pr (fo
+ ? process (pp, args.data (),
+ 0, 1, 2,
+ out.directory ().string ().c_str (),
+ env.vars)
+ : process (pp, args.data (),
+ 0, -1, 2,
+ nullptr /* cwd */, env.vars));
+
+ if (!fo && out_is != nullptr)
+ out_is->open (move (pr.in_ofd), out_ism);
+
+ return make_pair (move (pr), 0);
}
// curl
@@ -275,13 +293,23 @@ namespace bpkg
return false;
}
- static process
+ // If HTTP status code needs to be retrieved (out_is != NULL), then open the
+ // passed stream and read out the status line(s) extracting the status code
+ // and the headers. Otherwise, return 0 indicating that the status code is
+ // not available. In the former case if the output file is also specified,
+ // then read out and save the file if the status code is 200 and drop the
+ // HTTP response body otherwise.
+ //
+ static pair<process, uint16_t>
start_curl (const path& prog,
const optional<size_t>& timeout,
bool progress,
bool no_progress,
+ stderr_mode err_mode,
const strings& ops,
const string& url,
+ ifdstream* out_is,
+ fdstream_mode out_ism,
const path& out,
const string& user_agent,
const string& http_proxy)
@@ -294,7 +322,6 @@ namespace bpkg
cstrings args {
prog.string ().c_str (),
- "-f", // Fail on HTTP errors (e.g., 404).
"-L", // Follow redirects.
"-A", ua.c_str ()
};
@@ -313,28 +340,33 @@ namespace bpkg
// Higher than that -- run it verbose. Always show the progress
// bar if requested explicitly, even in the quiet mode.
//
- if (verb < (fo ? 1 : 2))
+ bool quiet (err_mode == stderr_mode::redirect_quiet);
+
+ if (!quiet)
{
- if (!progress)
+ if (verb < (fo ? 1 : 2))
{
- suppress_progress ();
- no_progress = false; // Already suppressed.
+ if (!progress)
+ {
+ suppress_progress ();
+ no_progress = false; // Already suppressed.
+ }
}
+ else if (fo && verb == 1)
+ {
+ if (!no_progress)
+ args.push_back ("--progress-bar");
+ }
+ else if (verb > 3)
+ args.push_back ("-v");
}
- else if (fo && verb == 1)
- {
- if (!no_progress)
- args.push_back ("--progress-bar");
- }
- else if (verb > 3)
- args.push_back ("-v");
// Suppress progress.
//
// Note: the `-v -s` options combination is valid and results in a verbose
// output without progress.
//
- if (no_progress)
+ if (no_progress || quiet)
suppress_progress ();
// Set download timeout if requested.
@@ -355,7 +387,7 @@ namespace bpkg
// Output. By default curl writes to stdout.
//
- if (fo)
+ if (fo && out_is == nullptr) // Output to file and don't query HTTP status?
{
args.push_back ("-o");
args.push_back (out.string ().c_str ());
@@ -369,11 +401,31 @@ namespace bpkg
args.push_back (http_proxy.c_str ());
}
+ // Status code.
+ //
+ // Add the --include|-i option if HTTP status code needs to be retrieved
+ // in order to include the HTTP response headers to the output. Otherwise,
+ // add the --fail|-f option not to print the response body and exit with
+ // non-zero status code on HTTP error (e.g., 404), so that the caller can
+ // recognize the request failure.
+ //
+ // Note that older versions of curl (e.g., 7.55.1) ignore the --include|-i
+ // option in the presence of the --fail|-f option on HTTP errors and don't
+ // print the response status line and headers.
+ //
+ if (out_is != nullptr)
+ args.push_back ("-i");
+ else
+ args.push_back ("-f");
+
args.push_back (url.c_str ());
args.push_back (nullptr);
process_path pp (process::path_search (args[0]));
+ // Let's still print the command line in the quiet mode to ease the
+ // troubleshooting.
+ //
if (verb >= 2)
print_process (args);
else if (verb == 1 && fo && !no_progress)
@@ -386,9 +438,115 @@ namespace bpkg
// Process exceptions must be handled by the caller.
//
- return fo
- ? process (pp, args.data ())
- : process (pp, args.data (), 0, -1);
+ process pr (fo && out_is == nullptr
+ ? process (pp, args.data ())
+ : process (pp, args.data (),
+ 0, -1, err_mode == stderr_mode::pass ? 2 : -1));
+
+ // Close the process stdout stream and read stderr stream out and dump.
+ //
+ // Needs to be called prior to failing, so that the process won't get
+ // blocked writing to stdout and so that stderr get dumped before the
+ // error message we issue.
+ //
+ auto close_streams = [&pr, out_is, err_mode] ()
+ {
+ try
+ {
+ assert (out_is != nullptr);
+
+ out_is->close ();
+
+ if (err_mode != stderr_mode::pass)
+ bpkg::dump_stderr (move (pr.in_efd));
+ }
+ catch (const io_error&)
+ {
+ // Not much we can do here.
+ }
+ };
+
+ // If HTTP status code needs to be retrieved, then open the passed stream
+ // and read out the status line(s) and headers.
+ //
+ // Note that this implementation is inspired by the bdep's
+ // http_service::post() function.
+ //
+ uint16_t sc (0);
+
+ if (out_is != nullptr)
+ try
+ {
+ ifdstream& is (*out_is);
+ is.open (move (pr.in_ofd), out_ism);
+ sc = curl::read_http_status (*out_is).code;
+ }
+ catch (const invalid_argument& e)
+ {
+ close_streams ();
+
+ fail << "unable to read HTTP response status line for " << url << ": "
+ << e;
+ }
+ catch (const io_error&)
+ {
+ close_streams ();
+
+ fail << "unable to read HTTP response status line for " << url;
+ }
+
+ // If the output file is specified and the HTTP status code needs to also
+ // be retrieved, then read out and save the file if the status code is 200
+ // and drop the HTTP response body otherwise.
+ //
+ bool io_read; // If true then io_error relates to a read operation.
+ if (fo && out_is != nullptr)
+ try
+ {
+ ifdstream& is (*out_is);
+
+ // Read and save the file if the HTTP status code is 200.
+ //
+ if (sc == 200)
+ {
+ io_read = false;
+ ofdstream os (out, fdopen_mode::binary);
+
+ bufstreambuf* buf (dynamic_cast<bufstreambuf*> (is.rdbuf ()));
+ assert (buf != nullptr);
+
+ for (io_read = true;
+ is.peek () != istream::traits_type::eof (); // Potentially reads.
+ io_read = true)
+ {
+ size_t n (buf->egptr () - buf->gptr ());
+
+ io_read = false;
+ os.write (buf->gptr (), n);
+
+ buf->gbump (static_cast<int> (n));
+ }
+
+ io_read = false;
+ os.close ();
+ }
+
+ // Close the stream, skipping the remaining content, if present.
+ //
+ io_read = true;
+ is.close ();
+ }
+ catch (const io_error& e)
+ {
+ close_streams ();
+
+ if (io_read)
+ fail << "unable to read fetched " << url << ": " << e;
+ else
+ fail << "unable to write to " << out << ": " << e;
+ }
+
+ return make_pair (move (pr), sc);
}
// fetch
@@ -438,13 +596,24 @@ namespace bpkg
return false;
}
- static process
+ // Note that there is no easy way to retrieve the HTTP status code for the
+ // fetch program and thus we always return 0.
+ //
+ // Also note that in the redirect* stderr modes we nevertheless redirect
+ // stderr to prevent the fetch program from interactively querying the user
+ // for the credentials. Thus, we also respect the redirect_quiet mode in
+ // contrast to start_wget().
+ //
+ static pair<process, uint16_t>
start_fetch (const path& prog,
const optional<size_t>& timeout,
bool progress,
bool no_progress,
+ stderr_mode err_mode,
const strings& ops,
const string& url,
+ ifdstream* out_is,
+ fdstream_mode out_ism,
const path& out,
const string& user_agent,
const string& http_proxy)
@@ -476,23 +645,28 @@ namespace bpkg
// unless the verbosity level is greater than three, in which case we will
// run verbose (and with progress). That's the best we can do.
//
- if (verb < (fo ? 1 : 2))
+ bool quiet (err_mode == stderr_mode::redirect_quiet);
+
+ if (!quiet)
{
- if (!progress)
+ if (verb < (fo ? 1 : 2))
{
- args.push_back ("-q");
- no_progress = false; // Already suppressed with -q.
+ if (!progress)
+ {
+ args.push_back ("-q");
+ no_progress = false; // Already suppressed with -q.
+ }
+ }
+ else if (verb > 3)
+ {
+ args.push_back ("-v");
+ no_progress = false; // Don't be quiet in the verbose mode (see above).
}
- }
- else if (verb > 3)
- {
- args.push_back ("-v");
- no_progress = false; // Don't be quiet in the verbose mode (see above).
}
// Suppress progress.
//
- if (no_progress)
+ if (no_progress || quiet)
args.push_back ("-q");
// Set download timeout if requested.
@@ -534,6 +708,9 @@ namespace bpkg
env.vars = evars;
}
+ // Let's still print the command line in the quiet mode to ease the
+ // troubleshooting.
+ //
if (verb >= 2)
print_process (env, args);
@@ -542,12 +719,19 @@ namespace bpkg
// just the file name (rather than the whole path) in the progress
// report. Process exceptions must be handled by the caller.
//
- return fo
- ? process (pp, args.data (),
- 0, 1, 2,
- out.directory ().string ().c_str (),
- env.vars)
- : process (pp, args.data (), 0, -1, 2, nullptr /* cwd */, env.vars);
+ process pr (fo
+ ? process (pp, args.data (),
+ 0, 1, 2,
+ out.directory ().string ().c_str (),
+ env.vars)
+ : process (pp, args.data (),
+ 0, -1, err_mode == stderr_mode::pass ? 2 : -1,
+ nullptr /* cwd */, env.vars));
+
+ if (!fo && out_is != nullptr)
+ out_is->open (move (pr.in_ofd), out_ism);
+
+ return make_pair (move (pr), 0);
}
// The dispatcher.
@@ -555,7 +739,7 @@ namespace bpkg
// Cache the result of finding/testing the fetch program. Sometimes a simple
// global variable is really the right solution...
//
- enum class fetch_kind {wget, curl, fetch};
+ enum class fetch_kind {curl, wget, fetch};
static path path_;
static fetch_kind kind_;
@@ -575,20 +759,20 @@ namespace bpkg
const path& n (p.leaf ());
const string& s (n.string ());
- if (s.find ("wget") != string::npos)
- {
- if (!check_wget (p))
- fail << p << " does not appear to be the 'wget' program";
-
- kind_ = fetch_kind::wget;
- }
- else if (s.find ("curl") != string::npos)
+ if (s.find ("curl") != string::npos)
{
if (!check_curl (p))
fail << p << " does not appear to be the 'curl' program";
kind_ = fetch_kind::curl;
}
+ else if (s.find ("wget") != string::npos)
+ {
+ if (!check_wget (p))
+ fail << p << " does not appear to be the 'wget' program";
+
+ kind_ = fetch_kind::wget;
+ }
else if (s.find ("fetch") != string::npos)
{
if (!check_fetch (p))
@@ -599,15 +783,45 @@ namespace bpkg
else
fail << "unknown fetch program " << p;
}
+ else if (o.curl_specified ())
+ {
+ const path& p (path_ = o.curl ());
+
+ if (!check_curl (p))
+ fail << p << " does not appear to be the 'curl' program";
+
+ kind_ = fetch_kind::curl;
+ }
else
{
// See if any is available. The preference order is:
//
+ // curl
+ // wget
+ // fetch
+#if 1
+ if (check_curl (path_ = path ("curl")))
+ {
+ kind_ = fetch_kind::curl;
+ }
+ else if (check_wget (path_ = path ("wget")))
+ {
+ kind_ = fetch_kind::wget;
+ }
+#else
+ // Old preference order:
+ //
// wget 1.16 or up
// curl
// wget
// fetch
//
+ // We used to prefer wget 1.16 because it has --show-progress which
+ // results in nicer progress. But experience shows that wget is quite
+ // unreliable plus with bdep always using curl, it would be strange
+ // to use both curl and wget (and expecting the user to setup proxy,
+ // authentication, etc., for both).
+ //
bool wg (check_wget (path_ = path ("wget")));
if (wg && (wget_major > 1 || (wget_major == 1 && wget_minor >= 16)))
@@ -623,12 +837,13 @@ namespace bpkg
path_ = path ("wget");
kind_ = fetch_kind::wget;
}
+#endif
else if (check_fetch (path_ = path ("fetch")))
{
kind_ = fetch_kind::fetch;
}
else
- fail << "unable to find 'wget', 'curl', or 'fetch'" <<
+ fail << "unable to find 'curl', 'wget', or 'fetch'" <<
info << "use --fetch to specify the fetch program location";
if (verb >= 3)
@@ -639,27 +854,47 @@ namespace bpkg
return kind_;
}
- process
+ static pair<process, uint16_t>
start_fetch (const common_options& o,
const string& src,
+ ifdstream* out_is,
+ fdstream_mode out_ism,
+ stderr_mode err_mode,
const path& out,
const string& user_agent,
const url& proxy)
{
- process (*f) (const path&,
- const optional<size_t>&,
- bool,
- bool,
- const strings&,
- const string&,
- const path&,
- const string&,
- const string&) = nullptr;
-
- switch (check (o))
+ // Currently, for the sake of simplicity, we don't support redirecting
+ // stderr if we fetch into a file.
+ //
+ assert (out.empty () || err_mode == stderr_mode::pass);
+
+ // If out_is is not NULL and out is not empty, then the former argument is
+ // unused by the caller and only indicates that the HTTP status code still
+ // needs to be retrieved while the requested file needs to be saved. In
+ // this case if the fetch program doesn't provide an easy way to retrieve
+ // the HTTP status code, then the respective start_*() function can just
+ // ignore the referred stream. Otherwise, it may or may not use it for
+ // convenience but should close it before returning if it does.
+ //
+ pair<process, uint16_t> (*f) (const path&,
+ const optional<size_t>&,
+ bool,
+ bool,
+ stderr_mode,
+ const strings&,
+ const string&,
+ ifdstream*,
+ fdstream_mode,
+ const path&,
+ const string&,
+ const string&) = nullptr;
+
+ fetch_kind fk (check (o));
+ switch (fk)
{
- case fetch_kind::wget: f = &start_wget; break;
case fetch_kind::curl: f = &start_curl; break;
+ case fetch_kind::wget: f = &start_wget; break;
case fetch_kind::fetch: f = &start_fetch; break;
}
@@ -732,12 +967,40 @@ namespace bpkg
}
}
+ // Note that the merge semantics here is not 100% accurate since we may
+ // override "later" --fetch-option with "earlier" --curl-option.
+ // However, this should be close enough for our use-case, which is
+ // bdep's --curl-option values overriding --fetch-option specified in
+ // the default options file. The situation that we will mis-handle is
+ // when both are specified on the command line, for example,
+ // --curl-option --max-time=2 --bpkg-option --fetch-option=--max-time=1,
+ // but that feel quite far fetched to complicate things here.
+ //
+ const strings& fos (o.fetch_option ());
+ const strings& cos (o.curl_option ());
+
+ const strings& os (
+ fk != fetch_kind::curl || cos.empty ()
+ ? fos
+ : (fos.empty ()
+ ? cos
+ : [&fos, &cos] ()
+ {
+ strings r (fos.begin (), fos.end ());
+ r.insert (r.end (), cos.begin (), cos.end ());
+ return r;
+ } ()));
+
+
return f (path_,
timeout,
o.progress (),
o.no_progress (),
- o.fetch_option (),
+ err_mode,
+ os,
!http_url.empty () ? http_url : src,
+ out_is,
+ out_ism,
out,
user_agent,
http_proxy);
@@ -752,4 +1015,61 @@ namespace bpkg
throw failed ();
}
}
+
+ process
+ start_fetch (const common_options& o,
+ const string& src,
+ const path& out,
+ const string& user_agent,
+ const url& proxy)
+ {
+ return start_fetch (o,
+ src,
+ nullptr /* out_is */,
+ fdstream_mode::none,
+ stderr_mode::pass,
+ out,
+ user_agent,
+ proxy).first;
+ }
+
+ pair<process, uint16_t>
+ start_fetch_http (const common_options& o,
+ const string& src,
+ ifdstream& out,
+ fdstream_mode out_mode,
+ stderr_mode err_mode,
+ const string& user_agent,
+ const url& proxy)
+ {
+ return start_fetch (o,
+ src,
+ &out,
+ out_mode,
+ err_mode,
+ path () /* out */,
+ user_agent,
+ proxy);
+ }
+
+ pair<process, uint16_t>
+ start_fetch_http (const common_options& o,
+ const string& src,
+ const path& out,
+ const string& user_agent,
+ const url& proxy)
+ {
+ assert (!out.empty ());
+
+ ifdstream is (ifdstream::badbit | ifdstream::failbit);
+
+ return start_fetch (o,
+ src,
+ &is,
+ fdstream_mode::skip | fdstream_mode::binary,
+ stderr_mode::pass,
+ out,
+ user_agent,
+ proxy);
+ }
}
diff --git a/bpkg/fetch.hxx b/bpkg/fetch.hxx
index c077079..daf1ffe 100644
--- a/bpkg/fetch.hxx
+++ b/bpkg/fetch.hxx
@@ -138,11 +138,65 @@ namespace bpkg
// option for details).
//
process
- start_fetch (const common_options& o,
+ start_fetch (const common_options&,
const string& url,
const path& out = {},
const string& user_agent = {},
const butl::url& proxy = {});
+
+ // Similar to the above but can only be used for fetching HTTP(S) URL to a
+ // file. Additionally return the HTTP status code, if the underlying fetch
+ // program provides an easy way to retrieve it, and 0 otherwise.
+ //
+ pair<process, uint16_t>
+ start_fetch_http (const common_options&,
+ const string& url,
+ const path& out,
+ const string& user_agent = {},
+ const butl::url& proxy = {});
+
+ // As above but fetches HTTP(S) URL to stdout, which can be read by the
+ // caller from the specified stream. On HTTP errors (e.g., 404) this stream
+ // may contain the error description returned by the server and the process
+ // may exit with 0 code.
+ //
+ // Fetch process stderr redirect mode.
+ //
+ enum class stderr_mode
+ {
+ // Don't redirect stderr.
+ //
+ pass,
+
+ // If the underlying fetch program provides an easy way to retrieve the
+ // HTTP status code, then redirect the fetch process stderr to a pipe, so
+ // that depending on the returned status code the caller can either drop
+ // or dump the fetch process diagnostics. Otherwise, may still redirect
+ // stderr for some implementation-specific reasons (to prevent the
+ // underlying fetch program from interacting with the user, etc). The
+ // caller can detect whether stderr is redirected or not by checking
+ // process::in_efd.
+ //
+ redirect,
+
+ // As above but if stderr is redirected, minimize the amount of
+ // diagnostics printed by the fetch program by only printing errors. That
+ // allows the caller to read stdout and stderr streams sequentially in the
+ // blocking mode by assuming that the diagnostics always fits into the
+ // pipe buffer. If stderr is not redirected, then ignore this mode in
+ // favor of the more informative diagnostics.
+ //
+ redirect_quiet
+ };
+
+ pair<process, uint16_t>
+ start_fetch_http (const common_options&,
+ const string& url,
+ ifdstream& out,
+ fdstream_mode out_mode,
+ stderr_mode,
+ const string& user_agent = {},
+ const butl::url& proxy = {});
}
#endif // BPKG_FETCH_HXX
diff --git a/bpkg/manifest-utility.cxx b/bpkg/manifest-utility.cxx
index 5bd273d..afcb1f7 100644
--- a/bpkg/manifest-utility.cxx
+++ b/bpkg/manifest-utility.cxx
@@ -24,7 +24,9 @@ namespace bpkg
const path manifest_file ("manifest");
vector<package_info>
- package_b_info (const common_options& o, const dir_paths& ds, bool ext_mods)
+ package_b_info (const common_options& o,
+ const dir_paths& ds,
+ b_info_flags fl)
{
path b (name_b (o));
@@ -33,7 +35,7 @@ namespace bpkg
{
b_info (r,
ds,
- ext_mods,
+ fl,
verb,
[] (const char* const args[], size_t n)
{
@@ -55,6 +57,8 @@ namespace bpkg
if (r.size () < ds.size ()) dr << ds[r.size ()] << ' ';
dr << "info: " << e <<
info << "produced by '" << b << "'; use --build to override" << endf;
+
+ return vector<package_info> (); // Work around GCC 13.2.1 segfault.
}
}
@@ -131,12 +135,16 @@ namespace bpkg
if (s[n] == '\0') // No version (constraint) is specified?
return nullopt;
- const char* v (s + n); // Constraint or version including '/'.
+ const char* v (s + n); // Constraint or version including leading '/'.
+
+ if (version_only && v[0] != '/')
+ fail << "exact package version expected instead of version constraint "
+ << "in '" << s << "'";
- // If only the version is allowed or the package name is followed by '/'
- // then fallback to the version parsing.
+ // If the package name is followed by '/' then fallback to the version
+ // parsing.
//
- if (version_only || v[0] == '/')
+ if (v[0] == '/')
try
{
return version_constraint (
@@ -309,9 +317,11 @@ namespace bpkg
}
package_version_infos
- package_versions (const common_options& o, const dir_paths& ds)
+ package_versions (const common_options& o,
+ const dir_paths& ds,
+ b_info_flags fl)
{
- vector<b_project_info> pis (package_b_info (o, ds, false /* ext_mods */));
+ vector<b_project_info> pis (package_b_info (o, ds, fl));
package_version_infos r;
r.reserve (pis.size ());
@@ -346,7 +356,7 @@ namespace bpkg
const vector<package_info::subproject>& sps (
pi != nullptr
? pi->subprojects
- : package_b_info (o, d, false /* ext_mods */).subprojects);
+ : package_b_info (o, d, b_info_flags::subprojects).subprojects);
for (const package_info::subproject& sp: sps)
cs.append (sp.path.string ());
@@ -373,8 +383,7 @@ namespace bpkg
{
vector<pair<path, path>> r;
- for (const dir_entry& de:
- dir_iterator (config, false /* ignore_dangling */))
+ for (const dir_entry& de: dir_iterator (config, dir_iterator::no_follow))
{
if (de.type () == entry_type::regular)
{
diff --git a/bpkg/manifest-utility.hxx b/bpkg/manifest-utility.hxx
index 85fbaee..a5ea962 100644
--- a/bpkg/manifest-utility.hxx
+++ b/bpkg/manifest-utility.hxx
@@ -7,6 +7,8 @@
#include <libbpkg/manifest.hxx>
#include <libbpkg/package-name.hxx>
+#include <libbutl/b.hxx> // b_info_flags
+
#include <bpkg/types.hxx>
#include <bpkg/utility.hxx>
@@ -17,17 +19,19 @@ namespace bpkg
extern const path signature_file; // signature.manifest
extern const path manifest_file; // manifest
+ using butl::b_info_flags;
+
// Obtain build2 projects info for package source or output directories.
//
vector<package_info>
- package_b_info (const common_options&, const dir_paths&, bool ext_mods);
+ package_b_info (const common_options&, const dir_paths&, b_info_flags);
// As above but return the info for a single package directory.
//
inline package_info
- package_b_info (const common_options& o, const dir_path& d, bool ext_mods)
+ package_b_info (const common_options& o, const dir_path& d, b_info_flags fl)
{
- vector<package_info> r (package_b_info (o, dir_paths ({d}), ext_mods));
+ vector<package_info> r (package_b_info (o, dir_paths ({d}), fl));
return move (r[0]);
}
@@ -131,14 +135,14 @@ namespace bpkg
using package_version_infos = vector<package_version_info>;
package_version_infos
- package_versions (const common_options&, const dir_paths&);
+ package_versions (const common_options&, const dir_paths&, b_info_flags);
// As above but return the version of a single package.
//
inline package_version_info
- package_version (const common_options& o, const dir_path& d)
+ package_version (const common_options& o, const dir_path& d, b_info_flags fl)
{
- package_version_infos r (package_versions (o, dir_paths ({d})));
+ package_version_infos r (package_versions (o, dir_paths ({d}), fl));
return move (r[0]);
}
@@ -147,7 +151,8 @@ namespace bpkg
//
// Pass the build2 project info for the package, if available, to speed up
// the call and NULL otherwise (in which case it will be queried by the
- // implementation).
+ // implementation). In the former case it is assumed that the package info
+ // has been retrieved with the b_info_flags::subprojects flag.
//
string
package_checksum (const common_options&,
diff --git a/bpkg/options-types.hxx b/bpkg/options-types.hxx
index 6576060..30d52a0 100644
--- a/bpkg/options-types.hxx
+++ b/bpkg/options-types.hxx
@@ -8,6 +8,8 @@
#include <cassert>
#include <utility> // move()
+#include <libbutl/prefix-map.hxx>
+
#include <bpkg/types.hxx>
namespace bpkg
@@ -27,6 +29,17 @@ namespace bpkg
json
};
+ enum class git_protocol_capabilities
+ {
+ dumb, // No shallow clone support.
+ smart, // Support for shallow clone, but not for unadvertised refs fetch.
+ unadv // Support for shallow clone and for unadvertised refs fetch.
+ };
+
+ using git_capabilities_map = butl::prefix_map<string,
+ git_protocol_capabilities,
+ '/'>;
+
// Qualified options.
//
// An option that uses this type can have its values qualified using the
diff --git a/bpkg/package-query.cxx b/bpkg/package-query.cxx
index 8d7b652..a90cdef 100644
--- a/bpkg/package-query.cxx
+++ b/bpkg/package-query.cxx
@@ -6,11 +6,15 @@
#include <bpkg/package.hxx>
#include <bpkg/package-odb.hxx>
#include <bpkg/database.hxx>
+#include <bpkg/rep-mask.hxx>
+#include <bpkg/satisfaction.hxx>
using namespace std;
namespace bpkg
{
+ // Search in the imaginary system repository.
+ //
vector<shared_ptr<available_package>> imaginary_stubs;
shared_ptr<available_package>
@@ -25,6 +29,36 @@ namespace bpkg
return i != imaginary_stubs.end () ? *i : nullptr;
}
+ // Search in the existing packages registry.
+ //
+ vector<pair<reference_wrapper<database>,
+ shared_ptr<available_package>>> existing_packages;
+
+ pair<shared_ptr<available_package>, lazy_shared_ptr<repository_fragment>>
+ find_existing (database& db,
+ const package_name& name,
+ const optional<version_constraint>& c)
+ {
+ pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>> r;
+
+ for (const auto& p: existing_packages)
+ {
+ if (p.first == db &&
+ p.second->id.name == name &&
+ (!c || satisfies (p.second->version, *c)))
+ {
+ r.first = p.second;
+ r.second = lazy_shared_ptr<repository_fragment> (db, empty_string);
+ break;
+ }
+ }
+
+ return r;
+ }
+
+ // Search in real repositories.
+ //
linked_databases repo_configs;
linked_databases
@@ -159,6 +193,9 @@ namespace bpkg
{
const lazy_shared_ptr<repository_fragment>& lrf (pl.repository_fragment);
+ if (rep_masked_fragment (lrf))
+ continue;
+
// First check the repository itself.
//
if (lrf.object_id () == rf->name)
@@ -175,27 +212,36 @@ namespace bpkg
for (const lazy_weak_ptr<repository>& r: cs)
{
- const auto& frs (r.load ()->fragments);
+ if (!rep_masked (r))
+ {
+ const auto& frs (r.load ()->fragments);
- if (find_if (frs.begin (), frs.end (), pr) != frs.end ())
- return lrf.load ();
+ if (find_if (frs.begin (), frs.end (), pr) != frs.end ())
+ return lrf.load ();
+ }
}
if (prereq)
{
for (const lazy_weak_ptr<repository>& r: ps)
{
- const auto& frs (r.load ()->fragments);
+ if (!rep_masked (r))
+ {
+ const auto& frs (r.load ()->fragments);
- if (find_if (frs.begin (), frs.end (), pr) != frs.end ())
- return lrf.load ();
+ if (find_if (frs.begin (), frs.end (), pr) != frs.end ())
+ return lrf.load ();
+ }
}
}
+ }
- // Finally, load the complements and prerequisites and check them
- // recursively.
- //
- for (const lazy_weak_ptr<repository>& cr: cs)
+ // Finally, load the complements and prerequisites and check them
+ // recursively.
+ //
+ for (const lazy_weak_ptr<repository>& cr: cs)
+ {
+ if (!rep_masked (cr))
{
for (const auto& fr: cr.load ()->fragments)
{
@@ -203,19 +249,22 @@ namespace bpkg
// prerequisites? I'd say not.
//
if (shared_ptr<repository_fragment> r =
- find (fr.fragment.load (), ap, chain, false))
+ find (fr.fragment.load (), ap, chain, false /* prereq */))
return r;
}
}
+ }
- if (prereq)
+ if (prereq)
+ {
+ for (const lazy_weak_ptr<repository>& pr: ps)
{
- for (const lazy_weak_ptr<repository>& pr: ps)
+ if (!rep_masked (pr))
{
for (const auto& fr: pr.load ()->fragments)
{
if (shared_ptr<repository_fragment> r =
- find (fr.fragment.load (), ap, chain, false))
+ find (fr.fragment.load (), ap, chain, false /* prereq */))
return r;
}
}
@@ -311,11 +360,11 @@ namespace bpkg
}
// Sort the available package fragments in the package version descending
- // order and suppress duplicate packages.
+ // order and suppress duplicate packages and, optionally, older package
+ // revisions.
//
static void
- sort_dedup (vector<pair<shared_ptr<available_package>,
- lazy_shared_ptr<repository_fragment>>>& pfs)
+ sort_dedup (available_packages& pfs, bool suppress_older_revisions = false)
{
sort (pfs.begin (), pfs.end (),
[] (const auto& x, const auto& y)
@@ -323,37 +372,42 @@ namespace bpkg
return x.first->version > y.first->version;
});
- pfs.erase (unique (pfs.begin(), pfs.end(),
- [] (const auto& x, const auto& y)
- {
- return x.first->version == y.first->version;
- }),
- pfs.end ());
+ pfs.erase (
+ unique (pfs.begin(), pfs.end(),
+ [suppress_older_revisions] (const auto& x, const auto& y)
+ {
+ return x.first->version.compare (y.first->version,
+ suppress_older_revisions) == 0;
+ }),
+ pfs.end ());
}
- vector<pair<shared_ptr<available_package>,
- lazy_shared_ptr<repository_fragment>>>
+ available_packages
find_available (const linked_databases& dbs,
const package_name& name,
const optional<version_constraint>& c)
{
- vector<pair<shared_ptr<available_package>,
- lazy_shared_ptr<repository_fragment>>> r;
+ available_packages r;
for (database& db: dbs)
{
for (shared_ptr<available_package> ap:
pointer_result (query_available (db, name, c)))
{
- // An available package should come from at least one fetched
- // repository fragment.
+ // All repository fragments the package comes from are equally good,
+ // so we pick the first unmasked one.
//
- assert (!ap->locations.empty ());
+ for (const auto& pl: ap->locations)
+ {
+ const lazy_shared_ptr<repository_fragment>& lrf (
+ pl.repository_fragment);
- // All repository fragments the package comes from are equally good, so
- // we pick the first one.
- //
- r.emplace_back (move (ap), ap->locations[0].repository_fragment);
+ if (!rep_masked_fragment (lrf))
+ {
+ r.emplace_back (move (ap), lrf);
+ break;
+ }
+ }
}
}
@@ -376,15 +430,13 @@ namespace bpkg
return r;
}
- vector<pair<shared_ptr<available_package>,
- lazy_shared_ptr<repository_fragment>>>
+ available_packages
find_available (const package_name& name,
const optional<version_constraint>& c,
const config_repo_fragments& rfs,
bool prereq)
{
- vector<pair<shared_ptr<available_package>,
- lazy_shared_ptr<repository_fragment>>> r;
+ available_packages r;
for (const auto& dfs: rfs)
{
@@ -417,6 +469,8 @@ namespace bpkg
const lazy_shared_ptr<repository_fragment>& rf,
bool prereq)
{
+ assert (!rep_masked_fragment (rf));
+
vector<shared_ptr<available_package>> r;
database& db (rf.database ());
@@ -440,6 +494,8 @@ namespace bpkg
bool prereq,
bool revision)
{
+ assert (!rep_masked_fragment (rf));
+
// Filter the result based on the repository fragment to which each
// version belongs.
//
@@ -529,23 +585,101 @@ namespace bpkg
const shared_ptr<selected_package>& sp)
{
available_package_id pid (sp->name, sp->version);
+ const string& cn (sp->repository_fragment.canonical_name ());
+
for (database& ddb: dependent_repo_configs (db))
{
shared_ptr<available_package> ap (ddb.find<available_package> (pid));
if (ap != nullptr && !ap->stub ())
{
- if (shared_ptr<repository_fragment> f = ddb.find<repository_fragment> (
- sp->repository_fragment.canonical_name ()))
- return make_pair (ap,
- lazy_shared_ptr<repository_fragment> (ddb,
- move (f)));
+ if (shared_ptr<repository_fragment> f =
+ ddb.find<repository_fragment> (cn))
+ {
+ if (!rep_masked_fragment (ddb, f))
+ return make_pair (ap,
+ lazy_shared_ptr<repository_fragment> (ddb,
+ move (f)));
+ }
}
}
return make_pair (find_available (options, db, sp), nullptr);
}
+ available_packages
+ find_available_all (const linked_databases& dbs,
+ const package_name& name,
+ bool suppress_older_revisions)
+ {
+ // Collect all the databases linked explicitly and implicitly to the
+ // specified databases, recursively.
+ //
+ // Note that this is a superset of the database cluster, since we descend
+ // into the database links regardless of their types (see
+ // cluster_configs() for details).
+ //
+ linked_databases all_dbs;
+ all_dbs.reserve (dbs.size ());
+
+ auto add = [&all_dbs] (database& db, const auto& add)
+ {
+ if (find (all_dbs.begin (), all_dbs.end (), db) != all_dbs.end ())
+ return;
+
+ all_dbs.push_back (db);
+
+ {
+ const linked_configs& cs (db.explicit_links ());
+ for (auto i (cs.begin_linked ()); i != cs.end (); ++i)
+ add (i->db, add);
+ }
+
+ {
+ const linked_databases& cs (db.implicit_links ());
+ for (auto i (cs.begin_linked ()); i != cs.end (); ++i)
+ add (*i, add);
+ }
+ };
+
+ for (database& db: dbs)
+ add (db, add);
+
+ // Collect all the available packages from all the collected databases.
+ //
+ available_packages r;
+
+ for (database& db: all_dbs)
+ {
+ for (shared_ptr<available_package> ap:
+ pointer_result (
+ query_available (db, name, nullopt /* version_constraint */)))
+ {
+ // All repository fragments the package comes from are equally good,
+ // so we pick the first unmasked one.
+ //
+ for (const auto& pl: ap->locations)
+ {
+ const lazy_shared_ptr<repository_fragment>& lrf (
+ pl.repository_fragment);
+
+ if (!rep_masked_fragment (lrf))
+ {
+ r.emplace_back (move (ap), lrf);
+ break;
+ }
+ }
+ }
+ }
+
+ // Sort the result in the package version descending order and suppress
+ // duplicates and, if requested, older package revisions.
+ //
+ sort_dedup (r, suppress_older_revisions);
+
+ return r;
+ }
+
pair<shared_ptr<available_package>,
lazy_shared_ptr<repository_fragment>>
make_available_fragment (const common_options& options,
@@ -572,14 +706,18 @@ namespace bpkg
// anyway.
//
lazy_shared_ptr<repository_fragment> rf;
+ const string& cn (sp->repository_fragment.canonical_name ());
for (database& ddb: dependent_repo_configs (db))
{
- if (shared_ptr<repository_fragment> f = ddb.find<repository_fragment> (
- sp->repository_fragment.canonical_name ()))
+ if (shared_ptr<repository_fragment> f =
+ ddb.find<repository_fragment> (cn))
{
- rf = lazy_shared_ptr<repository_fragment> (ddb, move (f));
- break;
+ if (!rep_masked_fragment (ddb, f))
+ {
+ rf = lazy_shared_ptr<repository_fragment> (ddb, move (f));
+ break;
+ }
}
}
diff --git a/bpkg/package-query.hxx b/bpkg/package-query.hxx
index ebe92ac..de389c1 100644
--- a/bpkg/package-query.hxx
+++ b/bpkg/package-query.hxx
@@ -75,14 +75,13 @@ namespace bpkg
// Try to find packages that optionally satisfy the specified version
// constraint in multiple databases, suppressing duplicates. Return the list
// of packages and repository fragments in which each was found in the
- // package version descending or empty list if none were found. Note that a
- // stub satisfies any constraint.
+ // package version descending order or empty list if none were found. Note
+ // that a stub satisfies any constraint.
//
// Note that we return (loaded) lazy_shared_ptr in order to also convey
// the database to which it belongs.
//
- vector<pair<shared_ptr<available_package>,
- lazy_shared_ptr<repository_fragment>>>
+ available_packages
find_available (const linked_databases&,
const package_name&,
const optional<version_constraint>&);
@@ -94,8 +93,7 @@ namespace bpkg
using config_repo_fragments =
database_map<vector<shared_ptr<repository_fragment>>>;
- vector<pair<shared_ptr<available_package>,
- lazy_shared_ptr<repository_fragment>>>
+ available_packages
find_available (const package_name&,
const optional<version_constraint>&,
const config_repo_fragments&,
@@ -155,7 +153,11 @@ namespace bpkg
bool revision = false);
// Try to find an available package corresponding to the specified selected
- // package and, if not found, return a transient one.
+ // package and, if not found, return a transient one. The search is
+ // performed in the ultimate dependent configurations of the selected
+ // package (see dependent_repo_configs() for details).
+ //
+ // NOTE: repo_configs needs to be filled prior to the function call.
//
shared_ptr<available_package>
find_available (const common_options&,
@@ -167,22 +169,44 @@ namespace bpkg
// left empty and that the returned repository fragment could be NULL if the
// package is an orphan.
//
+ // NOTE: repo_configs needs to be filled prior to the function call.
+ //
pair<shared_ptr<available_package>,
lazy_shared_ptr<repository_fragment>>
find_available_fragment (const common_options&,
database&,
const shared_ptr<selected_package>&);
+ // Try to find packages in multiple databases, traversing the explicitly and
+ // implicitly linked databases recursively and suppressing duplicates and,
+ // optionally, older package revisions. Return the list of packages and
+ // repository fragments in which each was found in the package version
+ // descending order or empty list if none were found.
+ //
+ // Note that we return (loaded) lazy_shared_ptr in order to also convey
+ // the database to which it belongs.
+ //
+ available_packages
+ find_available_all (const linked_databases&,
+ const package_name&,
+ bool suppress_older_revisions = true);
+
// Create a transient (or fake, if you prefer) available_package object
// corresponding to the specified selected object. Note that the package
// locations list is left empty and that the returned repository fragment
// could be NULL if the package is an orphan.
//
- // Note also that in our model we assume that make_available_fragment() is
+ // Note that the repository fragment is searched in the ultimate dependent
+ // configurations of the selected package (see dependent_repo_configs() for
+ // details).
+ //
+ // Also note that in our model we assume that make_available_fragment() is
// only called if there is no real available_package. This makes sure that
// if the package moves (e.g., from testing to stable), then we will be
// using stable to resolve its dependencies.
//
+ // NOTE: repo_configs needs to be filled prior to the function call.
+ //
pair<shared_ptr<available_package>,
lazy_shared_ptr<repository_fragment>>
make_available_fragment (const common_options&,
@@ -202,6 +226,34 @@ namespace bpkg
shared_ptr<available_package>
find_imaginary_stub (const package_name&);
+ // Try to find an available package in the existing packages registry. Such
+ // a registry is configuration-specific and contains package versions
+ // specified by the user on the command line as archives or directories for
+ // specific configurations (see pkg-build for details on such packages).
+ //
+ // Note that semantically such a registry can be considered as an imaginary
+ // repository which complements all the real repositories fetched in the
+ // respective configuration. Also note that normally this repository is used
+ // first (by calling this function) when trying to resolve a dependency
+ // package, prior to searching in the real repositories.
+ //
+ extern vector<pair<reference_wrapper<database>,
+ shared_ptr<available_package>>> existing_packages;
+
+ pair<shared_ptr<available_package>, lazy_shared_ptr<repository_fragment>>
+ find_existing (database&,
+ const package_name&,
+ const optional<version_constraint>&);
+
+ inline pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>>
+ find_existing (const package_name& n,
+ const optional<version_constraint>& c,
+ const lazy_shared_ptr<repository_fragment>& rf)
+ {
+ return find_existing (rf.database (), n, c);
+ }
+
// Configurations to use as the repository information sources.
//
// The list normally contains the current configurations and configurations
@@ -217,6 +269,11 @@ namespace bpkg
// Return the ultimate dependent configurations for packages in this
// configuration.
//
+ // Specifically, this is an intersection of all the dependent configurations
+ // for the specified configuration (see database::dependent_configs() for
+ // details) and configurations which contain repository information
+ // (repo_configs).
+ //
linked_databases
dependent_repo_configs (database&);
}
diff --git a/bpkg/package-skeleton.cxx b/bpkg/package-skeleton.cxx
index 6163d6c..78635e7 100644
--- a/bpkg/package-skeleton.cxx
+++ b/bpkg/package-skeleton.cxx
@@ -16,12 +16,14 @@
#include <libbuild2/context.hxx>
#include <libbuild2/variable.hxx>
#include <libbuild2/operation.hxx>
+#include <libbuild2/diagnostics.hxx>
#include <libbuild2/lexer.hxx>
#include <libbuild2/parser.hxx>
#include <libbuild2/config/utility.hxx>
+#include <bpkg/bpkg.hxx>
#include <bpkg/package.hxx>
#include <bpkg/database.hxx>
#include <bpkg/manifest-utility.hxx>
@@ -31,19 +33,6 @@ using namespace butl;
namespace bpkg
{
- // These are defined in bpkg.cxx and initialized in main().
- //
- extern strings build2_cmd_vars;
- extern build2::scheduler build2_sched;
- extern build2::global_mutexes build2_mutexes;
- extern build2::file_cache build2_fcache;
-
- void
- build2_init (const common_options&);
-}
-
-namespace bpkg
-{
// Check whether the specified configuration variable override has a project
// variable (i.e., its name starts with config.<project>). If the last
// argument is not NULL, then set it to the length of the variable portion.
@@ -152,7 +141,7 @@ namespace bpkg
// (build2 stuff is only forward-declared in the header).
//
static build2::scope_map::iterator
- bootstrap (package_skeleton&, const strings&);
+ bootstrap (package_skeleton&, const strings&, bool old = false);
package_skeleton::
~package_skeleton ()
@@ -160,18 +149,23 @@ namespace bpkg
}
package_skeleton::
- package_skeleton (package_skeleton&& v)
+ package_skeleton (package_skeleton&& v) noexcept
: package (move (v.package)),
system (v.system),
available (move (v.available)),
+ load_config_flags (v.load_config_flags),
co_ (v.co_),
db_ (v.db_),
var_prefix_ (move (v.var_prefix_)),
config_vars_ (move (v.config_vars_)),
+ config_var_srcs_ (move (v.config_var_srcs_)),
disfigure_ (v.disfigure_),
config_srcs_ (v.config_srcs_),
src_root_ (move (v.src_root_)),
out_root_ (move (v.out_root_)),
+ src_root_specified_ (v.src_root_specified_),
+ old_src_root_ (move (v.old_src_root_)),
+ old_out_root_ (move (v.old_out_root_)),
created_ (v.created_),
verified_ (v.verified_),
loaded_old_config_ (v.loaded_old_config_),
@@ -194,21 +188,26 @@ namespace bpkg
}
package_skeleton& package_skeleton::
- operator= (package_skeleton&& v)
+ operator= (package_skeleton&& v) noexcept
{
if (this != &v)
{
package = move (v.package);
system = v.system;
available = move (v.available);
+ load_config_flags = v.load_config_flags;
co_ = v.co_;
db_ = v.db_;
var_prefix_ = move (v.var_prefix_);
config_vars_ = move (v.config_vars_);
+ config_var_srcs_ = move (v.config_var_srcs_);
disfigure_ = v.disfigure_;
config_srcs_ = v.config_srcs_;
src_root_ = move (v.src_root_);
out_root_ = move (v.out_root_);
+ src_root_specified_ = v.src_root_specified_;
+ old_src_root_ = move (v.old_src_root_);
+ old_out_root_ = move (v.old_out_root_);
created_ = v.created_;
verified_ = v.verified_;
loaded_old_config_ = v.loaded_old_config_;
@@ -238,14 +237,19 @@ namespace bpkg
: package (v.package),
system (v.system),
available (v.available),
+ load_config_flags (v.load_config_flags),
co_ (v.co_),
db_ (v.db_),
var_prefix_ (v.var_prefix_),
config_vars_ (v.config_vars_),
+ config_var_srcs_ (v.config_var_srcs_),
disfigure_ (v.disfigure_),
config_srcs_ (v.config_srcs_),
src_root_ (v.src_root_),
out_root_ (v.out_root_),
+ src_root_specified_ (v.src_root_specified_),
+ old_src_root_ (v.old_src_root_),
+ old_out_root_ (v.old_out_root_),
created_ (v.created_),
verified_ (v.verified_),
loaded_old_config_ (v.loaded_old_config_),
@@ -307,10 +311,14 @@ namespace bpkg
bool df,
const vector<config_variable>* css,
optional<dir_path> src_root,
- optional<dir_path> out_root)
+ optional<dir_path> out_root,
+ optional<dir_path> old_src_root,
+ optional<dir_path> old_out_root,
+ uint16_t lcf)
: package (move (pk)),
system (sys),
available (move (ap)),
+ load_config_flags (lcf),
co_ (&co),
db_ (&package.db.get ()),
var_prefix_ ("config." + package.name.variable ()),
@@ -323,14 +331,21 @@ namespace bpkg
else
assert (system);
+ if (!config_vars_.empty ())
+ config_var_srcs_ = vector<config_source> (config_vars_.size (),
+ config_source::user);
+
// We are only interested in old user configuration variables.
//
if (config_srcs_ != nullptr)
{
if (find_if (config_srcs_->begin (), config_srcs_->end (),
- [] (const config_variable& v)
+ [this] (const config_variable& v)
{
- return v.source == config_source::user;
+ return ((load_config_flags & load_config_user) != 0 &&
+ v.source == config_source::user) ||
+ ((load_config_flags & load_config_dependent) != 0 &&
+ v.source == config_source::dependent);
}) == config_srcs_->end ())
config_srcs_ = nullptr;
}
@@ -352,8 +367,8 @@ namespace bpkg
{
// For now tighten it even further so that we can continue
// using repositories without package skeleton information
- // (bootstrap.build, root.build). See load_old_config() for
- // details.
+ // (bootstrap.build, root.build). See
+ // load_old_config_impl() for details.
//
#if 0
return project_override (v, var_prefix_);
@@ -369,11 +384,27 @@ namespace bpkg
{
src_root_ = move (*src_root);
+ assert (!src_root_.empty ()); // Must exist.
+
+ src_root_specified_ = true;
+
if (out_root)
out_root_ = move (*out_root);
}
else
assert (!out_root);
+
+ if (old_src_root)
+ {
+ old_src_root_ = move (*old_src_root);
+
+ assert (!old_src_root_.empty ()); // Must exist.
+
+ if (old_out_root)
+ old_out_root_ = move (*old_out_root);
+ }
+ else
+ assert (!old_out_root);
}
// Serialize a variable assignment for a command line override.
@@ -391,7 +422,7 @@ namespace bpkg
else
{
storage.clear ();
- names_view nv (reverse (val, storage));
+ names_view nv (reverse (val, storage, true /* reduce */));
if (!nv.empty ())
{
@@ -406,7 +437,8 @@ namespace bpkg
return r;
}
- // Reverse value to names.
+ // Reverse value to names reducing empty simple value to empty list of
+ // names.
//
static optional<build2::names>
reverse_value (const build2::value& val)
@@ -417,7 +449,7 @@ namespace bpkg
return nullopt;
names storage;
- names_view nv (reverse (val, storage));
+ names_view nv (reverse (val, storage, true /* reduce */));
return (nv.data () == storage.data ()
? move (storage)
@@ -462,11 +494,12 @@ namespace bpkg
ctx_ == nullptr);
if (!loaded_old_config_)
- load_old_config ();
+ load_old_config_impl ();
try
{
using namespace build2;
+ using build2::info;
// This is what needs to happen to the variables of different origins in
// the passed configuration:
@@ -486,13 +519,22 @@ namespace bpkg
// construction (in evaluate_{prefer_accept,require}()): we do not add
// as dependent variables that have the override origin.
//
- scope& rs (
- *bootstrap (
- *this, merge_cmd_vars (dependent_cmd_vars (cfg)))->second.front ());
+ scope* rs;
+ {
+ auto df = build2::make_diag_frame (
+ [this] (const build2::diag_record& dr)
+ {
+ dr << info << "while loading build system skeleton of package "
+ << package.name;
+ });
- // Load project's root.build.
- //
- load_root (rs);
+ rs = bootstrap (
+ *this, merge_cmd_vars (dependent_cmd_vars (cfg)))->second.front ();
+
+ // Load project's root.build.
+ //
+ load_root (*rs);
+ }
package_configuration old (move (cfg));
cfg.package = move (old.package);
@@ -517,14 +559,14 @@ namespace bpkg
//
// Note: go straight for the public variable pool.
//
- for (const variable& var: rs.ctx.var_pool)
+ for (const variable& var: rs->ctx.var_pool)
{
if (!project_variable (var.name, var_prefix_))
continue;
using config::variable_origin;
- pair<variable_origin, lookup> ol (config::origin (rs, var));
+ pair<variable_origin, lookup> ol (config::origin (*rs, var));
switch (ol.first)
{
@@ -694,11 +736,12 @@ namespace bpkg
ctx_ == nullptr);
if (!loaded_old_config_)
- load_old_config ();
+ load_old_config_impl ();
try
{
using namespace build2;
+ using build2::info;
// For now we treat any failure to load root.build as bad configuration,
// which is not very precise. One idea to make this more precise would
@@ -706,15 +749,23 @@ namespace bpkg
// (e.g., either via an attribute or via special config.assert directive
// or some such).
//
- // For now we rely on load_defaults() and load_old_config() to "flush"
- // out any unrelated errors (e.g., one of the modules configuration is
- // bad, etc). However, if that did not happen naturally, then we must do
- // it ourselves.
+ // For now we rely on load_defaults() and load_old_config_impl() to
+ // "flush" out any unrelated errors (e.g., one of the modules
+ // configuration is bad, etc). However, if that did not happen
+ // naturally, then we must do it ourselves.
//
if (!verified_)
{
+ auto df = build2::make_diag_frame (
+ [this] (const build2::diag_record& dr)
+ {
+ dr << info << "while loading build system skeleton of package "
+ << package.name;
+ });
+
scope& rs (
*bootstrap (*this, merge_cmd_vars (strings {}))->second.front ());
+
load_root (rs);
verified_ = true;
@@ -727,6 +778,8 @@ namespace bpkg
// Load project's root.build while redirecting the diagnostics stream.
//
+ // Note: no diag_frame unlike all the other places.
+ //
ostringstream ds;
auto dg (make_guard ([ods = diag_stream] () {diag_stream = ods;}));
diag_stream = &ds;
@@ -762,10 +815,12 @@ namespace bpkg
// Print the location of a depends value in the specified manifest file.
//
- // Note that currently we only use this function for the external packages.
- // We could also do something similar for normal packages by pointing to the
- // manifest we have serialized. In this case we would also need to make sure
- // the temp directory is not cleaned in case of an error. Maybe one day.
+ // Note that currently we only use this function for the being reconfigured
+ // and external packages (i.e. when the existing source directory is
+ // specified). We could also do something similar for the remaining cases by
+ // pointing to the manifest we have serialized. In this case we would also
+ // need to make sure the temp directory is not cleaned in case of an error.
+ // Maybe one day.
//
static void
depends_location (const build2::diag_record& dr,
@@ -838,20 +893,19 @@ namespace bpkg
uint64_t il (1);
auto df = build2::make_diag_frame (
- [this, &cond, &rs, depends_index] (const build2::diag_record& dr)
+ [this, &cond, depends_index] (const build2::diag_record& dr)
{
dr << info << "enable condition: (" << cond << ")";
- // For external packages we have the manifest so print the location
- // of the depends value in questions.
+ // If an existing source directory has been specified, then we have
+ // the manifest and so print the location of the depends value in
+ // questions.
//
- if (rs.out_eq_src ())
+ if (src_root_specified_)
+ depends_location (dr, src_root_ / manifest_file, depends_index);
+ else
dr << info << "in depends manifest value of package "
<< package.name;
- else
- depends_location (dr,
- rs.src_path () / manifest_file,
- depends_index);
});
lexer l (is, in, il /* start line */);
@@ -907,9 +961,9 @@ namespace bpkg
// values that are derived from them in root.build). It seems like we have
// two options here: either enter them as true overrides similar to
// config_vars_ or just evaluate them similar to loading config.build
- // (which, BTW, we might have, in case of an external package). The big
- // problem with the former approach is that it will then prevent any
- // further reflect clauses from modifying the same values.
+ // (which, BTW, we might have, in case of a being reconfigured or external
+ // package). The big problem with the former approach is that it will then
+ // prevent any further reflect clauses from modifying the same values.
//
// So overall it feels like we have iterative/compartmentalized
// configuration process. A feedback loop, in a sense. And it's the
@@ -1035,7 +1089,7 @@ namespace bpkg
// Note: keep it active until the end (see the override detection).
//
auto df = build2::make_diag_frame (
- [this, &refl, &rs, depends_index] (const build2::diag_record& dr)
+ [this, &refl, depends_index] (const build2::diag_record& dr)
{
// Probably safe to assume a one-line fragment contains a variable
// assignment.
@@ -1046,16 +1100,15 @@ namespace bpkg
dr << info << "reflect clause:\n"
<< trim_right (string (refl));
- // For external packages we have the manifest so print the
- // location of the depends value in questions.
+ // If an existing source directory has been specified, then we have
+ // the manifest and so print the location of the depends value in
+ // questions.
//
- if (rs.out_eq_src ())
+ if (src_root_specified_)
+ depends_location (dr, src_root_ / manifest_file, depends_index);
+ else
dr << info << "in depends manifest value of package "
<< package.name;
- else
- depends_location (dr,
- rs.src_path () / manifest_file,
- depends_index);
});
lexer l (is, in, il /* start line */);
@@ -1253,21 +1306,20 @@ namespace bpkg
uint64_t il (1);
auto df = build2::make_diag_frame (
- [this, &prefer, &rs, depends_index] (const build2::diag_record& dr)
+ [this, &prefer, depends_index] (const build2::diag_record& dr)
{
dr << info << "prefer clause:\n"
<< trim_right (string (prefer));
- // For external packages we have the manifest so print the
- // location of the depends value in questions.
+ // If an existing source directory has been specified, then we
+ // have the manifest and so print the location of the depends
+ // value in questions.
//
- if (rs.out_eq_src ())
+ if (src_root_specified_)
+ depends_location (dr, src_root_ / manifest_file, depends_index);
+ else
dr << info << "in depends manifest value of package "
<< package.name;
- else
- depends_location (dr,
- rs.src_path () / manifest_file,
- depends_index);
});
lexer l (is, in, il /* start line */);
@@ -1315,20 +1367,19 @@ namespace bpkg
uint64_t il (1);
auto df = build2::make_diag_frame (
- [this, &accept, &rs, depends_index] (const build2::diag_record& dr)
+ [this, &accept, depends_index] (const build2::diag_record& dr)
{
dr << info << "accept condition: (" << accept << ")";
- // For external packages we have the manifest so print the
- // location of the depends value in questions.
+ // If an existing source directory has been specified, then we
+ // have the manifest and so print the location of the depends
+ // value in questions.
//
- if (rs.out_eq_src ())
+ if (src_root_specified_)
+ depends_location (dr, src_root_ / manifest_file, depends_index);
+ else
dr << info << "in depends manifest value of package "
<< package.name;
- else
- depends_location (dr,
- rs.src_path () / manifest_file,
- depends_index);
});
lexer l (is, in, il /* start line */);
@@ -1548,21 +1599,20 @@ namespace bpkg
uint64_t il (1);
auto df = build2::make_diag_frame (
- [this, &require, &rs, depends_index] (const build2::diag_record& dr)
+ [this, &require, depends_index] (const build2::diag_record& dr)
{
dr << info << "require clause:\n"
<< trim_right (string (require));
- // For external packages we have the manifest so print the
- // location of the depends value in questions.
+ // If an existing source directory has been specified, then we
+ // have the manifest and so print the location of the depends
+ // value in questions.
//
- if (rs.out_eq_src ())
+ if (src_root_specified_)
+ depends_location (dr, src_root_ / manifest_file, depends_index);
+ else
dr << info << "in depends manifest value of package "
<< package.name;
- else
- depends_location (dr,
- rs.src_path () / manifest_file,
- depends_index);
});
lexer l (is, in, il /* start line */);
@@ -1829,7 +1879,7 @@ namespace bpkg
empty_print ()
{
if (!loaded_old_config_)
- load_old_config ();
+ load_old_config_impl ();
return (dependent_vars_.empty () &&
reflect_.empty () &&
@@ -1860,7 +1910,7 @@ namespace bpkg
using build2::config::variable_origin;
if (!loaded_old_config_)
- load_old_config ();
+ load_old_config_impl ();
auto print = [&os,
indent,
@@ -1885,8 +1935,10 @@ namespace bpkg
// First comes the user configuration.
//
- for (const string& v: config_vars_)
+ for (size_t i (0); i != config_vars_.size (); ++i)
{
+ const string& v (config_vars_[i]);
+
size_t vn;
if (project_override (v, var_prefix_, &vn))
{
@@ -1900,8 +1952,17 @@ namespace bpkg
continue;
}
+ const char* s (nullptr);
+
+ switch (config_var_srcs_[i])
+ {
+ case config_source::user: s = "user"; break;
+ case config_source::dependent: s = "dependent"; break;
+ case config_source::reflect: assert (false); // Must never be loaded.
+ }
+
print (v) << " (" << (system ? "expected " : "")
- << "user configuration)";
+ << s << " configuration)";
}
}
@@ -1929,15 +1990,24 @@ namespace bpkg
}
}
+ void package_skeleton::
+ load_old_config ()
+ {
+ if (!loaded_old_config_)
+ load_old_config_impl ();
+ }
+
pair<strings, vector<config_variable>> package_skeleton::
collect_config () &&
{
+ // NOTE: remember to update config_checksum() if changing anything here.
+
assert (db_ != nullptr); // Must be called only once.
using build2::config::variable_origin;
if (!loaded_old_config_)
- load_old_config ();
+ load_old_config_impl ();
// Merge all the variables into a single list in the correct order
// and assign their sources while at it.
@@ -1974,11 +2044,19 @@ namespace bpkg
// variables which are project variables (i.e., names start with
// config.<project>).
//
+ size_t pn (var_prefix_.size ());
for (const string& v: config_vars_)
{
- if (project_override (v, var_prefix_))
+ size_t vn;
+ if (project_override (v, var_prefix_, &vn))
{
- string n (var_name (v));
+ // Skip config.<project>.develop (can potentially be passed by
+ // bdep-init) if the package doesn't use it.
+ //
+ if (!develop_ && v.compare (pn, vn - pn, ".develop") == 0)
+ continue;
+
+ string n (v, 0, vn);
// Check for a duplicate.
//
@@ -2044,13 +2122,61 @@ namespace bpkg
return make_pair (move (vars), move (srcs));
}
+ string package_skeleton::
+ config_checksum ()
+ {
+ // Note: this is parallel to collect_config() logic but is not destructive.
+
+ assert (db_ != nullptr); // Must be called before collect_config().
+
+ if (!loaded_old_config_)
+ load_old_config_impl ();
+
+ sha256 cs;
+
+ if (!config_vars_.empty ())
+ {
+ cstrings vs;
+ size_t pn (var_prefix_.size ());
+ for (const string& v: config_vars_)
+ {
+ size_t vn;
+ if (project_override (v, var_prefix_, &vn))
+ {
+ // Skip config.<project>.develop (can potentially be passed by
+ // bdep-init) if the package doesn't use it.
+ //
+ if (develop_ || v.compare (pn, vn - pn, ".develop") != 0)
+ cs.append (v);
+ }
+ }
+ }
+
+ if (!dependent_vars_.empty ())
+ {
+ for (const string& v: dependent_vars_)
+ cs.append (v);
+ }
+
+ if (!reflect_.empty ())
+ {
+ for (const reflect_variable_value& v: reflect_)
+ {
+ if (v.origin != build2::config::variable_origin::override_)
+ cs.append (serialize_cmdline (v.name, v.value));
+ }
+ }
+
+ return !cs.empty () ? cs.string () : string ();
+ }
+
const strings& package_skeleton::
merge_cmd_vars (const strings& dependent_vars,
const strings& dependency_vars,
bool cache)
{
// Merge variable overrides (note that the order is important). See also a
- // custom/optimized version in load_old_config().
+ // custom/optimized version in load_old_config_impl().
//
if (!cache || !cmd_vars_cache_)
{
@@ -2098,13 +2224,14 @@ namespace bpkg
}
void package_skeleton::
- load_old_config ()
+ load_old_config_impl ()
{
assert (!loaded_old_config_ && ctx_ == nullptr);
try
{
using namespace build2;
+ using build2::info;
// This load that must be done without config.config.disfigure. Also, it
// would be nice to optimize for the common case where the only load is
@@ -2141,15 +2268,25 @@ namespace bpkg
}
}
- scope& rs (*bootstrap (*this, *cmd_vars)->second.front ());
+ scope* rs;
+ {
+ auto df = build2::make_diag_frame (
+ [this] (const build2::diag_record& dr)
+ {
+ dr << info << "while loading build system skeleton of package "
+ << package.name;
+ });
- // Load project's root.build.
- //
- load_root (rs);
+ rs = bootstrap (*this, *cmd_vars, true /* old */)->second.front ();
+
+ // Load project's root.build.
+ //
+ load_root (*rs);
+ }
// Note: go straight for the public variable pool.
//
- if (const variable* var = rs.ctx.var_pool.find (var_prefix_ + ".develop"))
+ if (const variable* var = rs->ctx.var_pool.find (var_prefix_ + ".develop"))
{
// Use the fact that the variable is typed as a proxy for it being
// defined with config directive (the more accurate way would be via
@@ -2163,27 +2300,32 @@ namespace bpkg
//
// Also, build2 warns about unused variables being dropped.
//
- // Note that currently load_old_config() is disabled unless there is
- // a config.*.develop variable; see package_skeleton ctor.
+ // Note that currently load_old_config_impl() is disabled unless
+ // there is a config.*.develop variable or we were asked to load
+ // dependent configuration; see package_skeleton ctor.
- // Extract and merge old user configuration variables from config.build
- // (or equivalent) into config_vars.
+ // Extract and merge old user and/or dependent configuration variables
+ // from config.build (or equivalent) into config_vars.
//
if (config_srcs_ != nullptr)
{
assert (!disfigure_);
- auto i (config_vars_.begin ()); // Insert position, see below.
+ auto i (config_vars_.begin ()); // Insert position, see below.
+ auto j (config_var_srcs_.begin ()); // Insert position, see below.
names storage;
for (const config_variable& v: *config_srcs_)
{
- if (v.source != config_source::user)
+ if (!(((load_config_flags & load_config_user) != 0 &&
+ v.source == config_source::user) ||
+ ((load_config_flags & load_config_dependent) != 0 &&
+ v.source == config_source::dependent)))
continue;
using config::variable_origin;
- pair<variable_origin, lookup> ol (config::origin (rs, v.name));
+ pair<variable_origin, lookup> ol (config::origin (*rs, v.name));
switch (ol.first)
{
@@ -2208,6 +2350,7 @@ namespace bpkg
i,
serialize_cmdline (v.name, *ol.second, storage)) + 1;
+ j = config_var_srcs_.insert (j, v.source) + 1;
break;
}
case variable_origin::undefined:
@@ -2226,7 +2369,10 @@ namespace bpkg
}
loaded_old_config_ = true;
- verified_ = true; // Managed to load without errors.
+
+ if (old_src_root_.empty ())
+ verified_ = true; // Managed to load without errors.
+
ctx_ = nullptr;
}
catch (const build2::failed&)
@@ -2249,11 +2395,12 @@ namespace bpkg
}
if (!loaded_old_config_)
- load_old_config ();
+ load_old_config_impl ();
try
{
using namespace build2;
+ using build2::info;
using build2::config::variable_origin;
// If we have any dependency configurations, then here we need to add
@@ -2290,6 +2437,13 @@ namespace bpkg
dependency_vars,
dependency_vars.empty () /* cache */));
+ auto df = build2::make_diag_frame (
+ [this] (const build2::diag_record& dr)
+ {
+ dr << info << "while loading build system skeleton of package "
+ << package.name;
+ });
+
auto rsi (bootstrap (*this, cmd_vars));
scope& rs (*rsi->second.front ());
@@ -2445,11 +2599,11 @@ namespace bpkg
new context (build2_sched,
build2_mutexes,
build2_fcache,
- false /* match_only */, // Shouldn't matter.
- false /* no_external_modules */,
- false /* dry_run */, // Shouldn't matter.
- false /* no_diag_buffer */, // Shouldn't matter.
- false /* keep_going */, // Shouldnt' matter.
+ nullopt /* match_only */, // Shouldn't matter.
+ false /* no_external_modules */,
+ false /* dry_run */, // Shouldn't matter.
+ false /* no_diag_buffer */, // Shouldn't matter.
+ false /* keep_going */, // Shouldnt' matter.
cmd_vars));
}
catch (const build2::failed&)
@@ -2461,7 +2615,7 @@ namespace bpkg
// Bootstrap the package skeleton.
//
static build2::scope_map::iterator
- bootstrap (package_skeleton& skl, const strings& cmd_vars)
+ bootstrap (package_skeleton& skl, const strings& cmd_vars, bool old)
{
assert (skl.db_ != nullptr &&
skl.ctx_ == nullptr &&
@@ -2483,6 +2637,12 @@ namespace bpkg
// Create the skeleton filesystem state, if it doesn't exist yet.
//
+ if (old && skl.old_src_root_.empty ())
+ old = false;
+
+ dir_path& skl_src_root (old ? skl.old_src_root_ : skl.src_root_);
+ dir_path& skl_out_root (old ? skl.old_out_root_ : skl.out_root_);
+
if (!skl.created_)
{
const available_package& ap (*skl.available);
@@ -2492,11 +2652,13 @@ namespace bpkg
// they never clash with other temporary subdirectories (git
// repositories, etc).
//
- if (skl.src_root_.empty () || skl.out_root_.empty ())
+ // Note: for old src/out, everything should already exist.
+ //
+ if (!old && (skl_src_root.empty () || skl_out_root.empty ()))
{
// Cannot be specified if src_root_ is unspecified.
//
- assert (skl.out_root_.empty ());
+ assert (skl_out_root.empty ());
// Note that only configurations which can be used as repository
// information sources has the temporary directory facility
@@ -2524,14 +2686,16 @@ namespace bpkg
d /= "skeletons";
d /= skl.package.name.string () + '-' + ap.version.string ();
- if (skl.src_root_.empty ())
- skl.src_root_ = move (d); // out_root_ is the same.
+ if (skl_src_root.empty ())
+ skl_src_root = move (d); // out_root_ is the same.
else
- skl.out_root_ = move (d); // Don't even need to create it.
+ skl_out_root = move (d); // Don't even need to create it.
}
- if (!exists (skl.src_root_))
+ if (!exists (skl_src_root))
{
+ assert (!old); // An old package version cannot not exist.
+
// Create the buildfiles.
//
// Note that it's probably doesn't matter which naming scheme to use
@@ -2541,7 +2705,7 @@ namespace bpkg
{
bool an (*ap.alt_naming);
- path bf (skl.src_root_ /
+ path bf (skl_src_root /
(an ? alt_bootstrap_file : std_bootstrap_file));
mk_p (bf.directory ());
@@ -2566,11 +2730,11 @@ namespace bpkg
if (ap.root_build)
save (*ap.root_build,
- skl.src_root_ / (an ? alt_root_file : std_root_file));
+ skl_src_root / (an ? alt_root_file : std_root_file));
for (const buildfile& f: ap.buildfiles)
{
- path p (skl.src_root_ /
+ path p (skl_src_root /
(an ? alt_build_dir : std_build_dir) /
f.path);
@@ -2611,7 +2775,7 @@ namespace bpkg
m.dependencies.push_back (das);
}
- path mf (skl.src_root_ / manifest_file);
+ path mf (skl_src_root / manifest_file);
try
{
@@ -2636,7 +2800,8 @@ namespace bpkg
}
}
- skl.created_ = true;
+ if (!old)
+ skl.created_ = true;
}
try
@@ -2669,10 +2834,10 @@ namespace bpkg
// Note that it's ok for out_root to not exist (external package).
//
- const dir_path& src_root (skl.src_root_);
- const dir_path& out_root (skl.out_root_.empty ()
- ? skl.src_root_
- : skl.out_root_);
+ const dir_path& src_root (skl_src_root);
+ const dir_path& out_root (skl_out_root.empty ()
+ ? skl_src_root
+ : skl_out_root);
auto rsi (create_root (ctx, out_root, src_root));
scope& rs (*rsi->second.front ());
diff --git a/bpkg/package-skeleton.hxx b/bpkg/package-skeleton.hxx
index 9f76221..947522e 100644
--- a/bpkg/package-skeleton.hxx
+++ b/bpkg/package-skeleton.hxx
@@ -27,14 +27,27 @@ namespace bpkg
// is NULL, then the skeleton can only be used to print and collect the
// configuration information.
//
- // If the package is external, then the existing package source root
+ // If the package is being reconfigured (rather than up/downgraded), then
+ // the existing package source and output root directories (src_root and
+ // out_root) need to be specified (as absolute and normalized). Otherwise,
+ // if the package is external, then the existing package source root
// directory needs to be specified (as absolute and normalized). In this
// case, if output root is specified (as absolute and normalized; normally
// <config-dir>/<package-name>), then it's used as is. Otherwise, an empty
// skeleton directory is used as output root.
//
- // If the package is not external, then none of the root directories
- // should be specified.
+ // If the package is neither being reconfigured nor is external, then none
+ // of the root directories should be specified.
+ //
+ // If the package is configured as source and the user and/or dependent
+ // configuration is requested to be loaded from config.build, then the
+ // existing package old source and output root directories (old_src_root
+ // and old_out_root) need to be specified (as absolute and normalized). If
+ // specified, they are used instead of package source and output root
+ // directories to load the current user and/or dependent configuration.
+ // The idea here is that during package upgrade/downgrade, we want to load
+ // the old configuration from the old version's src/out but then continue
+ // evaluating clauses using the new version's src/out.
//
// The disfigure argument should indicate whether the package is being
// reconfigured from scratch (--disfigure).
@@ -68,13 +81,22 @@ namespace bpkg
bool disfigure,
const vector<config_variable>* config_srcs,
optional<dir_path> src_root,
- optional<dir_path> out_root);
-
+ optional<dir_path> out_root,
+ optional<dir_path> old_src_root,
+ optional<dir_path> old_out_root,
+ uint16_t load_config_flags);
package_key package;
bool system;
shared_ptr<const available_package> available;
+ // Load package (old) configuration flags.
+ //
+ uint16_t load_config_flags;
+
+ static const uint16_t load_config_user = 0x1;
+ static const uint16_t load_config_dependent = 0x2;
+
// The following functions should be called in the following sequence
// (* -- zero or more, ? -- zero or one):
//
@@ -82,8 +104,13 @@ namespace bpkg
// ? dependent_config()
// * evaluate_*()
// * empty() | print_config()
+ // * config_checksum()
// collect_config()
//
+ // Note that the load_old_config() function can be called at eny point
+ // before collect_config() (and is called implicitly by most other
+ // functions).
+ //
// Note that a copy of the skeleton is expected to continue with the
// sequence rather than starting from scratch, unless reset() is called.
//
@@ -168,6 +195,11 @@ namespace bpkg
void
print_config (ostream&, const char* indent);
+ // Load the package's old configuration, unless it is already loaded.
+ //
+ void
+ load_old_config ();
+
// Return the accumulated configuration variables (first) and project
// configuration variable sources (second). Note that the arrays are not
// necessarily parallel (config_vars may contain non-project variables).
@@ -181,6 +213,12 @@ namespace bpkg
pair<strings, vector<config_variable>>
collect_config () &&;
+ // Return the checksum of the project configuration variables that will be
+ // returned by the collect_config() function call.
+ //
+ string
+ config_checksum ();
+
// Implementation details.
//
public:
@@ -188,16 +226,17 @@ namespace bpkg
// constructor has some special logic.
//
~package_skeleton ();
- package_skeleton (package_skeleton&&);
- package_skeleton& operator= (package_skeleton&&);
+ package_skeleton (package_skeleton&&) noexcept;
+ package_skeleton& operator= (package_skeleton&&) noexcept;
package_skeleton (const package_skeleton&);
package_skeleton& operator= (const package_skeleton&) = delete;
private:
- // Load old user configuration variables from config.build (or equivalent)
- // and merge them into config_vars_. Also verify new user configuration
- // already in config_vars_ makes sense.
+ // Load old user and/or dependent configuration variables from
+ // config.build (or equivalent) and merge them into config_vars_ and
+ // config_var_srcs_. Also verify new user configuration already in
+ // config_vars_ makes sense.
//
// This should be done before any attempt to load the configuration with
// config.config.disfigure and, if this did not happen, inside
@@ -205,7 +244,7 @@ namespace bpkg
// config.config.disfigure).
//
void
- load_old_config ();
+ load_old_config_impl ();
// (Re)load the build system state.
//
@@ -246,6 +285,13 @@ namespace bpkg
string var_prefix_; // config.<project>
strings config_vars_;
+
+ // Configuration sources for variables in config_vars_ (parallel). Can
+ // only contain config_source::{user,dependent} entries (see
+ // load_old_config_impl() for details).
+ //
+ vector<config_source> config_var_srcs_;
+
bool disfigure_;
const vector<config_variable>* config_srcs_; // NULL if nothing to do or
// already done.
@@ -253,6 +299,19 @@ namespace bpkg
dir_path src_root_; // Must be absolute and normalized.
dir_path out_root_; // If empty, the same as src_root_.
+ // True if the existing source root directory has been specified.
+ //
+ // Note that if that's the case, we can use the manifest file this
+ // directory contains for diagnostics.
+ //
+ bool src_root_specified_ = false;
+
+ // If specified, are used instead of {src,out}_root_ for loading of the
+ // project configuration variables.
+ //
+ dir_path old_src_root_;
+ dir_path old_out_root_;
+
bool created_ = false;
bool verified_ = false;
bool loaded_old_config_;
diff --git a/bpkg/package.cxx b/bpkg/package.cxx
index fe04248..05dbc0d 100644
--- a/bpkg/package.cxx
+++ b/bpkg/package.cxx
@@ -6,6 +6,7 @@
#include <bpkg/database.hxx>
#include <bpkg/checksum.hxx>
+#include <bpkg/rep-mask.hxx>
#include <bpkg/pkg-verify.hxx>
#include <bpkg/diagnostics.hxx>
#include <bpkg/satisfaction.hxx>
@@ -69,6 +70,42 @@ namespace bpkg
return r != 0 ? (r < 0) : (db < v.db);
}
+ // package_version_key
+ //
+ string package_version_key::
+ string (bool ignore_version) const
+ {
+ std::string r (name.string ());
+
+ if (version && !version->empty () && !ignore_version)
+ {
+ r += '/';
+ r += version->string ();
+ }
+
+ const std::string& d (db.get ().string);
+
+ if (!d.empty ())
+ {
+ r += ' ';
+ r += d;
+ }
+
+ return r;
+ }
+
+ bool package_version_key::
+ operator< (const package_version_key& v) const
+ {
+ // NOTE: remember to update cmdline_adjustments::tried_earlier() if
+ // changing anything here.
+ //
+ if (int r = name.compare (v.name))
+ return r < 0;
+
+ return version != v.version ? (version < v.version) : (db < v.db);
+ }
+
// available_package
//
const version* available_package::
@@ -295,12 +332,18 @@ namespace bpkg
// The package is in at least fetched state, which means we should
// be able to get its manifest.
//
- const optional<path>& a (sp->archive);
-
+ // @@ PERF We should probably implement the available package caching not
+ // to parse the same manifests multiple times during all that build
+ // plan refinement iterations. What should be the cache key? Feels like
+ // it should be the archive/directory path. Note that the package
+ // manifests can potentially differ in different external package
+ // directories for the same version iteration. Testing showed 6%
+ // speedup on tests (debug/sanitized).
+ //
package_manifest m (
sp->state == package_state::fetched
? pkg_verify (options,
- a->absolute () ? *a : db.config_orig / *a,
+ sp->effective_archive (db.config_orig),
true /* ignore_unknown */,
false /* ignore_toolchain */,
false /* expand_values */,
@@ -373,7 +416,7 @@ namespace bpkg
{
const shared_ptr<repository_fragment>& rf (prf.repository_fragment);
- if (rf->location.directory_based ())
+ if (!rep_masked_fragment (db, rf) && rf->location.directory_based ())
fail << "external package " << n << '/' << v
<< " is already available from "
<< rf->location.canonical_name ();
@@ -389,45 +432,54 @@ namespace bpkg
false /* iteration */))
return nullopt;
- string mc (package_checksum (o, d, pi));
-
- // The selected package must not be "simulated" (see pkg-build for
- // details).
- //
- assert (p->manifest_checksum);
-
- bool changed (mc != *p->manifest_checksum);
+ bool changed (!p->external ());
- // If the manifest hasn't changed and the package has buildfile clauses in
- // the dependencies, then check if the buildfiles haven't changed either.
+ // If the selected package is not external, then increment the iteration
+ // number to make the external package preferable. Note that for such
+ // packages the manifest/subprojects and buildfiles checksums are absent.
//
- if (!changed && p->buildfiles_checksum)
+ if (!changed)
{
- // Always calculate the checksum over the buildfiles since the package
- // is external.
+ // The selected package must not be "simulated" (see pkg-build for
+ // details).
//
- changed = package_buildfiles_checksum (
- nullopt /* bootstrap_build */,
- nullopt /* root_build */,
- {} /* buildfiles */,
- d) != *p->buildfiles_checksum;
- }
+ assert (p->manifest_checksum);
- // If the manifest hasn't changed but the selected package points to an
- // external source directory, then we also check if the directory have
- // moved.
- //
- if (!changed && p->external ())
- {
- dir_path src_root (p->effective_src_root (db.config));
+ changed = (package_checksum (o, d, pi) != *p->manifest_checksum);
- // We need to complete and normalize the source directory as it may
- // generally be completed against the configuration directory (unlikely
- // but possible), that can be relative and/or not normalized.
+ // If the manifest hasn't changed and the package has buildfile clauses
+ // in the dependencies, then check if the buildfiles haven't changed
+ // either.
//
- normalize (src_root, "package source");
+ if (!changed && p->buildfiles_checksum)
+ {
+ // Always calculate the checksum over the buildfiles since the package
+ // is external.
+ //
+ changed = package_buildfiles_checksum (
+ nullopt /* bootstrap_build */,
+ nullopt /* root_build */,
+ {} /* buildfiles */,
+ d) != *p->buildfiles_checksum;
+ }
+
+ // If the manifest hasn't changed but the selected package points to an
+ // external source directory, then we also check if the directory have
+ // moved.
+ //
+ if (!changed)
+ {
+ dir_path src_root (p->effective_src_root (db.config));
+
+ // We need to complete and normalize the source directory as it may
+ // generally be completed against the configuration directory
+ // (unlikely but possible), that can be relative and/or not
+ // normalized.
+ //
+ normalize (src_root, "package source");
- changed = src_root != normalize (d, "package source");
+ changed = src_root != normalize (d, "package source");
+ }
}
return !changed
diff --git a/bpkg/package.hxx b/bpkg/package.hxx
index 51f7219..400519a 100644
--- a/bpkg/package.hxx
+++ b/bpkg/package.hxx
@@ -11,6 +11,7 @@
#include <type_traits> // static_assert
#include <odb/core.hxx>
+#include <odb/section.hxx>
#include <odb/nested-container.hxx>
#include <libbutl/timestamp.hxx>
@@ -25,9 +26,13 @@
// Used by the data migration entries.
//
+// NOTE: drop all the `#pragma db member(...) default(...)` pragmas when
+// migration is no longer supported (i.e., the current and base schema
+// versions are the same).
+//
#define DB_SCHEMA_VERSION_BASE 12
-#pragma db model version(DB_SCHEMA_VERSION_BASE, 20, closed)
+#pragma db model version(DB_SCHEMA_VERSION_BASE, 26, closed)
namespace bpkg
{
@@ -513,6 +518,10 @@ namespace bpkg
operator size_t () const {return result;}
};
+ // language
+ //
+ #pragma db value(language) definition
+
// package_location
//
#pragma db value
@@ -613,9 +622,6 @@ namespace bpkg
//
#pragma db value(test_dependency) definition
- // @@ TMP Drop when database migration to the schema version 11 is no longer
- // supported.
- //
#pragma db member(test_dependency::buildtime) default(false)
using optional_test_dependency_type = optional<test_dependency_type>;
@@ -670,14 +676,27 @@ namespace bpkg
//
#pragma db value(buildfile) definition
+ // distribution_name_value
+ //
+ #pragma db value(distribution_name_value) definition
+
#pragma db object pointer(shared_ptr) session
class available_package
{
public:
using version_type = bpkg::version;
+ using upstream_version_type = bpkg::upstream_version;
available_package_id id;
- upstream_version version;
+ upstream_version_type version;
+
+ optional<string> upstream_version;
+ optional<string> type;
+
+ small_vector<language, 1> languages;
+ odb::section languages_section;
+
+ optional<package_name> project;
// List of repository fragments to which this package version belongs
// (yes, in our world, it can be in multiple, unrelated repositories)
@@ -697,8 +716,17 @@ namespace bpkg
// Package manifest data and, potentially, the special test dependencies.
//
- // Note that there can be only one special test dependencies entry in the
- // list and it's always the last one, if present.
+ // Note that there can only be one special test dependencies entry in the
+ // list. It can only be present for a test package and specifies all the
+ // main packages as the alternative dependencies. If present, it is
+ // located right after the last explicit depends clause which specifies a
+ // main package for this test package, if such a clause is present, and as
+ // the first entry otherwise. The idea here is to inject the special
+ // depends clause as early as possible, so that the other clauses could
+ // potentially refer to the reflection variables it may set. But not too
+ // early, so that the explicit main package dependencies are already
+ // resolved by the time of resolving the special clause to avoid the
+ // 'unable to select dependency alternative' error.
//
using dependencies_type = bpkg::dependencies;
@@ -716,6 +744,8 @@ namespace bpkg
optional<string> root_build;
vector<buildfile> buildfiles;
+ vector<distribution_name_value> distribution_values;
+
// Present for non-transient objects only (and only for certain repository
// types).
//
@@ -732,8 +762,13 @@ namespace bpkg
available_package (package_manifest&& m)
: id (move (m.name), m.version),
version (move (m.version)),
+ upstream_version (move (m.upstream_version)),
+ type (move (m.type)),
+ languages (move (m.languages)),
+ project (move (m.project)),
dependencies (convert (move (m.dependencies))),
tests (move (m.tests)),
+ distribution_values (move (m.distribution_values)),
sha256sum (move (m.sha256sum))
{
if (!stub ())
@@ -765,6 +800,18 @@ namespace bpkg
bool
stub () const {return version.compare (wildcard_version, true) == 0;}
+ string
+ effective_type () const
+ {
+ return package_manifest::effective_type (type, id.name);
+ }
+
+ small_vector<language, 1>
+ effective_languages () const
+ {
+ return package_manifest::effective_languages (languages, id.name);
+ }
+
// Return package system version if one has been discovered. Note that
// we do not implicitly assume a wildcard version.
//
@@ -781,6 +828,16 @@ namespace bpkg
//
#pragma db member(id) id column("")
#pragma db member(version) set(this.version.init (this.id.version, (?)))
+
+ // languages
+ //
+ #pragma db member(languages) id_column("") value_column("language_") \
+ section(languages_section)
+
+ #pragma db member(languages_section) load(lazy) update(always)
+
+ // locations
+ //
#pragma db member(locations) id_column("") value_column("") \
unordered value_not_null
@@ -834,31 +891,27 @@ namespace bpkg
//
#pragma db member(tests) id_column("") value_column("test_")
- // alt_naming
+ // distribution_values
//
- // @@ TMP Drop when database migration to the schema version 20 is no
- // longer supported.
+ #pragma db member(distribution_values) id_column("") value_column("dist_")
+
+ // alt_naming
//
- // Note that since no real packages with alternative buildfile naming
- // use conditional dependencies yet, we can just set alt_naming to
- // false during migration to the database schema version 20. Also we
- // never rely on alt_naming to be nullopt for the stub packages, so
- // let's not complicate things and set alt_naming to false for them
- // either.
+ // Note that since no real packages with alternative buildfile naming use
+ // conditional dependencies yet, we can just set alt_naming to false
+ // during migration to the database schema version 20. Also we never rely
+ // on alt_naming to be nullopt for the stub packages, so let's not
+ // complicate things and set alt_naming to false for them either.
//
#pragma db member(alt_naming) default(false)
// *_build
//
- // @@ TMP Drop when database migration to the schema version 15 is no
- // longer supported.
- //
- // Note that since no real packages use conditional dependencies yet,
- // we can just set bootstrap_build to the empty string during migration
- // to the database schema version 15. Also we never rely on
- // bootstrap_build to be nullopt for the stub packages, so let's not
- // complicate things and set bootstrap_build to the empty string for
- // them either.
+ // Note that since no real packages use conditional dependencies yet, we
+ // can just set bootstrap_build to the empty string during migration to
+ // the database schema version 15. Also we never rely on bootstrap_build
+ // to be nullopt for the stub packages, so let's not complicate things and
+ // set bootstrap_build to the empty string for them either.
//
#pragma db member(bootstrap_build) default("")
@@ -871,6 +924,15 @@ namespace bpkg
available_package () = default;
};
+ // The available packages together with the repository fragments they belong
+ // to.
+ //
+ // Note that lazy_shared_ptr is used to also convey the databases the
+ // objects belong to.
+ //
+ using available_packages = vector<pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>>>;
+
#pragma db view object(available_package)
struct available_package_count
{
@@ -1033,37 +1095,9 @@ namespace bpkg
//
optional<version_constraint> constraint;
- // Position of the first dependency alternative with a configuration
- // clause, if any.
- //
- // Specifically, if there is such an alternative then this is a pair of
- // 1-based indexes of the respective depends value (first) and the
- // dependency alternative (second) in the dependent's manifest. Otherwise,
- // this is a pair of zeros.
- //
- // For example, for the following dependent the position for libfoo/1.2.0
- // prerequisite will be {2,2}:
- //
- // libbar: depends: libfoo >= 1.1.0
- // depends: libfox | libfoo >= 1.2.0 {require {...}}
- //
- pair<size_t, size_t> config_position;
-
// Database mapping.
//
#pragma db member(constraint) column("")
-
- #pragma db member(config_position) transient
-
- #pragma db member(config_dependency_index) \
- virtual(size_t) \
- access(config_position.first) \
- default(0)
-
- #pragma db member(config_alternative_index) \
- virtual(size_t) \
- access(config_position.second) \
- default(0)
};
// Note that the keys for this map need to be created with the database
@@ -1177,9 +1211,9 @@ namespace bpkg
// package version revision increment. In particular, new subprojects
// should trigger the package reconfiguration.
//
- // Must be present if the source directory is present, unless the object
- // is created/updated during the package build simulation (see pkg-build
- // for details). Note that during the simulation the manifest may not be
+ // Only present for external packages, unless the objects are
+ // created/updated during the package build simulation (see pkg-build for
+ // details). Note that during the simulation the manifest may not be
// available.
//
// @@ Currently we don't consider subprojects recursively (would most
@@ -1191,30 +1225,46 @@ namespace bpkg
//
optional<std::string> manifest_checksum;
- // Absent if the package has no buildfile clauses in the dependencies.
- // Otherwise, the checksum of the buildfiles calculated over the *-build
- // manifest values or, if unspecified, the files in the package source
- // directory.
+ // Only present for external packages which have buildfile clauses in the
+ // dependencies, unless the objects are created/updated during the package
+ // build simulation (see pkg-build for details).
//
- // Note that for external packages the checksum is always calculated over
- // the files. This is "parallel" to the package skeleton logic.
+ // Note that the checksum is always calculated over the files rather than
+ // the *-build manifest values. This is "parallel" to the package skeleton
+ // logic.
//
optional<std::string> buildfiles_checksum;
- // Path to the output directory of this package, if any. It is
- // always relative to the configuration directory, and is <name>
- // for external packages and <name>-<version> for others. It is
- // only set once the package is configured and its main purse is
- // to keep track of what needs to be cleaned by the user before
- // a broken package can be purged. Note that it could be the
- // same as src_root.
+ // Path to the output directory of this package, if any. It is always
+ // relative to the configuration directory, and is <name> for external
+ // packages and <name>-<version> for others. It is only set once the
+ // package is configured and its main purpose is to keep track of what
+ // needs to be cleaned by the user before a broken package can be
+ // purged. Note that it could be the same as src_root.
//
optional<dir_path> out_root;
package_prerequisites prerequisites;
+ // 1-based indexes of the selected dependency alternatives which the
+ // prerequisite packages are resolved from. Parallel to the dependencies
+ // member of the respective available package. Entries which don't
+ // correspond to a selected alternative (toolchain build-time dependency,
+ // not enabled alternatives, etc) are set to 0.
+ //
+ using indexes_type = vector<size_t>; // Make sure ODB maps it portably.
+ indexes_type dependency_alternatives;
+ odb::section dependency_alternatives_section;
+
+ // Project configuration variable names and their sources.
+ //
vector<config_variable> config_variables;
+ // SHA256 checksum of variables (names and values) referred to by the
+ // config_variables member.
+ //
+ std::string config_checksum;
+
public:
bool
system () const
@@ -1259,6 +1309,18 @@ namespace bpkg
std::string
string (database&) const;
+ // Return the relative archive path completed using the configuration
+ // directory. Return the absolute archive path as is.
+ //
+ path
+ effective_archive (const dir_path& configuration) const
+ {
+ // Cast for compiling with ODB (see above).
+ //
+ assert (static_cast<bool> (archive));
+ return archive->absolute () ? *archive : configuration / *archive;
+ }
+
// Return the relative source directory completed using the configuration
// directory. Return the absolute source directory as is.
//
@@ -1271,8 +1333,7 @@ namespace bpkg
return src_root->absolute () ? *src_root : configuration / *src_root;
}
- // Return the output directory using the configuration directory. Note
- // that the output directory is always relative.
+ // Return the output directory using the configuration directory.
//
dir_path
effective_out_root (const dir_path& configuration) const
@@ -1280,6 +1341,9 @@ namespace bpkg
// Cast for compiling with ODB (see above).
//
assert (static_cast<bool> (out_root));
+
+ // Note that out_root is always relative.
+ //
return configuration / *out_root;
}
@@ -1290,8 +1354,21 @@ namespace bpkg
#pragma db member(prerequisites) id_column("package") \
key_column("") value_column("")
+ #pragma db member(dependency_alternatives) id_column("package") \
+ value_column("position") section(dependency_alternatives_section)
+
+ #pragma db member(dependency_alternatives_section) load(lazy) update(always)
+
#pragma db member(config_variables) id_column("package") value_column("")
+ // For the sake of simplicity let's not calculate the checksum during
+ // migration. It seems that the only drawback of this approach is a
+ // (single) spurious reconfiguration of a dependency of a dependent with
+ // configuration clause previously configured by bpkg with the database
+ // schema version prior to 24.
+ //
+ #pragma db member(config_checksum) default("")
+
// Explicit aggregate initialization for C++20 (private default ctor).
//
selected_package (package_name n,
@@ -1361,21 +1438,24 @@ namespace bpkg
//
// Pass the build2 project info for the package, if available, to speed up
// the call and NULL otherwise (in which case it will be queried by the
- // implementation).
+ // implementation). In the former case it is assumed that the package info
+ // has been retrieved with the b_info_flags::subprojects flag.
//
// Notes:
//
// - The package directory is considered an iteration of the package if this
// upstream version and revision is already present (selected) in the
- // configuration and has a source directory. If that's the case, then the
- // specified directory path and the checksum of the manifest file it
- // contains are compared to the ones of the package present in the
- // configuration. If both match, then the present package version
- // (including its iteration, if any) is returned. Otherwise (the package
- // has moved and/or the packaging information has changed), the present
- // package version with the incremented iteration number is returned. Note
- // that the directory path is matched only for the external selected
- // packages.
+ // configuration and has a source directory. If that's the case and if the
+ // present version is not external (the package is being switched to a
+ // local potentially amended version), then the present package version
+ // with the incremented iteration number is returned. Otherwise (the
+ // present package is external), the specified directory path and the
+ // package checksum (see package_checksum() for details) are compared to
+ // the ones of the package present in the configuration. If both match,
+ // then the present package version (including its iteration, if any) is
+ // returned. Otherwise (the package has moved and/or the package
+ // information has changed), the present package version with the
+ // incremented iteration number is returned.
//
// - Only a single package iteration is valid per version in the
// configuration. This, in particular, means that a package of the
@@ -1511,21 +1591,6 @@ namespace bpkg
#pragma db column("pp.package")
package_name name;
- #pragma db transient
- pair<size_t, size_t> config_position;
-
- #pragma db member(config_dependency_index) \
- column("pp.config_dependency_index") \
- virtual(size_t) \
- access(config_position.first) \
- default(0)
-
- #pragma db member(config_alternative_index) \
- column("pp.config_alternative_index") \
- virtual(size_t) \
- access(config_position.second) \
- default(0)
-
#pragma db column("pp.")
optional<version_constraint> constraint;
};
@@ -1558,12 +1623,6 @@ namespace bpkg
package_key (database& d, package_name n): db (d), name (move (n)) {}
- // Create a pseudo-package (command line as a dependent, etc).
- //
- package_key (database& d, string n)
- : db (d),
- name (n.empty () ? package_name () : package_name (move (n))) {}
-
bool
operator== (const package_key& v) const
{
@@ -1595,6 +1654,66 @@ namespace bpkg
return os << p.string ();
}
+ // Database, package name, and package version.
+ //
+ // It is normally used as a key for maps containing data for package
+ // versions across multiple linked configurations. Assumes that the
+ // respective databases are not detached during such map lifetimes.
+ // Considers all package name, package version, and database for objects
+ // comparison.
+ //
+ // The package name can be a pseudo-package (command line as a dependent,
+ // etc), in which case the version is absent. The version can also be empty,
+ // denoting a package of an unknown version.
+ //
+ struct package_version_key
+ {
+ reference_wrapper<database> db;
+ package_name name;
+ optional<bpkg::version> version;
+
+ package_version_key (database& d, package_name n, bpkg::version v)
+ : db (d), name (move (n)), version (move (v)) {}
+
+ // Create a pseudo-package (command line as a dependent, etc).
+ //
+ package_version_key (database& d, string n)
+ : db (d),
+ name (move (n), package_name::raw_string) {}
+
+ bool
+ operator== (const package_version_key& v) const
+ {
+ // See operator==(database, database).
+ //
+ return name == v.name &&
+ version == v.version &&
+ &db.get () == &v.db.get ();
+ }
+
+ bool
+ operator!= (const package_version_key& v) const
+ {
+ return !(*this == v);
+ }
+
+ bool
+ operator< (const package_version_key&) const;
+
+ // Return the package string representation in the form:
+ //
+ // <name>[/<version>] [ <config-dir>]
+ //
+ std::string
+ string (bool ignore_version = false) const;
+ };
+
+ inline ostream&
+ operator<< (ostream& os, const package_version_key& p)
+ {
+ return os << p.string ();
+ }
+
// Return a count of repositories that contain this repository fragment.
//
#pragma db view table("main.repository_fragments")
diff --git a/bpkg/package.xml b/bpkg/package.xml
index eafcaa8..8020ff3 100644
--- a/bpkg/package.xml
+++ b/bpkg/package.xml
@@ -1,4 +1,132 @@
<changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="sqlite" version="1">
+ <changeset version="26">
+ <alter-table name="main.available_package_tests">
+ <add-column name="test_enable" type="TEXT" null="true"/>
+ </alter-table>
+ </changeset>
+
+ <changeset version="25">
+ <alter-table name="main.selected_package_prerequisites">
+ <drop-column name="config_dependency_index"/>
+ <drop-column name="config_alternative_index"/>
+ </alter-table>
+ <add-table name="main.selected_package_dependency_alternatives" kind="container">
+ <column name="package" type="TEXT" null="true" options="COLLATE NOCASE"/>
+ <column name="index" type="INTEGER" null="true"/>
+ <column name="position" type="INTEGER" null="true"/>
+ <foreign-key name="package_fk" on-delete="CASCADE">
+ <column name="package"/>
+ <references table="main.selected_package">
+ <column name="name"/>
+ </references>
+ </foreign-key>
+ <index name="selected_package_dependency_alternatives_package_i">
+ <column name="package"/>
+ </index>
+ <index name="selected_package_dependency_alternatives_index_i">
+ <column name="index"/>
+ </index>
+ </add-table>
+ </changeset>
+
+ <changeset version="24">
+ <alter-table name="main.selected_package">
+ <add-column name="config_checksum" type="TEXT" null="true" default="''"/>
+ </alter-table>
+ </changeset>
+
+ <changeset version="23">
+ <alter-table name="main.available_package">
+ <add-column name="type" type="TEXT" null="true"/>
+ </alter-table>
+ <add-table name="main.available_package_languages" kind="container">
+ <column name="name" type="TEXT" null="true" options="COLLATE NOCASE"/>
+ <column name="version_epoch" type="INTEGER" null="true"/>
+ <column name="version_canonical_upstream" type="TEXT" null="true"/>
+ <column name="version_canonical_release" type="TEXT" null="true" options="COLLATE BINARY"/>
+ <column name="version_revision" type="INTEGER" null="true"/>
+ <column name="version_iteration" type="INTEGER" null="true"/>
+ <column name="index" type="INTEGER" null="true"/>
+ <column name="language_name" type="TEXT" null="true"/>
+ <column name="language_impl" type="INTEGER" null="true"/>
+ <foreign-key name="object_id_fk" on-delete="CASCADE">
+ <column name="name"/>
+ <column name="version_epoch"/>
+ <column name="version_canonical_upstream"/>
+ <column name="version_canonical_release"/>
+ <column name="version_revision"/>
+ <column name="version_iteration"/>
+ <references table="main.available_package">
+ <column name="name"/>
+ <column name="version_epoch"/>
+ <column name="version_canonical_upstream"/>
+ <column name="version_canonical_release"/>
+ <column name="version_revision"/>
+ <column name="version_iteration"/>
+ </references>
+ </foreign-key>
+ <index name="available_package_languages_object_id_i">
+ <column name="name"/>
+ <column name="version_epoch"/>
+ <column name="version_canonical_upstream"/>
+ <column name="version_canonical_release"/>
+ <column name="version_revision"/>
+ <column name="version_iteration"/>
+ </index>
+ <index name="available_package_languages_index_i">
+ <column name="index"/>
+ </index>
+ </add-table>
+ </changeset>
+
+ <changeset version="22">
+ <alter-table name="main.available_package">
+ <add-column name="upstream_version" type="TEXT" null="true"/>
+ <add-column name="project" type="TEXT" null="true" options="COLLATE NOCASE"/>
+ </alter-table>
+ </changeset>
+
+ <changeset version="21">
+ <add-table name="main.available_package_distribution_values" kind="container">
+ <column name="name" type="TEXT" null="true" options="COLLATE NOCASE"/>
+ <column name="version_epoch" type="INTEGER" null="true"/>
+ <column name="version_canonical_upstream" type="TEXT" null="true"/>
+ <column name="version_canonical_release" type="TEXT" null="true" options="COLLATE BINARY"/>
+ <column name="version_revision" type="INTEGER" null="true"/>
+ <column name="version_iteration" type="INTEGER" null="true"/>
+ <column name="index" type="INTEGER" null="true"/>
+ <column name="dist_name" type="TEXT" null="true"/>
+ <column name="dist_value" type="TEXT" null="true"/>
+ <foreign-key name="object_id_fk" on-delete="CASCADE">
+ <column name="name"/>
+ <column name="version_epoch"/>
+ <column name="version_canonical_upstream"/>
+ <column name="version_canonical_release"/>
+ <column name="version_revision"/>
+ <column name="version_iteration"/>
+ <references table="main.available_package">
+ <column name="name"/>
+ <column name="version_epoch"/>
+ <column name="version_canonical_upstream"/>
+ <column name="version_canonical_release"/>
+ <column name="version_revision"/>
+ <column name="version_iteration"/>
+ </references>
+ </foreign-key>
+ <index name="available_package_distribution_values_object_id_i">
+ <column name="name"/>
+ <column name="version_epoch"/>
+ <column name="version_canonical_upstream"/>
+ <column name="version_canonical_release"/>
+ <column name="version_revision"/>
+ <column name="version_iteration"/>
+ </index>
+ <index name="available_package_distribution_values_index_i">
+ <column name="index"/>
+ </index>
+ </add-table>
+ </changeset>
+
<changeset version="20">
<alter-table name="main.available_package">
<add-column name="alt_naming" type="INTEGER" null="true" default="0"/>
diff --git a/bpkg/pkg-bindist.cli b/bpkg/pkg-bindist.cli
new file mode 100644
index 0000000..1401723
--- /dev/null
+++ b/bpkg/pkg-bindist.cli
@@ -0,0 +1,908 @@
+// file : bpkg/pkg-bindist.cli
+// license : MIT; see accompanying LICENSE file
+
+include <map>;
+
+include <bpkg/configuration.cli>;
+
+"\section=1"
+"\name=bpkg-pkg-bindist"
+"\summary=generate binary distribution package"
+
+namespace bpkg
+{
+ {
+ "<options> <dir> <vars> <pkg>",
+
+ "\h|SYNOPSIS|
+
+ \c{\b{bpkg pkg-bindist}|\b{bindist} [\b{--output-root}|\b{-o} <dir>] [<options>] [<vars>] <pkg>...}
+
+ \h|DESCRIPTION|
+
+ The \cb{pkg-bindist} command generates a binary distribution package for
+ the specified package. If additional packages are specified, then they
+ are bundled in the same distribution package. All the specified packages
+ must have been previously configured with \l{bpkg-pkg-build(1)} or
+ \l{bpkg-pkg-configure(1)}. For some system package managers a directory
+ for intermediate files and subdirectories as well as the resulting binary
+ package may have to be specified explicitly with the
+ \c{\b{--output-root}|\b{-o}} option.
+
+ Underneath, this command roughly performs the following steps: First it
+ installs the specified packages similar to the \l{bpkg-pkg-install(1)}
+ command except that it may override the installation locations (via the
+ \cb{config.install.*} variables) to match the distribution's layout. Then
+ it generates any necessary distribution package metadata files based on
+ the information from the package \cb{manifest} files. Finally, it invokes
+ the distribution-specific command to produce the binary package. Unless
+ overridden with the \cb{--architecture} and \cb{--distribution} options,
+ the binary package is generated for the host architecture using the
+ host's standard system package manager. Additional command line variables
+ (<vars>, normally \cb{config.*}) can be passed to the build system during
+ the installation step. See the following distribution-specific
+ description sections below for details and invocation examples:
+
+ \l{#debian DEBIAN DESCRIPTION}
+
+ \l{#fedora FEDORA DESCRIPTION}
+
+ \l{#archive ARCHIVE DESCRIPTION}
+
+ The specified packages may have dependencies and the default behavior is
+ to not bundle them but rather to specify them as dependencies in the
+ corresponding distribution package metadata, if applicable. This default
+ behavior can be overridden with the \cb{--recursive} option (see the
+ option description for the available modes). Note, however, that
+ dependencies that are satisfied by system packages are always specified
+ as dependencies in the distribution package metadata (if applicable).
+ "
+ }
+
+ // Place distribution-specific options into separate classes in case one day
+ // we want to only pass their own options to each implementation.
+ //
+ class pkg_bindist_common_options: configuration_options
+ {
+ "\h|PKG-BINDIST OPTIONS|
+
+ See the following sections below for distribution-specific options:
+
+ \l{#debian-options PKG-BINDIST DEBIAN OPTIONS}
+
+ \l{#fedora-options PKG-BINDIST FEDORA OPTIONS}
+
+ \l{#archive-options PKG-BINDIST ARCHIVE OPTIONS}
+ "
+
+ string --distribution
+ {
+ "<name>",
+ "Alternative system/distribution package manager to generate the binary
+ package for. The valid <name> values are \cb{debian} (Debian and alike,
+ such as Ubuntu, etc), \cb{fedora} (Fedora and alike, such as RHEL,
+ CentOS, etc), and \cb{archive} (installation archive on any operating
+ system). Note that some package managers may only be supported when
+ running on certain host operating systems."
+ }
+
+ string --architecture
+ {
+ "<name>",
+ "Alternative architecture to generate the binary package for. The
+ valid <name> values are system/distribution package manager-specific.
+ If unspecified, the host architecture is used."
+ }
+
+ string --recursive = "none"
+ {
+ "<mode>",
+ "Bundle or generate dependencies of the specified packages. The <mode>
+ value can be either \cb{auto}, in which case only the required files
+ from each dependency package are bundled, \cb{full}, in which case
+ all the files are bundled, or \cb{separate}, in which case a separate
+ binary package is generated for each non-system dependency. It can
+ also be \cb{none} which is equivalent to not specifying this option
+ (primarily useful for overriding a previously-specified value).
+
+ Specifically, in the \cb{auto} mode any required files, such as shared
+ libraries, are pulled implicitly by the \cb{install} build system
+ operation, for example, as part of installing an executable from one of
+ the specified packages. In contrast, in the \cb{full} mode, each
+ dependency package is installed explicitly and completely, as if they
+ were specified as additional package on the command line. The
+ \cb{separate} mode is equivalent to invoking the \cb{pkg-bindist}
+ command on each dependency package. See also the \cb{--private} option."
+ }
+
+ bool --private
+ {
+ "Enable the private installation subdirectory functionality using the
+ package name as the private subdirectory. This is primarily useful when
+ bundling dependencies, such as shared libraries, of an executable that
+ is being installed into a shared location, such as \cb{/usr/}. See the
+ \cb{config.install.private} configuration variable documentation in the
+ build system manual for details. This option only makes sense together
+ with the \cb{--recursive} option \cb{auto} and \cb{full} modes."
+ }
+
+ dir_path --output-root|-o
+ {
+ "<dir>",
+ "Directory for intermediate files and subdirectories as well as the
+ resulting binary package. Note that this option may be required for
+ some system package managers and may not be specified for others."
+ }
+
+ bool --wipe-output
+ {
+ "Wipe the output root directory (either specified with \ci{--output-root}
+ or system package manager-specific) clean before using it to generate
+ the binary package."
+ }
+
+ bool --keep-output
+ {
+ "Keep intermediate files in the output root directory (either specified
+ with \ci{--output-root} or system package manager-specific) that were
+ used to generate the binary package. This is primarily useful for
+ troubleshooting."
+ }
+
+ bool --allow-dependent-config
+ {
+ "Allow configuration that is imposed by dependent packages. Normally
+ this is undesirable because the resulting binary packages become
+ configured specificaly for particular dependent packages."
+ }
+
+ string --os-release-id
+ {
+ "<v>",
+ "Override the \cb{ID} component in \cb{os-release(5)} or equivalent.
+ Note that unlike the rest of the \cb{--os-release-*} options, this
+ option suppresses automatic detection of the host operating system
+ information."
+ }
+
+ string --os-release-version-id
+ {
+ "<v>",
+ "Override the \cb{VERSION_ID} component in \cb{os-release(5)} or
+ equivalent."
+ }
+
+ string --os-release-name
+ {
+ "<v>",
+ "Override the \cb{NAME} component in \cb{os-release(5)} or equivalent."
+ }
+ };
+
+ class pkg_bindist_debian_options
+ {
+ "\h#debian|DEBIAN DESCRIPTION|
+
+ The Debian binary packages are generated by producing the standard
+ \cb{debian/control}, \cb{debian/rules}, and other package metadata files
+ and then invoking \cb{dpkg-buildpackage(1)} to build the binary package
+ from that. In particular, the \cb{debian/rules} implemenation is based on
+ the \cb{dh(1)} command sequencer. While this approach is normally used to
+ build packages from source, this implementation \"pretends\" that this is
+ what's happening by overriding a number of \cb{dh} targets to invoke the
+ \cb{build2} build system on the required packages directly in their
+ \cb{bpkg} configuration locations.
+
+ The \cb{dpkg-dev} (or \cb{build-essential}) and \cb{debhelper} Debian
+ packages must be installed before invocation. Typical invocation:
+
+ \
+ bpkg build libhello
+ bpkg test libhello
+ bpkg bindist -o /tmp/output/ libhello
+ \
+
+ Unless the \cb{--recursive} option \cb{auto} or \cb{full} modes are
+ specified, dependencies of the specified package are translated to
+ dependencies in the resulting binary package using names and versions
+ that refer to packages that would be generated by the \cb{pkg-bindist}
+ command (called \"non-native\" packages). If instead you would like
+ certain dependencies to refer to binary packages provided by the
+ distribution (called \"native\" packages), then you need to arrange for
+ them to be built as system (see \l{bpkg-pkg-build(1)} for details). For
+ example, if our \cb{libhello} has a dependency on \cb{libsqlite3} and we
+ would like the binary package for \cb{libhello} to refer to
+ \cb{libsqlite3} from Debian (or alike), then the \cb{pkg-build} command
+ would need to be (\cb{--sys-install} is optional):
+
+ \
+ bpkg build --sys-install libhello ?sys:libsqlite3
+ \
+
+ Such a package with native dependencies can then be installed (including
+ any missing native dependencies) using the \cb{apt} or \cb{apt-get}
+ \cb{install} command. Note that the specified \cb{.deb} file must include
+ a directory separator (\c{/}) in order to be recognized as a file rather
+ than a package name. For example:
+
+ \
+ sudo apt-get install ./libhello_1.2.3-0~debian11_amd64.deb \
+ ./libhello-dev_1.2.3-0~debian11_amd64.deb
+ \
+
+ See \l{bpkg#bindist-mapping-debian-produce Debian Package Mapping for
+ Production} for details on \cb{bpkg} to Debian package name and version
+ mapping.
+ "
+
+ "\h#debian-options|PKG-BINDIST DEBIAN OPTIONS|"
+
+ bool --debian-prepare-only
+ {
+ "Prepare all the package metadata files (\cb{control}, \cb{rules}, etc)
+ but do not invoke \cb{dpkg-buildpackage} to generate the binary
+ package, printing its command line instead unless requested to be
+ quiet. Implies \cb{--keep-output}."
+ }
+
+ string --debian-buildflags = "assign"
+ {
+ "<mode>",
+ "Package build flags (\cb{dpkg-buildflags}) usage mode. Valid <mode>
+ values are \cb{assign} (use the build flags instead of configured),
+ \cb{append} (use the build flags in addition to configured, putting
+ them last), \cb{prepend} (use the build flags in addition to
+ configured, putting them first), and \cb{ignore} (ignore build
+ flags). The default mode is \cb{assign}. Note that compiler mode
+ options, if any, are used as configured."
+ }
+
+ strings --debian-maint-option
+ {
+ "<o>",
+ "Alternative options to specify in the \cb{DEB_BUILD_MAINT_OPTIONS}
+ variable of the \cb{rules} file. To specify multiple maintainer options
+ repeat this option and/or specify them as a single value separated
+ with spaces."
+ }
+
+ strings --debian-build-option
+ {
+ "<o>",
+ "Additional option to pass to the \cb{dpkg-buildpackage} program. Repeat
+ this option to specify multiple build options."
+ }
+
+ string --debian-build-meta
+ {
+ "<data>",
+ "Alternative or additional build metadata to include in the binary
+ package version. If the specified value starts/ends with \cb{+} then
+ the value (with \cb{+} removed) is added after/before the default
+ metadata. Otherwise it is used as is instead of the default metadata.
+ If empty value is specified, then no build metadata is included. By
+ default, the build metadata is the \cb{ID} and \cb{VERSION_ID}
+ components from \cb{os-release(5)}, for example, \cb{debian10} in
+ version \cb{1.2.3-0~debian10}. See also \cb{--os-release-*}."
+ }
+
+ string --debian-section
+ {
+ "<v>",
+ "Alternative \cb{Section} \cb{control} file field value for the main
+ binary package. The default is either \cb{libs} or \cb{devel},
+ depending on the package type."
+ }
+
+ string --debian-priority
+ {
+ "<v>",
+ "Alternative \cb{Priority} \cb{control} file field value. The default
+ is \cb{optional}."
+ }
+
+ string --debian-maintainer
+ {
+ "<v>",
+ "Alternative \cb{Maintainer} \cb{control} file field value. The
+ default is the \cb{package-email} value from package \cb{manifest}."
+ }
+
+ string --debian-architecture
+ {
+ "<v>",
+ "Alternative \cb{Architecture} \cb{control} file field value for
+ the main binary package, normally \cb{all} (architecture-independent).
+ The default is \cb{any} (architecture-dependent)."
+ }
+
+ string --debian-main-langdep
+ {
+ "<v>",
+ "Override the language runtime dependencies (such as \cb{libc6},
+ \cb{libstdc++6}, etc) in the \cb{Depends} \cb{control} file field
+ value of the main binary package."
+ }
+
+ string --debian-dev-langdep
+ {
+ "<v>",
+ "Override the language runtime dependencies (such as \cb{libc-dev},
+ \cb{libstdc++-dev}, etc) in the \cb{Depends} \cb{control} file field
+ value of the development (\cb{-dev}) binary package."
+ }
+
+ string --debian-main-extradep
+ {
+ "<v>",
+ "Extra dependencies to add to the \cb{Depends} \cb{control} file field
+ value of the main binary package."
+ }
+
+ string --debian-dev-extradep
+ {
+ "<v>",
+ "Extra dependencies to add to the \cb{Depends} \cb{control} file field
+ value of the development (\cb{-dev}) binary package."
+ }
+ };
+
+ class pkg_bindist_fedora_options
+ {
+ "\h#fedora|FEDORA DESCRIPTION|
+
+ The Fedora binary packages are generated by producing the standard RPM
+ spec file and then invoking \cb{rpmbuild(8)} to build the binary package
+ from that. While this approach is normally used to build packages from
+ source, this implementation \"pretends\" that this is what's happening by
+ overriding a number of RPM spec file sections to invoke the \cb{build2}
+ build system on the required packages directly in their \cb{bpkg}
+ configuration locations.
+
+ The \cb{rpmdevtools} Fedora package must be installed before invocation.
+ Typical invocation:
+
+ \
+ bpkg build libhello
+ bpkg test libhello
+ bpkg bindist libhello
+ \
+
+ The resulting binary packages are placed into the standard \cb{rpmbuild}
+ output directory (normally \c{\b{~/rpmbuild/RPMS/}\i{arch}\b{/}}).
+
+ Unless the \cb{--recursive} option \cb{auto} or \cb{full} modes are
+ specified, dependencies of the specified package are translated to
+ dependencies in the resulting binary package using names and versions
+ that refer to packages that would be generated by the \cb{pkg-bindist}
+ command (called \"non-native\" packages). If instead you would like
+ certain dependencies to refer to binary packages provided by the
+ distribution (called \"native\" packages), then you need to arrange for
+ them to be built as system (see \l{bpkg-pkg-build(1)} for details). For
+ example, if our \cb{libhello} has a dependency on \cb{libsqlite3} and we
+ would like the binary package for \cb{libhello} to refer to
+ \cb{sqlite-libs} from Fedora (or alike), then the \cb{pkg-build} command
+ would need to be (\cb{--sys-install} is optional):
+
+ \
+ bpkg build --sys-install libhello ?sys:libsqlite3
+ \
+
+ Such a package with native dependencies can then be installed (including
+ any missing native dependencies) using the \cb{dnf install} command.
+ For example:
+
+ \
+ sudo dnf install libhello-1.2.3-1.fc35.x86_64.rpm \
+ libhello-devel-1.2.3-1.fc35.x86_64.rpm
+ \
+
+ See \l{bpkg#bindist-mapping-fedora-produce Fedora Package Mapping for
+ Production} for details on \cb{bpkg} to Fedora package name and version
+ mapping.
+ "
+
+ "\h#fedora-options|PKG-BINDIST FEDORA OPTIONS|"
+
+ bool --fedora-prepare-only
+ {
+ "Prepare the RPM spec file but do not invoke \cb{rpmbuild} to generate
+ the binary package, printing its command line instead unless requested
+ to be quiet."
+ }
+
+ string --fedora-buildflags = "assign"
+ {
+ "<mode>",
+ "Package build flags (\cb{%{build_*flags\}} macros) usage mode. Valid
+ <mode> values are \cb{assign} (use the build flags instead of
+ configured), \cb{append} (use the build flags in addition to
+ configured, putting them last), \cb{prepend} (use the build flags in
+ addition to configured, putting them first), and \cb{ignore} (ignore
+ build flags). The default mode is \cb{assign}. Note that compiler mode
+ options, if any, are used as configured."
+ }
+
+ strings --fedora-build-option
+ {
+ "<o>",
+ "Additional option to pass to the \cb{rpmbuild} program. If specified,
+ these options must be consistent with the query options
+ (\cb{--fedora-query-option}) to result in identical macro
+ expansions. Repeat this option to specify multiple build options."
+ }
+
+ strings --fedora-query-option
+ {
+ "<o>",
+ "Additional option to pass to the \cb{rpm} program. This program is used
+ to query RPM macro values which affect the binary package. If
+ specified, these options must be consistent with the build options
+ (\cb{--fedora-build-option}) to result in identical macro expansions.
+ Repeat this option to specify multiple query options."
+ }
+
+ string --fedora-dist-tag
+ {
+ "<tag>",
+ "Alternative or additional distribution tag to use in the binary package
+ release. If the specified value starts/ends with \cb{+} then the value
+ (with \cb{+} removed) is added after/before the default distribution
+ tag. Otherwise it is used as is instead of the default tag. If empty
+ value is specified, then no distribution tag is included. The default
+ is a value that identifies the distribution being used to build the
+ package, for example, \cb{fc35} for Fedora 35 or \cb{el8} for RHEL 8."
+ }
+
+ string --fedora-packager
+ {
+ "<v>",
+ "Alternative \cb{Packager} RPM spec file directive value. The default is
+ the \cb{package-email} value from package \cb{manifest}. If empty value
+ is specified, then the \cb{Packager} directive is omitted from the spec
+ file."
+ }
+
+ string --fedora-build-arch
+ {
+ "<v>",
+ "\cb{BuildArch} RPM spec file directive value for the main binary
+ package, normally \cb{noarch} (architecture-independent). By default
+ the directive is omitted, assuming that the package is
+ architecture-dependent."
+ }
+
+ strings --fedora-main-langreq
+ {
+ "<v>",
+ "Override the language runtime dependencies (such as \cb{glibc},
+ \cb{libstdc++}, etc) of the main binary package by replacing the
+ corresponding \cb{Requires} RPM spec file directives. If empty value is
+ specified then no language runtime dependencies are specified. Repeat
+ this option to specify multiple language runtime dependencies."
+ }
+
+ strings --fedora-devel-langreq
+ {
+ "<v>",
+ "Override the language runtime dependencies (such as \cb{glibc-devel},
+ \cb{libstdc++-devel}, etc) of the development (\cb{-devel}) binary
+ package by replacing the corresponding \cb{Requires} RPM spec file
+ directives. If empty value is specified then no language runtime
+ dependencies are specified. Repeat this option to specify multiple
+ language runtime dependencies."
+ }
+
+ strings --fedora-stat-langreq
+ {
+ "<v>",
+ "Override the language runtime dependencies (such as \cb{glibc-static},
+ \cb{libstdc++-static}, etc) of the static libraries (\cb{-static})
+ binary package by replacing the corresponding \cb{Requires} RPM spec
+ file directives. If empty value is specified then no language runtime
+ dependencies are specified. Repeat this option to specify multiple
+ language runtime dependencies."
+ }
+
+ strings --fedora-main-extrareq
+ {
+ "<v>",
+ "Extra dependency to add to the main binary package as an additional
+ \cb{Requires} RPM spec file directive. Repeat this option to specify
+ multiple extra dependencies."
+ }
+
+ strings --fedora-devel-extrareq
+ {
+ "<v>",
+ "Extra dependency to add to the development (\cb{-devel}) binary package
+ as an additional \cb{Requires} RPM spec file directive. Repeat this
+ option to specify multiple extra dependencies."
+ }
+
+ strings --fedora-stat-extrareq
+ {
+ "<v>",
+ "Extra dependency to add to the static libraries (\cb{-static}) binary
+ package as an additional \cb{Requires} RPM spec file directive. Repeat
+ this option to specify multiple extra dependencies."
+ }
+ };
+
+ class pkg_bindist_archive_options
+ {
+ "\h#archive|ARCHIVE DESCRIPTION|
+
+ The installation archive binary packages are generated by invoking the
+ \cb{build2} build system on the required packages directly in their
+ \cb{bpkg} configuration locations and installing them into the binary
+ package directory using the \cb{config.install.chroot} mechanism. Then
+ this directory is packaged with \cb{tar} or \cb{zip} to produce one or
+ more binary package archives.
+
+ The generation of installation archive packages is never the default and
+ should be requested explicitly with the \cb{--distribution=archive}
+ option. The installation directory layout and the package archives to
+ generate can be specified with the \cb{--archive-install-*} and
+ \cb{--archive-type} options (refer to their documentation for defaults).
+
+ The binary package directory (the top-level directory inside the
+ archive) as well as the archive file base (the file name without
+ the extension) are the same and have the following form:
+
+ \c{\i{package}-\i{version}-\i{build_metadata}}
+
+ Where \ci{package} is the package name and \ci{version} is the \cb{bpkg}
+ package version. Unless overridden with the \cb{--archive-build-meta}
+ option, \ci{build_metadata} has the following form:
+
+ \c{\i{cpu}-\i{os}[-\i{langrt}...]}
+
+ Where \ci{cpu} is the target CPU (for example, \cb{x86_64} or
+ \cb{aarch64}; omitted if \cb{--archive-no-cpu} is specified), \ci{os} is
+ the \cb{ID} and \cb{VERSION_ID} components from \cb{os-release(5)} (or
+ equivalent, for example, \cb{debian11} or \cb{windows10}; omitted if
+ \cb{--archive-no-os} is specified), and \ci{langrt} are the language
+ runtimes as mapped by the \cb{--archive-lang*} options (for example,
+ \cb{gcc12} or \cb{msvc17.4}).
+
+ For example, given the following invocation on Debian 11 running on
+ \cb{x86_64}:
+
+ \
+ bpkg build libhello
+ bpkg test libhello
+ bpkg bindist \
+ -o /tmp/output/ \
+ --distribution=archive \
+ --archive-lang cc=gcc12 \
+ libhello
+ \
+
+ We will end up with the package archive in the following form:
+
+ \
+ libhello-1.2.3-x86_64-debian11-gcc12.tar.xz
+ \
+
+ The recommended language runtime id format is the runtime name followed
+ by the version, for example, \cb{gcc12} or \cb{msvc17.4}. Note that its
+ purpose is not to provide a precise specification of requirements but
+ rather to help the user of a binary package to pick the appropriate
+ variant. Refer to the \cb{--archive-lang*} options documentation for
+ details on the mapping semantics.
+
+ Instead of mapping languages individually you can specify entire build
+ metadata as a single value with the \cb{--archive-build-meta} (it is also
+ possible to add additional metadata; see the option documentation for
+ details). For example:
+
+ \
+ bpkg bindist \
+ -o /tmp/output/ \
+ --distribution=archive \
+ --archive-build-meta=x86_64-linux-glibc
+ libhello
+ \
+
+ This will produce the package archive in the following form:
+
+ \
+ libhello-1.2.3-x86_64-linux-glibc.tar.xz
+ \
+
+ To install the binary package from archive simply unpack it using
+ \cb{tar} or \cb{zip}. You can use the \cb{--strip-components} \cb{tar}
+ option to remove the top-level package directory (the same can be
+ achieved for \cb{zip} archives by using \cb{bsdtar} on Windows). For
+ example, to unpack the package contents so that they end up in
+ \cb{/usr/local/}:
+
+ \
+ sudo tar -xf libhello-1.2.3-x86_64-debian11-gcc12.tar.xz \
+ -C / --strip-components=1
+ \
+
+ If you expect the binary package to be unpacked into a directory other
+ than its original installation directory (\cb{--archive-install-root}),
+ then it's recommended to make it relocatable by specifying the
+ \cb{config.install.relocatable=true} configuration variable. For example:
+
+ \
+ bpkg bindist \
+ ... \
+ config.install.relocatable=true \
+ libhello
+ \
+
+ Note that not all source packages support relocatable installation (see
+ \l{b#install-reloc Rolocatable Installation} for details).
+
+ Another mechanism that can useful when generating archive packages is the
+ ability to filter the files being installed. This, for example, can be
+ used to create binary packages that don't contain any development-related
+ files. See \l{b#install-filter Installation Filtering} for details. See
+ also the \cb{--archive-split} option.
+
+ The installation archive package can be generated for a target other than
+ the host by specifying the target triplet with the \cb{--architecture}
+ option. In this case the \cb{bpkg} configuration is assumed to be
+ appropriately configured for cross-compiling to the specified target. You
+ will also need to explicitly specify the \cb{--archive-install-root}
+ option (or \cb{--archive-install-config}) as well as the
+ \cb{--os-release-id} option (and likely want to specify other
+ \cb{--os-release-*} options). For example, for cross-compiling from Linux
+ to Windows using the MinGW GCC toolchain:
+
+ \
+ bpkg bindist \
+ --distribution=archive \
+ --architecture=x86_64-w64-mingw32 \
+ --os-release-id=windows \
+ --os-release-name=Windows \
+ --os-release-version-id=10 \
+ --archive-install-root / \
+ --archive-lang cc=mingw_w64_gcc12 \
+ ...
+ \
+ "
+
+ "\h#archive-options|PKG-BINDIST ARCHIVE OPTIONS|"
+
+ bool --archive-prepare-only
+ {
+ "Prepare all the package contents but do not create the binary package
+ archive, printing its directory instead unless requested to be quiet.
+ Implies \cb{--keep-output}."
+ }
+
+ strings --archive-type
+ {
+ "<ext>",
+ "Archive type to create specified as a file extension, for example,
+ \cb{tar.xz}, \cb{tar.gz}, \cb{tar}, \cb{zip}. Repeat this option to
+ generate multiple archive types. If unspecified, then a default type
+ appropriate for the target operating system is used, currently \cb{zip}
+ for Windows and \cb{tar.xz} for POSIX. Note, however, that these
+ defaults may change in the future."
+ }
+
+ std::multimap<string, string> --archive-lang
+ {
+ "<ln>=<rt>",
+ "Map interface language name <ln> to runtime id <rt>. If no mapping is
+ found for an interface language in this map, then fallback to the
+ \cb{--archive-lang-impl} map. If still no mapping is found, then
+ fail. If the information about an interface language is unimportant and
+ should be ignored, then empty runtime id can be specified. Note that
+ the mapping specified with this option is only considered if the
+ package type is a library (for other package types all languages used
+ are implementation). Note also that multiple runtime ids specified for
+ the same language are combined except for an empty id, which is treated
+ as a request to clear previous entries."
+ }
+
+ std::multimap<string, string> --archive-lang-impl
+ {
+ "<ln>=<rt>",
+ "Map implementation language name <ln> to runtime id <rt>. If no mapping
+ is found for an implementation language in this map, then assume
+ the information about this implementation language is unimportant
+ and ignore it (examples of such cases include static linking as well
+ as a language runtime that is always present). See \cb{--archive-lang}
+ for background."
+ }
+
+ bool --archive-no-cpu
+ {
+ "Assume the package is CPU architecture-independent and omit it from
+ the binary package directory name and archive file base."
+ }
+
+ bool --archive-no-os
+ {
+ "Assume the package is operating system-independent and omit it from
+ the binary package directory name and archive file base."
+ }
+
+ string --archive-build-meta
+ {
+ "<data>",
+ "Alternative or additional build metadata to include after the version
+ in the binary package directory and file names. If the specified value
+ starts/ends with \cb{+} then the value (with \cb{+} removed) is added
+ after/before the default metadata. Otherwise it is used as is instead
+ of the default metadata. If empty value is specified, then no build
+ metadata is included."
+ }
+
+ dir_path --archive-install-root
+ {
+ "<d>",
+ "Alternative installation root directory. The default is \cb{/usr/local/}
+ on POSIX and \c{\b{C:\\}\i{project}\b{\\}} on Windows, where
+ \ci{project} is the \l{bpkg#manifest-package-project \cb{project}}
+ package manifest value."
+ }
+
+ bool --archive-install-config
+ {
+ "Use the installation directory layout (\cb{config.install.*} variables)
+ as configured instead of overriding them with defaults appropriate for
+ the target operating system. Note that this includes
+ \cb{config.install.private} and \cb{config.bin.rpath} if needed for a
+ private installation. Note also that the \cb{config.install.root} value
+ is still overridden with the \cb{--archive-install-root} option value
+ if specified."
+ }
+
+ std::map<string, string> --archive-split
+ {
+ "<key>=<filt>",
+ "Split the installation into multiple binary packages. Specifically,
+ for each <key>=<filt> pair, perform the \cb{install} operation with
+ \c{\b{config.install.filter=}\i{filt}} and package the resulting files
+ as \ci{package-key-version-build_metadata} omitting the \ci{-key} part
+ if <key> is empty. Note that wildcard patterns in <filt> must be
+ quoted. See \l{b#install-filter Installation Filtering} for background."
+ }
+ };
+
+ "
+ \h|STRUCTURED RESULT|
+
+ Instead of printing to \cb{stderr} the list of generated binary packages in
+ a format more suitable for human consumption, the \cb{pkg-bindist} command
+ can be instructed to write it to \cb{stdout} in a machine-readable form by
+ specifying the \cb{--structured-result} option. Currently, the only
+ recognized format value for this option is \cb{json} with the output being
+ a JSON object that is a serialized representation of the following C++
+ struct \cb{bindist_result}:
+
+ \
+ struct os_release
+ {
+ string name_id; // ID
+ vector<string> like_ids; // ID_LIKE
+ optional<string> version_id; // VERSION_ID
+ optional<string> variant_id; // VARIANT_ID
+
+ optional<string> name; // NAME
+ optional<string> version_codename; // VERSION_CODENAME
+ optional<string> variant; // VARIANT
+ };
+
+ struct file
+ {
+ string type;
+ string path;
+ optional<string> system_name;
+ };
+
+ struct package
+ {
+ string name;
+ string version;
+ optional<string> system_version;
+ vector<file> files;
+ };
+
+ struct bindist_result
+ {
+ string distribution; // --distribution or auto-detected
+ string architecture; // --architecture or auto-detected
+ os_release os_release; // --os-release-* or auto-detected
+ optional<string> recursive; // --recursive
+ bool private; // --private
+ bool dependent_config; // See --allow-dependent-config
+
+ package package;
+ vector<package> dependencies; // Only in --recursive=separate
+ };
+ \
+
+ For example:
+
+ \
+ {
+ \"distribution\": \"debian\",
+ \"architecture\": \"amd64\",
+ \"os_release\": {
+ \"name_id\": \"debian\",
+ \"version_id\": \"11\",
+ \"name\": \"Debian GNU/Linux\"
+ },
+ \"package\": {
+ \"name\": \"libfoo\",
+ \"version\": \"2.5.0-b.23\",
+ \"system_version\": \"2.5.0~b.23-0~debian11\",
+ \"files\": [
+ {
+ \"type\": \"main.deb\",
+ \"path\": \"/tmp/libfoo_2.5.0~b.23-0~debian11_amd64.deb\",
+ \"system_name\": \"libfoo\"
+ },
+ {
+ \"type\": \"dev.deb\",
+ \"path\": \"/tmp/libfoo-dev_2.5.0~b.23-0~debian11_amd64.deb\",
+ \"system_name\": \"libfoo-dev\"
+ },
+ ...
+ ]
+ }
+ }
+ \
+
+ See the JSON OUTPUT section in \l{bpkg-common-options(1)} for details on
+ the overall properties of this format and the semantics of the \cb{struct}
+ serialization.
+
+ The \cb{file::type} member is a distribution-specific value that classifies
+ the file. For the \cb{debian} distribution the possible values are
+ \cb{main.deb}, \cb{dev.deb}, \cb{doc.deb}, \cb{common.deb},
+ \cb{dbgsym.deb}, \cb{changes} (\cb{.changes} file), and \cb{buildid}
+ (\cb{.buildid} file); see \l{bpkg#bindist-mapping-debian-produce Debian
+ Package Mapping for Production} for background. For the \cb{fedora}
+ distribution the possible values are \cb{main.rpm}, \cb{devel.rpm},
+ \cb{static.rpm}, \cb{doc.rpm}, \cb{common.rpm}, and \cb{debuginfo.rpm}; see
+ \l{bpkg#bindist-mapping-fedora-produce Fedora Package Mapping for
+ Production} for background. For the \cb{archive} distribution this is the
+ archive type (\cb{--archive-type}), for example, \cb{tar.xz} or \cb{zip},
+ potentially prefixed with \ci{key} if the \cb{--archive-split}
+ functionality is used, for example, \cb{dev.tar.xz}.
+
+ The \cb{package::system_version} and/or \cb{file::system_name} members are
+ absent if not applicable to the distribution. The \cb{file::system_name}
+ member is also absent if the file is not a binary package (for example,
+ \cb{.changes} and \cb{.buildid} files in the \cb{debian} distribution).
+ "
+
+ // NOTE: remember to add the corresponding `--class-doc ...=exclude-base`
+ // (both in bpkg/ and doc/) if adding a new base class.
+ //
+ class pkg_bindist_options: pkg_bindist_common_options,
+ pkg_bindist_debian_options,
+ pkg_bindist_fedora_options,
+ pkg_bindist_archive_options {};
+
+ "
+ \h|DEFAULT OPTIONS FILES|
+
+ See \l{bpkg-default-options-files(1)} for an overview of the default
+ options files. For the \cb{pkg-bindist} command the search start
+ directory is the configuration directory. The following options files are
+ searched for in each directory and, if found, loaded in the order listed:
+
+ \
+ bpkg.options
+ bpkg-pkg-bindist.options
+ \
+
+ The following \cb{pkg-bindist} command options cannot be specified in the
+ default options files:
+
+ \
+ --directory|-d
+ \
+ "
+}
diff --git a/bpkg/pkg-bindist.cxx b/bpkg/pkg-bindist.cxx
new file mode 100644
index 0000000..4639746
--- /dev/null
+++ b/bpkg/pkg-bindist.cxx
@@ -0,0 +1,689 @@
+// file : bpkg/pkg-bindist.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <bpkg/pkg-bindist.hxx>
+
+#include <list>
+#include <iostream> // cout
+
+#include <libbutl/json/serializer.hxx>
+
+#include <bpkg/package.hxx>
+#include <bpkg/package-odb.hxx>
+#include <bpkg/package-query.hxx>
+#include <bpkg/database.hxx>
+#include <bpkg/pkg-verify.hxx>
+#include <bpkg/diagnostics.hxx>
+#include <bpkg/system-package-manager.hxx>
+
+using namespace std;
+using namespace butl;
+
+namespace bpkg
+{
+ using package = system_package_manager::package;
+ using packages = system_package_manager::packages;
+
+ // Find the available package(s) for the specified selected package.
+ //
+ // Specifically, for non-system packages we look for a single available
+ // package. For system packages we look for all the available packages
+ // analogous to pkg-build. If none are found then we assume the
+ // --sys-no-stub option was used to configure this package and return an
+ // empty list. @@ What if it was configured with a specific bpkg version or
+ // `*`?
+ //
+ static available_packages
+ find_available_packages (const common_options& co,
+ database& db,
+ const shared_ptr<selected_package>& p)
+ {
+ assert (p->state == package_state::configured);
+
+ available_packages r;
+ if (p->substate == package_substate::system)
+ {
+ r = find_available_all (repo_configs, p->name);
+ }
+ else
+ {
+ pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>> ap (
+ find_available_fragment (co, db, p));
+
+ if (ap.second.loaded () && ap.second == nullptr)
+ {
+ // This is an orphan. We used to fail but there is no reason we cannot
+ // just load its manifest and make an available package out of that.
+ // And it's handy to be able to run this command on packages built
+ // from archives.
+ //
+ package_manifest m (
+ pkg_verify (co,
+ p->effective_src_root (db.config_orig),
+ true /* ignore_unknown */,
+ false /* ignore_toolchain */,
+ false /* load_buildfiles */,
+ // Copy potentially fixed up version from selected package.
+ [&p] (version& v) {v = p->version;}));
+
+ // Fake the buildfile information (not used).
+ //
+ m.alt_naming = false;
+ m.bootstrap_build = "project = " + p->name.string () + '\n';
+
+ ap.first = make_shared<available_package> (move (m));
+
+ // Fake the location (only used for diagnostics).
+ //
+ ap.second = make_shared<repository_fragment> (
+ repository_location (
+ p->effective_src_root (db.config).representation (),
+ repository_type::dir));
+
+ ap.first->locations.push_back (
+ package_location {ap.second, current_dir});
+ }
+
+ r.push_back (move (ap));
+ }
+
+ return r;
+ }
+
+ // Merge dependency languages for the (ultimate) dependent of the specified
+ // type.
+ //
+ static void
+ merge_languages (const string& type,
+ small_vector<language, 1>& langs,
+ const available_package& ap)
+ {
+ for (const language& l: ap.effective_languages ())
+ {
+ // Unless both the dependent and dependency types are libraries, the
+ // interface/implementation distinction does not apply.
+ //
+ bool lib (type == "lib" && ap.effective_type () == "lib");
+
+ auto i (find_if (langs.begin (), langs.end (),
+ [&l] (const language& x)
+ {
+ return x.name == l.name;
+ }));
+
+ if (i == langs.end ())
+ {
+ // If this is an implementation language for a dependency, then it is
+ // also an implementation language for a dependent. The converse,
+ // howevere, depends on whether this dependency is an interface or
+ // imlementation of this dependent, which we do not know. So we have
+ // to assume it's interface.
+ //
+ langs.push_back (language {l.name, lib && l.impl});
+ }
+ else
+ {
+ i->impl = i->impl && (lib && l.impl); // Merge.
+ }
+ }
+ }
+
+ // Collect dependencies of the specified package, potentially recursively.
+ // System dependencies go to deps, non-system -- to pkgs, which could be the
+ // same as deps or NULL, depending on the desired semantics (see the call
+ // site for details). Find available packages for pkgs and deps and merge
+ // languages.
+ //
+ static void
+ collect_dependencies (const common_options& co,
+ database& db,
+ packages* pkgs,
+ packages& deps,
+ const string& type,
+ small_vector<language, 1>& langs,
+ const selected_package& p,
+ bool recursive)
+ {
+ for (const auto& pr: p.prerequisites)
+ {
+ const lazy_shared_ptr<selected_package>& ld (pr.first);
+
+ // We only consider dependencies from target configurations, similar
+ // to pkg-install.
+ //
+ database& pdb (ld.database ());
+ if (pdb.type == host_config_type || pdb.type == build2_config_type)
+ continue;
+
+ shared_ptr<selected_package> d (ld.load ());
+
+ // Packaging stuff that is spread over multiple configurations is just
+ // too hairy so we don't support it. Specifically, it becomes tricky to
+ // override build options since using a global override will also affect
+ // host/build2 configurations.
+ //
+ if (db != pdb)
+ fail << "dependency package " << *d << " belongs to different "
+ << "configuration " << pdb.config_orig;
+
+ // The selected package can only be configured if all its dependencies
+ // are configured.
+ //
+ assert (d->state == package_state::configured);
+
+ bool sys (d->substate == package_substate::system);
+ packages* ps (sys ? &deps : pkgs);
+
+ // Skip duplicates.
+ //
+ if (ps == nullptr || find_if (ps->begin (), ps->end (),
+ [&d] (const package& p)
+ {
+ return p.selected == d;
+ }) == ps->end ())
+ {
+ const selected_package& p (*d);
+
+ if (ps != nullptr || (recursive && !sys))
+ {
+ available_packages aps (find_available_packages (co, db, d));
+
+ // Load and merge languages.
+ //
+ if (recursive && !sys)
+ {
+ const shared_ptr<available_package>& ap (aps.front ().first);
+ db.load (*ap, ap->languages_section);
+ merge_languages (type, langs, *ap);
+ }
+
+ if (ps != nullptr)
+ {
+ dir_path out;
+ if (ps != &deps)
+ out = p.effective_out_root (db.config);
+
+ ps->push_back (package {move (d), move (aps), move (out)});
+ }
+ }
+
+ if (recursive && !sys)
+ collect_dependencies (co, db, pkgs, deps, type, langs, p, recursive);
+ }
+ }
+ }
+
+ int
+ pkg_bindist (const pkg_bindist_options& o, cli::scanner& args)
+ {
+ tracer trace ("pkg_bindist");
+
+ dir_path c (o.directory ());
+ l4 ([&]{trace << "configuration: " << c;});
+
+ // Verify options.
+ //
+ enum class recursive_mode {auto_, full, separate};
+
+ optional<recursive_mode> rec;
+ {
+ diag_record dr;
+
+ if (o.recursive_specified ())
+ {
+ const string& m (o.recursive ());
+
+ if (m == "auto") rec = recursive_mode::auto_;
+ else if (m == "full") rec = recursive_mode::full;
+ else if (m == "separate") rec = recursive_mode::separate;
+ else if (m != "none")
+ dr << fail << "unknown --recursive mode '" << m << "'";
+ }
+
+ if (o.private_ ())
+ {
+ if (!rec)
+ {
+ dr << fail << "--private specified without --recursive";
+ }
+ else if (*rec == recursive_mode::separate)
+ {
+ dr << fail << "--private specified without --recursive=separate";
+ }
+ }
+
+ if (!dr.empty ())
+ dr << info << "run 'bpkg help pkg-bindist' for more information";
+ }
+
+ if (o.structured_result_specified ())
+ {
+ if (o.no_result ())
+ fail << "both --structured-result and --no-result specified";
+
+ if (o.structured_result () != "json")
+ fail << "unknown --structured-result format '"
+ << o.structured_result () << "'";
+ }
+
+ // Sort arguments into package names and configuration variables.
+ //
+ vector<package_name> pns;
+ strings vars;
+ {
+ bool sep (false); // Seen `--`.
+
+ while (args.more ())
+ {
+ string a (args.next ());
+
+ // If we see the `--` separator, then we are done parsing variables
+ // (while they won't clash with package names, we may be given a
+ // directory path that contains `=`).
+ //
+ if (!sep && a == "--")
+ {
+ sep = true;
+ continue;
+ }
+
+ if (a.find ('=') != string::npos)
+ vars.push_back (move (trim (a)));
+ else
+ {
+ try
+ {
+ pns.push_back (package_name (move (a))); // Not moved on failure.
+ }
+ catch (const invalid_argument& e)
+ {
+ fail << "invalid package name '" << a << "': " << e;
+ }
+ }
+ }
+
+ if (pns.empty ())
+ fail << "package name argument expected" <<
+ info << "run 'bpkg help pkg-bindist' for more information";
+ }
+
+ // Note that we shouldn't need to install anything or use sudo.
+ //
+ pair<unique_ptr<system_package_manager>, string> spm (
+ make_production_system_package_manager (o,
+ host_triplet,
+ o.distribution (),
+ o.architecture ()));
+ if (spm.first == nullptr)
+ {
+ fail << "no standard distribution package manager for this host "
+ << "or it is not yet supported" <<
+ info << "consider specifying alternative distribution package "
+ << "manager with --distribution" <<
+ info << "specify --distribution=archive to generate installation "
+ << "archive" <<
+ info << "consider specifying --os-release-* if unable to correctly "
+ << "auto-detect host operating system";
+ }
+
+ database db (c, trace, true /* pre_attach */);
+
+ // Similar to pkg-install we disallow generating packages from the
+ // host/build2 configurations.
+ //
+ if (db.type == host_config_type || db.type == build2_config_type)
+ {
+ fail << "unable to generate distribution package from " << db.type
+ << " configuration" <<
+ info << "use target configuration instead";
+ }
+
+ // Prepare for the find_available_*() calls.
+ //
+ repo_configs.push_back (db);
+
+ transaction t (db);
+
+ // We need to suppress duplicate dependencies for the recursive mode.
+ //
+ session ses;
+
+ // Generate one binary package.
+ //
+ using binary_file = system_package_manager::binary_file;
+ using binary_files = system_package_manager::binary_files;
+
+ struct result
+ {
+ binary_files bins;
+ packages deps;
+ shared_ptr<selected_package> pkg;
+ };
+
+ bool dependent_config (false);
+
+ auto generate = [&o, &vars,
+ rec, &spm,
+ &c, &db,
+ &dependent_config] (const vector<package_name>& pns,
+ bool first) -> result
+ {
+ // Resolve package names to selected packages and verify they are all
+ // configured. While at it collect their available packages and
+ // dependencies as well as figure out type and languages.
+ //
+ packages pkgs, deps;
+ string type;
+ small_vector<language, 1> langs;
+
+ for (const package_name& n: pns)
+ {
+ shared_ptr<selected_package> p (db.find<selected_package> (n));
+
+ if (p == nullptr)
+ fail << "package " << n << " does not exist in configuration " << c;
+
+ if (p->state != package_state::configured)
+ fail << "package " << n << " is " << p->state <<
+ info << "expected it to be configured";
+
+ if (p->substate == package_substate::system)
+ fail << "package " << n << " is configured as system";
+
+ // Make sure there are no dependent configuration variables. The
+ // rationale here is that we most likely don't want to generate a
+ // binary package in a configuration that is specific to some
+ // dependents.
+ //
+ for (const config_variable& v: p->config_variables)
+ {
+ switch (v.source)
+ {
+ case config_source::dependent:
+ {
+ if (!o.allow_dependent_config ())
+ {
+ fail << "configuration variable " << v.name << " is imposed "
+ << " by dependent package" <<
+ info << "specify it as user configuration to allow" <<
+ info << "or specify --allow-dependent-config";
+ }
+
+ dependent_config = true;
+ break;
+ }
+ case config_source::user:
+ case config_source::reflect:
+ break;
+ }
+
+ if (dependent_config)
+ break;
+ }
+
+ // Load the available package for type/languages as well as the
+ // mapping information.
+ //
+ available_packages aps (find_available_packages (o, db, p));
+ const shared_ptr<available_package>& ap (aps.front ().first);
+ db.load (*ap, ap->languages_section);
+
+ if (pkgs.empty ()) // First.
+ {
+ type = ap->effective_type ();
+ langs = ap->effective_languages ();
+ }
+ else
+ merge_languages (type, langs, *ap);
+
+ const selected_package& r (*p);
+ pkgs.push_back (
+ package {move (p), move (aps), r.effective_out_root (db.config)});
+
+ // If --recursive is not specified or specified with the seperate mode
+ // then we want all the immediate (system and non-) dependecies in
+ // deps. Otherwise, if the recursive mode is full, then we want all
+ // the transitive non-system dependecies in pkgs. In both recursive
+ // modes we also want all the transitive system dependecies in deps.
+ //
+ // Note also that in the auto recursive mode it's possible that some
+ // of the system dependencies are not really needed. But there is no
+ // way for us to detect this and it's better to over- than
+ // under-specify.
+ //
+ collect_dependencies (
+ o,
+ db,
+ (!rec || *rec == recursive_mode::separate
+ ? &deps
+ : *rec == recursive_mode::full ? &pkgs : nullptr),
+ deps,
+ type,
+ langs,
+ r,
+ rec.has_value ());
+ }
+
+ // Load the package manifest (source of extra metadata). This should be
+ // always possible since the package is configured and is not system.
+ //
+ const shared_ptr<selected_package>& sp (pkgs.front ().selected);
+
+ package_manifest pm (
+ pkg_verify (o,
+ sp->effective_src_root (db.config_orig),
+ true /* ignore_unknown */,
+ false /* ignore_toolchain */,
+ false /* load_buildfiles */,
+ // Copy potentially fixed up version from selected package.
+ [&sp] (version& v) {v = sp->version;}));
+
+ optional<bool> recursive_full;
+ if (rec && *rec != recursive_mode::separate)
+ recursive_full = (*rec == recursive_mode::full);
+
+ // Note that we pass type from here in case one day we want to provide
+ // an option to specify/override it (along with languages). Note that
+ // there will probably be no way to override type for dependencies.
+ //
+ binary_files r (spm.first->generate (pkgs,
+ deps,
+ vars,
+ db.config,
+ pm,
+ type, langs,
+ recursive_full,
+ first));
+
+ return result {move (r), move (deps), move (pkgs.front ().selected)};
+ };
+
+ list<result> rs; // Note: list for reference stability.
+
+ // Generate packages for dependencies, recursively, suppressing
+ // duplicates. Note: recursive lambda.
+ //
+ auto generate_deps = [&generate, &rs] (const packages& deps,
+ const auto& generate_deps) -> void
+ {
+ for (const package& d: deps)
+ {
+ const shared_ptr<selected_package>& p (d.selected);
+
+ // Skip system dependencies.
+ //
+ if (p->substate == package_substate::system)
+ continue;
+
+ // Make sure we don't generate the same dependency multiple times.
+ //
+ if (find_if (rs.begin (), rs.end (),
+ [&p] (const result& r)
+ {
+ return r.pkg == p;
+ }) != rs.end ())
+ continue;
+
+ if (verb >= 1)
+ text << "generating package for dependency " << p->name;
+
+ rs.push_back (generate ({p->name}, false /* first */));
+ generate_deps (rs.back ().deps, generate_deps);
+ }
+ };
+
+ // Generate top-level package(s).
+ //
+ rs.push_back (generate (pns, true /* first */));
+
+ // Generate dependencies, if requested.
+ //
+ if (rec && rec == recursive_mode::separate)
+ generate_deps (rs.back ().deps, generate_deps);
+
+ t.commit ();
+
+ if (rs.front ().bins.empty ())
+ return 0; // Assume prepare-only mode or similar.
+
+ if (o.no_result ())
+ ;
+ else if (!o.structured_result_specified ())
+ {
+ if (verb)
+ {
+ const string& d (o.distribution_specified ()
+ ? o.distribution ()
+ : spm.first->os_release.name_id);
+
+ for (auto b (rs.begin ()), i (b); i != rs.end (); ++i)
+ {
+ const selected_package& p (*i->pkg);
+
+ string ver (p.version.string (false /* ignore_revision */,
+ true /* ignore_iteration */));
+
+ diag_record dr (text);
+
+ dr << "generated " << d << " package for "
+ << (i != b ? "dependency " : "")
+ << p.name << '/' << ver << ':';
+
+ for (const binary_file& f: i->bins)
+ dr << "\n " << f.path;
+ }
+ }
+ }
+ else
+ {
+ json::stream_serializer s (cout);
+
+ auto member = [&s] (const char* n, const string& v, const char* d = "")
+ {
+ if (v != d)
+ s.member (n, v);
+ };
+
+ auto package = [&s, &member] (const result& r)
+ {
+ const selected_package& p (*r.pkg);
+ const binary_files& bfs (r.bins);
+
+ string ver (p.version.string (false /* ignore_revision */,
+ true /* ignore_iteration */));
+
+ s.begin_object (); // package
+ {
+ member ("name", p.name.string ());
+ member ("version", ver);
+ member ("system_version", bfs.system_version);
+ s.member_begin_array ("files");
+ for (const binary_file& bf: bfs)
+ {
+ s.begin_object (); // file
+ {
+ member ("type", bf.type);
+ member ("path", bf.path.string ());
+ member ("system_name", bf.system_name);
+ }
+ s.end_object (); // file
+ };
+ s.end_array ();
+ }
+ s.end_object (); // package
+ };
+
+ s.begin_object (); // bindist_result
+ {
+ member ("distribution", spm.second);
+ member ("architecture", spm.first->arch);
+
+ s.member_begin_object ("os_release");
+ {
+ const auto& r (spm.first->os_release);
+
+ member ("name_id", r.name_id);
+
+ if (!r.like_ids.empty ())
+ {
+ s.member_begin_array ("like_ids");
+ for (const string& id: r.like_ids) s.value (id);
+ s.end_array ();
+ }
+
+ member ("version_id", r.version_id);
+ member ("variant_id", r.variant_id);
+
+ member ("name", r.name);
+ member ("version_codename", r.version_codename);
+ member ("variant", r.variant);
+ }
+ s.end_object (); // os_release
+
+ member ("recursive", o.recursive (), "none");
+ if (o.private_ ()) s.member ("private", true);
+ if (dependent_config) s.member ("dependent_config", true);
+
+ s.member_name ("package");
+ package (rs.front ());
+
+ if (rs.size () > 1)
+ {
+ s.member_begin_array ("dependencies");
+ for (auto i (rs.begin ()); ++i != rs.end (); ) package (*i);
+ s.end_array ();
+ }
+ }
+ s.end_object (); // bindist_result
+
+ cout << endl;
+ }
+
+ return 0;
+ }
+
+ pkg_bindist_options
+ merge_options (const default_options<pkg_bindist_options>& defs,
+ const pkg_bindist_options& cmd)
+ {
+ // NOTE: remember to update the documentation if changing anything here.
+
+ return merge_default_options (
+ defs,
+ cmd,
+ [] (const default_options_entry<pkg_bindist_options>& e,
+ const pkg_bindist_options&)
+ {
+ const pkg_bindist_options& o (e.options);
+
+ auto forbid = [&e] (const char* opt, bool specified)
+ {
+ if (specified)
+ fail (e.file) << opt << " in default options file";
+ };
+
+ forbid ("--directory|-d", o.directory_specified ());
+ });
+ }
+}
diff --git a/bpkg/pkg-bindist.hxx b/bpkg/pkg-bindist.hxx
new file mode 100644
index 0000000..3a756f8
--- /dev/null
+++ b/bpkg/pkg-bindist.hxx
@@ -0,0 +1,27 @@
+// file : bpkg/pkg-bindist.hxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BPKG_PKG_BINDIST_HXX
+#define BPKG_PKG_BINDIST_HXX
+
+#include <bpkg/types.hxx>
+#include <bpkg/utility.hxx>
+
+#include <bpkg/pkg-command.hxx>
+#include <bpkg/pkg-bindist-options.hxx>
+
+namespace bpkg
+{
+ // Note that for now it doesn't seem we need to bother with package-
+ // specific configuration variables so it's scanner instead of
+ // group_scanner.
+ //
+ int
+ pkg_bindist (const pkg_bindist_options&, cli::scanner&);
+
+ pkg_bindist_options
+ merge_options (const default_options<pkg_bindist_options>&,
+ const pkg_bindist_options&);
+}
+
+#endif // BPKG_PKG_BINDIST_HXX
diff --git a/bpkg/pkg-build-collect.cxx b/bpkg/pkg-build-collect.cxx
index 244267b..352fa52 100644
--- a/bpkg/pkg-build-collect.cxx
+++ b/bpkg/pkg-build-collect.cxx
@@ -13,6 +13,7 @@
#include <bpkg/package.hxx>
#include <bpkg/package-odb.hxx>
#include <bpkg/database.hxx>
+#include <bpkg/rep-mask.hxx>
#include <bpkg/diagnostics.hxx>
#include <bpkg/satisfaction.hxx>
@@ -29,10 +30,40 @@ namespace bpkg
{
// build_package
//
+ const system_package_status* build_package::
+ system_status () const
+ {
+ assert (action);
+
+ if (*action != build_package::drop && system)
+ {
+ const optional<system_repository>& sys_rep (db.get ().system_repository);
+ assert (sys_rep);
+
+ if (const system_package* sys_pkg = sys_rep->find (name ()))
+ return sys_pkg->system_status;
+ }
+
+ return nullptr;
+ }
+
+ const system_package_status* build_package::
+ system_install () const
+ {
+ if (const system_package_status* s = system_status ())
+ return s->status == system_package_status::partially_installed ||
+ s->status == system_package_status::not_installed
+ ? s
+ : nullptr;
+
+ return nullptr;
+ }
+
bool build_package::
user_selection () const
{
- return required_by.find (package_key {db.get ().main_database (), ""}) !=
+ return required_by.find (package_version_key (db.get ().main_database (),
+ "command line")) !=
required_by.end ();
}
@@ -72,12 +103,22 @@ namespace bpkg
return !system &&
(dependencies ||
selected->version != available_version () ||
+ (flags & build_recollect) != 0 ||
((!config_vars.empty () || skeleton) &&
has_buildfile_clause (available->dependencies)) ||
rpt_depts.find (package_key (db, name ())) != rpt_depts.end ());
}
bool build_package::
+ recursive_collection_postponed () const
+ {
+ assert (action && *action == build_package::build && available != nullptr);
+
+ return dependencies &&
+ dependencies->size () != available->dependencies.size ();
+ }
+
+ bool build_package::
reconfigure () const
{
assert (action && *action != drop);
@@ -88,6 +129,7 @@ namespace bpkg
(*action == build &&
(selected->system () != system ||
selected->version != available_version () ||
+ replace () ||
(!system && (!config_vars.empty () || disfigure)))));
}
@@ -123,7 +165,23 @@ namespace bpkg
// If adjustment or orphan, then new and old are the same.
//
- if (available == nullptr || available->locations.empty ())
+ // Note that in the common case a package version doesn't come from too
+ // many repositories (8).
+ //
+ small_vector<reference_wrapper<const package_location>, 8> locations;
+
+ if (available != nullptr) // Not adjustment?
+ {
+ locations.reserve (available->locations.size ());
+
+ for (const package_location& pl: available->locations)
+ {
+ if (!rep_masked_fragment (pl.repository_fragment))
+ locations.push_back (pl);
+ }
+ }
+
+ if (locations.empty ())
{
assert (selected != nullptr);
@@ -139,7 +197,7 @@ namespace bpkg
}
else
{
- const package_location& pl (available->locations[0]);
+ const package_location& pl (locations[0]);
if (pl.repository_fragment.object_id () == "") // Special root?
{
@@ -159,7 +217,7 @@ namespace bpkg
// Note that such repository fragments are always preferred over
// others (see below).
//
- for (const package_location& pl: available->locations)
+ for (const package_location& pl: locations)
{
const repository_location& rl (
pl.repository_fragment.load ()->location);
@@ -199,10 +257,9 @@ namespace bpkg
//
assert ((flags & build_repoint) == 0 || (p.flags & build_repoint) == 0);
- // We never merge two existing dependent re-evaluations.
+ // If true, then add the user-selection tag.
//
- assert ((flags & build_reevaluate) == 0 ||
- (p.flags & build_reevaluate) == 0);
+ bool add_user_selection (false);
// Copy the user-specified options/variables.
//
@@ -251,21 +308,61 @@ namespace bpkg
// Propagate the user-selection tag.
//
- required_by.emplace (db.get ().main_database (), "");
+ add_user_selection = true;
}
- // Copy the required-by package names only if semantics matches.
+ // Merge in the required-by package names only if semantics matches.
+ // Otherwise, prefer the "required by dependents" semantics since we, in
+ // particular, should never replace such package builds in the map with
+ // package drops (see collect_drop() for details).
//
if (p.required_by_dependents == required_by_dependents)
+ {
required_by.insert (p.required_by.begin (), p.required_by.end ());
+ }
+ else if (p.required_by_dependents)
+ {
+ // Restore the user-selection tag.
+ //
+ if (user_selection ())
+ add_user_selection = true;
+
+ required_by_dependents = true;
+ required_by = move (p.required_by);
+ }
+
+ if (add_user_selection)
+ required_by.emplace (db.get ().main_database (), "command line");
+
+ // Copy constraints, suppressing duplicates.
+ //
+ if (!constraints.empty ())
+ {
+ for (constraint_type& c: p.constraints)
+ {
+ if (find_if (constraints.begin (), constraints.end (),
+ [&c] (const constraint_type& v)
+ {
+ return v.dependent == c.dependent && v.value == c.value;
+ }) == constraints.end ())
+ {
+ constraints.push_back (move (c));
+ }
+ }
+ }
+ else
+ constraints = move (p.constraints);
- // Copy constraints.
+ // Copy upgrade flag if "stronger" (existing wins over non-existing and
+ // upgrade wins over patch).
//
- // Note that we may duplicate them, but this is harmless.
+ if (upgrade < p.upgrade)
+ upgrade = p.upgrade;
+
+ // Copy deorphan flag if greater.
//
- constraints.insert (constraints.end (),
- make_move_iterator (p.constraints.begin ()),
- make_move_iterator (p.constraints.end ()));
+ if (p.deorphan)
+ deorphan = true;
// Copy hold_* flags if they are "stronger".
//
@@ -275,14 +372,19 @@ namespace bpkg
if (!hold_version || (p.hold_version && *p.hold_version > *hold_version))
hold_version = p.hold_version;
- // Copy state flags.
+ // Copy state flags and upgrade dependent repointments and re-evaluations
+ // to the full builds. But in contrast to the repointed dependents we may
+ // merge two dependent re-evaluations.
//
- flags |= p.flags;
+ flags |= (p.flags & ~build_reevaluate);
- // Upgrade dependent repointments and re-evaluations to the full builds.
- //
if (*action == build)
- flags &= ~(build_repoint | build_reevaluate);
+ {
+ flags &= ~build_repoint;
+
+ if ((p.flags & build_reevaluate) == 0)
+ flags &= ~build_reevaluate;
+ }
// Note that we don't copy the build_package::system flag. If it was
// set from the command line ("strong system") then we will also have
@@ -295,6 +397,7 @@ namespace bpkg
package_skeleton& build_package::
init_skeleton (const common_options& options,
+ bool load_old_dependent_config,
const shared_ptr<available_package>& override)
{
shared_ptr<available_package> ap (override != nullptr
@@ -318,14 +421,59 @@ namespace bpkg
ap = nullptr;
}
- optional<dir_path> src_root, out_root;
+ optional<dir_path> src_root;
+ optional<dir_path> out_root;
+
+ optional<dir_path> old_src_root;
+ optional<dir_path> old_out_root;
+ uint16_t load_config_flags (0);
if (ap != nullptr)
{
- src_root = external_dir ();
- out_root = (src_root && !disfigure
- ? dir_path (db.get ().config) /= name ().string ()
- : optional<dir_path> ());
+ bool src_conf (selected != nullptr &&
+ selected->state == package_state::configured &&
+ selected->substate != package_substate::system);
+
+ database& pdb (db);
+
+ // If the package is being reconfigured, then specify {src,out}_root as
+ // the existing source and output root directories not to create the
+ // skeleton directory needlessly. Otherwise, if the being built package
+ // is external, then specify src_root as its existing source directory
+ // and out_root as its potentially non-existing output directory.
+ //
+ // Can we actually use the existing output root directory if the package
+ // is being reconfigured but we are requested to ignore the current
+ // configuration? Yes we can, since load_config_flags stays 0 in this
+ // case and all the variables in config.build will be ignored.
+ //
+ if (src_conf && ap->version == selected->version)
+ {
+ src_root = selected->effective_src_root (pdb.config);
+ out_root = selected->effective_out_root (pdb.config);
+ }
+ else
+ {
+ src_root = external_dir ();
+
+ if (src_root)
+ out_root = dir_path (pdb.config) /= name ().string ();
+ }
+
+ // Specify old_{src,out}_root paths and set load_config_flags if the old
+ // configuration is present and is requested to be loaded.
+ //
+ if (src_conf && (!disfigure || load_old_dependent_config))
+ {
+ old_src_root = selected->effective_src_root (pdb.config);
+ old_out_root = selected->effective_out_root (pdb.config);
+
+ if (!disfigure)
+ load_config_flags |= package_skeleton::load_config_user;
+
+ if (load_old_dependent_config)
+ load_config_flags |= package_skeleton::load_config_dependent;
+ }
}
skeleton = package_skeleton (
@@ -337,7 +485,10 @@ namespace bpkg
disfigure,
(selected != nullptr ? &selected->config_variables : nullptr),
move (src_root),
- move (out_root));
+ move (out_root),
+ move (old_src_root),
+ move (old_out_root),
+ load_config_flags);
return *skeleton;
}
@@ -371,6 +522,231 @@ namespace bpkg
}
}
+ // unsatisfied_dependents
+ //
+ void unsatisfied_dependents::
+ add (const package_key& dpt,
+ const package_key& dep,
+ const version_constraint& c,
+ vector<unsatisfied_constraint>&& ucs,
+ vector<package_key>&& dc)
+ {
+ if (unsatisfied_dependent* ud = find_dependent (dpt))
+ {
+ vector<ignored_constraint>& ics (ud->ignored_constraints);
+
+ // Skip the dependency if it is already in the list.
+ //
+ // It feels that it may already be present in the list with a different
+ // constraint (think of multiple depends clauses with the same
+ // dependency), in which case we leave it unchanged.
+ //
+ if (find_if (ics.begin (), ics.end (),
+ [dep] (const auto& v) {return v.dependency == dep;}) ==
+ ics.end ())
+ {
+ ics.emplace_back (dep, c, move (ucs), move (dc));
+ }
+ }
+ else
+ push_back (
+ unsatisfied_dependent {
+ dpt, {ignored_constraint (dep, c, move (ucs), move (dc))}});
+ }
+
+ unsatisfied_dependent* unsatisfied_dependents::
+ find_dependent (const package_key& dk)
+ {
+ auto i (find_if (begin (), end (),
+ [&dk] (const unsatisfied_dependent& v)
+ {
+ return dk == v.dependent;
+ }));
+ return i != end () ? &*i : nullptr;
+ }
+
+ void unsatisfied_dependents::
+ diag (const build_packages& pkgs)
+ {
+ assert (!empty ());
+
+ const unsatisfied_dependent& dpt (front ());
+ const package_key& dk (dpt.dependent);
+
+ assert (!dpt.ignored_constraints.empty ());
+
+ const ignored_constraint& ic (dpt.ignored_constraints.front ());
+
+ const build_package* p (pkgs.entered_build (ic.dependency));
+ assert (p != nullptr); // The dependency must be collected.
+
+ const version_constraint& c (ic.constraint);
+ const vector<unsatisfied_constraint>& ucs (ic.unsatisfied_constraints);
+
+ const package_name& n (p->name ());
+
+ // " info: ..."
+ string indent (" ");
+
+ if (ucs.empty ()) // 'unable to up/downgrade package' failure.
+ {
+ database& pdb (p->db);
+ const shared_ptr<selected_package>& sp (p->selected);
+
+ // Otherwise, this would be a dependency adjustment (not an
+ // up/down-grade), and thus the dependent must be satisfied with the
+ // already configured dependency.
+ //
+ assert (p->available != nullptr);
+
+ const version& av (p->available_version ());
+
+ // See if we are upgrading or downgrading this package.
+ //
+ int ud (sp->version.compare (av));
+
+ // Otherwise, the dependent must be satisfied with the already
+ // configured dependency.
+ //
+ assert (ud != 0);
+
+ diag_record dr (fail);
+ dr << "unable to " << (ud < 0 ? "up" : "down") << "grade "
+ << "package " << *sp << pdb << " to ";
+
+ // Print both (old and new) package names in full if the system
+ // attribution changes.
+ //
+ if (p->system != sp->system ())
+ dr << p->available_name_version ();
+ else
+ dr << av; // Can't be the wildcard otherwise would satisfy.
+
+ shared_ptr<selected_package> dsp (
+ dk.db.get ().load<selected_package> (dk.name));
+
+ assert (dsp != nullptr); // By definition.
+
+ dr << info << "because configured package " << *dsp << dk.db
+ << " depends on (" << n << ' ' << c << ')';
+
+ // Print the dependency constraints tree for this unsatisfied dependent,
+ // which only contains constraints which come from its selected
+ // dependents, recursively.
+ //
+ {
+ set<package_key> printed;
+ pkgs.print_constraints (
+ dr,
+ dk,
+ indent,
+ printed,
+ (verb >= 2 ? optional<bool> () : true) /* selected_dependent */);
+ }
+
+ // If the dependency we failed to up/downgrade is not explicitly
+ // specified on the command line, then print its dependency constraints
+ // tree which only contains constraints which come from its being built
+ // dependents, recursively.
+ //
+ if (!p->user_selection ())
+ {
+ // The dependency upgrade is always required by someone, the command
+ // line or a package.
+ //
+ assert (!p->required_by.empty ());
+
+ dr << info << "package " << p->available_name_version_db ();
+
+ // Note that if the required_by member contains the dependencies,
+ // rather than the dependents, we will subsequently print the
+ // dependency constraints trees for these dependencies rather than a
+ // single constraints tree (rooted in the dependency we failed to
+ // up/downgrade). Also note that in this case we will still reuse the
+ // same printed packages cache for all print_constraints() calls,
+ // since it will likely be considered as a single dependency graph by
+ // the user.
+ //
+ bool rbd (p->required_by_dependents);
+ dr << (rbd ? " required by" : " dependent of");
+
+ set<package_key> printed;
+ for (const package_version_key& pvk: p->required_by)
+ {
+ dr << '\n' << indent << pvk;
+
+ if (rbd)
+ {
+ const vector<build_package::constraint_type>& cs (p->constraints);
+ auto i (find_if (cs.begin (), cs.end (),
+ [&pvk] (const build_package::constraint_type& v)
+ {
+ return v.dependent == pvk;
+ }));
+
+ if (i != cs.end ())
+ dr << " (" << p->name () << ' ' << i->value << ')';
+ }
+
+ indent += " ";
+ pkgs.print_constraints (
+ dr,
+ package_key (pvk.db, pvk.name),
+ indent,
+ printed,
+ (verb >= 2 ? optional<bool> () : false) /* selected_dependent */);
+
+ indent.resize (indent.size () - 2);
+ }
+ }
+
+ if (verb < 2)
+ dr << info << "re-run with -v for additional dependency information";
+
+ dr << info << "consider re-trying with --upgrade|-u potentially combined "
+ << "with --recursive|-r" <<
+ info << "or explicitly request up/downgrade of package " << dk.name <<
+ info << "or explicitly specify package " << n << " version to "
+ << "manually satisfy these constraints" << endf;
+ }
+ else // 'unable to satisfy constraints' failure.
+ {
+ diag_record dr (fail);
+ dr << "unable to satisfy constraints on package " << n;
+
+ for (const unsatisfied_constraint& uc: ucs)
+ {
+ const build_package::constraint_type& c (uc.constraint);
+
+ dr << info << c.dependent << " depends on (" << n << ' ' << c.value
+ << ')';
+
+ if (const build_package* d = pkgs.dependent_build (c))
+ {
+ set<package_key> printed;
+ pkgs.print_constraints (dr, *d, indent, printed);
+ }
+ }
+
+ for (const unsatisfied_constraint& uc: ucs)
+ {
+ dr << info << "available "
+ << package_string (n, uc.available_version, uc.available_system);
+ }
+
+ for (const package_key& d: reverse_iterate (ic.dependency_chain))
+ {
+ const build_package* p (pkgs.entered_build (d));
+ assert (p != nullptr);
+
+ dr << info << "while satisfying " << p->available_name_version_db ();
+ }
+
+ dr << info << "explicitly specify " << n << " version to "
+ << "manually satisfy both constraints" << endf;
+ }
+ }
+
// postponed_configuration
//
postponed_configuration::dependency*
@@ -390,17 +766,22 @@ namespace bpkg
{
if (dependency* d = find_dependency (dep.position))
{
- // Feels like we can accumulate dependencies into an existing
- // position only for an existing dependent.
- //
- assert (existing);
-
for (package_key& p: dep)
{
// Add the dependency unless it's already there.
//
if (find (d->begin (), d->end (), p) == d->end ())
+ {
+ // Feels like we can accumulate new dependencies into an existing
+ // position only for an existing dependent. Note that we could still
+ // try to add an (supposedly) identical entry for a non-existent
+ // dependent (via some murky paths). Feels like this should be
+ // harmless.
+ //
+ assert (existing);
+
d->push_back (move (p));
+ }
}
// Set the has_alternative flag for an existing dependent. Note that
@@ -409,7 +790,10 @@ namespace bpkg
if (dep.has_alternative)
{
if (!d->has_alternative)
+ {
+ assert (existing); // As above.
d->has_alternative = *dep.has_alternative;
+ }
else
assert (*d->has_alternative == *dep.has_alternative);
}
@@ -480,26 +864,6 @@ namespace bpkg
return false;
}
- const pair<size_t, size_t>* postponed_configuration::
- existing_dependent_position (const package_key& p) const
- {
- const pair<size_t, size_t>* r (nullptr);
-
- auto i (dependents.find (p));
- if (i != dependents.end () && i->second.existing)
- {
- for (const dependency& d: i->second.dependencies)
- {
- if (r == nullptr || d.position < *r)
- r = &d.position;
- }
-
- assert (r != nullptr);
- }
-
- return r;
- }
-
void postponed_configuration::
merge (postponed_configuration&& c)
{
@@ -507,6 +871,9 @@ namespace bpkg
merged_ids.push_back (c.id);
+ for (size_t mid: c.merged_ids)
+ merged_ids.push_back (mid);
+
// Merge dependents.
//
for (auto& d: c.dependents)
@@ -520,10 +887,6 @@ namespace bpkg
for (dependency& sd: sdi.dependencies)
ddi.add (move (sd));
-
- // As in add() above.
- //
- assert (ddi.existing || !sdi.existing);
}
else
dependents.emplace (d.first, move (d.second));
@@ -561,6 +924,33 @@ namespace bpkg
}
bool postponed_configuration::
+ is_shadow_cluster (const postponed_configuration& c)
+ {
+ if (shadow_cluster.size () != c.dependents.size ())
+ return false;
+
+ for (auto& dt: c.dependents)
+ {
+ auto i (shadow_cluster.find (dt.first));
+ if (i == shadow_cluster.end ())
+ return false;
+
+ const positions& ps (i->second);
+
+ if (ps.size () != dt.second.dependencies.size ())
+ return false;
+
+ for (auto& d: dt.second.dependencies)
+ {
+ if (find (ps.begin (), ps.end (), d.position) == ps.end ())
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool postponed_configuration::
contains_in_shadow_cluster (package_key dependent,
pair<size_t, size_t> pos) const
{
@@ -978,7 +1368,7 @@ namespace bpkg
}
build_packages& build_packages::
- operator= (build_packages&& v)
+ operator= (build_packages&& v) noexcept (false)
{
clear ();
@@ -1016,10 +1406,31 @@ namespace bpkg
return *this;
}
+ const build_package* build_packages::
+ dependent_build (const build_package::constraint_type& c) const
+ {
+ const build_package* r (nullptr);
+
+ if (c.dependent.version)
+ try
+ {
+ r = entered_build (c.dependent.db, c.dependent.name);
+ assert (r != nullptr); // Expected to be collected.
+ }
+ catch (const invalid_argument&)
+ {
+ // Must be a package name since the version is specified.
+ //
+ assert (false);
+ }
+
+ return r;
+ }
+
void build_packages::
enter (package_name name, build_package pkg)
{
- assert (!pkg.action);
+ assert (!pkg.action && pkg.repository_fragment == nullptr);
database& db (pkg.db); // Save before the move() call.
auto p (map_.emplace (package_key {db, move (name)},
@@ -1031,31 +1442,41 @@ namespace bpkg
build_package* build_packages::
collect_build (const pkg_build_options& options,
build_package pkg,
- const function<find_database_function>& fdb,
- const repointed_dependents& rpt_depts,
- const function<add_priv_cfg_function>& apc,
- bool initial_collection,
replaced_versions& replaced_vers,
postponed_configurations& postponed_cfgs,
+ unsatisfied_dependents& unsatisfied_depts,
build_package_refs* dep_chain,
+ const function<find_database_function>& fdb,
+ const function<add_priv_cfg_function>& apc,
+ const repointed_dependents* rpt_depts,
postponed_packages* postponed_repo,
postponed_packages* postponed_alts,
+ postponed_packages* postponed_recs,
+ postponed_existing_dependencies* postponed_edeps,
postponed_dependencies* postponed_deps,
- postponed_positions* postponed_poss,
unacceptable_alternatives* unacceptable_alts,
const function<verify_package_build_function>& vpb)
{
using std::swap; // ...and not list::swap().
+ using constraint_type = build_package::constraint_type;
+
tracer trace ("collect_build");
+ assert (pkg.repository_fragment == nullptr ||
+ !rep_masked_fragment (pkg.repository_fragment));
+
// See the above notes.
//
- bool recursive (dep_chain != nullptr);
- assert ((postponed_repo != nullptr) == recursive &&
+ bool recursive (fdb != nullptr);
+
+ assert ((!recursive || dep_chain != nullptr) &&
+ (rpt_depts != nullptr) == recursive &&
+ (postponed_repo != nullptr) == recursive &&
(postponed_alts != nullptr) == recursive &&
+ (postponed_recs != nullptr) == recursive &&
+ (postponed_edeps != nullptr) == recursive &&
(postponed_deps != nullptr) == recursive &&
- (postponed_poss != nullptr) == recursive &&
(unacceptable_alts != nullptr) == recursive);
// Only builds are allowed here.
@@ -1066,7 +1487,10 @@ namespace bpkg
package_key pk (pkg.db, pkg.available->id.name);
// Apply the version replacement, if requested, and indicate that it was
- // applied.
+ // applied. Ignore the replacement if its version doesn't satisfy the
+ // dependency constraints specified by the caller. Also ignore if this is
+ // a drop and the required-by package names of the specified build package
+ // object have the "required by dependents" semantics
//
auto vi (replaced_vers.find (pk));
@@ -1077,65 +1501,115 @@ namespace bpkg
replaced_version& v (vi->second);
- v.replaced = true;
-
if (v.available != nullptr)
{
- pkg.available = v.available;
- pkg.repository_fragment = v.repository_fragment;
- pkg.system = v.system;
+ const version& rv (v.system
+ ? *v.available->system_version (pk.db)
+ : v.available->version);
- l5 ([&]{trace << "replacement: "
- << pkg.available_name_version_db ();});
+ bool replace (true);
+ for (const constraint_type& c: pkg.constraints)
+ {
+ if (!satisfies (rv, c.value))
+ {
+ replace = false;
+
+ l5 ([&]{trace << "replacement to " << rv << " is denied since "
+ << c.dependent << " depends on (" << pk.name << ' '
+ << c.value << ')';});
+ }
+ }
+
+ if (replace)
+ {
+ v.replaced = true;
+
+ pkg.available = v.available;
+ pkg.repository_fragment = v.repository_fragment;
+ pkg.system = v.system;
+
+ l5 ([&]{trace << "replacement: "
+ << pkg.available_name_version_db ();});
+ }
}
else
{
- l5 ([&]{trace << "replacement: drop";});
+ if (!pkg.required_by_dependents)
+ {
+ v.replaced = true;
+
+ l5 ([&]{trace << "replacement: drop";});
- assert (pkg.selected != nullptr);
+ // We shouldn't be replacing a package build with the drop if someone
+ // depends on this package.
+ //
+ assert (pkg.selected != nullptr);
+
+ collect_drop (options, pkg.db, pkg.selected, replaced_vers);
+ return nullptr;
+ }
+ else
+ {
+ assert (!pkg.required_by.empty ());
- collect_drop (options, pkg.db, pkg.selected, replaced_vers);
- return nullptr;
+ l5 ([&]
+ {
+ diag_record dr (trace);
+ dr << "replacement to drop is denied since " << pk
+ << " is required by ";
+ for (auto b (pkg.required_by.begin ()), i (b);
+ i != pkg.required_by.end ();
+ ++i)
+ dr << (i != b ? ", " : "") << *i;
+ });
+ }
}
}
// Add the version replacement entry, call the verification function if
// specified, and throw replace_version.
//
- auto replace_ver = [&pk, &vpb, &vi, &replaced_vers]
- (const build_package& p)
- {
- replaced_version rv (p.available, p.repository_fragment, p.system);
+ // Note that this package can potentially be present in the unsatisfied
+ // dependents list on the dependency side with the replacement version
+ // being unsatisfactory for the ignored constraint. In this case, during
+ // the from-scratch re-collection this replacement will be ignored if/when
+ // this package is collected with this constraint specified. But it can
+ // still be applied for some later collect_build() call or potentially
+ // turn out bogus.
+ //
+ auto replace_ver = [&pk, &vpb, &vi, &replaced_vers] (const build_package& p)
+ {
+ replaced_version rv (p.available, p.repository_fragment, p.system);
- if (vi != replaced_vers.end ())
- vi->second = move (rv);
- else
- replaced_vers.emplace (move (pk), move (rv));
+ if (vi != replaced_vers.end ())
+ vi->second = move (rv);
+ else
+ replaced_vers.emplace (move (pk), move (rv));
- if (vpb)
- vpb (p, true /* scratch */);
+ if (vpb)
+ vpb (p, true /* scratch */);
- throw replace_version ();
- };
+ throw replace_version ();
+ };
auto i (map_.find (pk));
- // If we already have an entry for this package name, then we have to
- // pick one over the other.
+ // If we already have an entry for this package name, then we have to pick
+ // one over the other.
//
// If the existing entry is a drop, then we override it. If the existing
// entry is a pre-entered or is non-build one, then we merge it into the
- // new build entry. Otherwise (both are builds), we pick one and merge
- // the other into it.
+ // new build entry. Otherwise (both are builds), we pick one and merge the
+ // other into it.
//
if (i != map_.end ())
{
build_package& bp (i->second.package);
// Note that we used to think that the scenario when the build could
- // replace drop could never happen since we would start collecting
- // from scratch. This has changed when we introduced replaced_versions
- // for collecting drops.
+ // replace drop could never happen since we would start collecting from
+ // scratch. This has changed when we introduced replaced_versions for
+ // collecting drops.
//
if (bp.action && *bp.action == build_package::drop) // Drop.
{
@@ -1148,16 +1622,15 @@ namespace bpkg
}
else // Build.
{
- // At the end we want p1 to point to the object that we keep
- // and p2 to the object that we merge from.
+ // At the end we want p1 to point to the object that we keep and p2 to
+ // the object that we merge from.
//
build_package* p1 (&bp);
build_package* p2 (&pkg);
// Pick with the following preference order: user selection over
- // implicit one, source package over a system one, newer version
- // over an older one. So get the preferred into p1 and the other
- // into p2.
+ // implicit one, source package over a system one, newer version over
+ // an older one. So get the preferred into p1 and the other into p2.
//
{
int us (p1->user_selection () - p2->user_selection ());
@@ -1174,50 +1647,109 @@ namespace bpkg
// If the versions differ, pick the satisfactory one and if both are
// satisfactory, then keep the preferred.
//
+ // If neither of the versions is satisfactory, then ignore those
+ // unsatisfied constraints which prevent us from picking the package
+ // version which is currently in the map. It feels that the version in
+ // the map is no worse than the other one and we choose it
+ // specifically for the sake of optimization, trying to avoid throwing
+ // the replace_version exception.
+ //
if (p1->available_version () != p2->available_version ())
{
- using constraint_type = build_package::constraint_type;
-
- // See if pv's version satisfies pc's constraints. Return the
- // pointer to the unsatisfied constraint or NULL if all are
- // satisfied.
+ // See if pv's version satisfies pc's constraints, skipping those
+ // which are meant to be ignored (ics). Return the pointer to the
+ // unsatisfied constraint or NULL if all are satisfied.
//
- auto test = [] (build_package* pv,
- build_package* pc) -> const constraint_type*
+ vector<const constraint_type*> ics;
+
+ auto test = [&ics] (build_package* pv, build_package* pc)
+ -> const constraint_type*
{
for (const constraint_type& c: pc->constraints)
{
- if (!satisfies (pv->available_version (), c.value))
+ if (find (ics.begin (), ics.end (), &c) == ics.end () &&
+ !satisfies (pv->available_version (), c.value))
return &c;
}
return nullptr;
};
- // First see if p1 satisfies p2's constraints.
+ // Iterate until one of the versions becomes satisfactory due to
+ // ignoring some of the constraints.
//
- if (auto c2 = test (p1, p2))
+ for (;;)
{
- // If not, try the other way around.
+ // First see if p1 satisfies p2's constraints.
//
- if (auto c1 = test (p2, p1))
+ if (auto c2 = test (p1, p2))
{
- const package_name& n (i->first.name);
- const string& d1 (c1->dependent);
- const string& d2 (c2->dependent);
-
- fail << "unable to satisfy constraints on package " << n <<
- info << d1 << c1->db << " depends on (" << n << " "
- << c1->value << ")" <<
- info << d2 << c2->db << " depends on (" << n << " "
- << c2->value << ")" <<
- info << "available " << p1->available_name_version () <<
- info << "available " << p2->available_name_version () <<
- info << "explicitly specify " << n << " version to manually "
- << "satisfy both constraints";
+ // If not, try the other way around.
+ //
+ if (auto c1 = test (p2, p1))
+ {
+ // Add a constraint to the igrore-list and the dependent to
+ // the unsatisfied-list.
+ //
+ const constraint_type* c (p1 == &bp ? c2 : c1);
+ const build_package* p (dependent_build (*c));
+
+ // Note that if one of the constraints is imposed on the
+ // package by the command line, then another constraint must
+ // be imposed by a dependent. Also, in this case it feels that
+ // the map must contain the dependency constrained by the
+ // command line and so p may not be NULL. If that (suddenly)
+ // is not the case, then we will have to ignore the constraint
+ // imposed by the dependent which is not in the map, replace
+ // the version, and call replace_ver().
+ //
+ if (p == nullptr)
+ {
+ c = (c == c1 ? c2 : c1);
+ p = dependent_build (*c);
+
+ // One of the dependents must be a real package.
+ //
+ assert (p != nullptr);
+ }
+
+ ics.push_back (c);
+
+ package_key d (p->db, p->name ());
+
+ l5 ([&]{trace << "postpone failure for dependent " << d
+ << " unsatisfied with dependency "
+ << bp.available_name_version_db () << " ("
+ << c->value << ')';});
+
+ // Note that in contrast to collect_dependents(), here we also
+ // save both unsatisfied constraints and the dependency chain,
+ // for the sake of the diagnostics.
+ //
+ vector<unsatisfied_constraint> ucs {
+ unsatisfied_constraint {
+ *c1, p1->available_version (), p1->system},
+ unsatisfied_constraint {
+ *c2, p2->available_version (), p2->system}};
+
+ vector<package_key> dc;
+
+ if (dep_chain != nullptr)
+ {
+ dc.reserve (dep_chain->size ());
+
+ for (const build_package& p: *dep_chain)
+ dc.emplace_back (p.db, p.name ());
+ }
+
+ unsatisfied_depts.add (d, pk, c->value, move (ucs), move (dc));
+ continue;
+ }
+ else
+ swap (p1, p2);
}
- else
- swap (p1, p2);
+
+ break;
}
l4 ([&]{trace << "pick " << p1->available_name_version_db ()
@@ -1225,10 +1757,10 @@ namespace bpkg
}
// See if we are replacing the object. If not, then we don't need to
- // collect its prerequisites since that should have already been
- // done. Remember, p1 points to the object we want to keep.
+ // collect its prerequisites since that should have already been done.
+ // Remember, p1 points to the object we want to keep.
//
- bool replace (p1 != &i->second.package);
+ bool replace (p1 != &bp);
if (replace)
{
@@ -1257,10 +1789,10 @@ namespace bpkg
// altogether if we are the only dependent (so that it doesn't
// influence any subsequent dependent) or (2) making sure our
// constraint is a sub-constraint of any other constraint and
- // removing it from the dependency build_package. Maybe/later.
+ // removing it from the dependency build_package. Maybe/later.
//
// NOTE: remember to update collect_drop() if changing anything
- // here.
+ // here.
//
bool scratch (true);
@@ -1268,9 +1800,27 @@ namespace bpkg
// toolchain build-time dependencies since they should be quite
// common.
//
+ // An update: it turned out that just the absence of dependencies
+ // is not the only condition that causes a package to be replaced
+ // in place. The following conditions must also be met:
+ //
+ // - The package must not participate in any configuration
+ // negotiation on the dependency side (otherwise we could have
+ // missed collecting its existing dependents).
+ //
+ // - The package up/downgrade doesn't cause the selection of a
+ // different dependency alternative for any of its dependents
+ // (see postponed_packages for possible outcomes).
+ //
+ // - The package must not be added to unsatisfied_depts on the
+ // dependency side.
+ //
+ // This all sounds quite hairy at the moment, so we won't be
+ // replacing in place for now (which is an optimization).
+#if 0
if (!has_dependencies (options, p2->available->dependencies))
scratch = false;
-
+#endif
l5 ([&]{trace << p2->available_name_version_db ()
<< " package version needs to be replaced "
<< (!scratch ? "in-place " : "") << "with "
@@ -1295,27 +1845,6 @@ namespace bpkg
}
else
{
- // Treat the replacement of the existing dependent that is participating
- // in the configuration negotiation also as a version replacement. This
- // way we will not be treating the dependent as an existing on the
- // re-collection (see query_existing_dependents() for details).
- //
- // Note: an existing dependent may not be configured as system.
- //
- if (pkg.selected != nullptr &&
- (pkg.selected->version != pkg.available_version () ||
- pkg.system))
- {
-
- for (const postponed_configuration& cfg: postponed_cfgs)
- {
- auto i (cfg.dependents.find (pk));
-
- if (i != cfg.dependents.end () && i->second.existing)
- replace_ver (pkg);
- }
- }
-
// This is the first time we are adding this package name to the map.
//
l4 ([&]{trace << "add " << pkg.available_name_version_db ();});
@@ -1351,43 +1880,47 @@ namespace bpkg
if (recursive)
collect_build_prerequisites (options,
p,
+ *dep_chain,
fdb,
- rpt_depts,
apc,
- initial_collection,
+ *rpt_depts,
replaced_vers,
- *dep_chain,
postponed_repo,
postponed_alts,
0 /* max_alt_index */,
+ *postponed_recs,
+ *postponed_edeps,
*postponed_deps,
postponed_cfgs,
- *postponed_poss,
- *unacceptable_alts);
+ *unacceptable_alts,
+ unsatisfied_depts);
return &p;
}
- void build_packages::
+ optional<build_packages::pre_reevaluate_result> build_packages::
collect_build_prerequisites (const pkg_build_options& options,
build_package& pkg,
+ build_package_refs& dep_chain,
const function<find_database_function>& fdb,
- const repointed_dependents& rpt_depts,
const function<add_priv_cfg_function>& apc,
- bool initial_collection,
+ const repointed_dependents& rpt_depts,
replaced_versions& replaced_vers,
- build_package_refs& dep_chain,
postponed_packages* postponed_repo,
postponed_packages* postponed_alts,
size_t max_alt_index,
+ postponed_packages& postponed_recs,
+ postponed_existing_dependencies& postponed_edeps,
postponed_dependencies& postponed_deps,
postponed_configurations& postponed_cfgs,
- postponed_positions& postponed_poss,
unacceptable_alternatives& unacceptable_alts,
- pair<size_t, size_t> reeval_pos)
+ unsatisfied_dependents& unsatisfied_depts,
+ optional<pair<size_t, size_t>> reeval_pos,
+ const optional<package_key>& orig_dep)
{
// NOTE: don't forget to update collect_build_postponed() if changing
- // anything in this function.
+ // anything in this function. Also enable and run the tests with the
+ // config.bpkg.tests.all=true variable when done.
//
tracer trace ("collect_build_prerequisites");
@@ -1397,21 +1930,29 @@ namespace bpkg
database& pdb (pkg.db);
package_key pk (pdb, nm);
- bool reeval (reeval_pos.first != 0);
+ bool pre_reeval (reeval_pos && reeval_pos->first == 0);
+ assert (!pre_reeval || reeval_pos->second == 0);
+
+ // Must only be specified in the pre-reevaluation mode.
+ //
+ assert (orig_dep.has_value () == pre_reeval);
+
+ bool reeval (reeval_pos && reeval_pos->first != 0);
+ assert (!reeval || reeval_pos->second != 0);
- // The being re-evaluated dependent cannot be recursively collected yet.
- // Also, we don't expect it being configured as system.
+ // The being (pre-)re-evaluated dependent cannot be recursively collected
+ // yet. Also, we don't expect it being configured as system.
//
// Note that the configured package can still be re-evaluated after
// collect_build_prerequisites() has been called but didn't end up with
// the recursive collection.
//
- assert (!reeval ||
+ assert ((!pre_reeval && !reeval) ||
((!pkg.recursive_collection ||
!pkg.recollect_recursively (rpt_depts)) &&
!pkg.skeleton && !pkg.system));
- // If this package is not being re-evaluated, is not yet collected
+ // If this package is not being (pre-)re-evaluated, is not yet collected
// recursively, needs to be reconfigured, and is not yet postponed, then
// check if it is a dependency of any dependent with configuration clause
// and postpone the collection if that's the case.
@@ -1421,182 +1962,162 @@ namespace bpkg
// otherwise built (e.g., reconfigured) which means its externally-
// imposed configuration (user, dependents) is not being changed.
//
- if (!reeval &&
- !pkg.recursive_collection &&
- pkg.reconfigure () &&
- postponed_cfgs.find_dependency (pk) == nullptr)
+ if (!pre_reeval &&
+ !reeval &&
+ !pkg.recursive_collection &&
+ pkg.reconfigure () &&
+ postponed_cfgs.find_dependency (pk) == nullptr &&
+ postponed_edeps.find (pk) == postponed_edeps.end ())
{
- // If the dependent is being built, then check if it was re-evaluated to
- // the position greater than the dependency position. Return true if
- // that's the case, so this package is added to the resulting list and
- // we can handle this situation below.
- //
- // Note that we rely on "small function object" optimization here.
- //
- const function<verify_dependent_build_function> verify (
- [&postponed_cfgs]
- (const package_key& pk, pair<size_t, size_t> pos)
- {
- for (const postponed_configuration& cfg: postponed_cfgs)
- {
- if (cfg.negotiated)
- {
- if (const pair<size_t, size_t>* p =
- cfg.existing_dependent_position (pk))
- {
- if (p->first > pos.first)
- return true;
- }
- }
- }
-
- return false;
- });
-
// Note that there can be multiple existing dependents for a dependency.
- // Strictly speaking, we only need to add the first one with the
- // assumption that the remaining dependents will also be considered
- // comes the time for the negotiation. Let's, however, process all of
- // them to detect the potential "re-evaluation on the greater dependency
- // index" situation earlier. And, generally, have as much information as
- // possible up front.
+ // Also note that we skip the existing dependents for which re-
+ // evaluation is optional not to initiate any negotiation in a simple
+ // case (see collect_build_prerequisites() description for details).
//
vector<existing_dependent> eds (
query_existing_dependents (trace,
+ options,
pk.db,
pk.name,
- replaced_vers,
+ true /* exclude_optional */,
+ fdb,
rpt_depts,
- verify));
+ replaced_vers));
if (!eds.empty ())
{
+ bool postpone (false);
+
for (existing_dependent& ed: eds)
{
- package_key dpk (ed.db, ed.selected->name);
- size_t& di (ed.dependency_position.first);
+ if (ed.dependency) // Configuration clause is encountered.
+ {
+ const build_package* bp (&pkg);
- const build_package* bp (&pkg);
+ package_key& dep (*ed.dependency);
+ package_key dpt (ed.db, ed.selected->name);
- // Check if this dependent needs to be re-evaluated to an earlier
- // dependency position and, if that's the case, create the
- // configuration cluster with this dependency instead.
- //
- // Note that if the replace flag is false, we proceed normally with
- // the assumption that the dependency referred by the entry will be
- // collected later and its configuration cluster will be created
- // normally and will be negotiated earlier than the cluster being
- // created for the current dependency (see collect_build_postponed()
- // for details).
- //
- {
- auto pi (postponed_poss.find (dpk));
+ // If the earliest configuration clause applies to a different
+ // dependency, then collect it (non-recursively).
+ //
+ if (dep != pk)
+ bp = collect_existing_dependent_dependency (options,
+ ed,
+ replaced_vers,
+ postponed_cfgs,
+ unsatisfied_depts);
+
+ // If the dependency collection has already been postponed, then
+ // indicate that the dependent with configuration clauses is also
+ // present and thus the postponement is not bogus. But only add
+ // the new entry to postponed_deps and throw the
+ // postpone_dependency exception if the dependency is already
+ // collected. Note that adding the new entry unconditionally would
+ // be a bad idea, since by postponing the dependency collection we
+ // may not see its existing dependent with a configuration
+ // clauses, end up with a bogus postponement, and start
+ // yo-yoing. In other words, we add the entry only if absolutely
+ // necessary (who knows, maybe the existing dependent will be
+ // dropped before we try to collect it recursively).
+ //
+ auto i (postponed_deps.find (dep));
- if (pi != postponed_poss.end () && pi->second.first < di)
+ if (i != postponed_deps.end ())
+ i->second.with_config = true;
+
+ // Prematurely collected before we saw any config clauses.
+ //
+ if (bp->recursive_collection)
{
- // If requested, override the first encountered non-replace
- // position to replace. See collect_build_postponed () for
- // details.
- //
- if (!pi->second.replace && postponed_poss.replace)
- {
- pi->second.replace = true;
- postponed_poss.replace = false;
- }
+ l5 ([&]{trace << "cannot cfg-postpone dependency "
+ << bp->available_name_version_db ()
+ << " of existing dependent " << dpt
+ << " (collected prematurely), "
+ << "throwing postpone_dependency";});
- if (pi->second.replace)
+ if (i == postponed_deps.end ())
{
- // Overwrite the existing dependent dependency information and
- // fall through to proceed as for the normal case.
- //
- bp = replace_existing_dependent_dependency (
- trace,
- options,
- ed, // Note: modified.
- pi->second,
- fdb,
- rpt_depts,
- apc,
- initial_collection,
- replaced_vers,
- postponed_cfgs);
-
- pk = package_key (bp->db, bp->name ());
-
- // Note that here we side-step the bogus logic (by not setting
- // the skipped flag) because in this case (replace=true) our
- // choices are either (potentially) bogus or pathological
- // (where we have evaluated too far). In other words, the
- // postponed entry may cause the depends entry that triggered
- // it to disappear (and thus, strictly speaking, to become
- // bogus) but if we cancel it, we will be back to square one.
+ postponed_deps.emplace (dep,
+ postponed_dependency {
+ false /* without_config */,
+ true /* with_config */});
}
+
+ // Don't print the "while satisfying..." chain.
+ //
+ dep_chain.clear ();
+
+ throw postpone_dependency (move (dep));
}
+
+ l5 ([&]{trace << "cfg-postpone dependency "
+ << bp->available_name_version_db ()
+ << " of existing dependent " << *ed.selected
+ << ed.db << " due to dependency "
+ << pkg.available_name_version_db ();});
+
+ collect_existing_dependent (options,
+ ed,
+ {pk},
+ replaced_vers,
+ postponed_cfgs,
+ unsatisfied_depts);
+
+ // Only add this dependent/dependency to the newly created cluster
+ // if this dependency doesn't belong to any cluster yet, which may
+ // not be the case if there are multiple existing dependents with
+ // configuration clause for this dependency.
+ //
+ // To put it another way, if there are multiple such existing
+ // dependents for this dependency, here we will create the
+ // configuration cluster only for the first one. The remaining
+ // dependents will be added to this dependency's cluster when the
+ // existing dependents of dependencies in this cluster are all
+ // discovered and reevaluated (see collect_build_postponed() for
+ // details).
+ //
+ if (postponed_cfgs.find_dependency (dep) == nullptr)
+ postponed_cfgs.add (move (dpt),
+ ed.dependency_position,
+ move (dep));
+ }
+ else // Existing dependent is deviated.
+ {
+ // Note that we could probably re-collect deviated dependents
+ // recursively right away but such a two-directional recursion
+ // would complicate implementation and troubleshooting. Thus,
+ // given that the deviated dependents are not very common, we just
+ // postpone their re-collection.
+ //
+ l5 ([&]{trace << "schedule re-collection of deviated "
+ << "existing dependent " << *ed.selected
+ << ed.db;});
+
+ recollect_existing_dependent (options,
+ ed,
+ replaced_vers,
+ postponed_recs,
+ postponed_cfgs,
+ unsatisfied_depts,
+ true /* add_required_by */);
}
- // Make sure that this existing dependent doesn't belong to any
- // (being) negotiated configuration cluster with a greater
- // dependency index. That would mean that this dependent has already
- // been re-evaluated to this index and so cannot participate in the
- // configuration negotiation of this earlier dependency.
+ // Postpone the recursive collection of a dependency if the existing
+ // dependent has deviated or the dependency belongs to the earliest
+ // depends clause with configuration clause or to some later depends
+ // clause. It is supposed that it will be collected during its
+ // existing dependent re-collection.
//
- for (const postponed_configuration& cfg: postponed_cfgs)
+ if (!ed.dependency || // Dependent has deviated.
+ ed.originating_dependency_position >= ed.dependency_position)
{
- if (const pair<size_t, size_t>* p =
- cfg.existing_dependent_position (pk))
- {
- size_t ei (p->first);
-
- if (di < ei && cfg.negotiated)
- {
- // Feels like there cannot be an earlier position.
- //
- postponed_position pp (ed.dependency_position,
- false /* replace */);
-
- auto p (postponed_poss.emplace (move (pk), pp));
- if (!p.second)
- {
- assert (p.first->second > pp);
- p.first->second = pp;
- }
-
- l5 ([&]{trace << "cannot cfg-postpone dependency "
- << bp->available_name_version_db ()
- << " of existing dependent " << *ed.selected
- << ed.db << " (index " << di
- << ") due to earlier dependency index " << ei
- << " in " << cfg << ", throwing "
- << "postpone_position";});
-
- // Don't print the "while satisfying..." chain.
- //
- dep_chain.clear ();
-
- throw postpone_position ();
- }
-
- if (di == ei)
- {
- // For the negotiated cluster all the dependency packages
- // should have been added. For non-negotiated cluster we
- // cannot add the missing dependencies at the moment and will
- // do it as a part of the dependent re-evaluation.
- //
- assert (!cfg.negotiated);
- }
- }
+ postpone = true;
+ postponed_edeps[pk].emplace_back (ed.db, ed.selected->name);
}
-
- l5 ([&]{trace << "cfg-postpone dependency "
- << bp->available_name_version_db ()
- << " of existing dependent " << *ed.selected
- << ed.db;});
-
- postponed_cfgs.add (move (dpk), ed.dependency_position, move (pk));
}
- return;
+ if (postpone)
+ return nullopt;
}
}
@@ -1605,7 +2126,7 @@ namespace bpkg
if (pkg.system)
{
l5 ([&]{trace << "skip system " << pkg.available_name_version_db ();});
- return;
+ return nullopt;
}
const shared_ptr<available_package>& ap (pkg.available);
@@ -1613,6 +2134,8 @@ namespace bpkg
const shared_ptr<selected_package>& sp (pkg.selected);
+ assert ((!pre_reeval && !reeval) || sp != nullptr);
+
// True if this is an up/down-grade.
//
bool ud (sp != nullptr && sp->version != pkg.available_version ());
@@ -1625,28 +2148,29 @@ namespace bpkg
// Bail out if this is a configured non-system package and no recursive
// collection is required.
//
- bool src_conf (sp != nullptr &&
+ bool src_conf (sp != nullptr &&
sp->state == package_state::configured &&
sp->substate != package_substate::system);
- // The being re-evaluated dependent must be configured as a source package
- // and should not be collected recursively (due to upgrade, etc).
+ // The being (pre-)re-evaluated dependent must be configured as a source
+ // package and should not be collected recursively (due to upgrade, etc).
//
- assert (!reeval || (src_conf && !pkg.recollect_recursively (rpt_depts)));
+ assert ((!pre_reeval && !reeval) ||
+ (src_conf && !pkg.recollect_recursively (rpt_depts)));
if (src_conf)
{
- repointed_dependents::const_iterator i (rpt_depts.find (pk));
-
- if (i != rpt_depts.end ())
- rpt_prereq_flags = &i->second;
-
- if (!reeval && !pkg.recollect_recursively (rpt_depts))
+ if (!pre_reeval && !reeval && !pkg.recollect_recursively (rpt_depts))
{
l5 ([&]{trace << "skip configured "
<< pkg.available_name_version_db ();});
- return;
+ return nullopt;
}
+
+ repointed_dependents::const_iterator i (rpt_depts.find (pk));
+
+ if (i != rpt_depts.end ())
+ rpt_prereq_flags = &i->second;
}
// Iterate over dependencies, trying to unambiguously select a
@@ -1669,7 +2193,9 @@ namespace bpkg
//
if (!pkg.dependencies)
{
- l5 ([&]{trace << (reeval ? "reeval " : "begin ")
+ l5 ([&]{trace << (pre_reeval ? "pre-reeval " :
+ reeval ? "reeval " :
+ "begin " )
<< pkg.available_name_version_db ();});
pkg.dependencies = dependencies ();
@@ -1697,7 +2223,7 @@ namespace bpkg
if (sdeps.size () == deps.size ())
{
l5 ([&]{trace << "end " << pkg.available_name_version_db ();});
- return;
+ return nullopt;
}
// Show how we got here if things go wrong.
@@ -1721,28 +2247,77 @@ namespace bpkg
}
}));
- dep_chain.push_back (pkg);
+ if (!pre_reeval)
+ dep_chain.push_back (pkg);
assert (sdeps.size () < deps.size ());
package_skeleton& skel (*pkg.skeleton);
+ // We shouldn't be failing in the reevaluation mode, given that we only
+ // reevaluate a package if its pre-reevaluation succeeds.
+ //
auto fail_reeval = [&pkg] ()
- {
- fail << "unable to re-create dependency information of already "
- << "configured package " << pkg.available_name_version_db () <<
+ {
+ fail << "unable to re-create dependency information of already "
+ << "configured package " << pkg.available_name_version_db () <<
info << "likely cause is change in external environment" <<
- info << "consider resetting the build configuration";
- };
+ info << "if not, please report in https://github.com/build2/build2/issues/302";
+ };
bool postponed (false);
bool reevaluated (false);
+ // In the pre-reevaluation mode keep track of configuration variable
+ // prefixes similar to what we do in pkg_configure_prerequisites(). Stop
+ // tracking if we discovered that the dependent re-evaluation is not
+ // optional.
+ //
+ vector<string> banned_var_prefixes;
+
+ auto references_banned_var = [&banned_var_prefixes] (const string& clause)
+ {
+ for (const string& p: banned_var_prefixes)
+ {
+ if (clause.find (p) != string::npos)
+ return true;
+ }
+
+ return false;
+ };
+
+ if (pre_reeval)
+ {
+ if (!sp->dependency_alternatives_section.loaded ())
+ pdb.load (*sp, sp->dependency_alternatives_section);
+
+ // It doesn't feel like the number of depends clauses may differ for the
+ // available and selected packages in the pre-reevaluation mode since
+ // they must refer to the same package version. If it still happens,
+ // maybe due to some manual tampering, let's assume this as a deviation
+ // case.
+ //
+ size_t nn (deps.size ());
+ size_t on (sp->dependency_alternatives.size ());
+
+ if (nn != on)
+ {
+ l5 ([&]{trace << "re-evaluation of dependent "
+ << pkg.available_name_version_db ()
+ << " deviated: number of depends clauses changed to "
+ << nn << " from " << on;});
+
+ throw reevaluation_deviated ();
+ }
+ }
+
+ pre_reevaluate_result r;
+
for (size_t di (sdeps.size ()); di != deps.size (); ++di)
{
// Fail if we missed the re-evaluation target position for any reason.
//
- if (reeval && di == reeval_pos.first) // Note: reeval_pos is 1-based.
+ if (reeval && di == reeval_pos->first) // Note: reeval_pos is 1-based.
fail_reeval ();
const dependency_alternatives_ex& das (deps[di]);
@@ -1754,6 +2329,26 @@ namespace bpkg
if (toolchain_buildtime_dependency (options, das, &nm))
{
+ if (pre_reeval)
+ {
+ size_t oi (sp->dependency_alternatives[di]);
+
+ // It doesn't feel like it may happen in the pre-reevaluation
+ // mode. If it still happens, maybe due to some manual tampering,
+ // let's assume this as a deviation case.
+ //
+ if (oi != 0)
+ {
+ l5 ([&]{trace << "re-evaluation of dependent "
+ << pkg.available_name_version_db ()
+ << " deviated at depends clause " << di + 1
+ << ": toolchain buildtime dependency replaced the "
+ << " regular one with selected alternative " << oi;});
+
+ throw reevaluation_deviated ();
+ }
+ }
+
sdeps.push_back (move (sdas));
salts.push_back (0); // Keep parallel to sdeps.
continue;
@@ -1776,14 +2371,45 @@ namespace bpkg
{
const dependency_alternative& da (das[i]);
- if (!da.enable ||
- skel.evaluate_enable (*da.enable, make_pair (di, i)))
+ bool enabled;
+
+ if (da.enable)
+ {
+ if (pre_reeval &&
+ r.reevaluation_optional &&
+ references_banned_var (*da.enable))
+ {
+ r.reevaluation_optional = false;
+ }
+
+ enabled = skel.evaluate_enable (*da.enable, make_pair (di, i));
+ }
+ else
+ enabled = true;
+
+ if (enabled)
edas.push_back (make_pair (ref (da), i));
}
}
if (edas.empty ())
{
+ if (pre_reeval)
+ {
+ size_t oi (sp->dependency_alternatives[di]);
+
+ if (oi != 0)
+ {
+ l5 ([&]{trace << "re-evaluation of dependent "
+ << pkg.available_name_version_db ()
+ << " deviated at depends clause " << di + 1
+ << ": dependency with previously selected "
+ << "alternative " << oi << " is now disabled";});
+
+ throw reevaluation_deviated ();
+ }
+ }
+
sdeps.push_back (move (sdas));
salts.push_back (0); // Keep parallel to sdeps.
continue;
@@ -1794,6 +2420,18 @@ namespace bpkg
// the specified diag record. In the dry-run mode don't change the
// packages collection state (postponed_repo set, etc).
//
+ // If an alternative dependency package is specified as a dependency
+ // with a version constraint on the command line, then overwrite the
+ // dependent's constraint with the command line's constraint, if the
+ // latter is a subset of former. If it is not a subset, then bail out
+ // indicating that the alternative dependencies cannot be resolved
+ // (builds is nullopt), unless ignore_unsatisfactory_dep_spec argument
+ // is true. In the latter case continue precollecting as if no
+ // constraint is specified on the command line for this dependency. That
+ // will likely result in the unsatisfied dependent problem, which will
+ // be either resolved or end up with the failure (see
+ // unsatisfied_dependents for details).
+ //
// Note that rather than considering an alternative as unsatisfactory
// (returning no pre-builds) the function can fail in some cases
// (multiple possible configurations for a build-time dependency, orphan
@@ -1827,7 +2465,8 @@ namespace bpkg
//
optional<prebuilds> builds;
- // If some dependency of the alternative cannot be resolved because
+ // If true is passed as the check_constraints argument to precollect()
+ // and some dependency of the alternative cannot be resolved because
// there is no version available which can satisfy all the being built
// dependents, then this member contains all the dependency builds
// (which otherwise would be contained in the builds member).
@@ -1875,11 +2514,14 @@ namespace bpkg
&apc,
postponed_repo,
&dep_chain,
+ pre_reeval,
&trace,
this]
(const dependency_alternative& da,
bool buildtime,
const package_prerequisites* prereqs,
+ bool check_constraints,
+ bool ignore_unsatisfactory_dep_spec,
diag_record* dr = nullptr,
bool dry_run = false) -> precollect_result
{
@@ -1895,6 +2537,21 @@ namespace bpkg
if (buildtime && pdb.type == build2_config_type)
{
+ // It doesn't feel like it may happen in the pre-reevaluation
+ // mode. If it still happens, maybe due to some manual
+ // tampering, let's assume this as a deviation case.
+ //
+ if (pre_reeval)
+ {
+ l5 ([&]{trace << "re-evaluation of dependent "
+ << pkg.available_name_version_db ()
+ << " deviated: build-time dependency " << dn
+ << " is now in build system module "
+ << "configuration";});
+
+ throw reevaluation_deviated ();
+ }
+
assert (dr == nullptr); // Should fail on the "silent" run.
// Note that the dependent is not necessarily a build system
@@ -1944,32 +2601,59 @@ namespace bpkg
//
// The version constraint is specified,
//
- bp.hold_version && *bp.hold_version)
+ !bp.constraints.empty ())
{
assert (bp.constraints.size () == 1);
const build_package::constraint_type& c (bp.constraints[0]);
- dep_constr = &c.value;
- system = bp.system;
-
// If the user-specified dependency constraint is the wildcard
// version, then it satisfies any dependency constraint.
//
- if (!wildcard (*dep_constr) &&
- !satisfies (*dep_constr, dp.constraint))
+ if (!wildcard (c.value) && !satisfies (c.value, dp.constraint))
{
- if (dr != nullptr)
- *dr << error << "unable to satisfy constraints on package "
- << dn <<
- info << nm << pdb << " depends on (" << dn
- << " " << *dp.constraint << ")" <<
- info << c.dependent << c.db << " depends on (" << dn
- << " " << c.value << ")" <<
- info << "specify " << dn << " version to satisfy " << nm
- << " constraint";
+ // We should end up throwing reevaluation_deviated exception
+ // before the diagnostics run in the pre-reevaluation mode.
+ //
+ assert (!pre_reeval || dr == nullptr);
- return precollect_result (false /* postpone */);
+ if (!ignore_unsatisfactory_dep_spec)
+ {
+ if (dr != nullptr)
+ {
+ // " info: ..."
+ string indent (" ");
+
+ *dr << error << "unable to satisfy constraints on package "
+ << dn <<
+ info << nm << pdb << " depends on (" << dn << ' '
+ << *dp.constraint << ')';
+
+ {
+ set<package_key> printed;
+ print_constraints (*dr, pkg, indent, printed);
+ }
+
+ *dr << info << c.dependent << " depends on (" << dn << ' '
+ << c.value << ')';
+
+ if (const build_package* d = dependent_build (c))
+ {
+ set<package_key> printed;
+ print_constraints (*dr, *d, indent, printed);
+ }
+
+ *dr << info << "specify " << dn << " version to satisfy "
+ << nm << " constraint";
+ }
+
+ return precollect_result (false /* postpone */);
+ }
+ }
+ else
+ {
+ dep_constr = &c.value;
+ system = bp.system;
}
}
}
@@ -2048,6 +2732,21 @@ namespace bpkg
if (dsp->state == package_state::broken)
{
+ // If it happens in the pre-reevaluation mode, that may mean
+ // that the package has become broken since the time the
+ // dependent was built. Let's assume this as a deviation case
+ // and fail on the re-collection.
+ //
+ if (pre_reeval)
+ {
+ l5 ([&]{trace << "re-evaluation of dependent "
+ << pkg.available_name_version_db ()
+ << " deviated: package " << dn << *ddb
+ << " is broken";});
+
+ throw reevaluation_deviated ();
+ }
+
assert (dr == nullptr); // Should fail on the "silent" run.
fail << "unable to build broken package " << dn << *ddb <<
@@ -2165,10 +2864,28 @@ namespace bpkg
db = &ldb;
else
{
+ // If it happens in the pre-reevaluation mode, that may
+ // mean that some new configuration has been linked since
+ // the time the dependent was built. Let's assume this as
+ // a deviation case.
+ //
+ if (pre_reeval)
+ {
+ l5 ([&]{trace << "re-evaluation of dependent "
+ << pkg.available_name_version_db ()
+ << " deviated: now multiple possible "
+ << type << " configurations for "
+ << "build-time dependency (" << dp << "): "
+ << db->config_orig << ", "
+ << ldb.config_orig;});
+
+ throw reevaluation_deviated ();
+ }
+
assert (dr == nullptr); // Should fail on the "silent" run.
fail << "multiple possible " << type << " configurations "
- << "for build-time dependency (" << dp << ")" <<
+ << "for build-time dependency (" << dp << ')' <<
info << db->config_orig <<
info << ldb.config_orig <<
info << "use --config-* to select the configuration";
@@ -2183,6 +2900,22 @@ namespace bpkg
//
if (db == nullptr)
{
+ // If it happens in the pre-reevaluation mode, that may mean
+ // that some configuration has been unlinked since the time
+ // the dependent was built. Let's assume this as a deviation
+ // case.
+ //
+ if (pre_reeval)
+ {
+ l5 ([&]{trace << "re-evaluation of dependent "
+ << pkg.available_name_version_db ()
+ << " deviated: now no suitable configuration "
+ << "is found for build-time dependency ("
+ << dp << ')';});
+
+ throw reevaluation_deviated ();
+ }
+
// The private config should be created on the "silent" run
// and so there always should be a suitable configuration on
// the diagnostics run.
@@ -2280,6 +3013,21 @@ namespace bpkg
build2_module (dn) &&
pdb == *ddb)
{
+ // It doesn't feel like it may happen in the pre-reevaluation
+ // mode. If it still happens, maybe due to some manual
+ // tampering, let's assume this as a deviation case.
+ //
+ if (pre_reeval)
+ {
+ l5 ([&]{trace << "re-evaluation of dependent "
+ << pkg.available_name_version_db ()
+ << " deviated: now unable to build build system "
+ << "module " << dn << " in its dependent "
+ << "package configuration " << pdb.config_orig;});
+
+ throw reevaluation_deviated ();
+ }
+
assert (dr == nullptr); // Should fail on the "silent" run.
// Note that the dependent package information is printed by the
@@ -2303,6 +3051,19 @@ namespace bpkg
//
if (af == nullptr)
{
+ // If it happens in the pre-reevaluation mode, that may mean
+ // that the dependent has become an orphan since the time it
+ // was built. Let's assume this as a deviation case.
+ //
+ if (pre_reeval)
+ {
+ l5 ([&]{trace << "re-evaluation of dependent "
+ << pkg.available_name_version_db ()
+ << " deviated: is now orphaned";});
+
+ throw reevaluation_deviated ();
+ }
+
assert (dr == nullptr); // Should fail on the "silent" run.
fail << "package " << pkg.available_name_version_db ()
@@ -2356,13 +3117,32 @@ namespace bpkg
// recognized. An unrecognized package means the broken/stale
// repository (see below).
//
- rp = find_available_one (dn, d.constraint, af);
+ rp = find_existing (dn, d.constraint, af);
+
+ if (dap == nullptr)
+ rp = find_available_one (dn, d.constraint, af);
if (dap == nullptr && system && d.constraint)
rp = find_available_one (dn, nullopt, af);
if (dap == nullptr)
{
+ // If it happens in the pre-reevaluation mode, that may mean
+ // that the repositories has been refetched since the time the
+ // dependent was built and don't contain a satisfactory
+ // package anymore. Let's assume this as a deviation case.
+ //
+ if (pre_reeval)
+ {
+ l5 ([&]{trace << "re-evaluation of dependent "
+ << pkg.available_name_version_db ()
+ << " deviated: unable to satisfy "
+ << (!dep_constr ? "" : "user-specified ")
+ << "dependency constraint (" << d << ')';});
+
+ throw reevaluation_deviated ();
+ }
+
if (dep_constr && !system && postponed_repo != nullptr)
{
// We shouldn't be called in the diag mode for the postponed
@@ -2435,8 +3215,8 @@ namespace bpkg
(!dep_constr || system))
dr << info << "repository " << af->location << " appears "
<< "to be broken" <<
- info << "or the repository state could be stale" <<
- info << "run 'bpkg rep-fetch' to update";
+ info << "or the repository metadata could be stale" <<
+ info << "run 'bpkg rep-fetch' (or equivalent) to update";
}
// If all that's available is a stub then we need to make sure
@@ -2459,6 +3239,11 @@ namespace bpkg
//
if (dap->system_version (*ddb) == nullptr)
{
+ // We should end up throwing reevaluation_deviated exception
+ // before the diagnostics run in the pre-reevaluation mode.
+ //
+ assert (!pre_reeval || dr == nullptr);
+
if (dr != nullptr)
*dr << error << "dependency " << d << " of package "
<< nm << " is not available in source" <<
@@ -2470,13 +3255,18 @@ namespace bpkg
if (!satisfies (*dap->system_version (*ddb), d.constraint))
{
+ // We should end up throwing reevaluation_deviated exception
+ // before the diagnostics run in the pre-reevaluation mode.
+ //
+ assert (!pre_reeval || dr == nullptr);
+
if (dr != nullptr)
*dr << error << "dependency " << d << " of package "
<< nm << " is not available in source" <<
info << package_string (dn,
*dap->system_version (*ddb),
true /* system */)
- << " does not satisfy the constrains";
+ << " does not satisfy the constrains";
return precollect_result (false /* postpone */);
}
@@ -2500,82 +3290,113 @@ namespace bpkg
reused = false;
r.push_back (prebuild {d,
- *ddb,
- move (dsp),
- move (dap),
- move (rp.second),
- system,
- specified,
- force,
- ru});
+ *ddb,
+ move (dsp),
+ move (dap),
+ move (rp.second),
+ system,
+ specified,
+ force,
+ ru});
}
- // Now, as we have pre-collected the dependency builds, go through
- // them and check that for those dependencies which are already
- // being built we will be able to choose one of them (either
- // existing or new) which satisfies all the dependents. If that's
- // not the case, then issue the diagnostics, if requested, and
- // return the unsatisfactory dependency builds.
+ // Now, as we have pre-collected the dependency builds, if
+ // requested, go through them and check that for those dependencies
+ // which are already being built we will be able to choose one of
+ // them (either existing or new) which satisfies all the dependents.
+ // If that's not the case, then issue the diagnostics, if requested,
+ // and return the unsatisfactory dependency builds.
//
// Note that collect_build() also performs this check but postponing
// it till then can end up in failing instead of selecting some
// other dependency alternative.
//
- for (const prebuild& b: r)
+ if (check_constraints)
{
- const shared_ptr<available_package>& dap (b.available);
-
- assert (dap != nullptr); // Otherwise we would fail earlier.
+ for (const prebuild& b: r)
+ {
+ const shared_ptr<available_package>& dap (b.available);
- const dependency& d (b.dependency);
+ // Otherwise we would have failed earlier.
+ //
+ assert (dap != nullptr);
- auto i (map_.find (b.db, d.name));
+ const dependency& d (b.dependency);
- if (i != map_.end () && d.constraint)
- {
- const build_package& bp (i->second.package);
+ auto i (map_.find (b.db, d.name));
- if (bp.action && *bp.action == build_package::build)
+ if (i != map_.end () && d.constraint)
{
- const version& v1 (b.system
- ? *dap->system_version (b.db)
- : dap->version);
+ const build_package& bp (i->second.package);
- const version& v2 (bp.available_version ());
-
- if (v1 != v2)
+ if (bp.action && *bp.action == build_package::build)
{
- using constraint_type = build_package::constraint_type;
+ const version& v1 (b.system
+ ? *dap->system_version (b.db)
+ : dap->version);
- constraint_type c1 {pdb, nm.string (), *d.constraint};
+ const version& v2 (bp.available_version ());
- if (!satisfies (v2, c1.value))
+ if (v1 != v2)
{
- for (const constraint_type& c2: bp.constraints)
+ using constraint_type = build_package::constraint_type;
+
+ constraint_type c1 (*d.constraint,
+ pdb,
+ nm,
+ pkg.available_version (),
+ false /* selected_dependent */);
+
+ if (!satisfies (v2, c1.value))
{
- if (!satisfies (v1, c2.value))
+ for (const constraint_type& c2: bp.constraints)
{
- if (dr != nullptr)
+ if (!satisfies (v1, c2.value))
{
- const package_name& n (d.name);
- const string& d1 (c1.dependent);
- const string& d2 (c2.dependent);
-
- *dr << error << "unable to satisfy constraints on "
- << "package " << n <<
- info << d2 << c2.db << " depends on (" << n << ' '
- << c2.value << ")" <<
- info << d1 << c1.db << " depends on (" << n << ' '
- << c1.value << ")" <<
- info << "available "
- << bp.available_name_version () <<
- info << "available "
- << package_string (n, v1, b.system) <<
- info << "explicitly specify " << n << " version "
- << "to manually satisfy both constraints";
- }
+ // We should end up throwing reevaluation_deviated
+ // exception before the diagnostics run in the
+ // pre-reevaluation mode.
+ //
+ assert (!pre_reeval || dr == nullptr);
- return precollect_result (reused, move (r));
+ if (dr != nullptr)
+ {
+ const package_name& n (d.name);
+
+ // " info: ..."
+ string indent (" ");
+
+ *dr << error << "unable to satisfy constraints on "
+ << "package " << n <<
+ info << c2.dependent << " depends on (" << n
+ << ' ' << c2.value << ')';
+
+ if (const build_package* d = dependent_build (c2))
+ {
+ set<package_key> printed;
+ print_constraints (*dr, *d, indent, printed);
+ }
+
+ *dr << info << c1.dependent << " depends on ("
+ << n << ' ' << c1.value << ')';
+
+ if (const build_package* d = dependent_build (c1))
+ {
+ set<package_key> printed;
+ print_constraints (*dr, *d, indent, printed);
+ }
+
+ *dr << info << "available "
+ << bp.available_name_version () <<
+ info << "available "
+ << package_string (n, v1, b.system) <<
+ info << "explicitly specify " << n
+ << " version to manually satisfy both "
+ << "constraints";
+ }
+
+ return precollect_result (reused, move (r));
+ }
}
}
}
@@ -2600,15 +3421,16 @@ namespace bpkg
&fdb,
&rpt_depts,
&apc,
- initial_collection,
&replaced_vers,
&dep_chain,
postponed_repo,
postponed_alts,
+ &postponed_recs,
+ &postponed_edeps,
&postponed_deps,
&postponed_cfgs,
- &postponed_poss,
&unacceptable_alts,
+ &unsatisfied_depts,
&di,
reeval,
&reeval_pos,
@@ -2622,45 +3444,64 @@ namespace bpkg
(const dependency_alternative& da,
size_t dai,
prebuilds&& bs,
- const package_prerequisites* prereqs)
+ const package_prerequisites* prereqs,
+ bool check_constraints,
+ bool ignore_unsatisfactory_dep_spec)
{
// Dependency alternative position.
//
pair<size_t, size_t> dp (di + 1, dai + 1);
- if (reeval &&
- dp.first == reeval_pos.first &&
- dp.second != reeval_pos.second)
+ if (reeval &&
+ dp.first == reeval_pos->first &&
+ dp.second != reeval_pos->second)
fail_reeval ();
postponed_configuration::packages cfg_deps;
+ // Remove the temporary dependency collection postponements (see
+ // below for details).
+ //
+ postponed_configuration::packages temp_postponements;
+
+ auto g (
+ make_guard (
+ [&temp_postponements, &postponed_deps] ()
+ {
+ for (const package_key& d: temp_postponements)
+ postponed_deps.erase (d);
+ }));
+
+ package_version_key pvk (pk.db, pk.name, pkg.available_version ());
+
for (prebuild& b: bs)
{
- build_package bp {
+ build_package bpk {
build_package::build,
- b.db,
- b.selected,
- b.available,
- move (b.repository_fragment),
- nullopt, // Dependencies.
- nullopt, // Dependencies alternatives.
- nullopt, // Package skeleton.
- nullopt, // Postponed dependency alternatives.
- false, // Recursive collection.
- nullopt, // Hold package.
- nullopt, // Hold version.
- {}, // Constraints.
- b.system,
- false, // Keep output directory.
- false, // Disfigure (from-scratch reconf).
- false, // Configure-only.
- nullopt, // Checkout root.
- false, // Checkout purge.
- strings (), // Configuration variables.
- {pk}, // Required by (dependent).
- true, // Required by dependents.
- 0}; // State flags.
+ b.db,
+ b.selected,
+ b.available,
+ move (b.repository_fragment),
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ nullopt, // Hold package.
+ nullopt, // Hold version.
+ {}, // Constraints.
+ b.system,
+ false, // Keep output directory.
+ false, // Disfigure (from-scratch reconf).
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ nullopt, // Upgrade.
+ false, // Deorphan.
+ {pvk}, // Required by (dependent).
+ true, // Required by dependents.
+ 0}; // State flags.
const optional<version_constraint>& constraint (
b.dependency.constraint);
@@ -2668,12 +3509,16 @@ namespace bpkg
// Add our constraint, if we have one.
//
// Note that we always add the constraint implied by the
- // dependent. The user-implied constraint, if present, will be
+ // dependent. The user-implied constraint, if present, will be
// added when merging from the pre-entered entry. So we will have
// both constraints for completeness.
//
if (constraint)
- bp.constraints.emplace_back (pdb, nm.string (), *constraint);
+ bpk.constraints.emplace_back (*constraint,
+ pdb,
+ nm,
+ pkg.available_version (),
+ false /* selected_dependent */);
// Now collect this prerequisite. If it was actually collected
// (i.e., it wasn't already there) and we are forcing a downgrade
@@ -2779,18 +3624,19 @@ namespace bpkg
//
build_package* p (
collect_build (options,
- move (bp),
- fdb,
- rpt_depts,
- apc,
- initial_collection,
+ move (bpk),
replaced_vers,
postponed_cfgs,
- nullptr /* dep_chain */,
+ unsatisfied_depts,
+ &dep_chain,
+ nullptr /* fdb */,
+ nullptr /* apc */,
+ nullptr /* rpt_depts */,
nullptr /* postponed_repo */,
nullptr /* postponed_alts */,
+ nullptr /* postponed_recs */,
+ nullptr /* postponed_edeps */,
nullptr /* postponed_deps */,
- nullptr /* postponed_poss */,
nullptr /* unacceptable_alts */,
verify));
@@ -2798,83 +3644,148 @@ namespace bpkg
// Do not collect prerequisites recursively for dependent
// re-evaluation. Instead, if the re-evaluation position is
- // reached, collect the dependency packages to add them to the
+ // reached, stash the dependency packages to add them to the
// existing dependent's cluster.
//
- if (reeval)
+ if (reeval && dp != *reeval_pos)
+ continue;
+
+ // Note that while collect_build() may prefer an existing entry in
+ // the map and return NULL, the recursive collection of this
+ // preferred entry may has been postponed due to the existing
+ // dependent (see collect_build_prerequisites() for details). Now,
+ // we can potentially be recursively collecting such a dependent
+ // after its re-evaluation to some earlier than this dependency
+ // position. If that's the case, it is the time to collect this
+ // dependency (unless it has a config clause which will be handled
+ // below).
+ //
+ if (p == nullptr)
{
- if (dp == reeval_pos)
- cfg_deps.push_back (move (dpk));
+ p = entered_build (dpk);
- continue;
+ // We don't expect the collected build to be replaced with the
+ // drop since its required-by package names have the "required
+ // by dependents" semantics.
+ //
+ assert (p != nullptr &&
+ p->action &&
+ *p->action == build_package::build);
}
+ bool collect_prereqs (!p->recursive_collection);
+
// Do not recursively collect a dependency of a dependent with
// configuration clauses, which could be this or some other
- // (indicated by the presence in postponed_deps) dependent. In the
- // former case if the prerequisites were prematurely collected,
- // throw postpone_dependency.
+ // (indicated by the presence in postponed_deps or postponed_cfgs)
+ // dependent. In the former case if the prerequisites were
+ // prematurely collected, throw postpone_dependency.
//
// Note that such a dependency will be recursively collected
// directly right after the configuration negotiation (rather than
// via the dependent).
//
- bool collect_prereqs (p != nullptr);
-
{
- build_package* bp (entered_build (dpk));
- assert (bp != nullptr);
-
if (da.prefer || da.require)
{
- // Indicate that the dependent with configuration clauses is
- // present.
+ // If the dependency collection has already been postponed,
+ // then indicate that the dependent with configuration clauses
+ // is also present and thus the postponement is not bogus.
+ // Otherwise, if the dependency is already recursively
+ // collected (and we are not up-negotiating; see below) then
+ // add the new entry to postponed_deps and throw the
+ // postpone_dependency exception. Otherwise, temporarily add
+ // the new entry for the duration of the dependency collection
+ // loop to prevent recursive collection of this dependency via
+ // some other dependent. When out of the loop, we will add the
+ // dependency into some configuration cluster, effectively
+ // moving the dependency postponement information from
+ // postponed_deps to postponed_cfgs. Note that generally we
+ // add new entries to postponed_deps only if absolutely
+ // necessary to avoid yo-yoing (see the initial part of the
+ // collect_build_prerequisites() function for details).
//
+ auto i (postponed_deps.find (dpk));
+
+ bool new_postponement (false);
+
+ if (i == postponed_deps.end ())
{
- auto i (postponed_deps.find (dpk));
+ postponed_deps.emplace (dpk,
+ postponed_dependency {
+ false /* without_config */,
+ true /* with_config */});
+ new_postponement = true;
+ }
+ else
+ i->second.with_config = true;
- // Do not override postponements recorded during postponed
- // collection phase with those recorded during initial
- // phase.
+ // Throw postpone_dependency if the dependency is prematurely
+ // collected before we saw any config clauses.
+ //
+ // Note that we don't throw if the dependency already belongs
+ // to some (being) negotiated cluster since we will
+ // up-negotiate its configuration (at the end of the loop)
+ // instead.
+ //
+ if (p->recursive_collection)
+ {
+ const postponed_configuration* pcfg (
+ postponed_cfgs.find_dependency (dpk));
+
+ // Can it happen that an already recursively collected
+ // dependency (recursive_collection is true) belongs to a
+ // non (being) negotiated cluster? Yes, if, in particular,
+ // this dependency is an already re-evaluated existing
+ // dependent and we are currently re-evaluating its own
+ // existing dependent and its (as a dependency) cluster is
+ // not being negotiated yet (is in the existing dependents
+ // re-evaluation phase). See the
+ // pkg-build/.../collected-dependency-non-negotiated-cluster
+ // test for an example.
//
- if (i == postponed_deps.end ())
+ if (!(pcfg != nullptr && pcfg->negotiated))
{
- postponed_deps.emplace (dpk,
- postponed_dependency {
- false /* without_config */,
- true /* with_config */,
- initial_collection});
+ if (reeval)
+ {
+ l5 ([&]{trace << "cannot re-evaluate existing dependent "
+ << pkg.available_name_version_db ()
+ << " due to dependency "
+ << p->available_name_version_db ()
+ << " (collected prematurely), "
+ << "throwing postpone_dependency";});
+ }
+ else
+ {
+ l5 ([&]{trace << "cannot cfg-postpone dependency "
+ << p->available_name_version_db ()
+ << " of dependent "
+ << pkg.available_name_version_db ()
+ << " (collected prematurely), "
+ << "throwing postpone_dependency";});
+ }
+
+ // Don't print the "while satisfying..." chain.
+ //
+ dep_chain.clear ();
+
+ throw postpone_dependency (move (dpk));
}
- else
- i->second.with_config = true;
}
- // Prematurely collected before we saw any config clauses.
- //
- if (bp->recursive_collection &&
- postponed_cfgs.find_dependency (dpk) == nullptr)
- {
- l5 ([&]{trace << "cannot cfg-postpone dependency "
- << bp->available_name_version_db ()
- << " of dependent "
- << pkg.available_name_version_db ()
- << " (collected prematurely), "
- << "throwing postpone_dependency";});
+ if (new_postponement)
+ temp_postponements.push_back (dpk);
- // Don't print the "while satisfying..." chain.
+ if (!reeval)
+ {
+ // Postpone until (re-)negotiation.
//
- dep_chain.clear ();
-
- throw postpone_dependency (move (dpk));
+ l5 ([&]{trace << "cfg-postpone dependency "
+ << p->available_name_version_db ()
+ << " of dependent "
+ << pkg.available_name_version_db ();});
}
- // Postpone until (re-)negotiation.
- //
- l5 ([&]{trace << "cfg-postpone dependency "
- << bp->available_name_version_db ()
- << " of dependent "
- << pkg.available_name_version_db ();});
-
cfg_deps.push_back (move (dpk));
collect_prereqs = false;
@@ -2888,7 +3799,7 @@ namespace bpkg
if (i != postponed_deps.end ())
{
l5 ([&]{trace << "dep-postpone dependency "
- << bp->available_name_version_db ()
+ << p->available_name_version_db ()
<< " of dependent "
<< pkg.available_name_version_db ();});
@@ -2898,10 +3809,26 @@ namespace bpkg
}
else
{
- l5 ([&]{trace << "no cfg-clause for dependency "
- << bp->available_name_version_db ()
- << " of dependent "
- << pkg.available_name_version_db ();});
+ const postponed_configuration* pcfg (
+ postponed_cfgs.find_dependency (dpk));
+
+ if (pcfg != nullptr)
+ {
+ l5 ([&]{trace << "dep-postpone dependency "
+ << p->available_name_version_db ()
+ << " of dependent "
+ << pkg.available_name_version_db ()
+ << " since already in cluster " << *pcfg;});
+
+ collect_prereqs = false;
+ }
+ else
+ {
+ l5 ([&]{trace << "no cfg-clause for dependency "
+ << p->available_name_version_db ()
+ << " of dependent "
+ << pkg.available_name_version_db ();});
+ }
}
}
}
@@ -2909,19 +3836,20 @@ namespace bpkg
if (collect_prereqs)
collect_build_prerequisites (options,
*p,
+ dep_chain,
fdb,
- rpt_depts,
apc,
- initial_collection,
+ rpt_depts,
replaced_vers,
- dep_chain,
postponed_repo,
postponed_alts,
0 /* max_alt_index */,
+ postponed_recs,
+ postponed_edeps,
postponed_deps,
postponed_cfgs,
- postponed_poss,
- unacceptable_alts);
+ unacceptable_alts,
+ unsatisfied_depts);
}
// If this dependent has any dependencies with configurations
@@ -2969,7 +3897,7 @@ namespace bpkg
unacceptable_alternative (pk,
pkg.available->version,
pos)) !=
- unacceptable_alts.end ();
+ unacceptable_alts.end ();
};
// See if there is any unprocessed reused alternative to the
@@ -2978,6 +3906,8 @@ namespace bpkg
// Note that this is parallel to the alternative selection
// logic.
//
+ bool unsatisfactory (false);
+
for (++i; i != edas.size (); ++i)
{
if (unacceptable ())
@@ -2985,17 +3915,23 @@ namespace bpkg
const dependency_alternative& a (edas[i].first);
- precollect_result r (precollect (a,
- das.buildtime,
- prereqs,
- nullptr /* diag_record */,
- true /* dru_run */));
+ precollect_result r (
+ precollect (a,
+ das.buildtime,
+ prereqs,
+ check_constraints,
+ ignore_unsatisfactory_dep_spec,
+ nullptr /* diag_record */,
+ true /* dry_run */));
if (r.builds && r.reused)
{
has_alt = true;
break;
}
+
+ if (r.unsatisfactory)
+ unsatisfactory = true;
}
// If there are none and we are in the "recreate dependency
@@ -3004,6 +3940,75 @@ namespace bpkg
//
if (!has_alt && prereqs != nullptr)
{
+ unsatisfactory = false;
+
+ for (i = 0; i != edas.size (); ++i)
+ {
+ if (unacceptable ())
+ continue;
+
+ const dependency_alternative& a (edas[i].first);
+
+ if (&a != &da) // Skip the current dependency alternative.
+ {
+ precollect_result r (
+ precollect (a,
+ das.buildtime,
+ nullptr /* prereqs */,
+ check_constraints,
+ ignore_unsatisfactory_dep_spec,
+ nullptr /* diag_record */,
+ true /* dry_run */));
+
+ if (r.builds && r.reused)
+ {
+ has_alt = true;
+ break;
+ }
+
+ if (r.unsatisfactory)
+ unsatisfactory = true;
+ }
+ }
+ }
+
+ // If there are none and we are in the "check constraints" mode,
+ // then repeat the search with this mode off.
+ //
+ bool cc (check_constraints);
+ if (!has_alt && check_constraints && unsatisfactory)
+ {
+ cc = false;
+
+ for (i = 0; i != edas.size (); ++i)
+ {
+ if (unacceptable ())
+ continue;
+
+ const dependency_alternative& a (edas[i].first);
+
+ if (&a != &da) // Skip the current dependency alternative.
+ {
+ precollect_result r (
+ precollect (a,
+ das.buildtime,
+ nullptr /* prereqs */,
+ false /* check_constraints */,
+ ignore_unsatisfactory_dep_spec,
+ nullptr /* diag_record */,
+ true /* dry_run */));
+
+ if (r.builds && r.reused)
+ {
+ has_alt = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!has_alt && !ignore_unsatisfactory_dep_spec)
+ {
for (i = 0; i != edas.size (); ++i)
{
if (unacceptable ())
@@ -3013,11 +4018,14 @@ namespace bpkg
if (&a != &da) // Skip the current dependency alternative.
{
- precollect_result r (precollect (a,
- das.buildtime,
- nullptr /* prereqs */,
- nullptr /* diag_record */,
- true /* dru_run */));
+ precollect_result r (
+ precollect (a,
+ das.buildtime,
+ nullptr /* prereqs */,
+ cc,
+ true /* ignore_unsatisfactory_dep_spec */,
+ nullptr /* diag_record */,
+ true /* dry_run */));
if (r.builds && r.reused)
{
@@ -3036,8 +4044,30 @@ namespace bpkg
{
reevaluated = true;
- // Note: the dependent may already exist in the cluster with a
- // subset of dependencies.
+ // As a first step add this dependent/dependencies to one of the
+ // new/existing postponed_configuration clusters, which could
+ // potentially cause some of them to be merged. Note that when
+ // we re-evaluate existing dependents of dependencies in a
+ // cluster, these dependents can potentially be added to
+ // different clusters (see collect_build_postponed() for
+ // details). Here are the possibilities and what we should do in
+ // each case.
+ //
+ // 1. Got added to a new cluster -- this dependent got postponed
+ // and we return false.
+ //
+ // 2. Got added to an existing non-yet-negotiated cluster (which
+ // could potentially involve merging a bunch of them) --
+ // ditto. Note this also covers adding into a cluster which
+ // contain dependencies whose existing dependents we are
+ // currently re-evaluating (the negotiated member is absent
+ // but the depth is non-zero).
+ //
+ // 3. Got added to an existing already-negotiated cluster (which
+ // could potentially involve merging a bunch of them, some
+ // negotiated and some not yet negotiated). Perhaps just
+ // making the resulting cluster shadow and rolling back, just
+ // like in the other case (non-existing dependent), will do.
//
postponed_configuration& cfg (
postponed_cfgs.add (pk,
@@ -3046,41 +4076,56 @@ namespace bpkg
cfg_deps,
has_alt).first);
- // Can we merge clusters as a result? Seems so.
- //
- // - Simple case is if the cluster(s) being merged are not
- // negotiated. Then perhaps we could handle this via the same
- // logic that handles the addition of extra dependencies.
- //
- // - For the complex case, perhaps just making the resulting
- // cluster shadow and rolling back, just like in the other
- // case (non-existing dependent).
- //
- // Note: this is a special case of the below more general logic.
- //
- // Also note that we can distinguish the simple case by the fact
- // that the resulting cluster is not negotiated. Note however,
- // that in this case it is guaranteed that all the involved
- // clusters will be merged into the cluster which the being
- // re-evaluated dependent belongs to since this cluster (while
- // not being negotiated) already has non-zero depth (see
- // collect_build_postponed() for details).
- //
- assert (cfg.depth != 0);
-
- if (cfg.negotiated)
+ if (cfg.negotiated) // Case (3).
{
- l5 ([&]{trace << "re-evaluating dependent "
- << pkg.available_name_version_db ()
- << " involves negotiated configurations and "
- << "results in " << cfg << ", throwing "
- << "merge_configuration";});
+ // Note that the closest cluster up on the stack is in the
+ // existing dependents re-evaluation phase and thus is not
+ // being negotiated yet. The following clusters up on the
+ // stack can only be in the (fully) negotiated state. Thus, if
+ // cfg.negotiated member is present it can only be true.
+ //
+ // Also as a side-note: at any given moment there can only be
+ // 0 or 1 cluster being negotiated (the negotiate member is
+ // false).
+ //
+ assert (*cfg.negotiated);
// Don't print the "while satisfying..." chain.
//
dep_chain.clear ();
- throw merge_configuration {cfg.depth};
+ // There is just one complication:
+ //
+ // If the shadow cluster is already present and it is exactly
+ // the same as the resulting cluster which we are going to
+ // make a shadow, then we have already been here and we may
+ // start yo-yoing. To prevent that we will throw the
+ // merge_configuration_cycle exception instead of
+ // merge_configuration, so that the caller could handle this
+ // situation, for example, by just re-collecting the being
+ // re-evaluated existing dependent from scratch, reducing this
+ // case to the regular up-negotiating.
+ //
+ if (!cfg.is_shadow_cluster (cfg))
+ {
+ l5 ([&]{trace << "re-evaluating dependent "
+ << pkg.available_name_version_db ()
+ << " involves negotiated configurations and "
+ << "results in " << cfg << ", throwing "
+ << "merge_configuration";});
+
+ throw merge_configuration {cfg.depth};
+ }
+ else
+ {
+ l5 ([&]{trace << "merge configuration cycle detected for "
+ << "being re-evaluated dependent "
+ << pkg.available_name_version_db ()
+ << " since " << cfg << " is a shadow of itself"
+ << ", throwing merge_configuration_cycle";});
+
+ throw merge_configuration_cycle {cfg.depth};
+ }
}
l5 ([&]{trace << "re-evaluating dependent "
@@ -3152,8 +4197,9 @@ namespace bpkg
// To recap, r.second values mean:
//
// absent -- shadow cluster-based merge is/being negotiated
- // false -- some non or being negotiated
- // true -- all have been negotiated
+ // false -- some non or being negotiated clusters are merged
+ // true -- no clusters are merged or all merged have been
+ // negotiated
//
if (r.second && !*r.second)
{
@@ -3200,6 +4246,88 @@ namespace bpkg
throw merge_configuration {cfg.depth};
}
+ // Note that there can be some non-negotiated clusters which
+ // have been merged based on the shadow cluster into the
+ // resulting (being) negotiated cluster. If we had negotiated
+ // such non-negotiated clusters normally, we would query
+ // existing dependents for the dependencies they contain and
+ // consider them in the negotiation process by re-evaluating
+ // them (see collect_build_postponed() for details). But if we
+ // force-merge a non-negotiated cluster into the (being)
+ // negotiated cluster then the existing dependents of its
+ // dependencies won't participate in the negotiation, unless we
+ // take care of that now. We will recognize such dependencies as
+ // not yet (being) recursively collected and re-collect their
+ // existing dependents, if any.
+ //
+ vector<existing_dependent> depts;
+ string deps_trace;
+
+ for (const package_key& d: cfg.dependencies)
+ {
+ build_package* p (entered_build (d));
+
+ // Must be collected at least non-recursively.
+ //
+ assert (p != nullptr);
+
+ if (p->recursive_collection)
+ continue;
+
+ bool add_deps_trace (verb >= 5);
+
+ for (existing_dependent& ed:
+ query_existing_dependents (trace,
+ options,
+ d.db,
+ d.name,
+ false /* exclude_optional */,
+ fdb,
+ rpt_depts,
+ replaced_vers))
+ {
+ if (add_deps_trace)
+ {
+ deps_trace += p->available_name_version_db () + ' ';
+
+ // Make sure the dependency is only listed once in the
+ // trace record.
+ //
+ add_deps_trace = false;
+ }
+
+ // Add the existing dependent to the list, suppressing
+ // duplicates.
+ //
+ if (find_if (depts.begin (), depts.end (),
+ [&ed] (const existing_dependent& d)
+ {
+ return d.selected->name == ed.selected->name &&
+ d.db == ed.db;
+ }) == depts.end ())
+ {
+ depts.push_back (move (ed));
+ }
+ }
+ }
+
+ if (!depts.empty ())
+ {
+ l5 ([&]{trace << "cfg-postponing dependent "
+ << pkg.available_name_version_db ()
+ << " adds not (being) collected dependencies "
+ << deps_trace << "with not (being) collected "
+ << "existing dependents to (being) negotiated "
+ << "cluster and results in " << cfg
+ << ", throwing recollect_existing_dependents";});
+
+ // Don't print the "while satisfying..." chain.
+ //
+ dep_chain.clear ();
+
+ throw recollect_existing_dependents {cfg.depth, move (depts)};
+ }
+
// Up-negotiate the configuration and if it has changed, throw
// retry_configuration to the try/catch frame corresponding to
// the negotiation of the outermost merged cluster in order to
@@ -3228,7 +4356,8 @@ namespace bpkg
// then we wouldn't be able to continue using it if
// negotiate_configuration() below returns false. So it seems
// the most sensible approach is to make a temporary copy and
- // reset that.
+ // reset that (see the similar code in
+ // collect_build_postponed()).
//
small_vector<reference_wrapper<package_skeleton>, 1> depcs;
forward_list<package_skeleton> depcs_storage; // Ref stability.
@@ -3239,19 +4368,33 @@ namespace bpkg
build_package* b (entered_build (pk));
assert (b != nullptr);
+ optional<package_skeleton>& ps (b->skeleton);
+
+ // If the dependency's skeleton is already present, then
+ // this dependency's configuration has already been
+ // initially negotiated (see collect_build_postponed() for
+ // details) and will now be be up-negotiated. Thus, in
+ // particular, the skeleton must not have the old
+ // configuration dependent variables be loaded.
+ //
+ assert (!ps ||
+ (ps->load_config_flags &
+ package_skeleton::load_config_dependent) == 0);
+
package_skeleton* depc;
if (b->recursive_collection)
{
- assert (b->skeleton);
+ assert (ps);
- depcs_storage.push_front (*b->skeleton);
+ depcs_storage.push_front (*ps);
depc = &depcs_storage.front ();
depc->reset ();
}
else
- depc = &(b->skeleton
- ? *b->skeleton
- : b->init_skeleton (options));
+ depc = &(ps
+ ? *ps
+ : b->init_skeleton (options,
+ false /* load_old_dependent_config */));
depcs.push_back (*depc);
}
@@ -3322,12 +4465,9 @@ namespace bpkg
build_package* b (entered_build (p));
assert (b != nullptr);
- // Reconfigure the configured dependencies (see
- // collect_build_postponed() for details).
- //
- if (b->selected != nullptr &&
- b->selected->state == package_state::configured)
- b->flags |= build_package::adjust_reconfigure;
+ assert (b->skeleton); // Should have been init'ed above.
+
+ package_skeleton& ps (*b->skeleton);
if (!b->recursive_collection)
{
@@ -3340,13 +4480,11 @@ namespace bpkg
// the dependent configuration for this dependency.
//
{
- assert (b->skeleton); // Should have been init'ed above.
-
const package_configuration& pc (
cfg.dependency_configurations[p]);
- pair<bool, string> pr (b->skeleton->available != nullptr
- ? b->skeleton->verify_sensible (pc)
+ pair<bool, string> pr (ps.available != nullptr
+ ? ps.verify_sensible (pc)
: make_pair (true, string ()));
if (!pr.first)
@@ -3360,24 +4498,25 @@ namespace bpkg
pc.print (dr, " ");
}
- b->skeleton->dependent_config (pc);
+ ps.dependent_config (pc);
}
collect_build_prerequisites (options,
*b,
+ dep_chain,
fdb,
- rpt_depts,
apc,
- initial_collection,
+ rpt_depts,
replaced_vers,
- dep_chain,
postponed_repo,
postponed_alts,
0 /* max_alt_index */,
+ postponed_recs,
+ postponed_edeps,
postponed_deps,
postponed_cfgs,
- postponed_poss,
- unacceptable_alts);
+ unacceptable_alts,
+ unsatisfied_depts);
}
else
l5 ([&]{trace << "dependency "
@@ -3386,6 +4525,22 @@ namespace bpkg
<< pkg.available_name_version_db ()
<< " is already (being) recursively "
<< "collected, skipping";});
+
+ // Unless the dependency collection has been postponed or it
+ // is already being reconfigured, reconfigure it if its
+ // configuration changes.
+ //
+ if (!b->recursive_collection_postponed () && !b->reconfigure ())
+ {
+ const shared_ptr<selected_package>& sp (b->selected);
+
+ if (sp != nullptr &&
+ sp->state == package_state::configured &&
+ sp->config_checksum != ps.config_checksum ())
+ {
+ b->flags |= build_package::adjust_reconfigure;
+ }
+ }
}
return true;
@@ -3396,45 +4551,114 @@ namespace bpkg
};
// Select a dependency alternative, copying it alone into the resulting
- // dependencies list and evaluating its reflect clause, if present.
+ // dependencies list and evaluating its reflect clause, if present. In
+ // the pre-reevaluation mode update the variable prefixes list, if the
+ // selected alternative has config clause, and the pre-reevaluation
+ // resulting information (re-evaluation position, etc).
+ //
+ // Note that prebuilds are only used in the pre-reevaluation mode.
//
bool selected (false);
- auto select = [&sdeps, &salts, &sdas, &skel, di, &selected]
- (const dependency_alternative& da, size_t dai)
+ auto select = [&sdeps, &salts, &sdas,
+ &skel,
+ di,
+ &selected,
+ pre_reeval, &banned_var_prefixes, &references_banned_var,
+ &orig_dep,
+ &r] (const dependency_alternative& da,
+ size_t dai,
+ prebuilds&& pbs)
+ {
+ assert (sdas.empty ());
+
+ if (pre_reeval)
{
- assert (sdas.empty ());
+ pair<size_t, size_t> pos (di + 1, dai + 1);
- // Avoid copying enable/reflect not to evaluate them repeatedly.
+ bool contains_orig_dep (
+ find_if (pbs.begin (), pbs.end (),
+ [&orig_dep] (const prebuild& pb)
+ {
+ return pb.dependency.name == orig_dep->name &&
+ pb.db == orig_dep->db;
+ }) != pbs.end ());
+
+ // If the selected alternative contains the originating dependency,
+ // then set the originating dependency position, unless it is
+ // already set (note that the same dependency package may
+ // potentially be specified in multiple depends clauses).
//
- sdas.emplace_back (nullopt /* enable */,
- nullopt /* reflect */,
- da.prefer,
- da.accept,
- da.require,
- da /* dependencies */);
+ if (contains_orig_dep && r.originating_dependency_position.first == 0)
+ r.originating_dependency_position = pos;
- sdeps.push_back (move (sdas));
- salts.push_back (dai);
+ if (da.prefer || da.require)
+ {
+ if (contains_orig_dep)
+ r.reevaluation_optional = false;
- if (da.reflect)
- skel.evaluate_reflect (*da.reflect, make_pair (di, dai));
+ // If this is the first selected alternative with the config
+ // clauses, then save its position and the dependency packages.
+ //
+ if (r.reevaluation_position.first == 0)
+ {
+ r.reevaluation_position = pos;
- selected = true;
- };
+ for (prebuild& pb: pbs)
+ r.reevaluation_dependencies.emplace_back (
+ pb.db, move (pb.dependency.name));
+ }
+
+ // Save the variable prefixes for the selected alternative
+ // dependencies, if we still track them.
+ //
+ if (r.reevaluation_optional)
+ {
+ for (const dependency& d: da)
+ banned_var_prefixes.push_back (
+ "config." + d.name.variable () + '.');
+ }
+ }
+ }
+
+ // Avoid copying enable/reflect not to evaluate them repeatedly.
+ //
+ sdas.emplace_back (nullopt /* enable */,
+ nullopt /* reflect */,
+ da.prefer,
+ da.accept,
+ da.require,
+ da /* dependencies */);
+
+ sdeps.push_back (move (sdas));
+ salts.push_back (dai);
+
+ if (da.reflect)
+ {
+ if (pre_reeval &&
+ r.reevaluation_optional &&
+ references_banned_var (*da.reflect))
+ {
+ r.reevaluation_optional = false;
+ }
+
+ skel.evaluate_reflect (*da.reflect, make_pair (di, dai));
+ }
+
+ selected = true;
+ };
// Postpone the prerequisite builds collection, optionally inserting the
// package to the postponements set (can potentially already be there)
// and saving the enabled alternatives.
//
- auto postpone = [&pkg, &edas, &postponed]
- (postponed_packages* postpones)
- {
- if (postpones != nullptr)
- postpones->insert (&pkg);
+ auto postpone = [&pkg, &edas, &postponed] (postponed_packages* postpones)
+ {
+ if (postpones != nullptr)
+ postpones->insert (&pkg);
- pkg.postponed_dependency_alternatives = move (edas);
- postponed = true;
- };
+ pkg.postponed_dependency_alternatives = move (edas);
+ postponed = true;
+ };
// Iterate over the enabled dependencies and try to select a
// satisfactory alternative.
@@ -3456,10 +4680,33 @@ namespace bpkg
? &sp->prerequisites
: nullptr);
- // During the dependent re-evaluation we always try to reproduce the
- // existing setup.
+ // During the dependent (pre-)re-evaluation we always try to reproduce
+ // the existing setup.
//
- assert (!reeval || prereqs != nullptr);
+ assert ((!reeval && !pre_reeval) || prereqs != nullptr);
+
+ // Initially try to select an alternative checking that all the
+ // constraints imposed by the being built dependents of the dependencies
+ // in the alternative are satisfied. Failed that, re-try but this time
+ // disable this check so that the unsatisfactory dependency can be
+ // properly handled by collect_build() (which can fail, postpone
+ // failure, etc; see its implementation for details).
+ //
+ bool check_constraints (true);
+
+ // Initially don't ignore the unsatisfactory user-specified dependency
+ // specs, considering the dependency alternative as unsatisfactory if
+ // there are any. Failed that, re-try but this time ignore such specs,
+ // so that the unsatisfactory dependency can later be handled by
+ // collect_build() (which can fail, postpone failure, etc; see its
+ // implementation for details).
+ //
+ // The thinking here is that we don't ignore the unsatisfactory
+ // dependency specs initially to skip the alternatives which are
+ // unresolvable for that reason and prefer alternatives which satisfy
+ // the command line constraints.
+ //
+ bool ignore_unsatisfactory_dep_spec (false);
for (bool unacceptable (false);;)
{
@@ -3492,6 +4739,13 @@ namespace bpkg
//
bool reused_only (false);
+ // If true, then some alternatives with unsatisfactory dependencies
+ // are detected and, unless the alternative is selected or the
+ // selection is postponed, we should re-try with the constraints check
+ // disabled (see above for details).
+ //
+ bool unsatisfactory (false);
+
for (size_t i (0); i != edas.size (); ++i)
{
// Skip the unacceptable alternatives.
@@ -3518,7 +4772,12 @@ namespace bpkg
const dependency_alternative& da (edas[i].first);
- precollect_result r (precollect (da, das.buildtime, prereqs));
+ precollect_result pcr (
+ precollect (da,
+ das.buildtime,
+ prereqs,
+ check_constraints,
+ ignore_unsatisfactory_dep_spec));
// If we didn't come up with satisfactory dependency builds, then
// skip this alternative and try the next one, unless the collecting
@@ -3534,9 +4793,9 @@ namespace bpkg
//
// depends: libfoo >= 2.0.0 | {libfoo >= 1.0.0 libbar}
//
- if (!r.builds)
+ if (!pcr.builds)
{
- if (r.repo_postpone)
+ if (pcr.repo_postpone)
{
if (reeval)
fail_reeval ();
@@ -3548,8 +4807,13 @@ namespace bpkg
// If this alternative is reused but is not satisfactory, then
// switch to the reused-only mode.
//
- if (r.reused && r.unsatisfactory)
- reused_only = true;
+ if (pcr.unsatisfactory)
+ {
+ unsatisfactory = true;
+
+ if (pcr.reused)
+ reused_only = true;
+ }
continue;
}
@@ -3565,7 +4829,7 @@ namespace bpkg
//
if (!first_alt)
{
- first_alt = make_pair (i, move (r));
+ first_alt = make_pair (i, move (pcr));
continue;
}
@@ -3576,11 +4840,16 @@ namespace bpkg
//
auto try_select = [postponed_alts, &max_alt_index,
&edas, &pkg,
- prereqs,
+ di,
+ &prereqs,
+ &check_constraints,
+ &ignore_unsatisfactory_dep_spec,
+ pre_reeval,
reeval,
&trace,
- &postpone, &collect, &select]
- (size_t index, precollect_result&& r)
+ &postpone,
+ &collect,
+ &select] (size_t index, precollect_result&& pcr)
{
const auto& eda (edas[index]);
const dependency_alternative& da (eda.first);
@@ -3608,25 +4877,46 @@ namespace bpkg
// Select this alternative if all its dependencies are reused and
// do nothing about it otherwise.
//
- if (r.reused)
+ if (pcr.reused)
{
// On the diagnostics run there shouldn't be any alternatives
// that we could potentially select.
//
assert (postponed_alts != nullptr);
- if (!collect (da, dai, move (*r.builds), prereqs))
+ if (pre_reeval)
+ {
+ size_t ni (dai + 1);
+ size_t oi (pkg.selected->dependency_alternatives[di]);
+
+ if (ni != oi)
+ {
+ l5 ([&]{trace << "re-evaluation of dependent "
+ << pkg.available_name_version_db ()
+ << " deviated at depends clause " << di + 1
+ << ": selected alternative changed to " << ni
+ << " from " << oi;});
+
+ throw reevaluation_deviated ();
+ }
+ }
+ else if (!collect (da,
+ dai,
+ move (*pcr.builds),
+ prereqs,
+ check_constraints,
+ ignore_unsatisfactory_dep_spec))
{
postpone (nullptr); // Already inserted into postponed_cfgs.
return true;
}
- select (da, dai);
+ select (da, dai, move (*pcr.builds));
// Make sure no more true alternatives are selected during this
- // function call unless we are re-evaluating a dependent.
+ // function call unless we are (pre-)reevaluating a dependent.
//
- if (!reeval)
+ if (!reeval && !pre_reeval)
max_alt_index = 0;
return true;
@@ -3648,7 +4938,7 @@ namespace bpkg
break;
}
- if (try_select (i, move (r)))
+ if (try_select (i, move (pcr)))
break;
// Not all of the alternative dependencies are reused, so go to
@@ -3667,28 +4957,49 @@ namespace bpkg
{
assert (first_alt);
- precollect_result& r (first_alt->second);
+ precollect_result& pcr (first_alt->second);
- assert (r.builds);
+ assert (pcr.builds);
- if (r.reused || !reused_only)
+ if (pcr.reused || !reused_only)
{
// If there are any unacceptable alternatives, then the remaining
// one should be reused.
//
- assert (!unacceptable || r.reused);
+ assert (!unacceptable || pcr.reused);
const auto& eda (edas[first_alt->first]);
const dependency_alternative& da (eda.first);
size_t dai (eda.second);
- if (!collect (da, dai, move (*r.builds), prereqs))
+ if (pre_reeval)
+ {
+ size_t ni (dai + 1);
+ size_t oi (sp->dependency_alternatives[di]);
+
+ if (ni != oi)
+ {
+ l5 ([&]{trace << "re-evaluation of dependent "
+ << pkg.available_name_version_db ()
+ << " deviated for depends clause " << di + 1
+ << ": selected alternative (single) changed to "
+ << ni << " from " << oi;});
+
+ throw reevaluation_deviated ();
+ }
+ }
+ else if (!collect (da,
+ dai,
+ move (*pcr.builds),
+ prereqs,
+ check_constraints,
+ ignore_unsatisfactory_dep_spec))
{
postpone (nullptr); // Already inserted into postponed_cfgs.
break;
}
- select (da, dai);
+ select (da, dai, move (*pcr.builds));
}
}
@@ -3705,6 +5016,19 @@ namespace bpkg
//
if (prereqs != nullptr)
{
+ if (pre_reeval)
+ {
+ size_t oi (sp->dependency_alternatives[di]);
+
+ l5 ([&]{trace << "re-evaluation of dependent "
+ << pkg.available_name_version_db ()
+ << " deviated for depends clause " << di + 1
+ << ": now cannot select alternative, previously "
+ << oi << " was selected";});
+
+ throw reevaluation_deviated ();
+ }
+
if (reeval)
fail_reeval ();
@@ -3712,6 +5036,25 @@ namespace bpkg
continue;
}
+ // Retry with the constraints check disabled, if an alternative with
+ // the unsatisfactory dependencies is detected.
+ //
+ if (check_constraints && unsatisfactory)
+ {
+ check_constraints = false;
+ continue;
+ }
+
+ if (!ignore_unsatisfactory_dep_spec)
+ {
+ ignore_unsatisfactory_dep_spec = true;
+ continue;
+ }
+
+ // Otherwise we would have thrown/failed earlier.
+ //
+ assert (!pre_reeval && !reeval);
+
// We shouldn't end up with the "no alternative to select" case if any
// alternatives are unacceptable.
//
@@ -3724,7 +5067,14 @@ namespace bpkg
{
diag_record dr;
for (const auto& da: edas)
- precollect (da.first, das.buildtime, nullptr /* prereqs */, &dr);
+ {
+ precollect (da.first,
+ das.buildtime,
+ nullptr /* prereqs */,
+ true /* check_constraints */,
+ false /* ignore_unsatisfactory_dep_spec */,
+ &dr);
+ }
assert (!dr.empty ());
@@ -3756,7 +5106,6 @@ namespace bpkg
}
diag_record dr (fail);
-
dr << "unable to select dependency alternative for package "
<< pkg.available_name_version_db () <<
info << "explicitly specify dependency packages to manually "
@@ -3764,8 +5113,17 @@ namespace bpkg
for (const auto& da: edas)
{
+ // Note that we pass false as the check_constraints argument to make
+ // sure that the alternatives are always saved into
+ // precollect_result::builds rather than into
+ // precollect_result::unsatisfactory.
+ //
precollect_result r (
- precollect (da.first, das.buildtime, nullptr /* prereqs */));
+ precollect (da.first,
+ das.buildtime,
+ nullptr /* prereqs */,
+ false /* check_constraints */,
+ true /* ignore_unsatisfactory_dep_spec */));
if (r.builds)
{
@@ -3795,7 +5153,11 @@ namespace bpkg
for (const auto& da: edas)
{
precollect_result r (
- precollect (da.first, das.buildtime, nullptr /* prereqs */));
+ precollect (da.first,
+ das.buildtime,
+ nullptr /* prereqs */,
+ true /* check_constraints */,
+ false /* ignore_unsatisfactory_dep_spec */));
if (r.reused && r.unsatisfactory)
{
@@ -3811,12 +5173,22 @@ namespace bpkg
precollect (da.first,
das.buildtime,
nullptr /* prereqs */,
+ true /* check_constraints */,
+ false /* ignore_unsatisfactory_dep_spec */,
&dr);
}
}
}
}
+ // Bail out if the collection is postponed.
+ //
+ // Note that it's tempting to also bail out in the pre-reevaluation mode
+ // if we have already collected all the required resulting information
+ // (reevaluation position, originating dependency position, etc).
+ // However, in this case we may not detect the dependent deviation and
+ // thus we always iterate through all the depends clauses.
+ //
if (postponed)
break;
}
@@ -3829,12 +5201,54 @@ namespace bpkg
assert (postponed);
}
- dep_chain.pop_back ();
+ if (pre_reeval)
+ {
+ // It doesn't feel like it may happen in the pre-reevaluation mode. If
+ // it still happens, maybe due to some manual tampering, let's assume
+ // this as a deviation case.
+ //
+ if (r.originating_dependency_position.first == 0)
+ {
+ l5 ([&]{trace << "re-evaluation of dependent "
+ << pkg.available_name_version_db ()
+ << " deviated: previously selected dependency "
+ << *orig_dep << " is not selected anymore";});
+
+ throw reevaluation_deviated ();
+ }
+
+ l5 ([&]
+ {
+ diag_record dr (trace);
+ dr << "pre-reevaluated " << pkg.available_name_version_db ()
+ << ": ";
+
+ pair<size_t, size_t> pos (r.reevaluation_position);
+
+ if (pos.first != 0)
+ {
+ dr << pos.first << ',' << pos.second;
+
+ if (r.reevaluation_optional)
+ dr << " re-evaluation is optional";
+ }
+ else
+ dr << "end reached";
+ });
+ }
+ else
+ {
+ dep_chain.pop_back ();
+
+ l5 ([&]{trace << (!postponed ? "end " :
+ reeval ? "re-evaluated " :
+ "postpone ")
+ << pkg.available_name_version_db ();});
+ }
- l5 ([&]{trace << (!postponed ? "end " :
- reeval ? "re-evaluated " :
- "postpone ")
- << pkg.available_name_version_db ();});
+ return pre_reeval && r.reevaluation_position.first != 0
+ ? move (r)
+ : optional<pre_reevaluate_result> ();
}
void build_packages::
@@ -3842,17 +5256,18 @@ namespace bpkg
database& db,
const package_name& name,
const function<find_database_function>& fdb,
- const repointed_dependents& rpt_depts,
const function<add_priv_cfg_function>& apc,
- bool initial_collection,
+ const repointed_dependents& rpt_depts,
replaced_versions& replaced_vers,
postponed_packages& postponed_repo,
postponed_packages& postponed_alts,
size_t max_alt_index,
+ postponed_packages& postponed_recs,
+ postponed_existing_dependencies& postponed_edeps,
postponed_dependencies& postponed_deps,
postponed_configurations& postponed_cfgs,
- postponed_positions& postponed_poss,
- unacceptable_alternatives& unacceptable_alts)
+ unacceptable_alternatives& unacceptable_alts,
+ unsatisfied_dependents& unsatisfied_depts)
{
auto mi (map_.find (db, name));
assert (mi != map_.end ());
@@ -3861,51 +5276,59 @@ namespace bpkg
collect_build_prerequisites (o,
mi->second.package,
+ dep_chain,
fdb,
- rpt_depts,
apc,
- initial_collection,
+ rpt_depts,
replaced_vers,
- dep_chain,
&postponed_repo,
&postponed_alts,
max_alt_index,
+ postponed_recs,
+ postponed_edeps,
postponed_deps,
postponed_cfgs,
- postponed_poss,
- unacceptable_alts);
+ unacceptable_alts,
+ unsatisfied_depts);
}
void build_packages::
- collect_repointed_dependents (const pkg_build_options& o,
- const repointed_dependents& rpt_depts,
- replaced_versions& replaced_vers,
- postponed_packages& postponed_repo,
- postponed_packages& postponed_alts,
- postponed_dependencies& postponed_deps,
- postponed_configurations& postponed_cfgs,
- postponed_positions& postponed_poss,
- unacceptable_alternatives& unacceptable_alts,
- const function<find_database_function>& fdb,
- const function<add_priv_cfg_function>& apc)
+ collect_repointed_dependents (
+ const pkg_build_options& o,
+ const repointed_dependents& rpt_depts,
+ replaced_versions& replaced_vers,
+ postponed_packages& postponed_repo,
+ postponed_packages& postponed_alts,
+ postponed_packages& postponed_recs,
+ postponed_existing_dependencies& postponed_edeps,
+ postponed_dependencies& postponed_deps,
+ postponed_configurations& postponed_cfgs,
+ unacceptable_alternatives& unacceptable_alts,
+ unsatisfied_dependents& unsatisfied_depts,
+ const function<find_database_function>& fdb,
+ const function<add_priv_cfg_function>& apc)
{
+ tracer trace ("collect_repointed_dependents");
+
for (const auto& rd: rpt_depts)
{
database& db (rd.first.db);
const package_name& nm (rd.first.name);
- auto i (map_.find (db, nm));
- if (i != map_.end ())
{
- build_package& b (i->second.package);
-
- if (!b.action || *b.action != build_package::adjust)
+ auto i (map_.find (db, nm));
+ if (i != map_.end ())
{
- if (!b.action ||
- (*b.action != build_package::drop && !b.reconfigure ()))
- b.flags |= build_package::adjust_reconfigure;
+ build_package& b (i->second.package);
- continue;
+ if (!b.action || *b.action != build_package::adjust)
+ {
+ if (!b.action ||
+ (*b.action != build_package::drop && !b.reconfigure ()))
+ b.flags |= build_package::adjust_reconfigure;
+
+ continue;
+ }
}
}
@@ -3918,64 +5341,114 @@ namespace bpkg
// Add the prerequisite replacements as the required-by packages.
//
- set<package_key> required_by;
+ set<package_version_key> required_by;
for (const auto& prq: rd.second)
{
if (prq.second) // Prerequisite replacement?
{
const package_key& pk (prq.first);
- required_by.emplace (pk.db, pk.name);
+
+ // Note that the dependency can potentially be just pre-entered, in
+ // which case its version is not known at this point.
+ //
+ assert (entered_build (pk) != nullptr);
+
+ required_by.emplace (pk.db, pk.name, version ());
}
}
build_package p {
build_package::build,
- db,
- sp,
- move (rp.first),
- move (rp.second),
- nullopt, // Dependencies.
- nullopt, // Dependencies alternatives.
- nullopt, // Package skeleton.
- nullopt, // Postponed dependency alternatives.
- false, // Recursive collection.
- nullopt, // Hold package.
- nullopt, // Hold version.
- {}, // Constraints.
- sp->system (),
- false, // Keep output directory.
- false, // Disfigure (from-scratch reconf).
- false, // Configure-only.
- nullopt, // Checkout root.
- false, // Checkout purge.
- strings (), // Configuration variables.
- move (required_by), // Required by (dependencies).
- false, // Required by dependents.
- build_package::adjust_reconfigure | build_package::build_repoint};
+ db,
+ sp,
+ move (rp.first),
+ move (rp.second),
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ nullopt, // Hold package.
+ nullopt, // Hold version.
+ {}, // Constraints.
+ sp->system (),
+ false, // Keep output directory.
+ false, // Disfigure (from-scratch reconf).
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ nullopt, // Upgrade.
+ false, // Deorphan.
+ move (required_by), // Required by (dependencies).
+ false, // Required by dependents.
+ build_package::adjust_reconfigure | build_package::build_repoint};
build_package_refs dep_chain;
- // Note: recursive.
+ package_key pk {db, nm};
+
+ // Note that the repointed dependent can well be a dependency whose
+ // recursive processing should be postponed.
//
- collect_build (o,
- move (p),
- fdb,
- rpt_depts,
- apc,
- true /* initial_collection */,
- replaced_vers,
- postponed_cfgs,
- &dep_chain,
- &postponed_repo,
- &postponed_alts,
- &postponed_deps,
- &postponed_poss,
- &unacceptable_alts);
+ auto i (postponed_deps.find (pk));
+ if (i != postponed_deps.end ())
+ {
+ // Note that here we would collect the repointed dependent recursively
+ // without specifying any configuration for it.
+ //
+ i->second.wout_config = true;
+
+ // Note: not recursive.
+ //
+ collect_build (
+ o, move (p), replaced_vers, postponed_cfgs, unsatisfied_depts);
+
+ l5 ([&]{trace << "dep-postpone repointed dependent " << pk;});
+ }
+ else
+ {
+ const postponed_configuration* pcfg (
+ postponed_cfgs.find_dependency (pk));
+
+ if (pcfg != nullptr)
+ {
+ // Note: not recursive.
+ //
+ collect_build (
+ o, move (p), replaced_vers, postponed_cfgs, unsatisfied_depts);
+
+ l5 ([&]{trace << "dep-postpone repointed dependent " << pk
+ << " since already in cluster " << *pcfg;});
+ }
+ else
+ {
+ build_package_refs dep_chain;
+
+ // Note: recursive.
+ //
+ collect_build (o,
+ move (p),
+ replaced_vers,
+ postponed_cfgs,
+ unsatisfied_depts,
+ &dep_chain,
+ fdb,
+ apc,
+ &rpt_depts,
+ &postponed_repo,
+ &postponed_alts,
+ &postponed_recs,
+ &postponed_edeps,
+ &postponed_deps,
+ &unacceptable_alts);
+ }
+ }
}
}
void build_packages::
- collect_drop (const pkg_build_options& options,
+ collect_drop (const pkg_build_options&,
database& db,
shared_ptr<selected_package> sp,
replaced_versions& replaced_vers)
@@ -3985,7 +5458,7 @@ namespace bpkg
package_key pk (db, sp->name);
// If there is an entry for building specific version of the package (the
- // available member is not NULL), then it wasn't created to prevent out
+ // available member is not NULL), then it wasn't created to prevent our
// drop (see replaced_versions for details). This rather mean that the
// replacement version is not being built anymore due to the plan
// refinement. Thus, just erase the entry in this case and continue.
@@ -4016,28 +5489,30 @@ namespace bpkg
build_package p {
build_package::drop,
- db,
- move (sp),
- nullptr,
- nullptr,
- nullopt, // Dependencies.
- nullopt, // Dependencies alternatives.
- nullopt, // Package skeleton.
- nullopt, // Postponed dependency alternatives.
- false, // Recursive collection.
- nullopt, // Hold package.
- nullopt, // Hold version.
- {}, // Constraints.
- false, // System package.
- false, // Keep output directory.
- false, // Disfigure (from-scratch reconf).
- false, // Configure-only.
- nullopt, // Checkout root.
- false, // Checkout purge.
- strings (), // Configuration variables.
- {}, // Required by.
- false, // Required by dependents.
- 0}; // State flags.
+ db,
+ move (sp),
+ nullptr,
+ nullptr,
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ nullopt, // Hold package.
+ nullopt, // Hold version.
+ {}, // Constraints.
+ false, // System package.
+ false, // Keep output directory.
+ false, // Disfigure (from-scratch reconf).
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ nullopt, // Upgrade.
+ false, // Deorphan.
+ {}, // Required by.
+ false, // Required by dependents.
+ 0}; // State flags.
auto i (map_.find (pk));
@@ -4045,42 +5520,78 @@ namespace bpkg
{
build_package& bp (i->second.package);
- if (bp.available != nullptr)
+ // Don't overwrite the build object if its required-by package names
+ // have the "required by dependents" semantics.
+ //
+ if (!bp.required_by_dependents)
{
- // Similar to the version replacement in collect_build(), see if
- // in-place drop is possible (no dependencies, etc) and set scratch to
- // false if that's the case.
- //
- bool scratch (true);
+ if (bp.available != nullptr)
+ {
+ // Similar to the version replacement in collect_build(), see if
+ // in-place drop is possible (no dependencies, etc) and set scratch
+ // to false if that's the case.
+ //
+ bool scratch (true);
- // While checking if the package has any dependencies skip the
- // toolchain build-time dependencies since they should be quite
- // common.
- //
- if (!has_dependencies (options, bp.available->dependencies))
- scratch = false;
+ // While checking if the package has any dependencies skip the
+ // toolchain build-time dependencies since they should be quite
+ // common.
+ //
+ // An update: it turned out that just absence of dependencies is not
+ // the only condition that causes a package to be dropped in place.
+ // The following conditions must also be met:
+ //
+ // - The package must also not participate in any configuration
+ // negotiation on the dependency side (otherwise it could have
+ // been added to a cluster as a dependency).
+ //
+ // - The package must not be added to unsatisfied_depts on the
+ // dependency side.
+ //
+ // This feels quite hairy at the moment, so we won't be dropping in
+ // place for now.
+ //
+#if 0
+ if (!has_dependencies (options, bp.available->dependencies))
+ scratch = false;
+#endif
- l5 ([&]{trace << bp.available_name_version_db ()
- << " package version needs to be replaced "
- << (!scratch ? "in-place " : "") << "with drop";});
+ l5 ([&]{trace << bp.available_name_version_db ()
+ << " package version needs to be replaced "
+ << (!scratch ? "in-place " : "") << "with drop";});
- if (scratch)
- {
- if (vi != replaced_vers.end ())
- vi->second = replaced_version ();
- else
- replaced_vers.emplace (move (pk), replaced_version ());
+ if (scratch)
+ {
+ if (vi != replaced_vers.end ())
+ vi->second = replaced_version ();
+ else
+ replaced_vers.emplace (move (pk), replaced_version ());
- throw replace_version ();
+ throw replace_version ();
+ }
}
- }
- // Overwrite the existing (possibly pre-entered, adjustment, or repoint)
- // entry.
- //
- l4 ([&]{trace << "overwrite " << pk;});
+ // Overwrite the existing (possibly pre-entered, adjustment, or
+ // repoint) entry.
+ //
+ l4 ([&]{trace << "overwrite " << pk;});
- bp = move (p);
+ bp = move (p);
+ }
+ else
+ {
+ assert (!bp.required_by.empty ());
+
+ l5 ([&]
+ {
+ diag_record dr (trace);
+ dr << pk << " cannot be dropped since it is required by ";
+ for (auto b (bp.required_by.begin ()), i (b);
+ i != bp.required_by.end ();
+ ++i)
+ dr << (i != b ? ", " : "") << *i;
+ });
+ }
}
else
{
@@ -4105,28 +5616,30 @@ namespace bpkg
{
build_package p {
build_package::adjust,
- db,
- sp,
- nullptr,
- nullptr,
- nullopt, // Dependencies.
- nullopt, // Dependencies alternatives.
- nullopt, // Package skeleton.
- nullopt, // Postponed dependency alternatives.
- false, // Recursive collection.
- nullopt, // Hold package.
- nullopt, // Hold version.
- {}, // Constraints.
- sp->system (),
- false, // Keep output directory.
- false, // Disfigure (from-scratch reconf).
- false, // Configure-only.
- nullopt, // Checkout root.
- false, // Checkout purge.
- strings (), // Configuration variables.
- {}, // Required by.
- false, // Required by dependents.
- build_package::adjust_unhold};
+ db,
+ sp,
+ nullptr,
+ nullptr,
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ nullopt, // Hold package.
+ nullopt, // Hold version.
+ {}, // Constraints.
+ sp->system (),
+ false, // Keep output directory.
+ false, // Disfigure (from-scratch reconf).
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ nullopt, // Upgrade.
+ false, // Deorphan.
+ {}, // Required by.
+ false, // Required by dependents.
+ build_package::adjust_unhold};
p.merge (move (bp));
bp = move (p);
@@ -4140,16 +5653,22 @@ namespace bpkg
replaced_versions& replaced_vers,
postponed_packages& postponed_repo,
postponed_packages& postponed_alts,
+ postponed_packages& postponed_recs,
+ postponed_existing_dependencies& postponed_edeps,
postponed_dependencies& postponed_deps,
postponed_configurations& postponed_cfgs,
strings& postponed_cfgs_history,
- postponed_positions& postponed_poss,
unacceptable_alternatives& unacceptable_alts,
+ unsatisfied_dependents& unsatisfied_depts,
const function<find_database_function>& fdb,
const repointed_dependents& rpt_depts,
const function<add_priv_cfg_function>& apc,
postponed_configuration* pcfg)
{
+ // NOTE: enable and run the tests with the config.bpkg.tests.all=true
+ // variable if changing anything in this function.
+ //
+
// Snapshot of the package builds collection state.
//
// Note: should not include postponed_cfgs_history.
@@ -4160,11 +5679,18 @@ namespace bpkg
snapshot (const build_packages& pkgs,
const postponed_packages& postponed_repo,
const postponed_packages& postponed_alts,
+ const postponed_packages& postponed_recs,
+ const replaced_versions& replaced_vers,
+ const postponed_existing_dependencies& postponed_edeps,
const postponed_dependencies& postponed_deps,
- const postponed_configurations& postponed_cfgs)
+ const postponed_configurations& postponed_cfgs,
+ const unsatisfied_dependents& unsatisfied_depts)
: pkgs_ (pkgs),
+ replaced_vers_ (replaced_vers),
+ postponed_edeps_ (postponed_edeps),
postponed_deps_ (postponed_deps),
- postponed_cfgs_ (postponed_cfgs)
+ postponed_cfgs_ (postponed_cfgs),
+ unsatisfied_depts_ (unsatisfied_depts)
{
auto save = [] (vector<package_key>& d, const postponed_packages& s)
{
@@ -4176,18 +5702,25 @@ namespace bpkg
save (postponed_repo_, postponed_repo);
save (postponed_alts_, postponed_alts);
+ save (postponed_recs_, postponed_recs);
}
void
restore (build_packages& pkgs,
postponed_packages& postponed_repo,
postponed_packages& postponed_alts,
+ postponed_packages& postponed_recs,
+ replaced_versions& replaced_vers,
+ postponed_existing_dependencies& postponed_edeps,
postponed_dependencies& postponed_deps,
- postponed_configurations& postponed_cfgs)
+ postponed_configurations& postponed_cfgs,
+ unsatisfied_dependents& unsatisfied_depts)
{
- pkgs = move (pkgs_);
- postponed_cfgs = move (postponed_cfgs_);
- postponed_deps = move (postponed_deps_);
+ pkgs = move (pkgs_);
+ replaced_vers = move (replaced_vers_);
+ postponed_cfgs = move (postponed_cfgs_);
+ postponed_deps = move (postponed_deps_);
+ postponed_edeps = move (postponed_edeps_);
auto restore = [&pkgs] (postponed_packages& d,
const vector<package_key>& s)
@@ -4204,6 +5737,9 @@ namespace bpkg
restore (postponed_repo, postponed_repo_);
restore (postponed_alts, postponed_alts_);
+ restore (postponed_recs, postponed_recs_);
+
+ unsatisfied_depts = move (unsatisfied_depts_);
}
private:
@@ -4211,31 +5747,15 @@ namespace bpkg
// memory. We could probably optimize this some more if necessary
// (there are still sets/maps inside).
//
- build_packages pkgs_;
- vector<package_key> postponed_repo_;
- vector<package_key> postponed_alts_;
- postponed_dependencies postponed_deps_;
- postponed_configurations postponed_cfgs_;
- };
-
- // This exception is thrown if negotiation of the current cluster needs to
- // be skipped until later. This is normally required if this cluster
- // contains some existing dependent which needs to be re-evaluated to a
- // dependency position greater than some other not yet negotiated cluster
- // will re-evaluate this dependent to. Sometimes this another cluster yet
- // needs to be created in which case the exception carries the information
- // required for that (see the postponed_position's replace flag for
- // details).
- //
- struct skip_configuration
- {
- optional<existing_dependent> dependent;
- pair<size_t, size_t> new_position;
-
- skip_configuration () = default;
-
- skip_configuration (existing_dependent&& d, pair<size_t, size_t> n)
- : dependent (move (d)), new_position (n) {}
+ build_packages pkgs_;
+ vector<package_key> postponed_repo_;
+ vector<package_key> postponed_alts_;
+ vector<package_key> postponed_recs_;
+ replaced_versions replaced_vers_;
+ postponed_existing_dependencies postponed_edeps_;
+ postponed_dependencies postponed_deps_;
+ postponed_configurations postponed_cfgs_;
+ unsatisfied_dependents unsatisfied_depts_;
};
size_t depth (pcfg != nullptr ? pcfg->depth : 0);
@@ -4263,29 +5783,45 @@ namespace bpkg
assert (!pcfg->negotiated);
- // Re-evaluate existing dependents with configuration clause for
- // dependencies in this configuration cluster up to these
- // dependencies. Omit dependents which are already being built or
- // dropped. Note that these dependents, potentially with additional
- // dependencies, will be added to this cluster with the `existing` flag
- // as a part of the dependents' re-evaluation (see the collect lambda in
- // collect_build_prerequisites() for details).
+ // Re-evaluate existing dependents for dependencies in this
+ // configuration cluster. Omit dependents which are already being built,
+ // dropped, or postponed.
+ //
+ // Note that the existing dependent can be re-evaluated to an earlier
+ // position than the position of the dependency which has introduced
+ // this existing dependent. Thus, re-evaluating such a dependent does
+ // not necessarily add this dependent together with the dependencies at
+ // the re-evaluation target position specifically to this cluster. We,
+ // however, re-evaluate all the discovered existing dependents. Also
+ // note that these dependents will be added to their respective clusters
+ // with the `existing` flag as a part of the dependents' re-evaluation
+ // (see the collect lambda in collect_build_prerequisites() for
+ // details).
//
// After being re-evaluated the existing dependents are recursively
- // collected in the same way as the new dependents.
+ // collected in the same way and at the same time as the new dependents
+ // of the clusters they belong to.
//
+ // Note that some of the postponed existing dependents may already be in
+ // the cluster. Thus, collect the postponed existing dependents to omit
+ // them from the configuration negotiation and from the subsequent
+ // recursive collection. Note that we will up-negotiate the
+ // configuration these dependents apply to their dependencies after
+ // these dependents will be collected via their own dependents with the
+ // configuration clauses.
+ //
+ set<package_key> postponed_existing_dependents;
{
// Map existing dependents to the dependencies they apply a
// configuration to. Also, collect the information which is required
- // for a dependent re-evaluation and its subsequent recursive
- // collection (selected package, etc).
+ // for a dependent re-evaluation (selected package, etc).
//
- // As mentioned earlier, we may end up adding additional dependencies
- // to pcfg->dependencies which in turn may have additional existing
+ // Note that we may end up adding additional dependencies to
+ // pcfg->dependencies which in turn may have additional existing
// dependents which we need to process. Feels like doing this
// iteratively is the best option.
//
- // Note that we need to make sure we don't re-process the same
+ // Also note that we need to make sure we don't re-process the same
// existing dependents.
//
struct existing_dependent_ex: existing_dependent
@@ -4316,136 +5852,109 @@ namespace bpkg
//
const package_key& p (deps[i]);
- // If the dependent is being built, then check if it was
- // re-evaluated to the position greater than the dependency
- // position. Return true if that's the case, so this package is
- // added to the resulting list and we can handle this situation.
- //
- // Note that we rely on "small function object" optimization
- // here.
- //
- const function<verify_dependent_build_function> verify (
- [&postponed_cfgs, pcfg]
- (const package_key& pk, pair<size_t, size_t> pos)
- {
- for (const postponed_configuration& cfg: postponed_cfgs)
- {
- if (&cfg == pcfg || cfg.negotiated)
- {
- if (const pair<size_t, size_t>* p =
- cfg.existing_dependent_position (pk))
- {
- if (p->first > pos.first)
- return true;
- }
- }
- }
-
- return false;
- });
-
for (existing_dependent& ed:
query_existing_dependents (trace,
+ o,
p.db,
p.name,
- replaced_vers,
+ false /* exclude_optional */,
+ fdb,
rpt_depts,
- verify))
+ replaced_vers))
{
- package_key pk (ed.db, ed.selected->name);
-
- // If this dependent is present in postponed_deps, then it means
- // someone depends on it with configuration and it's no longer
- // considered an existing dependent (it will be reconfigured).
- // However, this fact may not be reflected yet. And it can
- // actually turn out bogus.
- //
- auto pi (postponed_deps.find (pk));
- if (pi != postponed_deps.end ())
+ if (ed.dependency)
{
- l5 ([&]{trace << "skip dep-postponed existing dependent "
- << pk << " of dependency " << p;});
-
- // Note that here we would re-evaluate the existing dependent
- // without specifying any configuration for it.
+ package_key pk (ed.db, ed.selected->name);
+
+ // If this dependent is present in postponed_deps or in some
+ // cluster as a dependency, then it means that someone depends
+ // on it with configuration and it's no longer considered an
+ // existing dependent (it will be reconfigured). However, this
+ // fact may not be reflected yet. And it can actually turn out
+ // bogus.
//
- pi->second.wout_config = true;
-
- continue;
- }
+ auto pi (postponed_deps.find (pk));
+ if (pi != postponed_deps.end ())
+ {
+ l5 ([&]{trace << "skip dep-postponed existing dependent "
+ << pk << " of dependency " << p;});
- auto i (dependents.find (pk));
- size_t di (ed.dependency_position.first);
+ // Note that here we would re-evaluate the existing
+ // dependent without specifying any configuration for it.
+ //
+ pi->second.wout_config = true;
- // Skip re-evaluated dependent if the dependency index is
- // greater than the one we have already re-evaluated to. If it
- // is earlier, then add the entry to postponed_poss and throw
- // postpone_position to recollect from scratch. Note that this
- // entry in postponed_poss is with replacement.
- //
- if (i != dependents.end () && i->second.reevaluated)
- {
- size_t ci (i->second.dependency_position.first);
+ collect_existing_dependent (o,
+ ed,
+ {p},
+ replaced_vers,
+ postponed_cfgs,
+ unsatisfied_depts);
- if (di > ci)
+ postponed_existing_dependents.insert (pk);
continue;
+ }
- // The newly-introduced dependency must belong to the depends
- // value other then the one we have re-evaluated to.
- //
- assert (di < ci);
-
- postponed_position pp (ed.dependency_position,
- true /* replace */);
-
- auto p (postponed_poss.emplace (pk, pp));
+ const postponed_configuration* pcfg (
+ postponed_cfgs.find_dependency (pk));
- if (!p.second)
+ if (pcfg != nullptr)
{
- assert (p.first->second > pp);
- p.first->second = pp;
+ l5 ([&]{trace << "skip existing dependent " << pk
+ << " of dependency " << p << " since "
+ << "dependent already in cluster " << *pcfg
+ << " (as a dependency)";});
+
+ postponed_existing_dependents.insert (pk);
+ continue;
}
- l5 ([&]{trace << "cannot re-evaluate dependent "
- << pk << " to dependency index " << di
- << " since it is already re-evaluated to "
- << "greater index " << ci << " in " << *pcfg
- << ", throwing postpone_position";});
+ auto i (dependents.find (pk));
- throw postpone_position ();
- }
+ // If the existing dependent is not in the map yet, then add
+ // it.
+ //
+ if (i == dependents.end ())
+ {
+ if (*ed.dependency != p)
+ collect_existing_dependent_dependency (o,
+ ed,
+ replaced_vers,
+ postponed_cfgs,
+ unsatisfied_depts);
+
+ i = dependents.emplace (
+ move (pk), existing_dependent_ex (move (ed))).first;
+ }
+ else
+ {
+ // We always re-evaluate to the earliest position.
+ //
+ assert (i->second.dependency_position ==
+ ed.dependency_position);
+ }
- // If the existing dependent is not in the map yet, then add
- // it. Otherwise, if the dependency position is greater than
- // that one in the existing map entry then skip it (this
- // position will be up-negotiated, if it's still present).
- // Otherwise, if the position is less then overwrite the
- // existing entry. Otherwise (the position is equal), just add
- // the dependency to the existing entry.
- //
- // Note that we want to re-evaluate the dependent up to the
- // earliest dependency position and continue with the regular
- // prerequisites collection (as we do for new dependents)
- // afterwards.
- //
- if (i == dependents.end ())
- {
- i = dependents.emplace (
- move (pk), existing_dependent_ex (move (ed))).first;
+ // Note that we add here the dependency which introduced this
+ // existing dependent, rather than the dependency which
+ // position we re-evaluate to, and which we want to be
+ // mentioned in the plan, if printed.
+ //
+ i->second.dependencies.push_back (p);
}
else
{
- size_t ci (i->second.dependency_position.first);
+ l5 ([&]{trace << "schedule re-collection of deviated "
+ << "existing dependent " << *ed.selected
+ << ed.db;});
- if (ci < di)
- continue;
- else if (ci > di)
- i->second = existing_dependent_ex (move (ed));
- //else if (ci == di)
- // ;
+ recollect_existing_dependent (o,
+ ed,
+ replaced_vers,
+ postponed_recs,
+ postponed_cfgs,
+ unsatisfied_depts,
+ true /* add_required_by */);
}
-
- i->second.dependencies.push_back (p);
}
}
@@ -4464,204 +5973,105 @@ namespace bpkg
if (ed.reevaluated)
continue;
- size_t di (ed.dependency_position.first);
- const package_key& pk (d.first);
-
- // Check if there is an earlier dependency position for this
- // dependent that will be participating in a configuration
- // negotiation and skip this cluster if that's the case. There
- // are two places to check: postponed_poss and other clusters.
- //
- auto pi (postponed_poss.find (pk));
- if (pi != postponed_poss.end () && pi->second.first < di)
- {
- l5 ([&]{trace << "pos-postpone existing dependent "
- << pk << " re-evaluation to dependency "
- << "index " << di << " due to recorded index "
- << pi->second.first << ", skipping " << *pcfg;});
-
- pi->second.skipped = true;
-
- // If requested, override the first encountered non-replace
- // position to replace (see below for details).
- //
- if (!pi->second.replace && postponed_poss.replace)
- {
- pi->second.replace = true;
- postponed_poss.replace = false;
- }
-
- if (pi->second.replace)
- throw skip_configuration (move (ed), pi->second);
- else
- throw skip_configuration ();
- }
-
- // The other clusters check is a bit more complicated: if the
- // other cluster (with the earlier position) is not yet
- // negotiated, then we skip. Otherwise, we have to add an entry
- // to postponed_poss and backtrack.
+ // Note that a re-evaluated package doesn't necessarily needs to
+ // be reconfigured and thus we don't add the
+ // build_package::adjust_reconfigure flag here.
//
- bool skip (false);
- for (const postponed_configuration& cfg: postponed_cfgs)
- {
- // Skip the current cluster.
- //
- if (&cfg == pcfg)
- continue;
-
- if (const pair<size_t, size_t>* p =
- cfg.existing_dependent_position (pk))
- {
- size_t ei (p->first); // Other position.
-
- if (!cfg.negotiated)
- {
- if (ei < di)
- {
- l5 ([&]{trace << "cannot re-evaluate dependent "
- << pk << " to dependency index " << di
- << " due to earlier dependency index "
- << ei << " in " << cfg << ", skipping "
- << *pcfg;});
-
- skip = true;
- }
- }
- else
- {
- // If this were not the case, then this dependent wouldn't
- // have been considered as an existing by
- // query_existing_dependents() since as it is (being)
- // negotiated then it is already re-evaluated and so is
- // being built (see the verify lambda above).
- //
- assert (ei > di);
-
- // Feels like there cannot be an earlier position.
- //
- postponed_position pp (ed.dependency_position,
- false /* replace */);
-
- auto p (postponed_poss.emplace (pk, pp));
- if (!p.second)
- {
- assert (p.first->second > pp);
- p.first->second = pp;
- }
-
- l5 ([&]{trace << "cannot re-evaluate dependent "
- << pk << " to dependency index " << di
- << " due to greater dependency "
- << "index " << ei << " in " << cfg
- << ", throwing postpone_position";});
-
- throw postpone_position ();
- }
- }
- }
-
- if (skip)
- throw skip_configuration ();
-
- // Finally, re-evaluate the dependent.
+ // Specifically, if none of its dependencies get reconfigured,
+ // then it doesn't need to be reconfigured either since nothing
+ // changes for its config clauses. Otherwise, the
+ // build_package::adjust_reconfigure flag will be added normally
+ // by collect_dependents().
//
- packages& ds (ed.dependencies);
-
- pair<shared_ptr<available_package>,
- lazy_shared_ptr<repository_fragment>> rp (
- find_available_fragment (o, pk.db, ed.selected));
-
- build_package p {
- build_package::build,
- pk.db,
- move (ed.selected),
- move (rp.first),
- move (rp.second),
- nullopt, // Dependencies.
- nullopt, // Dependencies alternatives.
- nullopt, // Package skeleton.
- nullopt, // Postponed dependency alternatives.
- false, // Recursive collection.
- nullopt, // Hold package.
- nullopt, // Hold version.
- {}, // Constraints.
- false, // System.
- false, // Keep output directory.
- false, // Disfigure (from-scratch reconf).
- false, // Configure-only.
- nullopt, // Checkout root.
- false, // Checkout purge.
- strings (), // Configuration variables.
- set<package_key> ( // Required by (dependency).
- ds.begin (), ds.end ()),
- false, // Required by dependents.
- build_package::adjust_reconfigure |
- build_package::build_reevaluate};
-
- // Note: not recursive.
- //
- collect_build (o,
- move (p),
- fdb,
- rpt_depts,
- apc,
- false /* initial_collection */,
- replaced_vers,
- postponed_cfgs);
-
- build_package* b (entered_build (pk));
+ collect_existing_dependent (o,
+ ed,
+ move (ed.dependencies),
+ replaced_vers,
+ postponed_cfgs,
+ unsatisfied_depts);
+
+ build_package* b (entered_build (d.first));
assert (b != nullptr);
// Re-evaluate up to the earliest position.
//
assert (ed.dependency_position.first != 0);
- build_package_refs dep_chain;
- collect_build_prerequisites (o,
- *b,
- fdb,
- rpt_depts,
- apc,
- false /* initial_collection */,
- replaced_vers,
- dep_chain,
- &postponed_repo,
- &postponed_alts,
- numeric_limits<size_t>::max (),
- postponed_deps,
- postponed_cfgs,
- postponed_poss,
- unacceptable_alts,
- ed.dependency_position);
-
- ed.reevaluated = true;
-
- if (pi != postponed_poss.end ())
+ try
{
- // Otherwise we should have thrown skip_configuration above.
- //
- assert (di <= pi->second.first);
+ build_package_refs dep_chain;
+ collect_build_prerequisites (o,
+ *b,
+ dep_chain,
+ fdb,
+ apc,
+ rpt_depts,
+ replaced_vers,
+ &postponed_repo,
+ &postponed_alts,
+ numeric_limits<size_t>::max (),
+ postponed_recs,
+ postponed_edeps,
+ postponed_deps,
+ postponed_cfgs,
+ unacceptable_alts,
+ unsatisfied_depts,
+ ed.dependency_position);
+ }
+ catch (const merge_configuration_cycle& e)
+ {
+ l5 ([&]{trace << "re-evaluation of existing dependent "
+ << b->available_name_version_db () << " failed "
+ << "due to merge configuration cycle for "
+ << *pcfg << ", throwing "
+ << "recollect_existing_dependents";});
- pi->second.reevaluated = true;
+ throw recollect_existing_dependents {e.depth, {move (ed)}};
}
+
+ ed.reevaluated = true;
}
}
}
}
- l5 ([&]{trace << "cfg-negotiate begin " << *pcfg;});
-
// Negotiate the configuration.
//
// The overall plan is as follows: continue refining the configuration
// until there are no more changes by giving each dependent a chance to
// make further adjustments.
//
+ l5 ([&]{trace << "cfg-negotiate begin " << *pcfg;});
+
+ // For the cluster's dependencies, the skeleton should not be present
+ // since we haven't yet started recursively collecting them. And we
+ // couldn't have started collecting them before we negotiated their
+ // configurations (that's in contrast to the up-negotiation). Let's
+ // assert for that here to make sure that's also true for dependencies
+ // of the postponed existing dependents of this cluster.
+ //
+#ifndef NDEBUG
+ for (const package_key& p: pcfg->dependencies)
+ {
+ build_package* b (entered_build (p));
+ assert (b != nullptr && !b->skeleton && !b->recursive_collection);
+ }
+#endif
+
for (auto b (pcfg->dependents.begin ()),
i (b),
e (pcfg->dependents.end ()); i != e; )
{
+ if (postponed_existing_dependents.find (i->first) !=
+ postponed_existing_dependents.end ())
+ {
+ l5 ([&]{trace << "skip dep-postponed existing dependent "
+ << i->first;});
+
+ ++i;
+ continue;
+ }
+
// Resolve package skeletons for the dependent and its dependencies.
//
// For the dependent, the skeleton should be already there (since we
@@ -4677,6 +6087,12 @@ namespace bpkg
dept = &*b->skeleton;
}
+ // If a dependency has already been recursively collected, then we can
+ // no longer call reload_defaults() or verify_sensible() on its
+ // skeleton. Thus, we make a temporary copy and reset that (see the
+ // collect() lambda in collect_build_prerequisites() for more
+ // details).
+ //
pair<size_t, size_t> pos;
small_vector<reference_wrapper<package_skeleton>, 1> depcs;
bool has_alt;
@@ -4703,11 +6119,18 @@ namespace bpkg
for (const package_key& pk: ds)
{
build_package* b (entered_build (pk));
- assert (b != nullptr);
- depcs.push_back (b->skeleton
- ? *b->skeleton
- : b->init_skeleton (o /* options */));
+ // Shouldn't be here otherwise.
+ //
+ assert (b != nullptr && !b->recursive_collection);
+
+ package_skeleton* depc (
+ &(b->skeleton
+ ? *b->skeleton
+ : b->init_skeleton (o,
+ false /* load_old_dependent_config */)));
+
+ depcs.push_back (*depc);
}
}
@@ -4780,38 +6203,40 @@ namespace bpkg
build_package* b (entered_build (p));
assert (b != nullptr);
- // Reconfigure the configured dependencies.
- //
- // Note that potentially this can be an overkill if the dependency
- // configuration doesn't really change. Later we can implement some
- // precise detection for that using configuration checksum or similar.
- //
- // Also note that for configured dependents which belong to the
- // configuration cluster this flag is already set (see above).
- //
- if (b->selected != nullptr &&
- b->selected->state == package_state::configured)
- b->flags |= build_package::adjust_reconfigure;
-
// Skip the dependencies which are already collected recursively.
//
if (!b->recursive_collection)
{
+ // Note that due to the existing dependents postponement some of the
+ // dependencies may have no dependent configuration applied to them
+ // at this time. In this case such dependencies may have no skeleton
+ // yet and thus we initialize it. Note that we will still apply the
+ // empty configuration to such dependencies and collect them
+ // recursively, since the negotiation machinery relies on the fact
+ // that the dependencies of a negotiated cluster are (being)
+ // recursively collected. When the time comes and such a dependency
+ // is collected via its (currently postponed) existing dependent,
+ // then its configuration will be up-negotiated (likely involving
+ // throwing the retry_configuration exception).
+ //
+ if (!b->skeleton)
+ b->init_skeleton (o, false /* load_old_dependent_config */);
+
+ package_skeleton& ps (*b->skeleton);
+
// Verify and set the dependent configuration for this dependency.
//
// Note: see similar code for the up-negotiation case.
//
{
- assert (b->skeleton); // Should have been init'ed above.
-
const package_configuration& pc (
pcfg->dependency_configurations[p]);
// Skip the verification if this is a system package without
// skeleton info.
//
- pair<bool, string> pr (b->skeleton->available != nullptr
- ? b->skeleton->verify_sensible (pc)
+ pair<bool, string> pr (ps.available != nullptr
+ ? ps.verify_sensible (pc)
: make_pair (true, string ()));
if (!pr.first)
@@ -4830,30 +6255,51 @@ namespace bpkg
pc.print (dr, " "); // Note 4 spaces since in nested info.
}
- b->skeleton->dependent_config (pc);
+ ps.dependent_config (pc);
}
build_package_refs dep_chain;
collect_build_prerequisites (o,
*b,
+ dep_chain,
fdb,
- rpt_depts,
apc,
- false /* initial_collection */,
+ rpt_depts,
replaced_vers,
- dep_chain,
&postponed_repo,
&postponed_alts,
0 /* max_alt_index */,
+ postponed_recs,
+ postponed_edeps,
postponed_deps,
postponed_cfgs,
- postponed_poss,
- unacceptable_alts);
+ unacceptable_alts,
+ unsatisfied_depts);
}
else
l5 ([&]{trace << "dependency " << b->available_name_version_db ()
<< " is already (being) recursively collected, "
<< "skipping";});
+
+ // Unless the dependency collection has been postponed or it is
+ // already being reconfigured, reconfigure it if its configuration
+ // changes.
+ //
+ if (!b->recursive_collection_postponed () && !b->reconfigure ())
+ {
+ const shared_ptr<selected_package>& sp (b->selected);
+
+ assert (b->skeleton); // Should have been init'ed above.
+
+ package_skeleton& ps (*b->skeleton);
+
+ if (sp != nullptr &&
+ sp->state == package_state::configured &&
+ sp->config_checksum != ps.config_checksum ())
+ {
+ b->flags |= build_package::adjust_reconfigure;
+ }
+ }
}
// Continue processing dependents with this config.
@@ -4862,6 +6308,13 @@ namespace bpkg
for (const auto& p: dependents)
{
+ if (postponed_existing_dependents.find (p) !=
+ postponed_existing_dependents.end ())
+ {
+ l5 ([&]{trace << "skip dep-postponed existing dependent " << p;});
+ continue;
+ }
+
// Select the dependency alternative for which configuration has been
// negotiated and collect this dependent starting from the next
// depends value.
@@ -4957,19 +6410,20 @@ namespace bpkg
collect_build_prerequisites (o,
*b,
+ dep_chain,
fdb,
- rpt_depts,
apc,
- false /* initial_collection */,
+ rpt_depts,
replaced_vers,
- dep_chain,
&postponed_repo,
&postponed_alts,
0 /* max_alt_index */,
+ postponed_recs,
+ postponed_edeps,
postponed_deps,
postponed_cfgs,
- postponed_poss,
- unacceptable_alts);
+ unacceptable_alts,
+ unsatisfied_depts);
}
// Negotiated (so can only be rolled back).
@@ -4986,16 +6440,120 @@ namespace bpkg
//
vector<build_package*> spas; // Reuse.
- for (bool prog (!postponed_repo.empty () ||
- !postponed_cfgs.negotiated () ||
- !postponed_alts.empty () ||
+ for (bool prog (find_if (postponed_recs.begin (), postponed_recs.end (),
+ [] (const build_package* p)
+ {
+ // Note that we check for the dependencies
+ // presence rather than for the
+ // recursive_collection flag (see below for
+ // details).
+ //
+ return !p->dependencies;
+ }) != postponed_recs.end () ||
+ !postponed_repo.empty () ||
+ !postponed_cfgs.negotiated () ||
+ !postponed_alts.empty () ||
postponed_deps.has_bogus ());
prog; )
{
+ // First, recursively recollect the not yet collected packages (deviated
+ // existing dependents, etc).
+ //
+ prog = false;
+
+ postponed_packages pcs;
+ for (build_package* p: postponed_recs)
+ {
+ // Note that we check for the dependencies presence rather than for
+ // the recursive_collection flag to also recollect the existing
+ // dependents which, for example, may have been specified on the
+ // command line and whose recursive collection has been pruned since
+ // there were no reason to collect it (configured, no upgrade,
+ // etc). Also note that this time we expect the collection to be
+ // enforced with the build_recollect flag.
+ //
+ assert ((p->flags & build_package::build_recollect) != 0);
+
+ if (!p->dependencies)
+ {
+ package_key pk (p->db, p->name ());
+
+ auto pi (postponed_deps.find (pk));
+ if (pi != postponed_deps.end ())
+ {
+ l5 ([&]{trace << "skip re-collection of dep-postponed package "
+ << pk;});
+
+ // Note that here we would re-collect the package without
+ // specifying any configuration for it.
+ //
+ pi->second.wout_config = true;
+
+ continue;
+ }
+ else
+ {
+ const postponed_configuration* pcfg (
+ postponed_cfgs.find_dependency (pk));
+
+ if (pcfg != nullptr)
+ {
+ l5 ([&]{trace << "skip re-collection of dep-postponed package "
+ << pk << " since already in cluster " << *pcfg;});
+
+ continue;
+ }
+ }
+
+ build_package_refs dep_chain;
+ collect_build_prerequisites (o,
+ *p,
+ dep_chain,
+ fdb,
+ apc,
+ rpt_depts,
+ replaced_vers,
+ &postponed_repo,
+ &postponed_alts,
+ 0 /* max_alt_index */,
+ pcs,
+ postponed_edeps,
+ postponed_deps,
+ postponed_cfgs,
+ unacceptable_alts,
+ unsatisfied_depts);
+
+ // Note that the existing dependent collection can be postponed
+ // due to it's own existing dependents.
+ //
+ if (p->recursive_collection)
+ {
+ // Must be present since the re-collection is enforced.
+ //
+ assert (p->dependencies);
+
+ prog = true;
+ }
+ }
+ }
+
+ // Scheduling new packages for re-collection is also a progress.
+ //
+ if (!prog)
+ prog = !pcs.empty ();
+
+ if (prog)
+ {
+ postponed_recs.insert (pcs.begin (), pcs.end ());
+ continue;
+ }
+
postponed_packages prs;
postponed_packages pas;
- // Try to collect the repository-related postponments first.
+ // Now, as there is no more progress made in recollecting of the not yet
+ // collected packages, try to collect the repository-related
+ // postponements.
//
for (build_package* p: postponed_repo)
{
@@ -5006,19 +6564,20 @@ namespace bpkg
collect_build_prerequisites (o,
*p,
+ dep_chain,
fdb,
- rpt_depts,
apc,
- false /* initial_collection */,
+ rpt_depts,
replaced_vers,
- dep_chain,
&prs,
&pas,
0 /* max_alt_index */,
+ postponed_recs,
+ postponed_edeps,
postponed_deps,
postponed_cfgs,
- postponed_poss,
- unacceptable_alts);
+ unacceptable_alts,
+ unsatisfied_depts);
}
// Save the potential new dependency alternative-related postponements.
@@ -5068,8 +6627,12 @@ namespace bpkg
snapshot s (*this,
postponed_repo,
postponed_alts,
+ postponed_recs,
+ replaced_vers,
+ postponed_edeps,
postponed_deps,
- postponed_cfgs);
+ postponed_cfgs,
+ unsatisfied_depts);
try
{
@@ -5077,11 +6640,13 @@ namespace bpkg
replaced_vers,
postponed_repo,
postponed_alts,
+ postponed_recs,
+ postponed_edeps,
postponed_deps,
postponed_cfgs,
postponed_cfgs_history,
- postponed_poss,
unacceptable_alts,
+ unsatisfied_depts,
fdb,
rpt_depts,
apc,
@@ -5099,55 +6664,6 @@ namespace bpkg
return;
}
- catch (skip_configuration& e)
- {
- // Restore the state from snapshot.
- //
- // Note: postponed_cfgs is re-assigned.
- //
- s.restore (*this,
- postponed_repo,
- postponed_alts,
- postponed_deps,
- postponed_cfgs);
-
- pc = &postponed_cfgs[ci];
-
- // Note that in this case we keep the accumulated configuration,
- // if any.
-
- pc->depth = 0;
-
- // If requested, "replace" the "later" dependent-dependency
- // cluster with an earlier.
- //
- if (e.dependent)
- {
- existing_dependent& ed (*e.dependent);
- pair<size_t, size_t> pos (e.new_position);
-
- const build_package* bp (
- replace_existing_dependent_dependency (
- trace,
- o,
- ed, // Note: modified.
- pos,
- fdb,
- rpt_depts,
- apc,
- false /* initial_collection */,
- replaced_vers,
- postponed_cfgs));
-
- postponed_cfgs.add (package_key (ed.db, ed.selected->name),
- pos,
- package_key (bp->db, bp->selected->name));
- }
-
- l5 ([&]{trace << "postpone cfg-negotiation of " << *pc;});
-
- break;
- }
catch (const retry_configuration& e)
{
// If this is not "our problem", then keep looking.
@@ -5165,8 +6681,12 @@ namespace bpkg
s.restore (*this,
postponed_repo,
postponed_alts,
+ postponed_recs,
+ replaced_vers,
+ postponed_edeps,
postponed_deps,
- postponed_cfgs);
+ postponed_cfgs,
+ unsatisfied_depts);
pc = &postponed_cfgs[ci];
@@ -5211,8 +6731,12 @@ namespace bpkg
s.restore (*this,
postponed_repo,
postponed_alts,
+ postponed_recs,
+ replaced_vers,
+ postponed_edeps,
postponed_deps,
- postponed_cfgs);
+ postponed_cfgs,
+ unsatisfied_depts);
pc = &postponed_cfgs[ci];
@@ -5276,6 +6800,67 @@ namespace bpkg
pc->set_shadow_cluster (move (shadow));
}
+ catch (const recollect_existing_dependents& e)
+ {
+ // If this is not "our problem", then keep looking.
+ //
+ if (e.depth != pcd)
+ throw;
+
+ // Restore the state from snapshot.
+ //
+ // Note: postponed_cfgs is re-assigned.
+ //
+ s.restore (*this,
+ postponed_repo,
+ postponed_alts,
+ postponed_recs,
+ replaced_vers,
+ postponed_edeps,
+ postponed_deps,
+ postponed_cfgs,
+ unsatisfied_depts);
+
+ pc = &postponed_cfgs[ci];
+
+ assert (!pc->negotiated);
+
+ // Drop any accumulated configuration (which could be carried
+ // over from retry_configuration logic).
+ //
+ pc->dependency_configurations.clear ();
+
+ // The shadow cluster likely contains the problematic
+ // dependent/dependencies. Thus, it feels right to drop the shadow
+ // before re-negotiating the cluster.
+ //
+ pc->shadow_cluster.clear ();
+
+ l5 ([&]{trace << "cfg-negotiation of " << *pc << " failed due to "
+ << "some existing dependents related problem, "
+ << "scheduling their re-collection";});
+
+ for (const existing_dependent& ed: e.dependents)
+ {
+ l5 ([&]{trace << "schedule re-collection of "
+ << (!ed.dependency ? "deviated " : "")
+ << "existing dependent " << *ed.selected
+ << ed.db;});
+
+ // Note that we pass false as the add_required_by argument since
+ // the package builds collection state has been restored and the
+ // originating dependency for this existing dependent may not be
+ // collected anymore.
+ //
+ recollect_existing_dependent (o,
+ ed,
+ replaced_vers,
+ postponed_recs,
+ postponed_cfgs,
+ unsatisfied_depts,
+ false /* add_required_by */);
+ }
+ }
}
}
@@ -5287,7 +6872,7 @@ namespace bpkg
//
if (!postponed_alts.empty ())
{
- // Sort the postponments in the unprocessed dependencies count
+ // Sort the postponements in the unprocessed dependencies count
// descending order.
//
// The idea here is to preferably handle those postponed packages
@@ -5354,19 +6939,20 @@ namespace bpkg
collect_build_prerequisites (o,
*p,
+ dep_chain,
fdb,
- rpt_depts,
apc,
- false /* initial_collection */,
+ rpt_depts,
replaced_vers,
- dep_chain,
&prs,
&pas,
i,
+ postponed_recs,
+ postponed_edeps,
postponed_deps,
postponed_cfgs,
- postponed_poss,
- unacceptable_alts);
+ unacceptable_alts,
+ unsatisfied_depts);
prog = (pas.find (p) == pas.end () ||
ndep != p->dependencies->size ());
@@ -5386,7 +6972,7 @@ namespace bpkg
// but producing new repository-related postponements is progress
// nevertheless.
//
- // Note that we don't need to check for new configuration- related
+ // Note that we don't need to check for new configuration-related
// postponements here since if they are present, then this package
// wouldn't be in pas and so prog would be true (see above for
// details).
@@ -5405,40 +6991,60 @@ namespace bpkg
assert (!prog);
- // If we still have any non-negotiated clusters and non-replace
- // postponed positions, then it's possible one of them is the cross-
- // dependent pathological case where we will never hit it unless we
- // force the re-evaluation to earlier position (similar to the
- // single-dependent case, which we handle accurately). For example:
- //
- // tex: depends: libbar(c)
- // depends: libfoo(c)
+ // Note that a bogus dependency postponement may, in particular, happen
+ // to an existing dependent due to the cycle introduced by its own
+ // existing dependent. For example, an existing dependent (libfoo)
+ // re-evaluation can be postponed since it starts a chain of
+ // re-evaluations which ends up with its own existing dependent (foo)
+ // with config clause, which being collected after re-evaluation is
+ // unable to collect the prematurely collected libfoo. In this case
+ // postponing collection of libfoo will also prevent foo from being
+ // re-evaluated, the postponement will turn out to be bogus, and we may
+ // start yo-yoing (see the
+ // pkg-build/.../recollect-dependent-bogus-dependency-postponement test
+ // for the real example). To prevent that, let's try to collect a
+ // postponed bogus dependency by recollecting its existing dependents,
+ // if present, prior to considering it as really bogus and re-collecting
+ // everything from scratch.
//
- // tix: depends: libbar(c)
- // depends: tex(c)
- //
- // Here tex and tix are existing dependent and we are upgrading tex.
- //
- // While it would be ideal to handle such cases accurately, it's not
- // trivial. So for now we resort to the following heuristics: when left
- // with no other option, we treat the first encountered non- replace
- // position as replace and see if that helps move things forward.
- //
- if (!postponed_cfgs.negotiated () &&
- find_if (postponed_poss.begin (), postponed_poss.end (),
- [] (const auto& v) {return !v.second.replace;}) !=
- postponed_poss.end () &&
- !postponed_poss.replace)
+ for (const auto& pd: postponed_deps)
{
- l5 ([&]{trace << "non-negotiated clusters left and non-replace "
- << "postponed positions are present, overriding first "
- << "encountered non-replace position to replace";});
-
- postponed_poss.replace = true;
- prog = true;
- continue; // Go back to negotiating skipped cluster.
+ if (pd.second.bogus ())
+ {
+ const package_key& pk (pd.first);
+
+ for (existing_dependent& ed:
+ query_existing_dependents (trace,
+ o,
+ pk.db,
+ pk.name,
+ false /* exclude_optional */,
+ fdb,
+ rpt_depts,
+ replaced_vers))
+ {
+ l5 ([&]{trace << "schedule re-collection of "
+ << (!ed.dependency ? "deviated " : "")
+ << "existing dependent " << *ed.selected
+ << ed.db << " due to bogus postponement of "
+ << "dependency " << pk;});
+
+ recollect_existing_dependent (o,
+ ed,
+ replaced_vers,
+ postponed_recs,
+ postponed_cfgs,
+ unsatisfied_depts,
+ true /* add_required_by */);
+ prog = true;
+ break;
+ }
+ }
}
+ if (prog)
+ continue;
+
// Finally, erase the bogus postponements and re-collect from scratch,
// if any (see postponed_dependencies for details).
//
@@ -5446,7 +7052,7 @@ namespace bpkg
// re-doing from scratch feels more correct (i.e., we may end up doing
// it earlier which will affect dependency alternatives).
//
- postponed_deps.cancel_bogus (trace, false /* initial_collection */);
+ postponed_deps.cancel_bogus (trace);
}
// Check if any negotiatiated configurations ended up with any bogus
@@ -5591,19 +7197,20 @@ namespace bpkg
collect_build_prerequisites (o,
**postponed_repo.begin (),
+ dep_chain,
fdb,
- rpt_depts,
apc,
- false /* initial_collection */,
+ rpt_depts,
replaced_vers,
- dep_chain,
nullptr,
nullptr,
0,
+ postponed_recs,
+ postponed_edeps,
postponed_deps,
postponed_cfgs,
- postponed_poss,
- unacceptable_alts);
+ unacceptable_alts,
+ unsatisfied_depts);
assert (false); // Can't be here.
}
@@ -5614,27 +7221,27 @@ namespace bpkg
collect_build_prerequisites (o,
**postponed_alts.begin (),
+ dep_chain,
fdb,
- rpt_depts,
apc,
- false /* initial_collection */,
+ rpt_depts,
replaced_vers,
- dep_chain,
nullptr,
nullptr,
0,
+ postponed_recs,
+ postponed_edeps,
postponed_deps,
postponed_cfgs,
- postponed_poss,
- unacceptable_alts);
+ unacceptable_alts,
+ unsatisfied_depts);
assert (false); // Can't be here.
}
// While the assumption is that we shouldn't leave any non-negotiated
- // clusters, we can potentially miss some corner cases in the above "skip
- // configuration" logic. Let's thus trace the non-negotiated clusters
- // before the assertion.
+ // clusters, let's verify that for good measure. Let's thus trace the
+ // non-negotiated clusters before the assertion.
//
#ifndef NDEBUG
for (const postponed_configuration& cfg: postponed_cfgs)
@@ -5652,48 +7259,62 @@ namespace bpkg
build_packages::iterator build_packages::
order (database& db,
const package_name& name,
- optional<bool> buildtime,
const function<find_database_function>& fdb,
bool reorder)
{
package_refs chain;
- return order (db, name, buildtime, chain, fdb, reorder);
+ return order (db, name, chain, fdb, reorder);
}
- void build_packages::
- collect_order_dependents (const repointed_dependents& rpt_depts)
+ set<package_key> build_packages::
+ collect_dependents (const repointed_dependents& rpt_depts,
+ unsatisfied_dependents& unsatisfied_depts)
{
- // For each package on the list we want to insert all its dependents
- // before it so that they get configured after the package on which they
- // depend is configured (remember, our build order is reverse, with the
- // last package being built first). This applies to both packages that are
- // already on the list as well as the ones that we add, recursively.
+ set<package_key> r;
+
+ // First, cache the packages in the map since we will be adding new
+ // entries to the map while collecting dependents of the initial package
+ // set, recursively.
+ //
+ // Note: the pointer is stable (points to a value in std::map).
//
- for (auto i (begin ()); i != end (); ++i)
+ vector<build_package*> deps;
+
+ for (auto& p: map_)
{
- const build_package& p (*i);
+ build_package& d (p.second.package);
// Prune if this is not a configured package being up/down-graded
// or reconfigured.
//
- assert (p.action);
-
- // Dropped package may have no dependents.
- //
- if (*p.action != build_package::drop && p.reconfigure ())
- collect_order_dependents (i, rpt_depts);
+ if (d.action && *d.action != build_package::drop && d.reconfigure ())
+ deps.push_back (&d);
}
+
+ // Note: the pointer is stable (see above for details).
+ //
+ set<const build_package*> visited_deps;
+
+ for (build_package* p: deps)
+ collect_dependents (*p, rpt_depts, unsatisfied_depts, visited_deps, r);
+
+ return r;
}
void build_packages::
- collect_order_dependents (iterator pos,
- const repointed_dependents& rpt_depts)
+ collect_dependents (build_package& p,
+ const repointed_dependents& rpt_depts,
+ unsatisfied_dependents& unsatisfied_depts,
+ set<const build_package*>& visited_deps,
+ set<package_key>& r)
{
- tracer trace ("collect_order_dependents");
+ tracer trace ("collect_dependents");
- assert (pos != end ());
-
- build_package& p (*pos);
+ // Bail out if the dependency has already been visited and add it to the
+ // visited set otherwise.
+ //
+ if (!visited_deps.insert (&p).second)
+ return;
database& pdb (p.db);
const shared_ptr<selected_package>& sp (p.selected);
@@ -5712,19 +7333,20 @@ namespace bpkg
for (auto& pd: query_dependents_cache (ddb, n, pdb))
{
package_name& dn (pd.name);
+ optional<version_constraint>& dc (pd.constraint);
+
auto i (map_.find (ddb, dn));
// Make sure the up/downgraded package still satisfies this
// dependent. But first "prune" if the dependent is being dropped or
// this is a replaced prerequisite of the repointed dependent.
//
- // Note that the repointed dependents are always collected and have
- // all their collected prerequisites ordered (including new and old
- // ones). See collect_build_prerequisites() and order() for details.
+ // Note that the repointed dependents are always collected (see
+ // collect_build_prerequisites() for details).
//
- bool check (ud != 0 && pd.constraint);
+ bool check (ud != 0 && dc);
- if (i != map_.end () && i->second.position != end ())
+ if (i != map_.end ())
{
build_package& dp (i->second.package);
@@ -5759,47 +7381,24 @@ namespace bpkg
if (check)
{
const version& av (p.available_version ());
- const version_constraint& c (*pd.constraint);
+ const version_constraint& c (*dc);
+ // If the new dependency version doesn't satisfy the existing
+ // dependent, then postpone the failure in the hope that this
+ // problem will be resolved naturally (the dependent will also be
+ // up/downgraded, etc; see unsatisfied_dependents for details).
+ //
if (!satisfies (av, c))
{
- diag_record dr (fail);
-
- dr << "unable to " << (ud < 0 ? "up" : "down") << "grade "
- << "package " << *sp << pdb << " to ";
-
- // Print both (old and new) package names in full if the system
- // attribution changes.
- //
- if (p.system != sp->system ())
- dr << p.available_name_version ();
- else
- dr << av; // Can't be the wildcard otherwise would satisfy.
-
- dr << info << "because package " << dn << ddb << " depends on ("
- << n << " " << c << ")";
-
- string rb;
- if (!p.user_selection ())
- {
- for (const package_key& pk: p.required_by)
- rb += (rb.empty () ? " " : ", ") + pk.string ();
- }
-
- if (!rb.empty ())
- dr << info << "package " << p.available_name_version ()
- << " required by" << rb;
+ package_key d (ddb, dn);
- dr << info << "explicitly request up/downgrade of package "
- << dn;
+ l5 ([&]{trace << "postpone failure for existing dependent " << d
+ << " unsatisfied with dependency "
+ << p.available_name_version_db () << " ("
+ << c << ')';});
- dr << info << "or explicitly specify package " << n
- << " version to manually satisfy these constraints";
+ unsatisfied_depts.add (d, package_key (p.db, p.name ()), c);
}
-
- // Add this contraint to the list for completeness.
- //
- p.constraints.emplace_back (ddb, dn.string (), c);
}
auto adjustment = [&dn, &ddb, &n, &pdb] () -> build_package
@@ -5810,77 +7409,62 @@ namespace bpkg
//
assert (!dsp->system ());
+ package_version_key pvk (pdb, n, version ());
+
return build_package {
build_package::adjust,
- ddb,
- move (dsp),
- nullptr, // No available pkg/repo fragment.
- nullptr,
- nullopt, // Dependencies.
- nullopt, // Dependencies alternatives.
- nullopt, // Package skeleton.
- nullopt, // Postponed dependency alternatives.
- false, // Recursive collection.
- nullopt, // Hold package.
- nullopt, // Hold version.
- {}, // Constraints.
- false, // System.
- false, // Keep output directory.
- false, // Disfigure (from-scratch reconf).
- false, // Configure-only.
- nullopt, // Checkout root.
- false, // Checkout purge.
- strings (), // Configuration variables.
- {package_key {pdb, n}}, // Required by (dependency).
- false, // Required by dependents.
- build_package::adjust_reconfigure};
+ ddb,
+ move (dsp),
+ nullptr, // No available pkg/repo fragment.
+ nullptr,
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ nullopt, // Hold package.
+ nullopt, // Hold version.
+ {}, // Constraints.
+ false, // System.
+ false, // Keep output directory.
+ false, // Disfigure (from-scratch reconf).
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ nullopt, // Upgrade.
+ false, // Deorphan.
+ {move (pvk)}, // Required by (dependency).
+ false, // Required by dependents.
+ build_package::adjust_reconfigure};
};
- // We can have three cases here: the package is already on the list,
- // the package is in the map (but not on the list) and it is in
- // neither.
- //
- // If the existing entry is pre-entered, is an adjustment, or is a
- // build that is not supposed to be built (not in the list), then we
- // merge it into the new adjustment entry. Otherwise (is a build in
- // the list), we just add the reconfigure adjustment flag to it.
+ // If the existing entry is pre-entered or is an adjustment, then we
+ // merge it into the new adjustment entry. Otherwise (is a build), we
+ // just add the reconfigure adjustment flag to it, unless it is
+ // already being reconfigured. In the later case we don't add the
+ // dependent to the resulting set since we neither add a new entry to
+ // the map nor modify an existing one.
//
+ bool add (true);
if (i != map_.end ())
{
build_package& dp (i->second.package);
- iterator& dpos (i->second.position);
- if (!dp.action || // Pre-entered.
- *dp.action != build_package::build || // Non-build.
- dpos == end ()) // Build not in the list.
+ if (!dp.action || // Pre-entered.
+ *dp.action != build_package::build) // Adjustment.
{
build_package bp (adjustment ());
bp.merge (move (dp));
dp = move (bp);
}
- else // Build in the list.
- dp.flags |= build_package::adjust_reconfigure;
-
- // It may happen that the dependent is already in the list but is
- // not properly ordered against its dependencies that get into the
- // list via another dependency path. Thus, we check if the dependent
- // is to the right of its dependency and, if that's the case,
- // reinsert it in front of the dependency.
- //
- if (dpos != end ())
+ else // Build.
{
- for (auto i (pos); i != end (); ++i)
- {
- if (i == dpos)
- {
- erase (dpos);
- dpos = insert (pos, dp);
- break;
- }
- }
+ if (!dp.reconfigure ())
+ dp.flags |= build_package::adjust_reconfigure;
+ else
+ add = false;
}
- else
- dpos = insert (pos, dp);
}
else
{
@@ -5888,17 +7472,44 @@ namespace bpkg
//
i = map_.emplace (package_key {ddb, dn},
data_type {end (), adjustment ()}).first;
+ }
+
+ if (add)
+ r.insert (i->first);
+
+ build_package& dp (i->second.package);
+
+ // Add this dependent's constraint, if present, to the dependency's
+ // constraints list for completeness, while suppressing duplicates.
+ //
+ if (dc)
+ {
+ using constraint_type = build_package::constraint_type;
- i->second.position = insert (pos, i->second.package);
+ constraint_type c (move (*dc),
+ ddb,
+ move (dn),
+ dp.selected->version,
+ true /* selected_dependent */);
+
+ if (find_if (p.constraints.begin (), p.constraints.end (),
+ [&c] (const constraint_type& v)
+ {
+ return v.dependent == c.dependent &&
+ v.value == c.value;
+ }) == p.constraints.end ())
+ {
+ p.constraints.emplace_back (move (c));
+ }
}
- // Recursively collect our own dependents inserting them before us.
+ // Recursively collect our own dependents.
//
// Note that we cannot end up with an infinite recursion for
- // configured packages due to a dependency cycle (see order() for
- // details).
+ // configured packages due to a dependency cycle since we "prune" for
+ // visited dependencies (also see order() for details).
//
- collect_order_dependents (i->second.position, rpt_depts);
+ collect_dependents (dp, rpt_depts, unsatisfied_depts, visited_deps, r);
}
}
}
@@ -5920,6 +7531,72 @@ namespace bpkg
}
void build_packages::
+ print_constraints (diag_record& dr,
+ const build_package& p,
+ string& indent,
+ set<package_key>& printed,
+ optional<bool> selected_dependent) const
+ {
+ using constraint_type = build_package::constraint_type;
+
+ const vector<constraint_type>& cs (p.constraints);
+
+ if (!cs.empty ())
+ {
+ package_key pk (p.db, p.name ());
+
+ if (printed.find (pk) == printed.end ())
+ {
+ printed.insert (pk);
+
+ for (const constraint_type& c: cs)
+ {
+ if (!selected_dependent ||
+ *selected_dependent == c.selected_dependent)
+ {
+ if (const build_package* d = dependent_build (c))
+ {
+ dr << '\n' << indent << c.dependent << " requires (" << pk
+ << ' ' << c.value << ')';
+
+ indent += " ";
+ print_constraints (dr, *d, indent, printed, selected_dependent);
+ indent.resize (indent.size () - 2);
+ }
+ else
+ dr << '\n' << indent << c.dependent << " requires (" << pk << ' '
+ << c.value << ')';
+ }
+ }
+ }
+ else
+ {
+ for (const constraint_type& c: cs)
+ {
+ if (!selected_dependent ||
+ *selected_dependent == c.selected_dependent)
+ {
+ dr << '\n' << indent << "...";
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ void build_packages::
+ print_constraints (diag_record& dr,
+ const package_key& pk,
+ string& indent,
+ set<package_key>& printed,
+ optional<bool> selected_dependent) const
+ {
+ const build_package* p (entered_build (pk));
+ assert (p != nullptr); // Expected to be collected.
+ print_constraints (dr, *p, indent, printed, selected_dependent);
+ }
+
+ void build_packages::
verify_ordering () const
{
for (const auto& b: map_)
@@ -5941,84 +7618,279 @@ namespace bpkg
// replaced_versions for details). Before that the whole dependency
// trees from the being replaced dependent stayed in the map.
//
- assert (bp.action.has_value () == (i != end ()));
+ if (bp.action.has_value () != (i != end ()))
+ {
+ diag_record dr (info);
+
+ if (!bp.action)
+ {
+ dr << "pre-entered builds must never be ordered" <<
+ info << "ordered pre-entered " << b.first;
+ }
+ else
+ {
+ dr << "build actions must be ordered" <<
+ info << "unordered ";
+
+ switch (*bp.action)
+ {
+ case build_package::build:
+ {
+ dr << "build " << bp.available_name_version_db () <<
+ info << "flags 0x" << hex << uppercase << bp.flags;
+ break;
+ }
+ case build_package::drop:
+ {
+ dr << "drop " << *bp.selected << bp.db;
+ break;
+ }
+ case build_package::adjust:
+ {
+ dr << "adjustment " << *bp.selected << bp.db <<
+ info << "flags 0x" << hex << uppercase << bp.flags;
+ break;
+ }
+ }
+ }
+
+ dr << info
+ << "please report in https://github.com/build2/build2/issues/318";
+
+ dr.flush ();
+
+ assert (bp.action.has_value () == (i != end ()));
+ }
}
}
vector<build_packages::existing_dependent> build_packages::
query_existing_dependents (
tracer& trace,
+ const pkg_build_options& o,
database& db,
const package_name& name,
- const replaced_versions& replaced_vers,
+ bool exclude_optional,
+ const function<find_database_function>& fdb,
const repointed_dependents& rpt_depts,
- const function<verify_dependent_build_function>& vdb)
+ const replaced_versions& replaced_vers)
{
vector<existing_dependent> r;
- lazy_shared_ptr<selected_package> sp (db, name);
+ // Lazily search for the dependency build and detect if it is being
+ // up/downgraded. Note that we will only do that if the dependency has an
+ // existing dependent which imposes a version constraint on this
+ // dependency.
+ //
+ const build_package* dep (nullptr);
+ int ud (0);
for (database& ddb: db.dependent_configs ())
{
for (auto& pd: query_dependents (ddb, name, db))
{
- shared_ptr<selected_package> dsp (
- ddb.load<selected_package> (pd.name));
-
- auto i (dsp->prerequisites.find (sp));
- assert (i != dsp->prerequisites.end ());
+ package_key pk (ddb, pd.name);
- const auto& pos (i->second.config_position);
+ // Ignore repointed dependents.
+ //
+ if (rpt_depts.find (pk) != rpt_depts.end ())
+ {
+ l5 ([&]{trace << "skip repointed existing dependent " << pk
+ << " of dependency " << name << db;});
+ continue;
+ }
- if (pos.first != 0) // Has config clause?
+ // Ignore dependent which is expected to be built or dropped.
+ //
+ auto vi (replaced_vers.find (pk));
+ if (vi != replaced_vers.end () && !vi->second.replaced)
{
- package_key pk (ddb, pd.name);
+ bool build (vi->second.available != nullptr);
- if (rpt_depts.find (pk) != rpt_depts.end ())
+ l5 ([&]{trace << "skip expected to be "
+ << (build ? "built" : "dropped")
+ << " existing dependent " << pk
+ << " of dependency " << name << db;});
+
+ continue;
+ }
+
+ // Ignore dependent which is already being built or dropped.
+ //
+ const build_package* p (entered_build (pk));
+
+ if (p != nullptr && p->action)
+ {
+ bool build;
+ if (((build = *p->action == build_package::build) &&
+ (p->system || p->recollect_recursively (rpt_depts))) ||
+ *p->action == build_package::drop)
{
- l5 ([&]{trace << "skip repointed existing dependent " << pk
+ l5 ([&]{trace << "skip being "
+ << (build ? "built" : "dropped")
+ << " existing dependent " << pk
<< " of dependency " << name << db;});
continue;
}
+ }
- // Ignore dependent which is already being built or dropped.
+ // Ignore dependent if this dependency up/downgrade won't satisfy the
+ // dependent's constraint. The thinking here is that we will either
+ // fail for this reason later or the problem will be resolved
+ // naturally due to the execution plan refinement (see
+ // unsatisfied_dependents for details).
+ //
+ if (pd.constraint)
+ {
+ // Search for the dependency build and detect if it is being
+ // up/downgraded, if not done yet. In particular, the available
+ // package could be NULL meaning we are just adjusting.
//
- const build_package* p (entered_build (pk));
-
- if (p != nullptr && p->action)
+ if (dep == nullptr)
{
- bool build;
- if (((build = *p->action == build_package::build) &&
- (p->system || p->recollect_recursively (rpt_depts))) ||
- *p->action == build_package::drop)
+ dep = entered_build (db, name);
+
+ assert (dep != nullptr); // Expected to be being built.
+
+ if (dep->available != nullptr)
{
- if (!build || !vdb || !vdb (pk, pos))
- {
- l5 ([&]{trace << "skip being "
- << (build ? "built" : "dropped")
- << " existing dependent " << pk
- << " of dependency " << name << db;});
- continue;
- }
+ const shared_ptr<selected_package>& sp (dep->selected);
+
+ // Expected to be selected since it has an existing dependent.
+ //
+ assert (sp != nullptr);
+
+ ud = sp->version.compare (dep->available_version ());
}
}
- // Ignore dependent which is expected to be built or dropped.
- //
- auto vi (replaced_vers.find (pk));
- if (vi != replaced_vers.end () && !vi->second.replaced)
+ if (ud != 0 &&
+ !satisfies (dep->available_version (), *pd.constraint))
{
- bool build (vi->second.available != nullptr);
-
- l5 ([&]{trace << "skip expected to be "
- << (build ? "built" : "dropped")
- << " existing dependent " << pk
- << " of dependency " << name << db;});
+ l5 ([&]{trace << "skip unsatisfied existing dependent " << pk
+ << " of dependency "
+ << dep->available_name_version_db () << " due to "
+ << "constraint (" << name << ' ' << *pd.constraint
+ << ')';});
continue;
}
+ }
+
+ // Pre-reevaluate the dependent to calculate the position which the
+ // dependent should be re-evaluated to.
+ //
+ shared_ptr<selected_package> dsp (
+ ddb.load<selected_package> (pd.name));
- r.push_back (existing_dependent {ddb, move (dsp), pos});
+ pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>> rp (
+ find_available_fragment (o, ddb, dsp));
+
+ optional<package_key> orig_dep (package_key {db, name});
+
+ try
+ {
+ build_package p {
+ build_package::build,
+ ddb,
+ dsp, // Don't move from since will be used later.
+ move (rp.first),
+ move (rp.second),
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ nullopt, // Hold package.
+ nullopt, // Hold version.
+ {}, // Constraints.
+ false, // System.
+ false, // Keep output directory.
+ false, // Disfigure (from-scratch reconf).
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ nullopt, // Upgrade.
+ false, // Deorphan.
+ {}, // Required by (dependency).
+ false, // Required by dependents.
+ 0}; // State flags.
+
+ build_package_refs dep_chain;
+ postponed_packages postponed_repo;
+ postponed_packages postponed_alts;
+ postponed_packages postponed_recs;
+ postponed_existing_dependencies postponed_edeps;
+ postponed_dependencies postponed_deps;
+ postponed_configurations postponed_cfgs;
+ unacceptable_alternatives unacceptable_alts;
+ unsatisfied_dependents unsatisfied_depts;
+ replaced_versions replaced_vers;
+
+ optional<pre_reevaluate_result> pr (
+ collect_build_prerequisites (o,
+ p,
+ dep_chain,
+ fdb,
+ nullptr /* add_priv_cfg_function */,
+ rpt_depts,
+ replaced_vers,
+ &postponed_repo,
+ &postponed_alts,
+ numeric_limits<size_t>::max (),
+ postponed_recs,
+ postponed_edeps,
+ postponed_deps,
+ postponed_cfgs,
+ unacceptable_alts,
+ unsatisfied_depts,
+ pair<size_t, size_t> (0, 0),
+ orig_dep));
+
+ // Must be read-only.
+ //
+ assert (postponed_repo.empty () &&
+ postponed_alts.empty () &&
+ postponed_recs.empty () &&
+ postponed_edeps.empty () &&
+ postponed_deps.empty () &&
+ postponed_cfgs.empty () &&
+ unacceptable_alts.empty () &&
+ unsatisfied_depts.empty () &&
+ replaced_vers.empty ());
+
+ if (pr && (!pr->reevaluation_optional || !exclude_optional))
+ {
+ // Try to preserve the name of the originating dependency as the
+ // one which brings the existing dependent to the config cluster.
+ // Failed that, use the first dependency in the alternative which
+ // we will be re-evaluating to.
+ //
+ package_key dep (*orig_dep);
+
+ pre_reevaluate_result::packages& deps (
+ pr->reevaluation_dependencies);
+
+ assert (!deps.empty ());
+
+ if (find (deps.begin (), deps.end (), dep) == deps.end ())
+ dep = move (deps.front ());
+
+ r.push_back (
+ existing_dependent {
+ ddb, move (dsp),
+ move (dep), pr->reevaluation_position,
+ move (*orig_dep), pr->originating_dependency_position});
+ }
+ }
+ catch (const reevaluation_deviated&)
+ {
+ r.push_back (
+ existing_dependent {ddb, move (dsp),
+ nullopt, {},
+ move (*orig_dep), {}});
}
}
}
@@ -6027,131 +7899,204 @@ namespace bpkg
}
const build_package* build_packages::
- replace_existing_dependent_dependency (
- tracer& trace,
+ collect_existing_dependent_dependency (
const pkg_build_options& o,
- existing_dependent& ed,
- pair<size_t, size_t> pos,
- const function<find_database_function>& fdb,
- const repointed_dependents& rpt_depts,
- const function<add_priv_cfg_function>& apc,
- bool initial_collection,
+ const existing_dependent& ed,
replaced_versions& replaced_vers,
- postponed_configurations& postponed_cfgs)
+ postponed_configurations& postponed_cfgs,
+ unsatisfied_dependents& unsatisfied_depts)
{
- // The repointed dependent cannot be returned by
- // query_existing_dependents(). Note that the repointed dependent
- // references both old and new prerequisites.
- //
- assert (rpt_depts.find (package_key (ed.db, ed.selected->name)) ==
- rpt_depts.end ());
+ assert (ed.dependency); // Shouldn't be called for deviated dependents.
+
+ const shared_ptr<selected_package>& dsp (ed.selected);
- shared_ptr<selected_package> dsp;
- database* pdb (nullptr);
- const version_constraint* vc (nullptr);
+ package_version_key dpt (ed.db, dsp->name, dsp->version);
+ const package_key& dep (*ed.dependency);
- // Find the dependency for this earlier dependency position. We know it
- // must be there since it's with configuration.
+ lazy_shared_ptr<selected_package> lsp (dep.db.get (), dep.name);
+ shared_ptr<selected_package> sp (lsp.load ());
+
+ pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>> rp (
+ find_available_fragment (o, dep.db, sp));
+
+ bool system (sp->system ());
+
+ build_package p {
+ build_package::build,
+ dep.db,
+ move (sp),
+ move (rp.first),
+ move (rp.second),
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ nullopt, // Hold package.
+ nullopt, // Hold version.
+ {}, // Constraints.
+ system, // System.
+ false, // Keep output directory.
+ false, // Disfigure (from-scratch reconf).
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ nullopt, // Upgrade.
+ false, // Deorphan.
+ {dpt}, // Required by (dependent).
+ true, // Required by dependents.
+ 0}; // State flags.
+
+ // Add constraints, if present.
//
- for (const auto& p: ed.selected->prerequisites)
{
- if (p.second.config_position == pos)
- {
- pdb = &p.first.database ();
+ auto i (dsp->prerequisites.find (lsp));
+ assert (i != dsp->prerequisites.end ());
+
+ if (i->second.constraint)
+ p.constraints.emplace_back (*i->second.constraint,
+ dpt.db,
+ dpt.name,
+ *dpt.version,
+ true /* selected_package */);
+ }
- dsp = p.first.load ();
+ // Note: not recursive.
+ //
+ collect_build (
+ o, move (p), replaced_vers, postponed_cfgs, unsatisfied_depts);
- l5 ([&]{trace << "replace dependency at index "
- << ed.dependency_position.first
- << " of existing dependent " << *ed.selected
- << ed.db << " with dependency " << *dsp
- << *pdb << " at index " << pos.first;});
+ return entered_build (dep);
+ }
- if (p.second.constraint)
- vc = &*p.second.constraint;
- }
- }
+ void build_packages::
+ collect_existing_dependent (const pkg_build_options& o,
+ const existing_dependent& ed,
+ postponed_configuration::packages&& ds,
+ replaced_versions& replaced_vers,
+ postponed_configurations& postponed_cfgs,
+ unsatisfied_dependents& unsatisfied_depts)
+ {
+ assert (ed.dependency); // May not be a deviated existing dependent.
- assert (dsp != nullptr);
+ pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>> rp (
+ find_available_fragment (o, ed.db, ed.selected));
- package_key pk (*pdb, dsp->name);
+ set<package_version_key> rb;
- // Adjust the existing dependent entry.
- //
- ed.dependency_position = pos;
+ for (package_key& p: ds)
+ rb.emplace (p.db, move (p.name), version ());
+
+ build_package p {
+ build_package::build,
+ ed.db,
+ ed.selected,
+ move (rp.first),
+ move (rp.second),
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ nullopt, // Hold package.
+ nullopt, // Hold version.
+ {}, // Constraints.
+ false, // System.
+ false, // Keep output directory.
+ false, // Disfigure (from-scratch reconf).
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ nullopt, // Upgrade.
+ false, // Deorphan.
+ move (rb), // Required by (dependency).
+ false, // Required by dependents.
+ build_package::build_reevaluate};
- // Collect the package build for this dependency.
+ // Note: not recursive.
//
+ collect_build (
+ o, move (p), replaced_vers, postponed_cfgs, unsatisfied_depts);
+ }
+
+ void build_packages::
+ recollect_existing_dependent (const pkg_build_options& o,
+ const existing_dependent& ed,
+ replaced_versions& replaced_vers,
+ postponed_packages& postponed_recs,
+ postponed_configurations& postponed_cfgs,
+ unsatisfied_dependents& unsatisfied_depts,
+ bool add_required_by)
+ {
pair<shared_ptr<available_package>,
lazy_shared_ptr<repository_fragment>> rp (
- find_available_fragment (o, pk.db, dsp));
+ find_available_fragment (o, ed.db, ed.selected));
+
+ uint16_t flags (build_package::build_recollect);
+
+ // Reconfigure the deviated dependents.
+ //
+ if (!ed.dependency)
+ flags |= build_package::adjust_reconfigure;
+
+ set<package_version_key> rb;
- bool system (dsp->system ());
+ if (add_required_by)
+ {
+ const package_key& pk (ed.originating_dependency);
- package_key dpk (ed.db, ed.selected->name);
+ assert (entered_build (pk) != nullptr); // Expected to be collected.
+
+ rb.emplace (pk.db, pk.name, version ());
+ }
build_package p {
build_package::build,
- pk.db,
- move (dsp),
- move (rp.first),
- move (rp.second),
- nullopt, // Dependencies.
- nullopt, // Dependencies alternatives.
- nullopt, // Package skeleton.
- nullopt, // Postponed dependency alternatives.
- false, // Recursive collection.
- nullopt, // Hold package.
- nullopt, // Hold version.
- {}, // Constraints.
- system, // System.
- false, // Keep output directory.
- false, // Disfigure (from-scratch reconf).
- false, // Configure-only.
- nullopt, // Checkout root.
- false, // Checkout purge.
- strings (), // Configuration variables.
- {dpk}, // Required by (dependent).
- true, // Required by dependents.
- build_package::adjust_reconfigure};
-
- if (vc != nullptr)
- p.constraints.emplace_back (dpk.db, dpk.name.string (), *vc);
+ ed.db,
+ ed.selected,
+ move (rp.first),
+ move (rp.second),
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ nullopt, // Hold package.
+ nullopt, // Hold version.
+ {}, // Constraints.
+ false, // System.
+ false, // Keep output directory.
+ false, // Disfigure (from-scratch reconf).
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ nullopt, // Upgrade.
+ false, // Deorphan.
+ move (rb), // Required by (dependency).
+ false, // Required by dependents.
+ flags};
// Note: not recursive.
//
- collect_build (o,
- move (p),
- fdb,
- rpt_depts,
- apc,
- initial_collection,
- replaced_vers,
- postponed_cfgs);
-
- return entered_build (pk);
+ collect_build (
+ o, move (p), replaced_vers, postponed_cfgs, unsatisfied_depts);
+
+ postponed_recs.insert (entered_build (ed.db, ed.selected->name));
}
build_packages::iterator build_packages::
order (database& db,
const package_name& name,
- optional<bool> buildtime,
package_refs& chain,
const function<find_database_function>& fdb,
bool reorder)
{
- package_map::iterator mi;
-
- if (buildtime)
- {
- database* ddb (fdb (db, name, *buildtime));
-
- mi = ddb != nullptr
- ? map_.find (*ddb, name)
- : map_.find_dependency (db, name, *buildtime);
- }
- else
- mi = map_.find (db, name);
+ package_map::iterator mi (map_.find (db, name));
// Every package that we order should have already been collected.
//
@@ -6161,18 +8106,16 @@ namespace bpkg
assert (p.action); // Can't order just a pre-entered package.
- database& pdb (p.db);
-
// Make sure there is no dependency cycle.
//
- package_ref cp {pdb, name};
+ package_ref cp {db, name};
{
auto i (find (chain.begin (), chain.end (), cp));
if (i != chain.end ())
{
diag_record dr (fail);
- dr << "dependency cycle detected involving package " << name << pdb;
+ dr << "dependency cycle detected involving package " << name << db;
auto nv = [this] (const package_ref& cp)
{
@@ -6241,20 +8184,21 @@ namespace bpkg
i = j;
};
- // Similar to collect_build(), we can prune if the package is already
- // configured, right? While in collect_build() we didn't need to add
- // prerequisites of such a package, it doesn't mean that they actually
- // never ended up in the map via another dependency path. For example,
- // some can be a part of the initial selection. And in that case we must
- // order things properly.
+ // Similar to collect_build_prerequisites(), we can prune if the package
+ // is already configured, right? While in collect_build_prerequisites() we
+ // didn't need to add prerequisites of such a package, it doesn't mean
+ // that they actually never ended up in the map via another dependency
+ // path. For example, some can be a part of the initial selection. And in
+ // that case we must order things properly.
//
// Also, if the package we are ordering is not a system one and needs to
// be disfigured during the plan execution, then we must order its
// (current) dependencies that also need to be disfigured.
//
// And yet, if the package we are ordering is a repointed dependent, then
- // we must order not only its unamended and new prerequisites but also its
- // replaced prerequisites, which can also be disfigured.
+ // we must order not only its unamended and new prerequisites
+ // (prerequisite replacements) but also its replaced prerequisites, which
+ // can also be disfigured.
//
bool src_conf (sp != nullptr &&
sp->state == package_state::configured &&
@@ -6274,34 +8218,38 @@ namespace bpkg
if (build && !p.system)
{
// So here we are going to do things differently depending on whether
- // the package is already configured or not. If it is and not as a
- // system package, then that means we can use its prerequisites
- // list. Otherwise, we use the manifest data.
+ // the package prerequisites builds are collected or not. If they are
+ // not, then the package is being reconfigured and we use its configured
+ // prerequisites list. Otherwise, we use its collected prerequisites
+ // builds.
//
- if (src_conf &&
- sp->version == p.available_version () &&
- (p.config_vars.empty () ||
- !has_buildfile_clause (ap->dependencies)))
+ if (!p.dependencies)
{
+ assert (src_conf); // Shouldn't be here otherwise.
+
+ // A repointed dependent have always its prerequisite replacements
+ // collected, so p.dependencies must always be present for them.
+ //
+ assert ((p.flags & build_package::build_repoint) == 0);
+
for (const auto& p: sp->prerequisites)
{
database& db (p.first.database ());
const package_name& name (p.first.object_id ());
- // The prerequisites may not necessarily be in the map.
- //
- // Note that for the repointed dependent we also order its new and
- // replaced prerequisites here, since they all are in the selected
- // package prerequisites set.
+ // The prerequisites may not necessarily be in the map or have an
+ // action be present, but they can never be dropped.
//
auto i (map_.find (db, name));
- if (i != map_.end () && i->second.package.action)
- update (order (db,
- name,
- nullopt /* buildtime */,
- chain,
- fdb,
- false /* reorder */));
+ if (i != map_.end ())
+ {
+ optional<build_package::action_type> a (i->second.package.action);
+
+ assert (!a || *a != build_package::drop); // See above.
+
+ if (a)
+ update (order (db, name, chain, fdb, false /* reorder */));
+ }
}
// We just ordered them among other prerequisites.
@@ -6310,11 +8258,10 @@ namespace bpkg
}
else
{
- // The package prerequisites builds must already be collected and
- // thus the resulting dependency list is complete.
+ // If the package prerequisites builds are collected, then the
+ // resulting dependency list must be complete.
//
- assert (p.dependencies &&
- p.dependencies->size () == ap->dependencies.size ());
+ assert (p.dependencies->size () == ap->dependencies.size ());
// We are iterating in reverse so that when we iterate over the
// dependency list (also in reverse), prerequisites will be built in
@@ -6333,18 +8280,44 @@ namespace bpkg
assert (das.size () == 1);
+ bool buildtime (das.buildtime);
+
for (const dependency& d: das.front ())
{
+ const package_name& n (d.name);
+
+ // Use the custom search function to find the dependency's build
+ // configuration. Failed that, search for it recursively.
+ //
+ database* ddb (fdb (db, n, buildtime));
+
+ auto i (ddb != nullptr
+ ? map_.find (*ddb, n)
+ : map_.find_dependency (db, n, buildtime));
+
// Note that for the repointed dependent we only order its new and
- // unamended prerequisites here. Its replaced prerequisites will
- // be ordered below.
+ // potentially unamended prerequisites here (see
+ // collect_build_prerequisites() for details). Thus its
+ // (unamended) prerequisites may not necessarily be in the map or
+ // have an action be present, but they can never be dropped. Its
+ // replaced prerequisites will be ordered below.
//
- update (order (pdb,
- d.name,
- das.buildtime,
- chain,
- fdb,
- false /* reorder */));
+ if (i != map_.end ())
+ {
+ optional<build_package::action_type> a (
+ i->second.package.action);
+
+ assert (!a || *a != build_package::drop); // See above.
+
+ if (a)
+ {
+ update (order (i->first.db,
+ n,
+ chain,
+ fdb,
+ false /* reorder */));
+ }
+ }
}
}
}
@@ -6369,12 +8342,7 @@ namespace bpkg
// since we do not reorder.
//
if (i != map_.end () && disfigure (i->second.package))
- update (order (db,
- name,
- nullopt /* buildtime */,
- chain,
- fdb,
- false /* reorder */));
+ update (order (db, name, chain, fdb, false /* reorder */));
}
}
diff --git a/bpkg/pkg-build-collect.hxx b/bpkg/pkg-build-collect.hxx
index 6451f19..f84c86f 100644
--- a/bpkg/pkg-build-collect.hxx
+++ b/bpkg/pkg-build-collect.hxx
@@ -10,7 +10,6 @@
#include <forward_list>
#include <bpkg/types.hxx>
-#include <bpkg/forward.hxx> // database, linked_databases
#include <bpkg/utility.hxx>
#include <bpkg/package.hxx>
@@ -19,8 +18,10 @@
#include <bpkg/common-options.hxx>
#include <bpkg/pkg-build-options.hxx>
-#include <bpkg/pkg-configure.hxx> // find_database_function()
+#include <bpkg/database.hxx>
+#include <bpkg/pkg-configure.hxx> // find_database_function()
#include <bpkg/package-skeleton.hxx>
+#include <bpkg/system-package-manager.hxx>
namespace bpkg
{
@@ -183,25 +184,64 @@ namespace bpkg
//
bool recursive_collection;
- // Hold flags. Note that we only "increase" the hold_package value that is
- // already in the selected package.
+ // Return true if the recursive collection started but has been postponed
+ // for any reason.
+ //
+ bool
+ recursive_collection_postponed () const;
+
+ // Hold flags.
+ //
+ // Note that we only "increase" the hold_package value that is already in
+ // the selected package, unless the adjust_unhold flag is set (see below).
//
optional<bool> hold_package;
+
+ // Note that it is perfectly valid for the hold_version flag to be false
+ // while the command line constraint is present in the constraints list
+ // (see below). This may happen if the package build is collected by the
+ // unsatisfied dependency constraints resolution logic (see
+ // try_replace_dependency() in pkg-build.cxx for details).
+ //
optional<bool> hold_version;
- // Constraint value plus, normally, the dependent package name that placed
- // this constraint but can also be some other name for the initial
- // selection (e.g., package version specified by the user on the command
- // line). This why we use the string type, rather than package_name.
+ // Constraint value plus, normally, the dependent package name/version
+ // that placed this constraint but can also be some other name (in which
+ // case the version is absent) for the initial selection. Currently, the
+ // only valid non-package name is 'command line', which is used when the
+ // package version is constrained by the user on the command line.
+ //
+ // Note that if the dependent is a package name, then this package is
+ // expected to be collected (present in the map).
//
struct constraint_type
{
- reference_wrapper<database> db; // Main database for non-packages.
- string dependent;
version_constraint value;
- constraint_type (database& d, string dp, version_constraint v)
- : db (d), dependent (move (dp)), value (move (v)) {}
+ package_version_key dependent;
+
+ // False for non-packages. Otherwise, indicates whether the constraint
+ // comes from the selected dependent or not.
+ //
+ bool selected_dependent;
+
+ // Create constraint for a package dependent.
+ //
+ constraint_type (version_constraint v,
+ database& db,
+ package_name nm,
+ version ver,
+ bool s)
+ : value (move (v)),
+ dependent (db, move (nm), move (ver)),
+ selected_dependent (s) {}
+
+ // Create constraint for a non-package dependent.
+ //
+ constraint_type (version_constraint v, database& db, string nm)
+ : value (move (v)),
+ dependent (db, move (nm)),
+ selected_dependent (false) {}
};
vector<constraint_type> constraints;
@@ -210,6 +250,26 @@ namespace bpkg
//
bool system;
+ // Return the system/distribution package status if this is a system
+ // package (re-)configuration and the package is being managed by the
+ // system package manager (as opposed to user/fallback). Otherwise, return
+ // NULL (so can be used as bool).
+ //
+ // Note on terminology: We call the bpkg package that is being configured
+ // as available from the system as "system package" and we call the
+ // underlying package managed by the system/distribution package manager
+ // as "system/distribution package". See system-package-manager.hxx for
+ // background.
+ //
+ const system_package_status*
+ system_status () const;
+
+ // As above but only return the status if the package needs to be
+ // installed.
+ //
+ const system_package_status*
+ system_install () const;
+
// If this flag is set and the external package is being replaced with an
// external one, then keep its output directory between upgrades and
// downgrades.
@@ -240,14 +300,43 @@ namespace bpkg
//
strings config_vars;
+ // If present, then the package is requested to be upgraded (true) or
+ // patched (false). Can only be present if the package is already
+ // selected. Can only be false if the selected package version is
+ // patchable. Used by the unsatisfied dependency constraints resolution
+ // logic (see try_replace_dependency() in pkg-build.cxx for details).
+ //
+ optional<bool> upgrade;
+
+ // If true, then this package is requested to be deorphaned. Can only be
+ // true if the package is already selected and is orphaned. Used by the
+ // unsatisfied dependency constraints resolution logic (see
+ // try_replace_dependency() in pkg-build.cxx for details).
+ //
+ bool deorphan;
+
// Set of packages (dependents or dependencies but not a mix) that caused
- // this package to be built or adjusted. Empty name signifies user
- // selection and can be present regardless of the required_by_dependents
- // flag value.
+ // this package to be built or adjusted. The 'command line' name signifies
+ // user selection and can be present regardless of the
+ // required_by_dependents flag value.
//
- std::set<package_key> required_by;
+ // Note that if this is a package name, then this package is expected to
+ // be collected (present in the map), potentially just pre-entered if
+ // required_by_dependents is false. If required_by_dependents is true,
+ // then the packages in the set are all expected to be collected as builds
+ // (action is build, available is not NULL, etc).
+ //
+ // Also note that if required_by_dependents is true, then all the
+ // dependent package versions in the required_by set are expected to be
+ // known (the version members are not empty). Otherwise (the required_by
+ // set contains dependencies), since it's not always easy to deduce the
+ // dependency versions at the time of collecting the dependent build (see
+ // collect_repointed_dependents() implementation for details), the
+ // dependency package versions are expected to all be unknown.
+ //
+ std::set<package_version_key> required_by;
- // If this flags is true, then required_by contains dependents.
+ // If this flag is true, then required_by contains dependents.
//
// We need this because required_by packages have different semantics for
// different actions: the dependent for regular builds and dependency for
@@ -276,7 +365,9 @@ namespace bpkg
// This is required if it is being built as a source package and needs to
// be up/down-graded and/or reconfigured and has some buildfile clauses,
// it is a repointed dependent, or it is already in the process of being
- // collected.
+ // collected. Also configured dependents can be scheduled for recollection
+ // explicitly (see postponed_packages and build_recollect flag for
+ // details).
//
bool
recollect_recursively (const repointed_dependents&) const;
@@ -324,6 +415,26 @@ namespace bpkg
//
static const uint16_t build_reevaluate = 0x0008;
+ // Set if this build action is for recursive re-collecting of an existing
+ // dependent due to deviation, detecting merge configuration cycle, etc.
+ //
+ static const uint16_t build_recollect = 0x0010;
+
+ // Set if this build action is for replacing of an existing package due to
+ // deorphaning or rebuilding as an archive or directory.
+ //
+ // Note that to replace a package we need to re-fetch it from an existing
+ // repository fragment, archive, or directory (even if its version doesn't
+ // change).
+ //
+ static const uint16_t build_replace = 0x0020;
+
+ bool
+ replace () const
+ {
+ return (flags & build_replace) != 0;
+ }
+
bool
configure_only () const;
@@ -368,6 +479,7 @@ namespace bpkg
//
package_skeleton&
init_skeleton (const common_options&,
+ bool load_old_dependent_config = true,
const shared_ptr<available_package>& override = nullptr);
};
@@ -379,11 +491,11 @@ namespace bpkg
// Packages with postponed prerequisites collection, for one of the
// following reasons:
//
- // - Postponed due to the inability to find a version satisfying the pre-
- // entered constraint from repositories available to this package. The
- // idea is that this constraint could still be satisfied from a repository
- // fragment of some other package (that we haven't processed yet) that
- // also depends on this prerequisite.
+ // - Postponed due to the inability to find a dependency version satisfying
+ // the pre-entered constraint from repositories available to this
+ // package. The idea is that this constraint could still be satisfied from
+ // a repository fragment of some other package (that we haven't processed
+ // yet) that also depends on this prerequisite.
//
// - Postponed due to the inability to choose between two dependency
// alternatives, both having dependency packages which are not yet
@@ -391,7 +503,33 @@ namespace bpkg
// ambiguity could still be resolved after some of those dependency
// packages get built via some other dependents.
//
- using postponed_packages = std::set<build_package*>;
+ // - Postponed recollection of configured dependents whose dependencies
+ // up/downgrade causes selection of different dependency alternatives.
+ // This, in particular, may end up in resolving different dependency
+ // packages and affect the dependent and dependency configurations.
+ //
+ // - Postponed recollection of configured dependents for resolving merge
+ // configuration cycles and as a fallback for missed re-evaluations due to
+ // the shadow-based configuration clusters merge (see
+ // collect_build_prerequisites() for details).
+ //
+ // For the sake of testing, make sure the order in the set is stable.
+ //
+ struct compare_build_package
+ {
+ bool
+ operator() (const build_package* x, const build_package* y) const
+ {
+ const package_name& nx (x->name ());
+ const package_name& ny (y->name ());
+
+ if (int d = nx.compare (ny))
+ return d < 0;
+
+ return x->db.get () < y->db.get ();
+ }
+ };
+ using postponed_packages = std::set<build_package*, compare_build_package>;
// Base for exception types that indicate an inability to collect a package
// build because it was collected prematurely (version needs to be replaced,
@@ -422,20 +560,20 @@ namespace bpkg
// (e.g., because postponement caused cross-talk between dependency
// alternatives). Thus we keep flags that indicate whether we have seen each
// type of dependent and then just process dependencies that have the first
- // (without config) but not the second (with config). We also need to track
- // at which phase of collection an entry has been added to process the bogus
- // entries accordingly.
+ // (without config) but not the second (with config).
+ //
+ // Note that if any of these flags is set to true, then the dependency is
+ // expected to be collected (present in the build_packages's map; see below
+ // for the class definition).
//
struct postponed_dependency
{
bool wout_config; // Has dependent without config.
bool with_config; // Has dependent with config.
- bool initial_collection;
- postponed_dependency (bool woc, bool wic, bool ic)
+ postponed_dependency (bool woc, bool wic)
: wout_config (woc),
- with_config (wic),
- initial_collection (ic) {}
+ with_config (wic) {}
bool
bogus () const {return wout_config && !with_config;}
@@ -466,14 +604,14 @@ namespace bpkg
};
void
- cancel_bogus (tracer& trace, bool initial_collection)
+ cancel_bogus (tracer& trace)
{
bool bogus (false);
for (auto i (begin ()); i != end (); )
{
const postponed_dependency& d (i->second);
- if (d.bogus () && (!initial_collection || d.initial_collection))
+ if (d.bogus ())
{
bogus = true;
@@ -493,101 +631,13 @@ namespace bpkg
}
};
- // Map of existing dependents which may not be re-evaluated to a position
- // with the dependency index greater than the specified one.
- //
- // This mechanism applies when we re-evaluate an existing dependent to a
- // certain position but later realize we've gone too far. In this case we
- // note the earlier position information and re-collect from scratch. On the
- // re-collection any re-evaluation of the dependent to a greater position
- // will be either skipped or performed but to this earlier position (see the
- // replace member for details).
- //
- // We consider the postponement bogus if some dependent re-evaluation was
- // skipped due to its presence but no re-evaluation to this (or earlier)
- // dependency index was performed. Thus, if after the collection of packages
- // some bogus entries are present in the map, then it means that we have
- // skipped the respective re-evaluations erroneously and so need to erase
- // these entries and re-collect.
+ // Map of the dependencies whose recursive collection is postponed until
+ // their existing dependents re-collection/re-evaluation to the lists of the
+ // respective existing dependents (see collect_build_prerequisites() for
+ // details).
//
- // Note that if no re-evaluation is skipped due to a postponement then it
- // is harmless and we don't consider it bogus.
- //
- struct postponed_position: pair<size_t, size_t>
- {
- // True if the "later" position should be replaced rather than merely
- // skipped. The replacement deals with the case where the "earlier"
- // position is encountered while processing the same cluster as what
- // contains the later position. In this case, if we merely skip, then we
- // will never naturally encounter the earlier position. So we have to
- // force the issue (even if things change enough for us to never see the
- // later position again).
- //
- bool replace;
-
- // Re-evaluation was skipped due to this postponement.
- //
- bool skipped = false;
-
- // The dependent was re-evaluated. Note that it can be only re-evaluated
- // to this or earlier dependency index.
- //
- bool reevaluated = false;
-
- postponed_position (pair<size_t, size_t> p, bool r)
- : pair<size_t, size_t> (p), replace (r) {}
- };
-
- class postponed_positions: public std::map<package_key, postponed_position>
- {
- public:
- // If true, override the first encountered non-replace position to replace
- // and clear this flag. See collect_build_postponed() for details.
- //
- bool replace = false;
-
- // Erase the bogus postponements and throw cancel_postponement, if any.
- //
- struct cancel_postponement: scratch_collection
- {
- cancel_postponement ()
- : scratch_collection ("bogus existing dependent re-evaluation "
- "postponement cancellation") {}
- };
-
- void
- cancel_bogus (tracer& trace)
- {
- bool bogus (false);
- for (auto i (begin ()); i != end (); )
- {
- const postponed_position& p (i->second);
-
- if (p.skipped && !p.reevaluated)
- {
- bogus = true;
-
- l5 ([&]{trace << "erase bogus existing dependent " << i->first
- << " re-evaluation postponement with dependency index "
- << i->second.first;});
-
- // It seems that the replacement may never be bogus.
- //
- assert (!p.replace);
-
- i = erase (i);
- }
- else
- ++i;
- }
-
- if (bogus)
- {
- l5 ([&]{trace << "bogus re-evaluation postponement erased, throwing";});
- throw cancel_postponement ();
- }
- }
- };
+ using postponed_existing_dependencies = std::map<package_key,
+ vector<package_key>>;
// Set of dependency alternatives which were found unacceptable by the
// configuration negotiation machinery and need to be ignored on re-
@@ -712,6 +762,140 @@ namespace bpkg
cancel_bogus (tracer&, bool scratch);
};
+
+ // Dependents with their unsatisfactory dependencies and the respective
+ // ignored constraints.
+ //
+ // Note that during the collecting of all the explicitly specified packages
+ // and their dependencies for the build, we may discover that a being
+ // up/downgraded dependency doesn't satisfy all the being reconfigured,
+ // up/downgraded, or newly built dependents. Rather than fail immediately in
+ // such a case, we postpone the failure, add the unsatisfied dependents and
+ // their respective constraints to the unsatisfied dependents list, and
+ // continue the collection/ordering in the hope that these problems will be
+ // resolved naturally as a result of the requested recollection from scratch
+ // or execution plan refinement (dependents will also be up/downgraded or
+ // dropped, dependencies will be up/downgraded to a different versions,
+ // etc).
+ //
+ // Also note that after collecting/ordering of all the explicitly specified
+ // packages and their dependencies for the build we also collect/order their
+ // existing dependents for reconfiguration, recursively. It may happen that
+ // some of the up/downgraded dependencies don't satisfy the version
+ // constraints which some of the existing dependents impose on them. Rather
+ // than fail immediately in such a case, we postpone the failure, add this
+ // dependent and the unsatisfactory dependency to the unsatisfied dependents
+ // list, and continue the collection/ordering in the hope that these
+ // problems will be resolved naturally as a result of the execution plan
+ // refinement.
+ //
+ // And yet, if these problems do not resolve naturally, then we still try to
+ // resolve them by finding dependency versions which satisfy all the imposed
+ // constraints.
+ //
+ // Specifically, we cache such unsatisfied dependents/constraints, pretend
+ // that the dependents don't impose them and proceed with the remaining
+ // collecting/ordering, simulating the plan execution, and evaluating the
+ // dependency versions. After that, if scratch_collection exception has not
+ // been thrown, we check if the execution plan is finalized or a further
+ // refinement is required. In the latter case we drop the cache and proceed
+ // with the next iteration of the execution plan refinement which may
+ // resolve these problems naturally. Otherwise, we pick the first collected
+ // unsatisfactory dependency and try to find the best available version,
+ // considering all the constraints imposed by the user (explicit version
+ // constraint, --patch and/or --deorphan options, etc) as well as by its new
+ // and existing dependents. If the search succeeds, we update an existing
+ // package spec or add the new one to the command line and recollect from
+ // the very beginning. Note that we always add a new spec with the
+ // hold_version flag set to false. If the search fails, then, similarily, we
+ // try to find the replacement for some of the dependency's dependents,
+ // recursively. Note that we track the package build replacements and never
+ // repeat a replacement for the same command line state (which we adjust for
+ // each replacement). If no replacement is deduced, then we roll back the
+ // latest command line adjustment and recollect from the very beginning. If
+ // there are no adjustments left to try, then we give up the resolution
+ // search and report the first encountered unsatisfied (and ignored)
+ // dependency constraint and fail.
+ //
+ // Note that while we are trying to pick a dependent replacement for the
+ // subsequent re-collection, we cannot easily detect if the replacement is
+ // satisfied with the currently collected dependencies since that would
+ // effectively require to collect the replacement (select dependency
+ // alternatives, potentially re-negotiate dependency configurations,
+ // etc). Thus, we only verify that the replacement version satisfies its
+ // currently collected dependents. To reduce the number of potential
+ // dependent replacements to consider, we apply the heuristics and only
+ // consider those dependents which have or may have some satisfaction
+ // problems (not satisfied with a collected dependency, apply a dependency
+ // constraint which is incompatible with other dependents, etc; see
+ // try_replace_dependent() for details).
+ //
+ struct unsatisfied_constraint
+ {
+ // Note: also contains the unsatisfied dependent information.
+ //
+ build_package::constraint_type constraint;
+
+ // Available package version which satisfies the above constraint.
+ //
+ version available_version;
+ bool available_system;
+ };
+
+ struct ignored_constraint
+ {
+ package_key dependency;
+ version_constraint constraint;
+
+ // Only specified when the failure is postponed during the collection of
+ // the explicitly specified packages and their dependencies.
+ //
+ vector<unsatisfied_constraint> unsatisfied_constraints;
+ vector<package_key> dependency_chain;
+
+ ignored_constraint (const package_key& d,
+ const version_constraint& c,
+ vector<unsatisfied_constraint>&& ucs = {},
+ vector<package_key>&& dc = {})
+ : dependency (d),
+ constraint (c),
+ unsatisfied_constraints (move (ucs)),
+ dependency_chain (move (dc)) {}
+ };
+
+ struct unsatisfied_dependent
+ {
+ package_key dependent;
+ vector<ignored_constraint> ignored_constraints;
+ };
+
+ struct build_packages;
+
+ class unsatisfied_dependents: public vector<unsatisfied_dependent>
+ {
+ public:
+ // Add a dependent together with the ignored dependency constraint and,
+ // potentially, with the unsatisfied constraints and the dependency chain.
+ //
+ void
+ add (const package_key& dependent,
+ const package_key& dependency,
+ const version_constraint&,
+ vector<unsatisfied_constraint>&& ucs = {},
+ vector<package_key>&& dc = {});
+
+ // Try to find the dependent entry and return NULL if not found.
+ //
+ unsatisfied_dependent*
+ find_dependent (const package_key&);
+
+ // Issue the diagnostics for the first unsatisfied (and ignored)
+ // dependency constraint and throw failed.
+ //
+ [[noreturn]] void
+ diag (const build_packages&);
+ };
+
// List of dependency groups whose recursive processing should be postponed
// due to dependents with configuration clauses, together with these
// dependents (we will call them package clusters).
@@ -772,7 +956,7 @@ namespace bpkg
{
public:
// The id of the cluster plus the ids of all the clusters that have been
- // merged into it.
+ // merged into it directly or as their components.
//
size_t id;
small_vector<size_t, 1> merged_ids;
@@ -842,6 +1026,10 @@ namespace bpkg
// The depth of the negotiating recursion (see collect_build_postponed()
// for details).
//
+ // Note that non-zero depth for an absent negotiated member indicates that
+ // the cluster is in the existing dependents re-evaluation or
+ // configuration refinment phases.
+ //
size_t depth = 0;
// Add dependencies of a new dependent.
@@ -910,12 +1098,6 @@ namespace bpkg
bool
contains_dependency (const postponed_configuration&) const;
- // If the configuration contains the specified existing dependent, then
- // return the earliest dependency position. Otherwise return NULL.
- //
- const pair<size_t, size_t>*
- existing_dependent_position (const package_key&) const;
-
// Notes:
//
// - Adds dependencies of the being merged from configuration to the end
@@ -931,6 +1113,9 @@ namespace bpkg
set_shadow_cluster (postponed_configuration&&);
bool
+ is_shadow_cluster (const postponed_configuration&);
+
+ bool
contains_in_shadow_cluster (package_key dependent,
pair<size_t, size_t> pos) const;
@@ -1056,7 +1241,7 @@ namespace bpkg
build_packages& operator= (const build_packages&) = delete;
build_packages&
- operator= (build_packages&&);
+ operator= (build_packages&&) noexcept (false);
// Pre-enter a build_package without an action. No entry for this package
// may already exists.
@@ -1080,18 +1265,45 @@ namespace bpkg
return entered_build (p.db, p.name);
}
+ const build_package*
+ entered_build (database& db, const package_name& name) const
+ {
+ auto i (map_.find (db, name));
+ return i != map_.end () ? &i->second.package : nullptr;
+ }
+
+ const build_package*
+ entered_build (const package_key& p) const
+ {
+ return entered_build (p.db, p.name);
+ }
+
+ // Return NULL if the dependent in the constraint is not a package name
+ // (command line, etc; see build_package::constraint_type for details).
+ // Otherwise, return the dependent package build which is expected to be
+ // collected.
+ //
+ const build_package*
+ dependent_build (const build_package::constraint_type&) const;
+
// Collect the package being built. Return its pointer if this package
// version was, in fact, added to the map and NULL if it was already there
// and the existing version was preferred or if the package build has been
// replaced with the drop. So can be used as bool.
//
// Consult replaced_vers for an existing version replacement entry and
- // follow it, if present, potentially collecting the package drop
- // instead. Add entry to replaced_vers and throw replace_version if the
+ // follow it, if present, potentially collecting the package drop instead.
+ // Ignore the entry if its version doesn't satisfy the specified
+ // dependency constraints or the entry is a package drop and the specified
+ // required-by package names have the "required by dependents" semantics.
+ // In this case it's likely that this replacement will be applied for some
+ // later collect_build() call but can potentially turn out bogus. Note
+ // that a version replacement for a specific package may only be applied
+ // once during the collection iteration.
+ //
+ // Add entry to replaced_vers and throw replace_version if the
// existing version needs to be replaced but the new version cannot be
// re-collected recursively in-place (see replaced_versions for details).
- // Also add an entry and throw if the existing dependent needs to be
- // replaced.
//
// Optionally, pass the function which verifies the chosen package
// version. It is called before replace_version is potentially thrown or
@@ -1099,7 +1311,7 @@ namespace bpkg
// the package version needs to be replaced but in-place replacement is
// not possible (see replaced_versions for details).
//
- // Also, in the recursive mode (dep_chain is not NULL):
+ // Also, in the recursive mode (find database function is not NULL):
//
// - Use the custom search function to find the package dependency
// databases.
@@ -1110,8 +1322,10 @@ namespace bpkg
// - Call add_priv_cfg_function callback for the created private
// configurations.
//
- // Note that postponed_* and dep_chain arguments must all be either
- // specified or not.
+ // Note that postponed_* arguments must all be either specified or not.
+ // The dep_chain argument can be specified in the non-recursive mode (for
+ // the sake of the diagnostics) and must be specified in the recursive
+ // mode.
//
struct replace_version: scratch_collection
{
@@ -1126,21 +1340,23 @@ namespace bpkg
build_package*
collect_build (const pkg_build_options&,
build_package,
- const function<find_database_function>&,
- const repointed_dependents&,
- const function<add_priv_cfg_function>&,
- bool initial_collection,
replaced_versions&,
postponed_configurations&,
+ unsatisfied_dependents&,
build_package_refs* dep_chain = nullptr,
+ const function<find_database_function>& = nullptr,
+ const function<add_priv_cfg_function>& = nullptr,
+ const repointed_dependents* = nullptr,
postponed_packages* postponed_repo = nullptr,
postponed_packages* postponed_alts = nullptr,
+ postponed_packages* postponed_recs = nullptr,
+ postponed_existing_dependencies* = nullptr,
postponed_dependencies* = nullptr,
- postponed_positions* = nullptr,
unacceptable_alternatives* = nullptr,
const function<verify_package_build_function>& = nullptr);
- // Collect prerequisites of the package being built recursively.
+ // Collect prerequisites of the package being built recursively. Return
+ // nullopt, unless in the pre-reevaluation mode (see below).
//
// But first "prune" this process if the package we build is a system one
// or is already configured, since that would mean all its prerequisites
@@ -1164,18 +1380,27 @@ namespace bpkg
// recursively.
//
// - For an existing dependent being re-evaluated to the specific
- // dependency position.
+ // dependency position (reeval_pos argument is specified and is not
+ // {0,0}).
+ //
+ // - For an existing dependent being pre-reevaluated (reeval_pos argument
+ // is {0,0}).
+ //
+ // - For an existing dependent being re-collected due to the selected
+ // dependency alternatives deviation, etc which may be caused by its
+ // dependency up/downgrade (see postponed_packages and
+ // build_package::build_recollect flag for details).
//
// Note that for these cases, as it was said above, we can potentially
// fail if the dependent is an orphan, but this is exactly what we need to
// do in that case, since we won't be able to re-collect its dependencies.
//
// Only a single true dependency alternative can be selected per function
- // call. Such an alternative can only be selected if its index in the
- // postponed alternatives list is less than the specified maximum (used by
- // the heuristics that determines in which order to process packages with
- // alternatives; if 0 is passed, then no true alternative will be
- // selected).
+ // call, unless we are (pre-)re-evaluating. Such an alternative can only
+ // be selected if its index in the postponed alternatives list is less
+ // than the specified maximum (used by the heuristics that determines in
+ // which order to process packages with alternatives; if 0 is passed, then
+ // no true alternative will be selected).
//
// The idea here is to postpone the true alternatives selection till the
// end of the packages collection and then try to optimize the overall
@@ -1184,31 +1409,91 @@ namespace bpkg
// details).
//
// Always postpone recursive collection of dependencies for a dependent
- // with configuration clauses, recording them in postponed_deps (see
- // postponed_dependencies for details) and also recording the dependent in
- // postponed_cfgs (see postponed_configurations for details). If it turns
- // out that some dependency of such a dependent has already been collected
- // via some other dependent without configuration clauses, then throw the
- // postpone_dependency exception. This exception is handled via
- // re-collecting packages from scratch, but now with the knowledge about
- // premature dependency collection. If some dependency already belongs to
- // some non or being negotiated cluster then throw merge_configuration.
- // If some dependency configuration has already been negotiated between
- // some other dependents, then up-negotiate the configuration and throw
+ // with configuration clauses, recording them together with the dependent
+ // in postponed_cfgs (see postponed_configurations for details). If it
+ // turns out that some dependency of such a dependent has already been
+ // collected via some other dependent without configuration clauses, then
+ // record it in postponed_deps and throw the postpone_dependency
+ // exception. This exception is handled via re-collecting packages from
+ // scratch, but now with the knowledge about premature dependency
+ // collection. If some dependency already belongs to some non or being
+ // negotiated cluster then throw merge_configuration. If some dependencies
+ // have existing dependents with config clauses which have not been
+ // considered for the configuration negotiation yet, then throw
+ // recollect_existing_dependents exception to re-collect these dependents.
+ // If configuration has already been negotiated between some other
+ // dependents, then up-negotiate the configuration and throw
// retry_configuration exception so that the configuration refinement can
// be performed. See the collect lambda implementation for details on the
// configuration refinement machinery.
//
- // If the package is a dependency of a configured dependent with
- // configuration clause and needs to be reconfigured (being upgraded, has
- // configuration specified, etc), then postpone its recursive collection
- // by recording it in postponed_cfgs as a single-dependency cluster with
- // an existing dependent (see postponed_configurations for details). If
- // this dependent already belongs to some (being) negotiated configuration
- // cluster with a greater dependency position then record this dependency
- // position in postponed_poss and throw postpone_position. This exception
- // is handled by re-collecting packages from scratch, but now with the
- // knowledge about position this dependent needs to be re-evaluated to.
+ // If the reeval_pos argument is specified and is not {0,0}, then
+ // re-evaluate the package to the specified position. In this mode perform
+ // the regular dependency alternative selection and non-recursive
+ // dependency collection. When the specified position is reached, postpone
+ // the collection by recording the dependent together with the
+ // dependencies at that position in postponed_cfgs (see
+ // postponed_configurations for details). If the dependent/dependencies
+ // are added to an already negotiated cluster, then throw
+ // merge_configuration, similar to the regular collection mode (see
+ // above). Also check for the merge configuration cycles (see the function
+ // implementation for details) and throw the merge_configuration_cycle
+ // exception if such a cycle is detected.
+ //
+ // If {0,0} is specified as the reeval_pos argument, then perform the
+ // pre-reevaluation of an existing dependent, requested due to the
+ // specific dependency up/down-grade or reconfiguration (must be passed as
+ // the orig_dep; we call it originating dependency). The main purpose of
+ // this read-only mode is to obtain the position of the earliest selected
+ // dependency alternative with the config clause, if any, which the
+ // re-evaluation needs to be performed to and to determine if such a
+ // re-evaluation is optional (see pre_reevaluate_result for the full
+ // information being retrieved). The re-evaluation is considered to be
+ // optional if the existing dependent has no config clause for the
+ // originating dependency and the enable and reflect clauses do not refer
+ // to any of the dependency configuration variables (which can only be
+ // those which the dependent has the configuration clauses for; see the
+ // bpkg manual for details). The thinking here is that such an existing
+ // dependent may not change any configuration it applies to its
+ // dependencies and thus it doesn't call for any negotiations (note: if
+ // there are config clauses for the upgraded originating dependency, then
+ // the potentially different defaults for its config variables may affect
+ // the configuration this dependent applies to its dependencies). Such a
+ // dependent can also be reconfigured without pre-selection of its
+ // dependency alternatives since pkg-configure is capable of doing that on
+ // its own for such a simple case (see pkg_configure_prerequisites() for
+ // details). Also look for any deviation in the dependency alternatives
+ // selection and throw reevaluation_deviated exception if such a deviation
+ // is detected. Return nullopt if no dependency alternative with the
+ // config clause is selected.
+ //
+ // If the package is a dependency of configured dependents and needs to be
+ // reconfigured (being upgraded, has configuration specified, etc), then
+ // do the following for each such dependent prior to collecting its own
+ // prerequisites:
+ //
+ // - If the dependent is not already being built/dropped, expected to be
+ // built/dropped, and doesn't apply constraints which the dependency
+ // doesn't satisfy anymore, then pre-reevaluate the dependent.
+ //
+ // - If the dependency alternative with configuration clause has been
+ // encountered during the pre-reevaluation, then record it in
+ // postponed_cfgs as a single-dependency cluster with an existing
+ // dependent (see postponed_configurations for details). If the index of
+ // the encountered depends clause is equal/less than the index of the
+ // depends clause the dependency belongs to, then postpone the recursive
+ // collection of this dependency assuming that it will be collected
+ // later, during/after its existing dependent re-evaluation.
+ //
+ // - If the dependency alternatives selection has deviated, then record
+ // the dependent in postponed_recs (so that it can be re-collected
+ // later) and postpone recursive collection of this dependency assuming
+ // that it will be collected later, during its existing dependent
+ // re-collection. Also record this dependency in the postponed existing
+ // dependencies map (postponed_existing_dependencies argument). This way
+ // the caller can track if the postponed dependencies have never been
+ // collected recursively (deviations are too large, etc) and handle this
+ // situation (currently just fail).
//
// If a dependency alternative configuration cannot be negotiated between
// all the dependents, then unaccept_alternative can be thrown (see
@@ -1227,12 +1512,6 @@ namespace bpkg
}
};
- struct postpone_position: scratch_collection
- {
- postpone_position ()
- : scratch_collection ("earlier dependency position") {}
- };
-
struct retry_configuration
{
size_t depth;
@@ -1244,41 +1523,60 @@ namespace bpkg
size_t depth;
};
- void
+ struct merge_configuration_cycle
+ {
+ size_t depth;
+ };
+
+ struct reevaluation_deviated {};
+
+ struct pre_reevaluate_result
+ {
+ using packages = postponed_configuration::packages;
+
+ pair<size_t, size_t> reevaluation_position;
+ packages reevaluation_dependencies;
+ bool reevaluation_optional = true;
+ pair<size_t, size_t> originating_dependency_position;
+ };
+
+ optional<pre_reevaluate_result>
collect_build_prerequisites (const pkg_build_options&,
build_package&,
+ build_package_refs& dep_chain,
const function<find_database_function>&,
- const repointed_dependents&,
const function<add_priv_cfg_function>&,
- bool initial_collection,
+ const repointed_dependents&,
replaced_versions&,
- build_package_refs& dep_chain,
postponed_packages* postponed_repo,
postponed_packages* postponed_alts,
size_t max_alt_index,
+ postponed_packages& postponed_recs,
+ postponed_existing_dependencies&,
postponed_dependencies&,
postponed_configurations&,
- postponed_positions&,
unacceptable_alternatives&,
- pair<size_t, size_t> reeval_pos =
- make_pair(0, 0));
+ unsatisfied_dependents&,
+ optional<pair<size_t, size_t>> reeval_pos = nullopt,
+ const optional<package_key>& orig_dep = nullopt);
void
collect_build_prerequisites (const pkg_build_options&,
database&,
const package_name&,
const function<find_database_function>&,
- const repointed_dependents&,
const function<add_priv_cfg_function>&,
- bool initial_collection,
+ const repointed_dependents&,
replaced_versions&,
postponed_packages& postponed_repo,
postponed_packages& postponed_alts,
size_t max_alt_index,
+ postponed_packages& postponed_recs,
+ postponed_existing_dependencies&,
postponed_dependencies&,
postponed_configurations&,
- postponed_positions&,
- unacceptable_alternatives&);
+ unacceptable_alternatives&,
+ unsatisfied_dependents&);
// Collect the repointed dependents and their replaced prerequisites,
// recursively.
@@ -1294,14 +1592,18 @@ namespace bpkg
replaced_versions&,
postponed_packages& postponed_repo,
postponed_packages& postponed_alts,
+ postponed_packages& postponed_recs,
+ postponed_existing_dependencies&,
postponed_dependencies&,
postponed_configurations&,
- postponed_positions&,
unacceptable_alternatives&,
+ unsatisfied_dependents&,
const function<find_database_function>&,
const function<add_priv_cfg_function>&);
- // Collect the package being dropped.
+ // Collect the package being dropped. Noop if the specified package is
+ // already being built and its required-by package names have the
+ // "required by dependents" semantics.
//
// Add entry to replaced_vers and throw replace_version if the existing
// version needs to be dropped but this can't be done in-place (see
@@ -1323,61 +1625,80 @@ namespace bpkg
replaced_versions&,
postponed_packages& postponed_repo,
postponed_packages& postponed_alts,
+ postponed_packages& postponed_recs,
+ postponed_existing_dependencies&,
postponed_dependencies&,
postponed_configurations&,
strings& postponed_cfgs_history,
- postponed_positions&,
unacceptable_alternatives&,
+ unsatisfied_dependents&,
const function<find_database_function>&,
const repointed_dependents&,
const function<add_priv_cfg_function>&,
postponed_configuration* = nullptr);
- // Order the previously-collected package with the specified name
- // returning its positions.
+ // If a configured package is being up/down-graded or reconfigured then
+ // that means all its configured dependents could be affected and we have
+ // to reconfigure them. This function examines every such a package that
+ // is already in the map and collects all its configured dependents. We
+ // also need to make sure the dependents are ok with the up/downgrade. If
+ // some dependency constraints are not satisfied, then cache them and
+ // proceed further as if no problematic constraints are imposed (see
+ // unsatisfied_dependents for details). Return the set of the collected
+ // dependents.
//
- // If buildtime is nullopt, then search for the specified package build in
- // only the specified configuration. Otherwise, treat the package as a
- // dependency and use the custom search function to find its build
- // configuration. Failed that, search for it recursively (see
- // package_map::find_dependency() for details).
+ // Should we reconfigure just the direct depends or also include indirect,
+ // recursively? Consider this plausible scenario as an example: We are
+ // upgrading a package to a version that provides an additional API. When
+ // its direct dependent gets reconfigured, it notices this new API and
+ // exposes its own extra functionality that is based on it. Now it would
+ // make sense to let its own dependents (which would be our original
+ // package's indirect ones) to also notice this.
+ //
+ std::set<package_key>
+ collect_dependents (const repointed_dependents&, unsatisfied_dependents&);
+
+ // Order the previously-collected package with the specified name and
+ // configuration returning its position.
//
- // Recursively order the package dependencies being ordered failing if a
+ // Recursively order the collected package dependencies, failing if a
// dependency cycle is detected. If reorder is true, then reorder this
// package to be considered as "early" as possible.
//
iterator
order (database&,
const package_name&,
- optional<bool> buildtime,
const function<find_database_function>&,
bool reorder = true);
- // If a configured package is being up/down-graded then that means all its
- // dependents could be affected and we have to reconfigure them. This
- // function examines every package that is already on the list and collects
- // and orders all its dependents. We also need to make sure the dependents
- // are ok with the up/downgrade.
- //
- // Should we reconfigure just the direct depends or also include indirect,
- // recursively? Consider this plauisible scenario as an example: We are
- // upgrading a package to a version that provides an additional API. When
- // its direct dependent gets reconfigured, it notices this new API and
- // exposes its own extra functionality that is based on it. Now it would
- // make sense to let its own dependents (which would be our original
- // package's indirect ones) to also notice this.
- //
void
- collect_order_dependents (const repointed_dependents&);
+ clear ();
void
- collect_order_dependents (iterator, const repointed_dependents&);
+ clear_order ();
+ // Print all the version constraints (one per line) applied to this
+ // package and its dependents, recursively. The specified package is
+ // expected to be collected (present in the map). Don't print the version
+ // constraints for the same package twice, printing "..." instead. Noop if
+ // there are no constraints for this package.
+ //
+ // Optionally, only print constraints from the selected or being built
+ // dependents (see build_package::constraint_type for details).
+ //
void
- clear ();
+ print_constraints (diag_record&,
+ const build_package&,
+ string& indent,
+ std::set<package_key>& printed,
+ optional<bool> selected_dependent = nullopt) const;
void
- clear_order ();
+ print_constraints (diag_record&,
+ const package_key&,
+ string& indent,
+ std::set<package_key>& printed,
+ optional<bool> selected_dependent = nullopt) const;
// Verify that builds ordering is consistent across all the data
// structures and the ordering expectations are fulfilled (real build
@@ -1388,50 +1709,120 @@ namespace bpkg
private:
// Return the list of existing dependents that has a configuration clause
- // for the specified dependency. Skip dependents which are being built and
- // require recursive recollection or dropped (present in the map) or
- // expected to be built or dropped (present in rpt_depts or replaced_vers).
+ // for any of the selected alternatives together with the dependencies for
+ // the earliest such an alternative and the originating dependency (for
+ // which the function is called for) position. Return absent dependency
+ // for those dependents which dependency alternatives selection has
+ // deviated (normally due to the dependency up/downgrade). Skip dependents
+ // which are being built and require recursive recollection or dropped
+ // (present in the map) or expected to be built or dropped (present in
+ // rpt_depts or replaced_vers). Also skip dependents which impose the
+ // version constraint on this dependency and the dependency doesn't
+ // satisfy this constraint. Optionally, skip the existing dependents for
+ // which re-evaluation is considered optional (exclude_optional argument;
+ // see pre-reevaluation mode of collect_build_prerequisites() for
+ // details).
//
- // Optionally, specify the function which can verify the dependent build
- // and decide whether to override the default behavior and still add the
- // dependent package to the resulting list, returning true in this case.
+ // Note that the originating dependency is expected to be collected
+ // (present in the map).
//
struct existing_dependent
{
- reference_wrapper<database> db;
- shared_ptr<selected_package> selected;
- pair<size_t, size_t> dependency_position;
+ // Dependent.
+ //
+ reference_wrapper<database> db;
+ shared_ptr<selected_package> selected;
+
+ // Earliest dependency with config clause.
+ //
+ optional<package_key> dependency;
+ pair<size_t, size_t> dependency_position;
+
+ // Originating dependency passed to the function call.
+ //
+ package_key originating_dependency;
+ pair<size_t, size_t> originating_dependency_position;
};
- using verify_dependent_build_function = bool (const package_key&,
- pair<size_t, size_t>);
+ // This exception is thrown by collect_build_prerequisites() and
+ // collect_build_postponed() to resolve different kinds of existing
+ // dependent re-evaluation related cycles by re-collecting the problematic
+ // dependents from scratch.
+ //
+ struct recollect_existing_dependents
+ {
+ size_t depth;
+ vector<existing_dependent> dependents;
+ };
vector<existing_dependent>
query_existing_dependents (
tracer&,
+ const pkg_build_options&,
database&,
const package_name&,
- const replaced_versions&,
+ bool exclude_optional,
+ const function<find_database_function>&,
const repointed_dependents&,
- const function<verify_dependent_build_function>& = nullptr);
+ const replaced_versions&);
- // Update the existing dependent object (previously obtained with the
- // query_existing_dependents() call) with the new dependency position and
- // collect the dependency referred by this position. Return the pointer to
- // the collected build package object.
+ // Non-recursively collect the dependency of an existing dependent
+ // previously returned by the query_existing_dependents() function call
+ // with the build_package::build_reevaluate flag.
//
const build_package*
- replace_existing_dependent_dependency (
- tracer&,
+ collect_existing_dependent_dependency (
const pkg_build_options&,
- existing_dependent&,
- pair<size_t, size_t>,
- const function<find_database_function>&,
- const repointed_dependents&,
- const function<add_priv_cfg_function>&,
- bool initial_collection,
+ const existing_dependent&,
replaced_versions&,
- postponed_configurations&);
+ postponed_configurations&,
+ unsatisfied_dependents&);
+
+ // Non-recursively collect an existing non-deviated dependent previously
+ // returned by the query_existing_dependents() function call for the
+ // subsequent re-evaluation.
+ //
+ void
+ collect_existing_dependent (
+ const pkg_build_options&,
+ const existing_dependent&,
+ postponed_configuration::packages&& dependencies,
+ replaced_versions&,
+ postponed_configurations&,
+ unsatisfied_dependents&);
+
+ // Non-recursively collect an existing dependent previously returned by
+ // the query_existing_dependents() function call with the
+ // build_package::build_recollect flag and add it to the postponed package
+ // recollections list. Also add the build_package::adjust_reconfigure flag
+ // for the deviated dependents (existing_dependent::dependency is absent).
+ //
+ // Note that after this function call the existing dependent may not be
+ // returned as a result by the query_existing_dependents() function
+ // anymore (due to the build_package::build_recollect flag presence).
+ //
+ void
+ recollect_existing_dependent (const pkg_build_options&,
+ const existing_dependent&,
+ replaced_versions&,
+ postponed_packages& postponed_recs,
+ postponed_configurations&,
+ unsatisfied_dependents&,
+ bool add_required_by);
+
+ // Skip the dependents collection for the specified dependency if that has
+ // already been done.
+ //
+ // Note that if this function has already been called for this dependency,
+ // then all its dependents are already in the map and their dependency
+ // constraints have been checked.
+ //
+ void
+ collect_dependents (build_package&,
+ const repointed_dependents&,
+ unsatisfied_dependents&,
+ std::set<const build_package*>& visited_deps,
+ std::set<package_key>& result);
struct package_ref
{
@@ -1446,7 +1837,6 @@ namespace bpkg
iterator
order (database&,
const package_name&,
- optional<bool> buildtime,
package_refs& chain,
const function<find_database_function>&,
bool reorder);
@@ -1471,6 +1861,12 @@ namespace bpkg
return find (package_key {db, pn});
}
+ const_iterator
+ find (database& db, const package_name& pn) const
+ {
+ return find (package_key {db, pn});
+ }
+
// Try to find a package build in the dependency configurations (see
// database::dependency_configs() for details). Return the end iterator
// if no build is found and issue diagnostics and fail if multiple
diff --git a/bpkg/pkg-build.cli b/bpkg/pkg-build.cli
index 493ffbe..a365082 100644
--- a/bpkg/pkg-build.cli
+++ b/bpkg/pkg-build.cli
@@ -95,12 +95,20 @@ namespace bpkg
A package name (<pkg>) can be prefixed with a package scheme
(<scheme>). Currently the only recognized scheme is \cb{sys} which
instructs \cb{pkg-build} to configure the package as available from the
- system rather than building it from source. If the system package version
- (<ver-spec>) is not specified or is '\cb{/*}', then it is considered to
- be unknown but satisfying any version constraint. If specified,
- <ver-spec> may not be a version constraint. If the version is not
- explicitly specified, then at least a stub package must be available from
- one of the repositories.
+ system rather than building it from source.
+
+ The system package version (<ver-spec>) may not be a version constraint
+ but may be the special '\cb{/*}' value, which indicates that the version
+ should be considered unknown but satisfying any version constraint. If
+ unspecified, then \cb{pkg-build} will attempt to query the system package
+ manager for the installed version unless the system package manager is
+ unsupported or this functionality is disabled with \cb{--sys-no-query},
+ in which case the '\cb{/*}' <ver-spec> is assumed. If the system package
+ manager is supported, then the automatic installation of an available
+ package can be requested with the \cb{--sys-install} option. Note that if
+ the version is not explicitly specified, then at least a stub package
+ must be available from one of the repositories unless the
+ \cb{--sys-no-stub} option is specified.
Finally, a package can be specified as either the path to the package
archive (<file>) or to the package directory (<dir>\cb{/}; note that it
@@ -111,10 +119,11 @@ namespace bpkg
Additional configuration variables (<cfg-var>), if any, should be
specified before packages (<pkg-spec>) and should be separated with
\cb{--}. Such variables are effective only when configuring and only for
- packages that were explicitly specified on the command line (they can
- also be specified to only apply to specific packages using the argument
- grouping mechanism discussed below). See \l{bpkg-pkg-configure(1)} for
- more information on configuration variables.
+ packages that were explicitly specified on the command line (unless
+ global overrides). They can also be specified to only apply to specific
+ packages using the argument grouping mechanism discussed below. See
+ \l{bpkg-pkg-configure(1)} for more information on configuration
+ variables.
By default a package that is specified explicitly on the command line is
built to \i{hold}: it will not be considered for automatic removal if it
@@ -194,18 +203,44 @@ namespace bpkg
all the constraints."
}
+ bool --deorphan
+ {
+ "Replace orphaned packages with the best matching available package
+ versions which satisfy all the constraints.
+
+ It may happen that a built package no longer has the corresponding
+ package available in the repository it came from (for example, as a
+ result of \l{bpkg-rep-fetch(1)} or \l{bpkg-rep-remove(1)}). Such a
+ package is called an \i{orphan}. Without the \cb{--deorphan} option,
+ upgrading, downgrading, or patching an orphan will leave it unchanged
+ if a more suitable version of the package is not available. If the
+ \cb{--deorphan} option is specified, then an orphan will be replaced
+ with a non-orphan. In this case, if \cb{--upgrade}, \cb{--patch}, or
+ the package version is specified, then the new version is selected
+ accordingly. Otherwise, the closest version to the orphaned version is
+ selected using the following preference order:
+ (1) same version, revision, and iteration,
+ (2) latest iteration of same version and revision,
+ (3) later revision of same version,
+ (4) later patch of same version,
+ (5) later minor of same version,
+ (6) latest available version, including earlier
+ (see \l{bpkg#package-version Package Version} for details)."
+ }
+
bool --immediate|-i
{
- "Also upgrade or patch immediate dependencies."
+ "Also upgrade, patch, or deorphan immediate dependencies."
}
bool --recursive|-r
{
- "Also upgrade or patch all dependencies, recursively."
+ "Also upgrade, patch, or deorphan all dependencies, recursively."
}
// Sometimes we may want to upgrade/patch the package itself but to
- // patch/upgrade its dependencies.
+ // patch/upgrade its dependencies. Also we may want to deorphan
+ // dependencies, potentially upgrading/patching the package itself.
//
bool --upgrade-immediate
{
@@ -217,6 +252,11 @@ namespace bpkg
"Patch immediate dependencies."
}
+ bool --deorphan-immediate
+ {
+ "Deorphan immediate dependencies."
+ }
+
bool --upgrade-recursive
{
"Upgrade all dependencies, recursively."
@@ -227,6 +267,11 @@ namespace bpkg
"Patch all dependencies, recursively."
}
+ bool --deorphan-recursive
+ {
+ "Deorphan all dependencies, recursively."
+ }
+
bool --dependency
{
"Build, upgrade, or downgrade a package as a dependency rather than to
@@ -293,7 +338,8 @@ namespace bpkg
bool --yes|-y
{
- "Assume the answer to all prompts is \cb{yes}."
+ "Assume the answer to all prompts is \cb{yes}. Note that this excludes
+ the system package manager prompts; see \cb{--sys-yes} for details."
}
string --for|-f
@@ -352,6 +398,32 @@ namespace bpkg
option in \l{bpkg-rep-fetch(1)} for details."
}
+ strings --mask-repository
+ {
+ "<rep>",
+ "For the duration of the command execution pretend the specified
+ repository was removed as if by performing the \cb{rep-remove}
+ command. The repository can be specified either as a repository name or
+ as a repository location (URL or a directory path). Note that the
+ repository's complement and prerequisite repositories are also
+ considered masked, recursively, unless they are complements and/or
+ prerequisites of other unmasked repositories. Repeat this option to
+ mask multiple repositories."
+ }
+
+ strings --mask-repository-uuid
+ {
+ "<v>",
+ "For the duration of the command execution pretend the specified
+ repository was removed from the specified configuration. Similar to
+ \cb{--mask-repository} but only masks the repository in a single
+ configuration. The option value is a key-value pair in the form:
+
+ \c{\i{config-uuid}\b{=}\i{rep}}
+
+ Repeat this option to mask multiple repositories."
+ }
+
bool --no-refinement
{
"Don't try to refine the configuration by offering to drop any unused
@@ -408,6 +480,74 @@ namespace bpkg
See \l{bpkg-cfg-create(1)} for details on linked configurations."
}
+ bool --sys-no-query
+ {
+ "Do not query the system package manager for the installed versions of
+ packages specified with the \cb{sys} scheme."
+ }
+
+ bool --sys-install
+ {
+ "Instruct the system package manager to install available versions of
+ packages specified with the \cb{sys} scheme that are not already
+ installed. See also the \cb{--sys-no-fetch}, \cb{--sys-yes}, and
+ \cb{--sys-sudo} options."
+ }
+
+ bool --sys-no-fetch
+ {
+ "Do not fetch the system package manager metadata before querying for
+ available versions of packages specified with the \cb{sys} scheme.
+ This option only makes sense together with \cb{--sys-install}."
+ }
+
+ bool --sys-no-stub
+ {
+ "Do no require a stub for packages specified with the \cb{sys} scheme.
+ Note that this option has effect only if the system package manager
+ interactions are supported and not disabled."
+ }
+
+ bool --sys-yes
+ {
+ "Assume the answer to the system package manager prompts is \cb{yes}.
+ Note that system package manager interactions may break your system
+ and you should normally only use this option on throw-away setups
+ (test virtual machines, etc)."
+ }
+
+ string --sys-sudo = "sudo"
+ {
+ "<prog>",
+
+ "The \cb{sudo} program to use for system package manager interactions
+ that normally require administrative privileges (fetch package
+ metadata, install packages, etc). If unspecified, \cb{sudo} is used
+ by default. Pass empty or the special \cb{false} value to disable the
+ use of the \cb{sudo} program. Note that the \cb{sudo} program is
+ normally only needed if the system package installation is enabled
+ with the \cb{--sys-install} option."
+ }
+
+ string --sys-distribution
+ {
+ "<name>",
+ "Alternative system/distribution package manager to interact with. The
+ valid <name> values are \cb{debian} (Debian and alike, such as Ubuntu,
+ etc) and \cb{fedora} (Fedora and alike, such as RHEL, CentOS, etc).
+ Note that some package managers may only be supported when running on
+ certain host operating systems."
+ }
+
+ string --sys-architecture
+ {
+ "<name>",
+ "Alternative architecture to use when interacting with the system
+ package manager. The valid <name> values are system/distribution
+ package manager-specific. If unspecified, the host architecture
+ is used."
+ }
+
dir_paths --directory|-d
{
"<dir>",
diff --git a/bpkg/pkg-build.cxx b/bpkg/pkg-build.cxx
index a5dd813..fac79c2 100644
--- a/bpkg/pkg-build.cxx
+++ b/bpkg/pkg-build.cxx
@@ -21,6 +21,7 @@
#include <bpkg/common-options.hxx>
#include <bpkg/cfg-link.hxx>
+#include <bpkg/rep-mask.hxx>
#include <bpkg/pkg-purge.hxx>
#include <bpkg/pkg-fetch.hxx>
#include <bpkg/rep-fetch.hxx>
@@ -32,7 +33,9 @@
#include <bpkg/pkg-disfigure.hxx>
#include <bpkg/package-query.hxx>
#include <bpkg/package-skeleton.hxx>
+
#include <bpkg/system-repository.hxx>
+#include <bpkg/system-package-manager.hxx>
#include <bpkg/pkg-build-collect.hxx>
@@ -41,10 +44,10 @@ using namespace butl;
namespace bpkg
{
- // @@ Overall TODO:
- //
- // - Configuration vars (both passed and preserved)
+ // System package manager. Resolved lazily if and when needed. Present NULL
+ // value means no system package manager is available for this host.
//
+ static optional<unique_ptr<system_package_manager>> sys_pkg_mgr;
// Current configurations as specified with --directory|-d (or the current
// working directory if none specified).
@@ -68,11 +71,31 @@ namespace bpkg
// ultimate dependent configurations and add them to the respective
// configuration-associated fragment lists.
//
+ // If this package's repository fragment is a root fragment (package is
+ // fetched/unpacked using the existing archive/directory), then also add
+ // this repository fragment to the resulting list assuming that this
+ // package's dependencies can be resolved from this repository fragment or
+ // its complements (user-added repositories) as well.
+ //
static void
add_dependent_repo_fragments (database& db,
- const available_package_id& id,
+ const shared_ptr<selected_package>& p,
config_repo_fragments& r)
{
+ available_package_id id (p->name, p->version);
+
+ // Add a repository fragment to the specified list, suppressing duplicates.
+ //
+ auto add = [] (shared_ptr<repository_fragment>&& rf,
+ vector<shared_ptr<repository_fragment>>& rfs)
+ {
+ if (find (rfs.begin (), rfs.end (), rf) == rfs.end ())
+ rfs.push_back (move (rf));
+ };
+
+ if (p->repository_fragment.empty ()) // Root repository fragment?
+ add (db.find<repository_fragment> (empty_string), r[db]);
+
for (database& ddb: dependent_repo_configs (db))
{
shared_ptr<available_package> dap (ddb.find<available_package> (id));
@@ -91,39 +114,45 @@ namespace bpkg
for (const auto& pl: dap->locations)
{
- shared_ptr<repository_fragment> rf (pl.repository_fragment.load ());
+ const lazy_shared_ptr<repository_fragment>& lrf (
+ pl.repository_fragment);
- if (find (rfs.begin (), rfs.end (), rf) == rfs.end ())
- rfs.push_back (move (rf));
+ if (!rep_masked_fragment (lrf))
+ add (lrf.load (), rfs);
}
+
+ // Erase the entry from the map if it contains no fragments, which may
+ // happen if all the available package repositories are masked.
+ //
+ if (rfs.empty ())
+ r.erase (i);
}
}
}
- // Return a patch version constraint for the selected package if it has a
- // standard version, otherwise, if requested, issue a warning and return
- // nullopt.
+ // Return a patch version constraint for the specified package version if it
+ // is a standard version (~ shortcut). Otherwise, if requested, issue a
+ // warning and return nullopt.
//
// Note that the function may also issue a warning and return nullopt if the
- // selected package minor version reached the limit (see
- // standard-version.cxx for details).
+ // package minor version reached the limit (see standard-version.cxx for
+ // details).
//
static optional<version_constraint>
- patch_constraint (const shared_ptr<selected_package>& sp, bool quiet = false)
+ patch_constraint (const package_name& nm,
+ const version& pv,
+ bool quiet = false)
{
- const package_name& nm (sp->name);
- const version& sv (sp->version);
-
// Note that we don't pass allow_stub flag so the system wildcard version
// will (naturally) not be patched.
//
- string vs (sv.string ());
+ string vs (pv.string ());
optional<standard_version> v (parse_standard_version (vs));
if (!v)
{
if (!quiet)
- warn << "unable to patch " << package_string (nm, sv) <<
+ warn << "unable to patch " << package_string (nm, pv) <<
info << "package is not using semantic/standard version";
return nullopt;
@@ -133,20 +162,121 @@ namespace bpkg
{
return version_constraint ('~' + vs);
}
- // Note that the only possible reason for invalid_argument exception to
- // be thrown is that minor version reached the 99999 limit (see
+ // Note that the only possible reason for invalid_argument exception to be
+ // thrown is that minor version reached the 99999 limit (see
// standard-version.cxx for details).
//
catch (const invalid_argument&)
{
if (!quiet)
- warn << "unable to patch " << package_string (nm, sv) <<
+ warn << "unable to patch " << package_string (nm, pv) <<
info << "minor version limit reached";
return nullopt;
}
}
+ static inline optional<version_constraint>
+ patch_constraint (const shared_ptr<selected_package>& sp, bool quiet = false)
+ {
+ return patch_constraint (sp->name, sp->version, quiet);
+ }
+
+ // As above but returns a minor version constraint (^ shortcut) instead of
+ // the patch version constraint (~ shortcut).
+ //
+ static optional<version_constraint>
+ minor_constraint (const package_name& nm,
+ const version& pv,
+ bool quiet = false)
+ {
+ // Note that we don't pass allow_stub flag so the system wildcard version
+ // will (naturally) not be patched.
+ //
+ string vs (pv.string ());
+ optional<standard_version> v (parse_standard_version (vs));
+
+ if (!v)
+ {
+ if (!quiet)
+ warn << "unable to upgrade " << package_string (nm, pv)
+ << " to latest minor version" <<
+ info << "package is not using semantic/standard version";
+
+ return nullopt;
+ }
+
+ try
+ {
+ return version_constraint ('^' + vs);
+ }
+ // Note that the only possible reason for invalid_argument exception to be
+ // thrown is that major version reached the 99999 limit (see
+ // standard-version.cxx for details).
+ //
+ catch (const invalid_argument&)
+ {
+ if (!quiet)
+ warn << "unable to upgrade " << package_string (nm, pv)
+ << " to latest minor version" <<
+ info << "major version limit reached";
+
+ return nullopt;
+ }
+ }
+
+ // Return true if the selected package is not configured as system and its
+ // repository fragment is not present in any ultimate dependent
+ // configuration (see dependent_repo_configs() for details) or this exact
+ // version is not available from this repository fragment nor from its
+ // complements. Also return true if the selected package repository fragment
+ // is a root fragment (package is fetched/unpacked using the existing
+ // archive/directory).
+ //
+ // Note that the orphan definition here is stronger than in the rest of the
+ // code, since we request the available package to also be present in the
+ // repository fragment and consider packages built as existing archives or
+ // directories as orphans. It feels that such a definition aligns better
+ // with the user expectations about deorphaning.
+ //
+ static bool
+ orphan_package (database& db, const shared_ptr<selected_package>& sp)
+ {
+ assert (sp != nullptr);
+
+ if (sp->system ())
+ return false;
+
+ const string& cn (sp->repository_fragment.canonical_name ());
+
+ if (cn.empty ()) // Root repository fragment?
+ return true;
+
+ for (database& ddb: dependent_repo_configs (db))
+ {
+ const shared_ptr<repository_fragment> rf (
+ ddb.find<repository_fragment> (cn));
+
+ if (rf != nullptr && !rep_masked_fragment (ddb, rf))
+ {
+ auto af (
+ find_available_one (sp->name,
+ version_constraint (sp->version),
+ lazy_shared_ptr<repository_fragment> (ddb,
+ move (rf)),
+ false /* prereq */,
+ true /* revision */));
+
+ const shared_ptr<available_package>& ap (af.first);
+
+ if (ap != nullptr && !ap->stub ())
+ return false;
+ }
+ }
+
+ return true;
+ }
+
// List of dependency packages (specified with ? on the command line).
//
// If configuration is not specified for a system dependency package (db is
@@ -160,17 +290,29 @@ namespace bpkg
//
struct dependency_package
{
- database* db; // Can only be NULL if system.
+ database* db; // Can only be NULL if system.
package_name name;
- optional<version_constraint> constraint; // nullopt if unspecified.
+ optional<version_constraint> constraint; // nullopt if unspecified.
+
+ // Can only be true if constraint is specified.
+ //
+ bool hold_version;
+
shared_ptr<selected_package> selected;
bool system;
- bool patch; // Only for an empty version.
+ bool existing; // Build as archive or directory.
+
+ // true -- upgrade, false -- patch.
+ //
+ optional<bool> upgrade; // Only for absent constraint.
+
+ bool deorphan;
bool keep_out;
bool disfigure;
optional<dir_path> checkout_root;
bool checkout_purge;
- strings config_vars; // Only if not system.
+ strings config_vars; // Only if not system.
+ const system_package_status* system_status; // See struct pkg_arg.
};
using dependency_packages = vector<dependency_package>;
@@ -179,8 +321,44 @@ namespace bpkg
// this dependency. If the result is a NULL available_package, then it is
// either no longer used and can be dropped, or no changes to the dependency
// are necessary. Otherwise, the result is available_package to
- // upgrade/downgrade to as well as the repository fragment it must come
- // from, and the system flag.
+ // upgrade/downgrade to or replace with the same version (deorphan, rebuild
+ // as an existing archive or directory, etc) as well as the repository
+ // fragment it must come from, the system flag, and the database it must be
+ // configured in.
+ //
+ // If the dependency is being rebuilt as an existing archive or directory we
+ // may end up with the available package version being the same as the
+ // selected package version. In this case the dependency needs to be
+ // re-fetched/re-unpacked from this archive/directory. Also note that if the
+ // dependency needs to be rebuilt as an existing archive or directory the
+ // caller may need to stash its name/database. This way on the subsequent
+ // call this function may return the "no change" recommendation rather than
+ // the "replace" recommendation.
+ //
+ // If in the deorphan mode it turns out that the package is not an orphan
+ // and there is no version constraint specified and upgrade/patch is not
+ // requested, then assume that no changes are necessary for the dependency.
+ // Otherwise, if the package version is not constrained and no upgrade/patch
+ // is requested, then pick the version that matches the dependency version
+ // best in the following preference order:
+ //
+ // - same version, revision, and iteration
+ // - latest iteration of same version and revision
+ // - later revision of same version
+ // - later patch of same version
+ // - later minor of same version
+ // - latest available version, including earlier
+ //
+ // Otherwise, always upgrade/downgrade the orphan or fail if no satisfactory
+ // version is available. Note that in the both cases (deorphan and
+ // upgrade/downgrade+deorphan) we may end up with the available package
+ // version being the same as the selected package version. In this case the
+ // dependency needs to be re-fetched from an existing repository. Also note
+ // that if the dependency needs to be deorphaned the caller may need to
+ // cache the original orphan version. This way on the subsequent calls this
+ // function still considers this package as an orphan and uses its original
+ // version to deduce the best match, which may change due, for example, to a
+ // change of the constraining dependents set.
//
// If the package version that satisfies explicitly specified dependency
// version constraint can not be found in the dependents repositories, then
@@ -191,13 +369,21 @@ namespace bpkg
//
struct evaluate_result
{
- // The system flag is meaningless if the unused flag is true.
+ // The system, existing, upgrade, and orphan members are meaningless if
+ // the unused flag is true.
//
reference_wrapper<database> db;
shared_ptr<available_package> available;
lazy_shared_ptr<bpkg::repository_fragment> repository_fragment;
bool unused;
bool system;
+ bool existing;
+ optional<bool> upgrade;
+
+ // Original orphan version which needs to be deorphaned. May only be
+ // present for the deorphan mode.
+ //
+ optional<version> orphan;
};
struct dependent_constraint
@@ -213,32 +399,44 @@ namespace bpkg
};
using dependent_constraints = vector<dependent_constraint>;
+ using deorphaned_dependencies = map<package_key, version>;
+ using existing_dependencies = vector<package_key>;
- static optional<evaluate_result>
- evaluate_dependency (database&,
+ static evaluate_result
+ evaluate_dependency (const common_options&,
+ database&,
const shared_ptr<selected_package>&,
const optional<version_constraint>& desired,
bool desired_sys,
+ bool existing,
database& desired_db,
const shared_ptr<selected_package>& desired_db_sp,
- bool patch,
+ optional<bool> upgrade,
+ bool deorphan,
bool explicitly,
const config_repo_fragments&,
const dependent_constraints&,
+ const existing_dependencies&,
+ const deorphaned_dependencies&,
+ const build_packages&,
bool ignore_unsatisfiable);
// If there are no user expectations regarding this dependency, then we give
- // no up/down-grade recommendation, unless there are no dependents in which
- // case we recommend to drop the dependency.
+ // no up/down-grade/replace recommendation, unless there are no dependents
+ // in which case we recommend to drop the dependency.
//
// Note that the user expectations are only applied for dependencies that
// have dependents in the current configurations.
//
static optional<evaluate_result>
- evaluate_dependency (database& db,
+ evaluate_dependency (const common_options& o,
+ database& db,
const shared_ptr<selected_package>& sp,
const dependency_packages& deps,
bool no_move,
+ const existing_dependencies& existing_deps,
+ const deorphaned_dependencies& deorphaned_deps,
+ const build_packages& pkgs,
bool ignore_unsatisfiable)
{
tracer trace ("evaluate_dependency");
@@ -253,7 +451,10 @@ namespace bpkg
nullptr /* available */,
nullptr /* repository_fragment */,
false /* unused */,
- false /* system */};
+ false /* system */,
+ false /* existing */,
+ nullopt /* upgrade */,
+ nullopt /* orphan */};
};
// Only search for the user expectations regarding this dependency if it
@@ -388,7 +589,10 @@ namespace bpkg
nullptr /* available */,
nullptr /* repository_fragment */,
true /* unused */,
- false /* system */};
+ false /* system */,
+ false /* existing */,
+ nullopt /* upgrade */,
+ nullopt /* orphan */};
}
// The requested dependency database, version constraint, and system flag.
@@ -398,6 +602,8 @@ namespace bpkg
database& ddb (i->db != nullptr ? *i->db : db);
const optional<version_constraint>& dvc (i->constraint); // May be nullopt.
bool dsys (i->system);
+ bool existing (i->existing);
+ bool deorphan (i->deorphan);
// The selected package in the desired database which we copy over.
//
@@ -409,14 +615,18 @@ namespace bpkg
: ddb.find<selected_package> (nm));
// If a package in the desired database is already selected and matches
- // the user expectations then no package change is required.
+ // the user expectations then no package change is required, unless the
+ // package is also being built as an existing archive or directory or
+ // needs to be deorphaned.
//
if (dsp != nullptr && dvc)
{
const version& sv (dsp->version);
bool ssys (dsp->system ());
- if (ssys == dsys &&
+ if (!existing &&
+ !deorphan &&
+ ssys == dsys &&
(ssys ? sv == *dvc->min_version : satisfies (sv, dvc)))
{
l5 ([&]{trace << *dsp << ddb << ": unchanged";});
@@ -437,25 +647,27 @@ namespace bpkg
package_dependent& dep (pd.second);
shared_ptr<selected_package> p (ddb.load<selected_package> (dep.name));
-
- add_dependent_repo_fragments (
- ddb,
- available_package_id (p->name, p->version),
- repo_frags);
+ add_dependent_repo_fragments (ddb, p, repo_frags);
dpt_constrs.emplace_back (ddb, move (p), move (dep.constraint));
}
- return evaluate_dependency (db,
+ return evaluate_dependency (o,
+ db,
sp,
dvc,
dsys,
+ existing,
ddb,
dsp,
- i->patch,
+ i->upgrade,
+ deorphan,
true /* explicitly */,
repo_frags,
dpt_constrs,
+ existing_deps,
+ deorphaned_deps,
+ pkgs,
ignore_unsatisfiable);
}
@@ -482,17 +694,23 @@ namespace bpkg
}
};
- static optional<evaluate_result>
- evaluate_dependency (database& db,
+ static evaluate_result
+ evaluate_dependency (const common_options& o,
+ database& db,
const shared_ptr<selected_package>& sp,
const optional<version_constraint>& dvc,
bool dsys,
+ bool existing,
database& ddb,
const shared_ptr<selected_package>& dsp,
- bool patch,
+ optional<bool> upgrade,
+ bool deorphan,
bool explicitly,
const config_repo_fragments& rfs,
const dependent_constraints& dpt_constrs,
+ const existing_dependencies& existing_deps,
+ const deorphaned_dependencies& deorphaned_deps,
+ const build_packages& pkgs,
bool ignore_unsatisfiable)
{
tracer trace ("evaluate_dependency");
@@ -505,7 +723,10 @@ namespace bpkg
nullptr /* available */,
nullptr /* repository_fragment */,
false /* unused */,
- false /* system */};
+ false /* system */,
+ false /* existing */,
+ nullopt /* upgrade */,
+ nullopt /* orphan */};
};
// Build the list of available packages for the potential up/down-grade
@@ -516,36 +737,115 @@ namespace bpkg
// the configuration negotiation machinery) and, if fail, fallback to
// picking the latest one just to make sure the package is recognized.
//
- optional<version_constraint> c;
+ // But first check if this package is specified as an existing archive or
+ // directory. If that's the case, then only consider its (transient)
+ // available package instead of the above.
+ //
+ bool patch (false);
+ available_packages afs;
- if (!dvc)
+ if (existing)
{
- assert (!dsys); // The version can't be empty for the system package.
+ // By definition such a dependency has a version specified and may not
+ // be system.
+ //
+ assert (dvc && !dsys);
- if (patch)
+ pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>> rp (
+ find_existing (ddb, nm, *dvc));
+
+ // Must have been added to the existing packages registry.
+ //
+ assert (rp.first != nullptr);
+
+ afs.push_back (move (rp));
+ }
+ else
+ {
+ optional<version_constraint> c;
+
+ if (!dvc)
{
- c = patch_constraint (sp, ignore_unsatisfiable);
+ assert (!dsys); // The version can't be empty for the system package.
+
+ patch = (upgrade && !*upgrade);
- if (!c)
+ if (patch)
{
- l5 ([&]{trace << *sp << db << ": non-patchable";});
- return no_change ();
+ c = patch_constraint (sp, ignore_unsatisfiable);
+
+ if (!c)
+ {
+ l5 ([&]{trace << *sp << db << ": non-patchable";});
+ return no_change ();
+ }
}
}
+ else if (!dsys || !wildcard (*dvc))
+ c = dvc;
+
+ afs = find_available (nm, c, rfs);
+
+ if (afs.empty () && dsys && c)
+ afs = find_available (nm, nullopt, rfs);
}
- else if (!dsys || !wildcard (*dvc))
- c = dvc;
- vector<pair<shared_ptr<available_package>,
- lazy_shared_ptr<repository_fragment>>> afs (
- find_available (nm, c, rfs));
+ // In the deorphan mode check that the dependency is an orphan or was
+ // deorphaned on some previous refinement iteration. If that's not the
+ // case, then just disable the deorphan mode for this dependency and, if
+ // the version is not constrained and upgrade/patch is not requested, bail
+ // out indicating that no change is required.
+ //
+ // Note that in the move mode (dsp != sp) we deorphan the dependency in
+ // its destination configuration, if present. In the worst case scenario
+ // both the source and destination selected packages may need to be
+ // deorphaned since the source selected package may also stay if some
+ // dependents were not repointed to the new dependency (remember that the
+ // move mode is actually a copy mode). We, however, have no easy way to
+ // issue recommendations for both the old and the new dependencies at the
+ // moment. Given that in the common case the old dependency get dropped,
+ // let's keep it simple and do nothing about the old dependency and see
+ // how it goes.
+ //
+ const version* deorphaned (nullptr);
+
+ if (deorphan)
+ {
+ bool orphan (dsp != nullptr && !dsp->system () && !dsys);
- if (afs.empty () && dsys && c)
- afs = find_available (nm, nullopt, rfs);
+ if (orphan)
+ {
+ auto i (deorphaned_deps.find (package_key (ddb, nm)));
+
+ if (i == deorphaned_deps.end ())
+ orphan = orphan_package (ddb, dsp);
+ else
+ deorphaned = &i->second;
+ }
+
+ if (!orphan)
+ {
+ if (!dvc && !upgrade)
+ {
+ l5 ([&]{trace << *sp << db << ": non-orphan";});
+ return no_change ();
+ }
+
+ deorphan = false;
+ }
+ }
// Go through up/down-grade candidates and pick the first one that
- // satisfies all the dependents. Collect (and sort) unsatisfied dependents
- // per the unsatisfiable version in case we need to print them.
+ // satisfies all the dependents. In the deorphan mode if the package
+ // version is not constrained and upgrade/patch is not requested, then
+ // pick the version that matches the dependency version best (see the
+ // function description for details). Collect (and sort) unsatisfied
+ // dependents per the unsatisfiable version in case we need to print them.
+ //
+ // NOTE: don't forget to update the find_orphan_match() lambda and the
+ // try_replace_dependency() function if changing anything deorphan-related
+ // here.
//
using sp_set = set<config_selected_package>;
@@ -557,14 +857,115 @@ namespace bpkg
(ddb.system_repository &&
ddb.system_repository->find (nm) != nullptr));
- for (auto& af: afs)
+ // Version to deorphan (original orphan version).
+ //
+ const version* dov (deorphaned != nullptr ? deorphaned :
+ deorphan ? &dsp->version :
+ nullptr);
+
+ optional<version_constraint> dopc; // Patch constraint for the above.
+ optional<version_constraint> domc; // Minor constraint for the above.
+
+ bool orphan_best_match (deorphan && !dvc && !upgrade);
+
+ if (orphan_best_match)
+ {
+ // Note that non-zero iteration makes a version non-standard, so we
+ // reset it to 0 to produce the patch/minor constraints.
+ //
+ version v (dov->epoch,
+ dov->upstream,
+ dov->release,
+ dov->revision,
+ 0 /* iteration */);
+
+ dopc = patch_constraint (nm, v, true /* quiet */);
+ domc = minor_constraint (nm, v, true /* quiet */);
+ }
+
+ using available = pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>>;
+
+ available deorphan_latest_iteration;
+ available deorphan_later_revision;
+ available deorphan_later_patch;
+ available deorphan_later_minor;
+ available deorphan_latest_available;
+
+ // If the dependency is deorphaned to the same version as on the previous
+ // call, then return the "no change" result. Otherwise, return the
+ // deorphan result.
+ //
+ auto deorphan_result = [&sp, &db,
+ &ddb, &dsp,
+ dsys,
+ deorphaned, dov,
+ existing,
+ upgrade,
+ &no_change,
+ &trace] (available&& a, const char* what)
+ {
+ if (deorphaned != nullptr && dsp->version == a.first->version)
+ {
+ l5 ([&]{trace << *sp << db << ": already deorphaned";});
+ return no_change ();
+ }
+
+ l5 ([&]{trace << *sp << db << ": deorphan to " << what << ' '
+ << package_string (sp->name, a.first->version)
+ << ddb;});
+
+ return evaluate_result {
+ ddb, move (a.first), move (a.second),
+ false /* unused */,
+ dsys,
+ existing,
+ upgrade,
+ *dov};
+ };
+
+ auto build_result = [&ddb, dsys, existing, upgrade] (available&& a)
+ {
+ return evaluate_result {
+ ddb, move (a.first), move (a.second),
+ false /* unused */,
+ dsys,
+ existing,
+ upgrade,
+ nullopt /* orphan */};
+ };
+
+ // Note that if the selected dependency is the best that we can get, we
+ // normally issue the "no change" recommendation. However, if the
+ // configuration variables are specified for this dependency on the
+ // command line, then we issue the "reconfigure" recommendation instead.
+ //
+ // Return true, if the already selected dependency has been specified on
+ // the command line with the configuration variables, but has not yet been
+ // built on this pkg-build run.
+ //
+ auto reconfigure = [&ddb, &dsp, &nm, dsys, &pkgs] ()
+ {
+ assert (dsp != nullptr);
+
+ if (!dsys)
+ {
+ const build_package* p (pkgs.entered_build (ddb, nm));
+ return p != nullptr && !p->action && !p->config_vars.empty ();
+ }
+ else
+ return false;
+ };
+
+ for (available& af: afs)
{
shared_ptr<available_package>& ap (af.first);
const version& av (!dsys ? ap->version : *ap->system_version (ddb));
// If we aim to upgrade to the latest version and it tends to be less
// then the selected one, then what we currently have is the best that
- // we can get, and so we return the "no change" result.
+ // we can get, and so we return the "no change" result, unless we are
+ // deorphaning.
//
// Note that we also handle a package stub here.
//
@@ -575,14 +976,21 @@ namespace bpkg
// For the selected system package we still need to pick a source
// package version to downgrade to.
//
- if (!dsp->system ())
+ if (!dsp->system () && !deorphan)
{
- l5 ([&]{trace << *dsp << ddb << ": best";});
- return no_change ();
+ if (reconfigure ())
+ {
+ l5 ([&]{trace << *dsp << ddb << ": reconfigure (best)";});
+ return build_result (find_available_fragment (o, ddb, dsp));
+ }
+ else
+ {
+ l5 ([&]{trace << *dsp << ddb << ": best";});
+ return no_change ();
+ }
}
- // We can not upgrade the (system) package to a stub version, so just
- // skip it.
+ // We can not upgrade the package to a stub version, so just skip it.
//
if (ap->stub ())
{
@@ -628,33 +1036,161 @@ namespace bpkg
continue;
}
- // If the best satisfactory version and the desired system flag perfectly
- // match the ones of the selected package, then no package change is
- // required. Otherwise, recommend an up/down-grade.
- //
- if (dsp != nullptr && av == dsp->version && dsp->system () == dsys)
+ if (orphan_best_match)
{
- l5 ([&]{trace << *dsp << ddb << ": unchanged";});
- return no_change ();
+ // If the exact orphan version is encountered, then we are done.
+ //
+ if (av == *dov)
+ return deorphan_result (move (af), "exactly same version");
+
+ // If the available package is of the same revision as orphan but a
+ // different iteration, then save it as the latest iteration of same
+ // orphan version and revision.
+ //
+ if (deorphan_latest_iteration.first == nullptr &&
+ av.compare (*dov, false /* revision */, true /* iteration */) == 0)
+ deorphan_latest_iteration = af;
+
+ // If the available package is of the same version as orphan and its
+ // revision is greater, then save it as the later revision of same
+ // version.
+ //
+ if (deorphan_later_revision.first == nullptr &&
+ av.compare (*dov, true /* revision */) == 0 &&
+ av.compare (*dov, false /* revision */, true /* iteration */) > 0)
+ deorphan_later_revision = af;
+
+ // If the available package is of the same minor version as orphan but
+ // of the greater patch version, then save it as the later patch of
+ // same version.
+ //
+ if (deorphan_later_patch.first == nullptr &&
+ dopc && satisfies (av, *dopc) &&
+ av.compare (*dov, true /* revision */) > 0) // Patch is greater?
+ deorphan_later_patch = af;
+
+ // If the available package is of the same major version as orphan but
+ // of the greater minor version, then save it as the later minor of
+ // same version.
+ //
+ // Note that we can't easily compare minor versions here since these
+ // are bpkg version objects. Thus, we consider that this is a greater
+ // minor version if the version is greater (ignoring revisions) and
+ // the latest patch is not yet saved.
+ //
+ if (deorphan_later_minor.first == nullptr &&
+ domc && satisfies (av, *domc) &&
+ av.compare (*dov, true /* revision */) > 0 &&
+ deorphan_later_patch.first == nullptr)
+ deorphan_later_minor = af;
+
+ // Save the latest available package version.
+ //
+ if (deorphan_latest_available.first == nullptr)
+ deorphan_latest_available = move (af);
+
+ // If the available package version is less then the orphan revision
+ // then we can bail out from the loop, since all the versions from the
+ // preference list have already been encountered, if present.
+ //
+ if (av.compare (*dov, false /* revision */, true /* iteration */) < 0)
+ {
+ assert (deorphan_latest_iteration.first != nullptr ||
+ deorphan_later_revision.first != nullptr ||
+ deorphan_later_patch.first != nullptr ||
+ deorphan_later_minor.first != nullptr ||
+ deorphan_latest_available.first != nullptr);
+ break;
+ }
}
+ else
+ {
+ // In the up/downgrade+deorphan mode always replace the dependency,
+ // re-fetching it from an existing repository if the version stays the
+ // same.
+ //
+ if (deorphan)
+ return deorphan_result (move (af), "constrained version");
- l5 ([&]{trace << *sp << db << ": update to "
- << package_string (nm, av, dsys) << ddb;});
+ // For the regular up/downgrade if the best satisfactory version and
+ // the desired system flag perfectly match the ones of the selected
+ // package, then no package change is required. Otherwise, recommend
+ // an upgrade/downgrade/replacement.
+ //
+ // Note: we need to be careful here not to start yo-yo'ing for a
+ // dependency being built as an existing archive or directory. For
+ // such a dependency we need to return the "no change" recommendation
+ // if any version recommendation (which may not change) has already
+ // been returned.
+ //
+ if (dsp != nullptr &&
+ av == dsp->version &&
+ dsp->system () == dsys &&
+ (!existing ||
+ find (existing_deps.begin (), existing_deps.end (),
+ package_key (ddb, nm)) != existing_deps.end ()))
+ {
+ if (reconfigure ())
+ {
+ l5 ([&]{trace << *dsp << ddb << ": reconfigure";});
+ return build_result (move (af));
+ }
+ else
+ {
+ l5 ([&]{trace << *dsp << ddb << ": unchanged";});
+ return no_change ();
+ }
+ }
+ else
+ {
+ l5 ([&]{trace << *sp << db << ": update to "
+ << package_string (nm, av, dsys) << ddb;});
- return evaluate_result {
- ddb, move (ap), move (af.second), false /* unused */, dsys};
+ return build_result (move (af));
+ }
+ }
+ }
+
+ if (orphan_best_match)
+ {
+ if (deorphan_latest_iteration.first != nullptr)
+ return deorphan_result (move (deorphan_latest_iteration),
+ "latest iteration");
+
+ if (deorphan_later_revision.first != nullptr)
+ return deorphan_result (move (deorphan_later_revision),
+ "later revision");
+
+ if (deorphan_later_patch.first != nullptr)
+ return deorphan_result (move (deorphan_later_patch), "later patch");
+
+ if (deorphan_later_minor.first != nullptr)
+ return deorphan_result (move (deorphan_later_minor), "later minor");
+
+ if (deorphan_latest_available.first != nullptr)
+ return deorphan_result (move (deorphan_latest_available),
+ "latest available");
}
// If we aim to upgrade to the latest version, then what we currently have
// is the only thing that we can get, and so returning the "no change"
- // result, unless we need to upgrade a package configured as system.
+ // result, unless we need to upgrade a package configured as system or to
+ // deorphan.
//
- if (!dvc && dsp != nullptr && !dsp->system ())
+ if (!dvc && dsp != nullptr && !dsp->system () && !deorphan)
{
assert (!dsys); // Version cannot be empty for the system package.
- l5 ([&]{trace << *dsp << ddb << ": only";});
- return no_change ();
+ if (reconfigure ())
+ {
+ l5 ([&]{trace << *dsp << ddb << ": reconfigure (only)";});
+ return build_result (find_available_fragment (o, ddb, dsp));
+ }
+ else
+ {
+ l5 ([&]{trace << *dsp << ddb << ": only";});
+ return no_change ();
+ }
}
// If the version satisfying the desired dependency version constraint is
@@ -679,11 +1215,12 @@ namespace bpkg
{
diag_record dr (fail);
- if (!dvc && patch)
+ if (patch)
{
- // Otherwise, we should have bailed out earlier (see above).
+ // Otherwise, we should have bailed out earlier returning "no change"
+ // (see above).
//
- assert (dsp != nullptr && dsp->system ());
+ assert (dsp != nullptr && (dsp->system () || deorphan));
// Patch (as any upgrade) of a system package is always explicit, so
// we always fail and never treat the package as being up to date.
@@ -698,10 +1235,10 @@ namespace bpkg
<< " is not available from its dependents' repositories";
else // The only available package is a stub.
{
- // Note that we don't advise to "build" the package as a system one as
- // it is already as such (see above).
+ // Otherwise, we should have bailed out earlier, returning "no change"
+ // rather then setting the stub flag to true (see above).
//
- assert (!dvc && !dsys && dsp != nullptr && dsp->system ());
+ assert (!dvc && !dsys && dsp != nullptr && (dsp->system () || deorphan));
fail << package_string (nm, dvc) << ddb << " is not available in "
<< "source from its dependents' repositories";
@@ -727,6 +1264,9 @@ namespace bpkg
size_t i (0), n (ps.size ());
for (auto p (ps.begin ()); i != n; ++p)
{
+ // It would probably be nice to also print the unsatisfied constraint
+ // here, but let's keep it simple for now.
+ //
dr << (i == 0 ? " " : ", ") << *p->package << p->db;
if (++i == 5 && n != 6) // Printing 'and 1 more' looks stupid.
@@ -747,41 +1287,99 @@ namespace bpkg
}
// List of dependent packages whose immediate/recursive dependencies must be
- // upgraded (specified with -i/-r on the command line).
+ // upgraded and/or deorphaned (specified with -i/-r on the command line).
//
struct recursive_package
{
- database& db;
- package_name name;
- bool upgrade; // true -- upgrade, false -- patch.
- bool recursive; // true -- recursive, false -- immediate.
+ database& db;
+ package_name name;
+
+ // Recursive/immediate upgrade/patch. Note the upgrade member is only
+ // meaningful if recursive is present.
+ //
+ optional<bool> recursive; // true -- recursive, false -- immediate.
+ bool upgrade; // true -- upgrade, false -- patch.
+
+ // Recursive/immediate deorphaning.
+ //
+ optional<bool> deorphan; // true -- recursive, false -- immediate.
};
using recursive_packages = vector<recursive_package>;
// Recursively check if immediate dependencies of this dependent must be
- // upgraded or patched. Return true if it must be upgraded, false if
- // patched, and nullopt otherwise.
+ // upgraded or patched and/or deorphaned.
//
- static optional<bool>
+ // Cache the results of this function calls to avoid multiple traversals of
+ // the same dependency graphs.
+ //
+ struct upgrade_dependencies_key
+ {
+ package_key dependent;
+ bool recursion;
+
+ bool
+ operator< (const upgrade_dependencies_key& v) const
+ {
+ if (recursion != v.recursion)
+ return recursion < v.recursion;
+
+ return dependent < v.dependent;
+ }
+ };
+
+ struct upgrade_deorphan
+ {
+ optional<bool> upgrade; // true -- upgrade, false -- patch.
+ bool deorphan;
+ };
+
+ using upgrade_dependencies_cache = map<upgrade_dependencies_key,
+ upgrade_deorphan>;
+
+ static upgrade_deorphan
upgrade_dependencies (database& db,
const package_name& nm,
const recursive_packages& rs,
+ upgrade_dependencies_cache& cache,
bool recursion = false)
{
+ // If the result of the upgrade_dependencies() call for these dependent
+ // and recursion flag value is cached, then return that. Otherwise, cache
+ // the calculated result prior to returning it to the caller.
+ //
+ upgrade_dependencies_key k {package_key (db, nm), recursion};
+ {
+ auto i (cache.find (k));
+
+ if (i != cache.end ())
+ return i->second;
+ }
+
auto i (find_if (rs.begin (), rs.end (),
[&nm, &db] (const recursive_package& i) -> bool
{
return i.name == nm && i.db == db;
}));
- optional<bool> r;
+ upgrade_deorphan r {nullopt /* upgrade */, false /* deorphan */};
- if (i != rs.end () && i->recursive >= recursion)
+ if (i != rs.end ())
{
- r = i->upgrade;
+ if (i->recursive && *i->recursive >= recursion)
+ r.upgrade = i->upgrade;
- if (*r) // Upgrade (vs patch)?
+ if (i->deorphan && *i->deorphan >= recursion)
+ r.deorphan = true;
+
+ // If we both upgrade and deorphan, then we can bail out since the value
+ // may not change any further (upgrade wins over patch and deorphaning
+ // can't be canceled).
+ //
+ if (r.upgrade && *r.upgrade && r.deorphan)
+ {
+ cache[move (k)] = r;
return r;
+ }
}
for (database& ddb: db.dependent_configs ())
@@ -792,27 +1390,40 @@ namespace bpkg
// configured packages due to a dependency cycle (see order() for
// details).
//
- if (optional<bool> u = upgrade_dependencies (ddb, pd.name, rs, true))
+ upgrade_deorphan ud (
+ upgrade_dependencies (ddb, pd.name, rs, cache, true /* recursion */));
+
+ if (ud.upgrade || ud.deorphan)
{
- if (!r || *r < *u) // Upgrade wins patch.
- {
- r = u;
+ // Upgrade wins over patch.
+ //
+ if (ud.upgrade && (!r.upgrade || *r.upgrade < *ud.upgrade))
+ r.upgrade = *ud.upgrade;
+
+ if (ud.deorphan)
+ r.deorphan = true;
- if (*r) // Upgrade (vs patch)?
- return r;
+ // If we both upgrade and deorphan, then we can bail out (see above
+ // for details).
+ //
+ if (r.upgrade && *r.upgrade && r.deorphan)
+ {
+ cache[move (k)] = r;
+ return r;
}
}
}
}
+ cache[move (k)] = r;
return r;
}
// Evaluate a package (not necessarily dependency) and return a new desired
// version. If the result is absent (nullopt), then no changes to the
// package are necessary. Otherwise, the result is available_package to
- // upgrade/downgrade to as well as the repository fragment it must come
- // from.
+ // upgrade/downgrade to or replace with, as well as the repository fragment
+ // it must come from.
//
// If the system package cannot be upgraded to the source one, not being
// found in the dependents repositories, then return nullopt if
@@ -820,10 +1431,15 @@ namespace bpkg
// evaluate_dependency() function description for details).
//
static optional<evaluate_result>
- evaluate_recursive (database& db,
+ evaluate_recursive (const common_options& o,
+ database& db,
const shared_ptr<selected_package>& sp,
const recursive_packages& recs,
- bool ignore_unsatisfiable)
+ const existing_dependencies& existing_deps,
+ const deorphaned_dependencies& deorphaned_deps,
+ const build_packages& pkgs,
+ bool ignore_unsatisfiable,
+ upgrade_dependencies_cache& cache)
{
tracer trace ("evaluate_recursive");
@@ -840,7 +1456,7 @@ namespace bpkg
// (immediate) dependents that have a hit (direct or indirect) in recs.
// Note, however, that we collect constraints from all the dependents.
//
- optional<bool> upgrade;
+ upgrade_deorphan ud {nullopt /* upgrade */, false /* deorphan */};
for (database& ddb: db.dependent_configs ())
{
@@ -850,10 +1466,17 @@ namespace bpkg
dpt_constrs.emplace_back (ddb, p, move (pd.constraint));
- if (optional<bool> u = upgrade_dependencies (ddb, pd.name, recs))
+ upgrade_deorphan u (upgrade_dependencies (ddb, pd.name, recs, cache));
+
+ if (u.upgrade || u.deorphan)
{
- if (!upgrade || *upgrade < *u) // Upgrade wins patch.
- upgrade = u;
+ // Upgrade wins over patch.
+ //
+ if (u.upgrade && (!ud.upgrade || *ud.upgrade < *u.upgrade))
+ ud.upgrade = *u.upgrade;
+
+ if (u.deorphan)
+ ud.deorphan = true;
}
else
continue;
@@ -862,32 +1485,37 @@ namespace bpkg
// continue to iterate over dependents, collecting the repository
// fragments and the constraints.
//
- add_dependent_repo_fragments (
- ddb,
- available_package_id (p->name, p->version),
- repo_frags);
+ add_dependent_repo_fragments (ddb, p, repo_frags);
}
}
- if (!upgrade)
+ if (!ud.upgrade && !ud.deorphan)
{
l5 ([&]{trace << *sp << db << ": no hit";});
return nullopt;
}
- // Recommends the highest possible version.
- //
+ pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>> rp (
+ find_existing (db, sp->name, nullopt /* version_constraint */));
+
optional<evaluate_result> r (
- evaluate_dependency (db,
+ evaluate_dependency (o,
+ db,
sp,
nullopt /* desired */,
false /* desired_sys */,
+ rp.first != nullptr /* existing */,
db,
sp,
- !*upgrade /* patch */,
+ ud.upgrade,
+ ud.deorphan,
false /* explicitly */,
repo_frags,
dpt_constrs,
+ existing_deps,
+ deorphaned_deps,
+ pkgs,
ignore_unsatisfiable));
// Translate the "no change" result into nullopt.
@@ -896,12 +1524,1404 @@ namespace bpkg
return r && r->available == nullptr ? nullopt : r;
}
- // Return false if the plan execution was noop.
+ // Stack of the command line adjustments as per unsatisfied_dependents
+ // description.
+ //
+ struct cmdline_adjustment
+ {
+ enum class adjustment_type: uint8_t
+ {
+ hold_existing, // Adjust constraint in existing build-to-hold spec.
+ dep_existing, // Adjust constraint in existing dependency spec.
+ hold_new, // Add new build-to-hold spec.
+ dep_new // Add new dependency spec.
+ };
+
+ adjustment_type type;
+ reference_wrapper<database> db;
+ package_name name;
+ bpkg::version version; // Replacement.
+
+ // Meaningful only for the *_new types.
+ //
+ optional<bool> upgrade;
+ bool deorphan = false;
+
+ // For the newly created or popped from the stack object the following
+ // three members contain the package version replacement information.
+ // Otherwise (pushed to the stack), they contain the original command line
+ // spec information.
+ //
+ shared_ptr<available_package> available; // NULL for dep_* types.
+ lazy_shared_ptr<bpkg::repository_fragment> repository_fragment; // As above.
+ optional<version_constraint> constraint;
+
+ // Create object of the hold_existing type.
+ //
+ cmdline_adjustment (database& d,
+ const package_name& n,
+ shared_ptr<available_package>&& a,
+ lazy_shared_ptr<bpkg::repository_fragment>&& f)
+ : type (adjustment_type::hold_existing),
+ db (d),
+ name (n),
+ version (a->version),
+ available (move (a)),
+ repository_fragment (move (f)),
+ constraint (version_constraint (version)) {}
+
+ // Create object of the dep_existing type.
+ //
+ cmdline_adjustment (database& d,
+ const package_name& n,
+ const bpkg::version& v)
+ : type (adjustment_type::dep_existing),
+ db (d),
+ name (n),
+ version (v),
+ constraint (version_constraint (version)) {}
+
+ // Create object of the hold_new type.
+ //
+ cmdline_adjustment (database& d,
+ const package_name& n,
+ shared_ptr<available_package>&& a,
+ lazy_shared_ptr<bpkg::repository_fragment>&& f,
+ optional<bool> u,
+ bool o)
+ : type (adjustment_type::hold_new),
+ db (d),
+ name (n),
+ version (a->version),
+ upgrade (u),
+ deorphan (o),
+ available (move (a)),
+ repository_fragment (move (f)),
+ constraint (version_constraint (version)) {}
+
+ // Create object of the dep_new type.
+ //
+ cmdline_adjustment (database& d,
+ const package_name& n,
+ const bpkg::version& v,
+ optional<bool> u,
+ bool o)
+ : type (adjustment_type::dep_new),
+ db (d),
+ name (n),
+ version (v),
+ upgrade (u),
+ deorphan (o),
+ constraint (version_constraint (version)) {}
+ };
+
+ class cmdline_adjustments
+ {
+ public:
+ cmdline_adjustments (vector<build_package>& hps, dependency_packages& dps)
+ : hold_pkgs_ (hps),
+ dep_pkgs_ (dps) {}
+
+ // Apply the specified adjustment to the command line, push the adjustment
+ // to the stack, and record the resulting command line state as the SHA256
+ // checksum.
+ //
+ void
+ push (cmdline_adjustment&& a)
+ {
+ using type = cmdline_adjustment::adjustment_type;
+
+ // We always set the `== <version>` constraint in the resulting spec.
+ //
+ assert (a.constraint);
+
+ database& db (a.db);
+ const package_name& nm (a.name);
+ package_version_key cmd_line (db.main_database (), "command line");
+
+ switch (a.type)
+ {
+ case type::hold_existing:
+ {
+ auto i (find_hold_pkg (a));
+ assert (i != hold_pkgs_.end ()); // As per adjustment type.
+
+ build_package& bp (*i);
+ swap (bp.available, a.available);
+ swap (bp.repository_fragment, a.repository_fragment);
+
+ if (!bp.constraints.empty ())
+ {
+ swap (bp.constraints[0].value, *a.constraint);
+ }
+ else
+ {
+ bp.constraints.emplace_back (move (*a.constraint),
+ cmd_line.db,
+ cmd_line.name.string ());
+ a.constraint = nullopt;
+ }
+
+ break;
+ }
+ case type::dep_existing:
+ {
+ auto i (find_dep_pkg (a));
+ assert (i != dep_pkgs_.end ()); // As per adjustment type.
+ swap (i->constraint, a.constraint);
+ break;
+ }
+ case type::hold_new:
+ {
+ // As per adjustment type.
+ //
+ assert (find_hold_pkg (a) == hold_pkgs_.end ());
+
+ // Start the database transaction to perform the
+ // database::find<selected_package> call, unless we are already in
+ // the transaction.
+ //
+ transaction t (db, !transaction::has_current ());
+
+ build_package bp {
+ build_package::build,
+ db,
+ db.find<selected_package> (nm),
+ move (a.available),
+ move (a.repository_fragment),
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ true, // Hold package.
+ false, // Hold version.
+ {}, // Constraints.
+ false, // System.
+ false, // Keep output directory.
+ false, // Disfigure (from-scratch reconf).
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ a.upgrade,
+ a.deorphan,
+ {cmd_line}, // Required by (command line).
+ false, // Required by dependents.
+ (a.deorphan
+ ? build_package::build_replace
+ : uint16_t (0))};
+
+ t.commit ();
+
+ bp.constraints.emplace_back (move (*a.constraint),
+ cmd_line.db,
+ cmd_line.name.string ());
+
+ a.constraint = nullopt;
+
+ hold_pkgs_.push_back (move (bp));
+ break;
+ }
+ case type::dep_new:
+ {
+ // As per adjustment type.
+ //
+ assert (find_dep_pkg (a) == dep_pkgs_.end ());
+
+ // Start the database transaction to perform the
+ // database::find<selected_package> call, unless we are already in
+ // the transaction.
+ //
+ transaction t (db, !transaction::has_current ());
+
+ dep_pkgs_.push_back (
+ dependency_package {&db,
+ nm,
+ move (*a.constraint),
+ false /* hold_version */,
+ db.find<selected_package> (nm),
+ false /* system */,
+ false /* existing */,
+ a.upgrade,
+ a.deorphan,
+ false /* keep_out */,
+ false /* disfigure */,
+ nullopt /* checkout_root */,
+ false /* checkout_purge */,
+ strings () /* config_vars */,
+ nullptr /* system_status */});
+
+ t.commit ();
+
+ a.constraint = nullopt;
+ break;
+ }
+ }
+
+ packages_.insert (package_version_key (db, nm, a.version));
+ adjustments_.push_back (move (a));
+ former_states_.insert (state ());
+ }
+
+ // Roll back the latest (default) or first command line adjustment, pop it
+ // from the stack, and return the popped adjustment. Assume that the stack
+ // is not empty.
+ //
+ // Note that the returned object can be pushed to the stack again.
+ //
+ cmdline_adjustment
+ pop (bool first = false)
+ {
+ using type = cmdline_adjustment::adjustment_type;
+
+ assert (!empty ());
+
+ // Pop the adjustment.
+ //
+ cmdline_adjustment a (move (!first
+ ? adjustments_.back ()
+ : adjustments_.front ()));
+ if (!first)
+ adjustments_.pop_back ();
+ else
+ adjustments_.erase (adjustments_.begin ());
+
+ packages_.erase (package_version_key (a.db, a.name, a.version));
+
+ // Roll back the adjustment.
+ //
+ switch (a.type)
+ {
+ case type::hold_existing:
+ {
+ auto i (find_hold_pkg (a));
+ assert (i != hold_pkgs_.end ());
+
+ build_package& bp (*i);
+ swap (bp.available, a.available);
+ swap (bp.repository_fragment, a.repository_fragment);
+
+ // Must contain the replacement version.
+ //
+ assert (!bp.constraints.empty ());
+
+ version_constraint& c (bp.constraints[0].value);
+
+ if (a.constraint) // Original spec contains a version constraint?
+ {
+ swap (c, *a.constraint);
+ }
+ else
+ {
+ a.constraint = move (c);
+ bp.constraints.clear ();
+ }
+
+ break;
+ }
+ case type::dep_existing:
+ {
+ auto i (find_dep_pkg (a));
+ assert (i != dep_pkgs_.end ());
+ swap (i->constraint, a.constraint);
+ break;
+ }
+ case type::hold_new:
+ {
+ auto i (find_hold_pkg (a));
+ assert (i != hold_pkgs_.end ());
+
+ build_package& bp (*i);
+ a.available = move (bp.available);
+ a.repository_fragment = move (bp.repository_fragment);
+
+ // Must contain the replacement version.
+ //
+ assert (!bp.constraints.empty ());
+
+ a.constraint = move (bp.constraints[0].value);
+
+ hold_pkgs_.erase (i);
+ break;
+ }
+ case type::dep_new:
+ {
+ auto i (find_dep_pkg (a));
+ assert (i != dep_pkgs_.end ());
+
+ a.constraint = move (i->constraint);
+
+ dep_pkgs_.erase (i);
+ break;
+ }
+ }
+
+ return a;
+ }
+
+ // Return the specified adjustment's string representation in the
+ // following form:
+ //
+ // hold_existing: '<pkg>[ <constraint>][ <database>]' -> '<pkg> <constraint>'
+ // dep_existing: '?<pkg>[ <constraint>][ <database>]' -> '?<pkg> <constraint>'
+ // hold_new: '<pkg> <constraint>[ <database>]'
+ // dep_new: '?<pkg> <constraint>[ <database>]'
+ //
+ // Note: the adjustment is assumed to be newly created or be popped from
+ // the stack.
+ //
+ string
+ to_string (const cmdline_adjustment& a) const
+ {
+ using type = cmdline_adjustment::adjustment_type;
+
+ assert (a.constraint); // Since not pushed.
+
+ const string& s (a.db.get ().string);
+
+ switch (a.type)
+ {
+ case type::hold_existing:
+ {
+ string r ("'" + a.name.string ());
+
+ auto i (find_hold_pkg (a));
+ assert (i != hold_pkgs_.end ());
+
+ const build_package& bp (*i);
+ if (!bp.constraints.empty ())
+ r += ' ' + bp.constraints[0].value.string ();
+
+ if (!s.empty ())
+ r += ' ' + s;
+
+ r += "' -> '" + a.name.string () + ' ' + a.constraint->string () +
+ "'";
+
+ return r;
+ }
+ case type::dep_existing:
+ {
+ string r ("'?" + a.name.string ());
+
+ auto i (find_dep_pkg (a));
+ assert (i != dep_pkgs_.end ());
+
+ if (i->constraint)
+ r += ' ' + i->constraint->string ();
+
+ if (!s.empty ())
+ r += ' ' + s;
+
+ r += "' -> '?" + a.name.string () + ' ' + a.constraint->string () +
+ "'";
+
+ return r;
+ }
+ case type::hold_new:
+ {
+ assert (find_hold_pkg (a) == hold_pkgs_.end ());
+
+ string r ("'" + a.name.string () + ' ' + a.constraint->string ());
+
+ if (!s.empty ())
+ r += ' ' + s;
+
+ r += "'";
+ return r;
+ }
+ case type::dep_new:
+ {
+ assert (find_dep_pkg (a) == dep_pkgs_.end ());
+
+ string r ("'?" + a.name.string () + ' ' + a.constraint->string ());
+
+ if (!s.empty ())
+ r += ' ' + s;
+
+ r += "'";
+ return r;
+ }
+ }
+
+ assert (false); // Can't be here.
+ return "";
+ }
+
+ // Return true, if there are no adjustments in the stack.
+ //
+ bool
+ empty () const
+ {
+ return adjustments_.empty ();
+ }
+
+ // Return true, if push() has been called at least once.
+ //
+ bool
+ tried () const
+ {
+ return !former_states_.empty ();
+ }
+
+ // Return the number of adjustments in the stack.
+ //
+ size_t
+ size () const
+ {
+ return adjustments_.size ();
+ }
+
+ // Return true if replacing a package build with the specified version
+ // will result in a command line which has already been (unsuccessfully)
+ // tried as a starting point for the package builds re-collection.
+ //
+ bool
+ tried_earlier (database& db, const package_name& n, const version& v) const
+ {
+ if (former_states_.empty ())
+ return false;
+
+ // Similar to the state() function, calculate the checksum over the
+ // packages set, but also consider the specified package version as if
+ // it were present in the set.
+ //
+ // Note that the specified package version may not be in the set, since
+ // we shouldn't be trying to replace with the package version which is
+ // already in the command line.
+ //
+ sha256 cs;
+
+ auto lt = [&db, &n, &v] (const package_version_key& pvk)
+ {
+ if (int r = n.compare (pvk.name))
+ return r < 0;
+
+ if (int r = v.compare (*pvk.version))
+ return r < 0;
+
+ return db < pvk.db;
+ };
+
+ bool appended (false);
+ for (const package_version_key& p: packages_)
+ {
+ assert (p.version); // Only the real packages can be here.
+
+ if (!appended && lt (p))
+ {
+ cs.append (db.config.string ());
+ cs.append (n.string ());
+ cs.append (v.string ());
+
+ appended = true;
+ }
+
+ cs.append (p.db.get ().config.string ());
+ cs.append (p.name.string ());
+ cs.append (p.version->string ());
+ }
+
+ if (!appended)
+ {
+ cs.append (db.config.string ());
+ cs.append (n.string ());
+ cs.append (v.string ());
+ }
+
+ return former_states_.find (cs.string ()) != former_states_.end ();
+ }
+
+ private:
+ // Return the SHA256 checksum of the current command line state.
+ //
+ string
+ state () const
+ {
+ // NOTE: remember to update tried_earlier() if changing anything here.
+ //
+ sha256 cs;
+ for (const package_version_key& p: packages_)
+ {
+ assert (p.version); // Only the real packages can be here.
+
+ cs.append (p.db.get ().config.string ());
+ cs.append (p.name.string ());
+ cs.append (p.version->string ());
+ }
+
+ return cs.string ();
+ }
+
+ // Find the command line package spec an adjustment applies to.
+ //
+ vector<build_package>::iterator
+ find_hold_pkg (const cmdline_adjustment& a) const
+ {
+ return find_if (hold_pkgs_.begin (), hold_pkgs_.end (),
+ [&a] (const build_package& p)
+ {
+ return p.name () == a.name && p.db == a.db;
+ });
+ }
+
+ dependency_packages::iterator
+ find_dep_pkg (const cmdline_adjustment& a) const
+ {
+ return find_if (dep_pkgs_.begin (), dep_pkgs_.end (),
+ [&a] (const dependency_package& p)
+ {
+ return p.name == a.name &&
+ p.db != nullptr &&
+ *p.db == a.db;
+ });
+ }
+
+ private:
+ vector<build_package>& hold_pkgs_;
+ dependency_packages& dep_pkgs_;
+
+ vector<cmdline_adjustment> adjustments_; // Adjustments stack.
+ set<package_version_key> packages_; // Replacements.
+ set<string> former_states_; // Command line seen states.
+ };
+
+ // Try to replace a collected package with a different available version,
+ // satisfactory for all its new and/or existing dependents. Return the
+ // command line adjustment if such a replacement is deduced and nullopt
+ // otherwise. In the latter case, also return the list of the being built
+ // dependents which are unsatisfied by some of the dependency available
+ // versions (unsatisfied_dpts argument).
+ //
+ // Specifically, try to find the best available package version considering
+ // all the imposed constraints as per unsatisfied_dependents description. If
+ // succeed, return the command line adjustment reflecting the replacement.
+ //
+ // Notes:
+ //
+ // - Doesn't perform the actual adjustment of the command line.
+ //
+ // - Expected to be called after the execution plan is fully refined. That,
+ // in particular, means that all the existing dependents are also
+ // collected and thus the constraints they impose are already in their
+ // dependencies' constraints lists.
+ //
+ // - The specified package version may or may not be satisfactory for its
+ // new and existing dependents.
+ //
+ // - The replacement is denied in the following cases:
+ //
+ // - If it turns out that the package have been specified on the command
+ // line (by the user or by us on some previous iteration) with an exact
+ // version constraint, then we cannot try any other version.
+ //
+ // - If the dependency is system, then it is either specified with the
+ // wildcard version or its exact version have been specified by the user
+ // or have been deduced by the system package manager. In the former
+ // case we actually won't be calling this function for this package
+ // since the wildcard version satisfies any constraint. Thus, an exact
+ // version has been specified/deduced for this dependency and so we
+ // cannot try any other version.
+ //
+ // - If the dependency is being built as an existing archive/directory,
+ // then its version is determined and so we cannot try any other
+ // version.
+ //
+ // - If the package is already configured with the version held and the
+ // user didn't specify this package on the command line and it is not
+ // requested to be upgraded, patched, and/or deorphaned, then we
+ // shouldn't be silently up/down-grading it.
+ //
+ optional<cmdline_adjustment>
+ try_replace_dependency (const common_options& o,
+ const build_package& p,
+ const build_packages& pkgs,
+ const vector<build_package>& hold_pkgs,
+ const dependency_packages& dep_pkgs,
+ const cmdline_adjustments& cmdline_adjs,
+ vector<package_key>& unsatisfied_dpts,
+ const char* what)
+ {
+ tracer trace ("try_replace_dependency");
+
+ assert (p.available != nullptr); // By definition.
+
+ // Bail out for the system package build.
+ //
+ if (p.system)
+ {
+ l5 ([&]{trace << "replacement of " << what << " version "
+ << p.available_name_version_db () << " is denied "
+ << "since it is being configured as system";});
+
+ return nullopt;
+ }
+
+ // Bail out for an existing package archive/directory.
+ //
+ database& db (p.db);
+ const package_name& nm (p.name ());
+ const version& ver (p.available->version);
+
+ if (find_existing (db,
+ nm,
+ nullopt /* version_constraint */).first != nullptr)
+ {
+ l5 ([&]{trace << "replacement of " << what << " version "
+ << p.available_name_version_db () << " is denied since "
+ << "it is being built as existing archive/directory";});
+
+ return nullopt;
+ }
+
+ // Find the package command line entry and stash the reference to its
+ // version constraint, if any. Bail out if the constraint is specified as
+ // an exact package version.
+ //
+ const build_package* hold_pkg (nullptr);
+ const dependency_package* dep_pkg (nullptr);
+ const version_constraint* constraint (nullptr);
+
+ for (const build_package& hp: hold_pkgs)
+ {
+ if (hp.name () == nm && hp.db == db)
+ {
+ hold_pkg = &hp;
+
+ if (!hp.constraints.empty ())
+ {
+ // Can only contain the user-specified constraint.
+ //
+ assert (hp.constraints.size () == 1);
+
+ const version_constraint& c (hp.constraints[0].value);
+
+ if (c.min_version == c.max_version)
+ {
+ l5 ([&]{trace << "replacement of " << what << " version "
+ << p.available_name_version_db () << " is denied "
+ << "since it is specified on command line as '"
+ << nm << ' ' << c << "'";});
+
+ return nullopt;
+ }
+ else
+ constraint = &c;
+ }
+
+ break;
+ }
+ }
+
+ if (hold_pkg == nullptr)
+ {
+ for (const dependency_package& dp: dep_pkgs)
+ {
+ if (dp.name == nm && dp.db != nullptr && *dp.db == db)
+ {
+ dep_pkg = &dp;
+
+ if (dp.constraint)
+ {
+ const version_constraint& c (*dp.constraint);
+
+ if (c.min_version == c.max_version)
+ {
+ l5 ([&]{trace << "replacement of " << what << " version "
+ << p.available_name_version_db () << " is denied "
+ << "since it is specified on command line as '?"
+ << nm << ' ' << c << "'";});
+
+ return nullopt;
+ }
+ else
+ constraint = &c;
+ }
+
+ break;
+ }
+ }
+ }
+
+ // Bail out if the selected package version is held and the package is not
+ // specified on the command line nor is being upgraded/deorphaned via its
+ // dependents recursively.
+ //
+ const shared_ptr<selected_package>& sp (p.selected);
+
+ if (sp != nullptr && sp->hold_version &&
+ hold_pkg == nullptr && dep_pkg == nullptr &&
+ !p.upgrade && !p.deorphan)
+ {
+ l5 ([&]{trace << "replacement of " << what << " version "
+ << p.available_name_version_db () << " is denied since "
+ << "it is already built to hold version and it is not "
+ << "specified on command line nor is being upgraded or "
+ << "deorphaned";});
+
+ return nullopt;
+ }
+
+ transaction t (db);
+
+ // Collect the repository fragments to search the available packages in.
+ //
+ config_repo_fragments rfs;
+
+ // Add a repository fragment to the specified list, suppressing duplicates.
+ //
+ auto add = [] (shared_ptr<repository_fragment>&& rf,
+ vector<shared_ptr<repository_fragment>>& rfs)
+ {
+ if (find (rfs.begin (), rfs.end (), rf) == rfs.end ())
+ rfs.push_back (move (rf));
+ };
+
+ // If the package is specified as build-to-hold on the command line, then
+ // collect the root repository fragment from its database. Otherwise,
+ // collect the repository fragments its dependent packages come from.
+ //
+ if (hold_pkg != nullptr)
+ {
+ add (db.find<repository_fragment> (empty_string), rfs[db]);
+ }
+ else
+ {
+ // Collect the repository fragments the new dependents come from.
+ //
+ if (p.required_by_dependents)
+ {
+ for (const package_version_key& dvk: p.required_by)
+ {
+ if (dvk.version) // Real package?
+ {
+ const build_package* d (pkgs.entered_build (dvk.db, dvk.name));
+
+ // Must be collected as a package build (see
+ // build_package::required_by for details).
+ //
+ assert (d != nullptr &&
+ d->action &&
+ *d->action == build_package::build &&
+ d->available != nullptr);
+
+ for (const package_location& pl: d->available->locations)
+ {
+ const lazy_shared_ptr<repository_fragment>& lrf (
+ pl.repository_fragment);
+
+ // Note that here we also handle dependents fetched/unpacked
+ // using the existing archive/directory adding the root
+ // repository fragments from their configurations.
+ //
+ if (!rep_masked_fragment (lrf))
+ add (lrf.load (), rfs[lrf.database ()]);
+ }
+ }
+ }
+ }
+
+ // Collect the repository fragments the existing dependents come from.
+ //
+ // Note that all the existing dependents are already in the map (since
+ // collect_dependents() has already been called) and are either
+ // reconfigure adjustments or non-collected recursively builds.
+ //
+ if (sp != nullptr)
+ {
+ for (database& ddb: db.dependent_configs ())
+ {
+ for (const auto& pd: query_dependents (ddb, nm, db))
+ {
+ const build_package* d (pkgs.entered_build (ddb, pd.name));
+
+ // See collect_dependents() for details.
+ //
+ assert (d != nullptr && d->action);
+
+ if ((*d->action == build_package::adjust &&
+ (d->flags & build_package::adjust_reconfigure) != 0) ||
+ (*d->action == build_package::build && !d->dependencies))
+ {
+ shared_ptr<selected_package> p (
+ ddb.load<selected_package> (pd.name));
+
+ add_dependent_repo_fragments (ddb, p, rfs);
+ }
+ }
+ }
+ }
+ }
+
+ // Query the dependency available packages from all the collected
+ // repository fragments and select the most appropriate one. Note that
+ // this code is inspired by the evaluate_dependency() function
+ // implementation, which documents the below logic in great detail.
+ //
+ optional<version_constraint> c (constraint != nullptr
+ ? *constraint
+ : optional<version_constraint> ());
+
+ if (!c && p.upgrade && !*p.upgrade)
+ {
+ assert (sp != nullptr); // See build_package::upgrade.
+
+ c = patch_constraint (sp);
+
+ assert (c); // See build_package::upgrade.
+ }
+
+ available_packages afs (find_available (nm, c, rfs));
+
+ using available = pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>>;
+
+ available ra;
+
+ // Version to deorphan.
+ //
+ const version* dov (p.deorphan ? &sp->version : nullptr);
+
+ optional<version_constraint> dopc; // Patch constraint for the above.
+ optional<version_constraint> domc; // Minor constraint for the above.
+
+ bool orphan_best_match (p.deorphan && constraint == nullptr && !p.upgrade);
+
+ if (orphan_best_match)
+ {
+ // Note that non-zero iteration makes a version non-standard, so we
+ // reset it to 0 to produce the patch/minor constraints.
+ //
+ version v (dov->epoch,
+ dov->upstream,
+ dov->release,
+ dov->revision,
+ 0 /* iteration */);
+
+ dopc = patch_constraint (nm, v, true /* quiet */);
+ domc = minor_constraint (nm, v, true /* quiet */);
+ }
+
+ available deorphan_latest_iteration;
+ available deorphan_later_revision;
+ available deorphan_later_patch;
+ available deorphan_later_minor;
+ available deorphan_latest_available;
+
+ // Return true if a version satisfies all the dependency constraints.
+ // Otherwise, save all the being built unsatisfied dependents into the
+ // resulting list, suppressing duplicates.
+ //
+ auto satisfactory = [&p, &unsatisfied_dpts] (const version& v)
+ {
+ bool r (true);
+
+ for (const auto& c: p.constraints)
+ {
+ if (!satisfies (v, c.value))
+ {
+ r = false;
+
+ if (c.dependent.version && !c.selected_dependent)
+ {
+ package_key pk (c.dependent.db, c.dependent.name);
+
+ if (find (unsatisfied_dpts.begin (),
+ unsatisfied_dpts.end (),
+ pk) == unsatisfied_dpts.end ())
+ unsatisfied_dpts.push_back (move (pk));
+ }
+ }
+ }
+
+ return r;
+ };
+
+ for (available& af: afs)
+ {
+ shared_ptr<available_package>& ap (af.first);
+
+ if (ap->stub ())
+ continue;
+
+ const version& av (ap->version);
+
+ // Skip if the available package version doesn't satisfy all the
+ // constraints (note: must be checked first since has a byproduct).
+ //
+ if (!satisfactory (av))
+ continue;
+
+ // Don't offer to replace to the same version.
+ //
+ if (av == ver)
+ continue;
+
+ // Don't repeatedly offer the same adjustments for the same command
+ // line.
+ //
+ if (cmdline_adjs.tried_earlier (db, nm, av))
+ {
+ l5 ([&]{trace << "replacement " << package_version_key (db, nm, av)
+ << " tried earlier for same command line, skipping";});
+
+ continue;
+ }
+
+ // If we aim to upgrade to the latest version and it tends to be less
+ // then the selected one, then what we currently have is the best that
+ // we can get. Thus, we use the selected version as a replacement,
+ // unless it doesn't satisfy all the constraints or we are deorphaning.
+ //
+ if (constraint == nullptr && sp != nullptr)
+ {
+ const version& sv (sp->version);
+ if (av < sv && !sp->system () && !p.deorphan)
+ {
+ // Only consider the selected package if its version is satisfactory
+ // for its new dependents (note: must be checked first since has a
+ // byproduct), differs from the version being replaced, and was
+ // never used for the same command line (see above for details).
+ //
+ if (satisfactory (sv) && sv != ver)
+ {
+ if (!cmdline_adjs.tried_earlier (db, nm, sv))
+ {
+ ra = make_available_fragment (o, db, sp);
+ break;
+ }
+ else
+ l5 ([&]{trace << "selected package replacement "
+ << package_version_key (db, nm, sp->version)
+ << " tried earlier for same command line, "
+ << "skipping";});
+ }
+ }
+ }
+
+ if (orphan_best_match)
+ {
+ if (av == *dov)
+ {
+ ra = move (af);
+ break;
+ }
+
+ if (deorphan_latest_iteration.first == nullptr &&
+ av.compare (*dov, false /* revision */, true /* iteration */) == 0)
+ deorphan_latest_iteration = af;
+
+ if (deorphan_later_revision.first == nullptr &&
+ av.compare (*dov, true /* revision */) == 0 &&
+ av.compare (*dov, false /* revision */, true /* iteration */) > 0)
+ deorphan_later_revision = af;
+
+ if (deorphan_later_patch.first == nullptr &&
+ dopc && satisfies (av, *dopc) &&
+ av.compare (*dov, true /* revision */) > 0) // Patch is greater?
+ deorphan_later_patch = af;
+
+ if (deorphan_later_minor.first == nullptr &&
+ domc && satisfies (av, *domc) &&
+ av.compare (*dov, true /* revision */) > 0 &&
+ deorphan_later_patch.first == nullptr)
+ deorphan_later_minor = af;
+
+ if (deorphan_latest_available.first == nullptr)
+ deorphan_latest_available = move (af);
+
+ if (av.compare (*dov, false /* revision */, true /* iteration */) < 0)
+ {
+ assert (deorphan_latest_iteration.first != nullptr ||
+ deorphan_later_revision.first != nullptr ||
+ deorphan_later_patch.first != nullptr ||
+ deorphan_later_minor.first != nullptr ||
+ deorphan_latest_available.first != nullptr);
+
+ break;
+ }
+ }
+ else
+ {
+ ra = move (af);
+ break;
+ }
+ }
+
+ shared_ptr<available_package>& rap (ra.first);
+
+ if (rap == nullptr && orphan_best_match)
+ {
+ if (deorphan_latest_iteration.first != nullptr)
+ ra = move (deorphan_latest_iteration);
+ else if (deorphan_later_revision.first != nullptr)
+ ra = move (deorphan_later_revision);
+ else if (deorphan_later_patch.first != nullptr)
+ ra = move (deorphan_later_patch);
+ else if (deorphan_later_minor.first != nullptr)
+ ra = move (deorphan_later_minor);
+ else if (deorphan_latest_available.first != nullptr)
+ ra = move (deorphan_latest_available);
+ }
+
+ t.commit ();
+
+ // Bail out if no appropriate replacement is found and return the
+ // command line adjustment object otherwise.
+ //
+ if (rap == nullptr)
+ return nullopt;
+
+ optional<cmdline_adjustment> r;
+
+ lazy_shared_ptr<repository_fragment>& raf (ra.second);
+
+ if (hold_pkg != nullptr || dep_pkg != nullptr) // Specified on command line?
+ {
+ if (hold_pkg != nullptr)
+ {
+ r = cmdline_adjustment (hold_pkg->db,
+ hold_pkg->name (),
+ move (rap),
+ move (raf));
+
+ if (constraint != nullptr)
+ {
+ l5 ([&]{trace << "replace " << what << " version "
+ << p.available_name_version () << " with "
+ << r->version << " by overwriting constraint "
+ << cmdline_adjs.to_string (*r) << " on command line";});
+ }
+ else
+ {
+ l5 ([&]{trace << "replace " << what << " version "
+ << p.available_name_version () << " with "
+ << r->version << " by adding constraint "
+ << cmdline_adjs.to_string (*r) << " on command line";});
+ }
+ }
+ else // dep_pkg != nullptr
+ {
+ r = cmdline_adjustment (*dep_pkg->db, dep_pkg->name, rap->version);
+
+ if (constraint != nullptr)
+ {
+ l5 ([&]{trace << "replace " << what << " version "
+ << p.available_name_version () << " with "
+ << r->version << " by overwriting constraint "
+ << cmdline_adjs.to_string (*r) << " on command line";});
+ }
+ else
+ {
+ l5 ([&]{trace << "replace " << what << " version "
+ << p.available_name_version () << " with "
+ << r->version << " by adding constraint "
+ << cmdline_adjs.to_string (*r) << " on command line";});
+ }
+ }
+ }
+ else // The package is not specified on the command line.
+ {
+ // If the package is configured as system, then since it is not
+ // specified by the user (both hold_pkg and dep_pkg are NULL) we may
+ // only build it as system. Thus we wouldn't be here (see above).
+ //
+ assert (sp == nullptr || !sp->system ());
+
+ // Similar to the collect lambda in collect_build_prerequisites(), issue
+ // the warning if we are forcing an up/down-grade.
+ //
+ if (sp != nullptr && (sp->hold_package || verb >= 2))
+ {
+ const version& av (rap->version);
+ const version& sv (sp->version);
+
+ int ud (sv.compare (av));
+
+ if (ud != 0)
+ {
+ for (const auto& c: p.constraints)
+ {
+ if (c.dependent.version && !satisfies (sv, c.value))
+ {
+ warn << "package " << c.dependent << " dependency on ("
+ << nm << ' ' << c.value << ") is forcing "
+ << (ud < 0 ? "up" : "down") << "grade of " << *sp << db
+ << " to " << av;
+
+ break;
+ }
+ }
+ }
+ }
+
+ // For the selected built-to-hold package create the build-to-hold
+ // package spec and the dependency spec otherwise.
+ //
+ if (sp != nullptr && sp->hold_package)
+ {
+ r = cmdline_adjustment (db,
+ nm,
+ move (rap),
+ move (raf),
+ p.upgrade,
+ p.deorphan);
+
+ l5 ([&]{trace << "replace " << what << " version "
+ << p.available_name_version () << " with " << r->version
+ << " by adding package spec "
+ << cmdline_adjs.to_string (*r)
+ << " to command line";});
+ }
+ else
+ {
+ r = cmdline_adjustment (db, nm, rap->version, p.upgrade, p.deorphan);
+
+ l5 ([&]{trace << "replace " << what << " version "
+ << p.available_name_version () << " with " << r->version
+ << " by adding package spec "
+ << cmdline_adjs.to_string (*r)
+ << " to command line";});
+ }
+ }
+
+ return r;
+ }
+
+ // Try to replace some of the being built, potentially indirect, dependents
+ // of the specified dependency with a different available version,
+ // satisfactory for all its new and existing dependents (if any). Return the
+ // command line adjustment if such a replacement is deduced and nullopt
+ // otherwise. It is assumed that the dependency replacement has been
+ // (unsuccessfully) tried by using the try_replace_dependency() call and its
+ // resulting list of the dependents, unsatisfied by some of the dependency
+ // available versions, is also passed to the function call as the
+ // unsatisfied_dpts argument.
+ //
+ // Specifically, try to replace the dependents in the following order by
+ // calling try_replace_dependency() for them:
+ //
+ // - Immediate dependents unsatisfied with the specified dependency. For the
+ // sake of tracing and documentation, we (naturally) call them unsatisfied
+ // dependents.
+ //
+ // - Immediate dependents satisfied with the dependency but applying the
+ // version constraint which has prevented us from picking a version which
+ // would be satisfactory to the unsatisfied dependents. Note that this
+ // information is only available for the being built unsatisfied
+ // dependents (added by collect_build() rather than collect_dependents()).
+ // We call them conflicting dependents.
+ //
+ // - Immediate dependents which apply constraint to this dependency,
+ // incompatible with constraints of some other dependents (both new and
+ // existing). We call them unsatisfiable dependents.
+ //
+ // - Immediate dependents from unsatisfied_dpts argument. We call them
+ // constraining dependents.
+ //
+ // - Dependents of all the above types of dependents, discovered by
+ // recursively calling try_replace_dependent() for them.
+ //
+ optional<cmdline_adjustment>
+ try_replace_dependent (const common_options& o,
+ const build_package& p, // Dependency.
+ const vector<unsatisfied_constraint>* ucs,
+ const build_packages& pkgs,
+ const cmdline_adjustments& cmdline_adjs,
+ const vector<package_key>& unsatisfied_dpts,
+ vector<build_package>& hold_pkgs,
+ dependency_packages& dep_pkgs,
+ set<const build_package*>& visited_dpts)
+ {
+ tracer trace ("try_replace_dependent");
+
+ // Bail out if the dependent has already been visited and add it to the
+ // visited set otherwise.
+ //
+ if (!visited_dpts.insert (&p).second)
+ return nullopt;
+
+ using constraint_type = build_package::constraint_type;
+
+ const shared_ptr<available_package>& ap (p.available);
+ assert (ap != nullptr); // By definition.
+
+ const version& av (ap->version);
+
+ // List of the dependents which we have (unsuccessfully) tried to replace
+ // together with the lists of the constraining dependents.
+ //
+ vector<pair<package_key, vector<package_key>>> dpts;
+
+ // Try to replace a dependent, unless we have already tried to replace it.
+ //
+ auto try_replace = [&o,
+ &p,
+ &pkgs,
+ &cmdline_adjs,
+ &hold_pkgs,
+ &dep_pkgs,
+ &visited_dpts,
+ &dpts,
+ &trace] (package_key dk, const char* what)
+ -> optional<cmdline_adjustment>
+ {
+ if (find_if (dpts.begin (), dpts.end (),
+ [&dk] (const auto& v) {return v.first == dk;}) ==
+ dpts.end ())
+ {
+ const build_package* d (pkgs.entered_build (dk));
+
+ // Always come from the dependency's constraints member.
+ //
+ assert (d != nullptr);
+
+ // Skip the visited dependents since, by definition, we have already
+ // tried to replace them.
+ //
+ if (find (visited_dpts.begin (), visited_dpts.end (), d) ==
+ visited_dpts.end ())
+ {
+ l5 ([&]{trace << "try to replace " << what << ' '
+ << d->available_name_version_db () << " of dependency "
+ << p.available_name_version_db () << " with some "
+ << "other version";});
+
+ vector<package_key> uds;
+
+ if (optional<cmdline_adjustment> a = try_replace_dependency (
+ o,
+ *d,
+ pkgs,
+ hold_pkgs,
+ dep_pkgs,
+ cmdline_adjs,
+ uds,
+ what))
+ {
+ return a;
+ }
+
+ dpts.emplace_back (move (dk), move (uds));
+ }
+ }
+
+ return nullopt;
+ };
+
+ // Try to replace unsatisfied dependents.
+ //
+ for (const constraint_type& c: p.constraints)
+ {
+ const package_version_key& dvk (c.dependent);
+
+ if (dvk.version && !c.selected_dependent && !satisfies (av, c.value))
+ {
+ if (optional<cmdline_adjustment> a = try_replace (
+ package_key (dvk.db, dvk.name), "unsatisfied dependent"))
+ {
+ return a;
+ }
+ }
+ }
+
+ // Try to replace conflicting dependents.
+ //
+ if (ucs != nullptr)
+ {
+ for (const unsatisfied_constraint& uc: *ucs)
+ {
+ const package_version_key& dvk (uc.constraint.dependent);
+
+ if (dvk.version)
+ {
+ if (optional<cmdline_adjustment> a = try_replace (
+ package_key (dvk.db, dvk.name), "conflicting dependent"))
+ {
+ return a;
+ }
+ }
+ }
+ }
+
+ // Try to replace unsatisfiable dependents.
+ //
+ for (const constraint_type& c1: p.constraints)
+ {
+ const package_version_key& dvk (c1.dependent);
+
+ if (dvk.version && !c1.selected_dependent)
+ {
+ const version_constraint& v1 (c1.value);
+
+ bool unsatisfiable (false);
+ for (const constraint_type& c2: p.constraints)
+ {
+ const version_constraint& v2 (c2.value);
+
+ if (!satisfies (v1, v2) && !satisfies (v2, v1))
+ {
+ unsatisfiable = true;
+ break;
+ }
+ }
+
+ if (unsatisfiable)
+ {
+ if (optional<cmdline_adjustment> a = try_replace (
+ package_key (dvk.db, dvk.name), "unsatisfiable dependent"))
+ {
+ return a;
+ }
+ }
+ }
+ }
+
+ // Try to replace constraining dependents.
+ //
+ for (const auto& dk: unsatisfied_dpts)
+ {
+ if (optional<cmdline_adjustment> a = try_replace (
+ dk, "constraining dependent"))
+ {
+ return a;
+ }
+ }
+
+ // Try to replace dependents of the above dependents, recursively.
+ //
+ for (const auto& dep: dpts)
+ {
+ const build_package* d (pkgs.entered_build (dep.first));
+
+ assert (d != nullptr);
+
+ if (optional<cmdline_adjustment> a = try_replace_dependent (
+ o,
+ *d,
+ nullptr /* unsatisfied_constraints */,
+ pkgs,
+ cmdline_adjs,
+ dep.second,
+ hold_pkgs,
+ dep_pkgs,
+ visited_dpts))
+ {
+ return a;
+ }
+ }
+
+ return nullopt;
+ }
+
+ // Return false if the plan execution was noop. If unsatisfied dependents
+ // are specified then we are in the simulation mode.
//
static bool
execute_plan (const pkg_build_options&,
build_package_list&,
- bool simulate,
+ unsatisfied_dependents* simulate,
const function<find_database_function>&);
using pkg_options = pkg_build_pkg_options;
@@ -918,13 +2938,14 @@ namespace bpkg
dr << fail << "both --immediate|-i and --recursive|-r specified";
// The --immediate or --recursive option can only be specified with an
- // explicit --upgrade or --patch.
+ // explicit --upgrade, --patch, or --deorphan.
//
if (const char* n = (o.immediate () ? "--immediate" :
o.recursive () ? "--recursive" : nullptr))
{
- if (!o.upgrade () && !o.patch ())
- dr << fail << n << " requires explicit --upgrade|-u or --patch|-p";
+ if (!o.upgrade () && !o.patch () && !o.deorphan ())
+ dr << fail << n << " requires explicit --upgrade|-u, --patch|-p, or "
+ << "--deorphan";
}
if (((o.upgrade_immediate () ? 1 : 0) +
@@ -934,6 +2955,10 @@ namespace bpkg
dr << fail << "multiple --(upgrade|patch)-(immediate|recursive) "
<< "specified";
+ if (o.deorphan_immediate () && o.deorphan_recursive ())
+ dr << fail << "both --deorphan-immediate and --deorphan-recursive "
+ << "specified";
+
if (multi_config ())
{
if (const char* opt = o.config_name_specified () ? "--config-name" :
@@ -960,13 +2985,16 @@ namespace bpkg
dst.recursive (src.recursive ());
// If -r|-i was specified at the package level, then so should
- // -u|-p.
+ // -u|-p and --deorphan.
//
if (!(dst.upgrade () || dst.patch ()))
{
dst.upgrade (src.upgrade ());
dst.patch (src.patch ());
}
+
+ if (!dst.deorphan ())
+ dst.deorphan (src.deorphan ());
}
if (!(dst.upgrade_immediate () || dst.upgrade_recursive () ||
@@ -978,6 +3006,12 @@ namespace bpkg
dst.patch_recursive (src.patch_recursive ());
}
+ if (!(dst.deorphan_immediate () || dst.deorphan_recursive ()))
+ {
+ dst.deorphan_immediate (src.deorphan_immediate ());
+ dst.deorphan_recursive (src.deorphan_recursive ());
+ }
+
dst.dependency (src.dependency () || dst.dependency ());
dst.keep_out (src.keep_out () || dst.keep_out ());
dst.disfigure (src.disfigure () || dst.disfigure ());
@@ -1021,19 +3055,22 @@ namespace bpkg
static bool
compare_options (const pkg_options& x, const pkg_options& y)
{
- return x.keep_out () == y.keep_out () &&
- x.disfigure () == y.disfigure () &&
- x.dependency () == y.dependency () &&
- x.upgrade () == y.upgrade () &&
- x.patch () == y.patch () &&
- x.immediate () == y.immediate () &&
- x.recursive () == y.recursive () &&
- x.upgrade_immediate () == y.upgrade_immediate () &&
- x.upgrade_recursive () == y.upgrade_recursive () &&
- x.patch_immediate () == y.patch_immediate () &&
- x.patch_recursive () == y.patch_recursive () &&
- x.checkout_root () == y.checkout_root () &&
- x.checkout_purge () == y.checkout_purge ();
+ return x.keep_out () == y.keep_out () &&
+ x.disfigure () == y.disfigure () &&
+ x.dependency () == y.dependency () &&
+ x.upgrade () == y.upgrade () &&
+ x.patch () == y.patch () &&
+ x.deorphan () == y.deorphan () &&
+ x.immediate () == y.immediate () &&
+ x.recursive () == y.recursive () &&
+ x.upgrade_immediate () == y.upgrade_immediate () &&
+ x.upgrade_recursive () == y.upgrade_recursive () &&
+ x.patch_immediate () == y.patch_immediate () &&
+ x.patch_recursive () == y.patch_recursive () &&
+ x.deorphan_immediate () == y.deorphan_immediate () &&
+ x.deorphan_recursive () == y.deorphan_recursive () &&
+ x.checkout_root () == y.checkout_root () &&
+ x.checkout_purge () == y.checkout_purge ();
}
int
@@ -1071,7 +3108,11 @@ namespace bpkg
<< "specified" <<
info << "run 'bpkg help pkg-build' for more information";
- if (!args.more () && !o.upgrade () && !o.patch ())
+ if (o.sys_no_query () && o.sys_install ())
+ fail << "both --sys-no-query and --sys-install specified" <<
+ info << "run 'bpkg help pkg-build' for more information";
+
+ if (!args.more () && !o.upgrade () && !o.patch () && !o.deorphan ())
fail << "package name argument expected" <<
info << "run 'bpkg help pkg-build' for more information";
@@ -1094,6 +3135,10 @@ namespace bpkg
? empty_string
: '[' + config_dirs[0].representation () + ']'));
+ // Command line as a dependent.
+ //
+ package_version_key cmd_line (mdb, "command line");
+
current_configs.push_back (mdb);
if (config_dirs.size () != 1)
@@ -1119,6 +3164,8 @@ namespace bpkg
if (!current (db))
current_configs.push_back (db);
}
+
+ t.commit ();
}
validate_options (o, ""); // Global package options.
@@ -1129,7 +3176,7 @@ namespace bpkg
// will modify the cached instance, which means our list will always "see"
// their updated state.
//
- // Also note that rep_fetch() must be called in session.
+ // Also note that rep_fetch() and pkg_fetch() must be called in session.
//
session ses;
@@ -1240,7 +3287,13 @@ namespace bpkg
if (a.find ('=') == string::npos)
fail << "unexpected group argument '" << a << "'";
- cvs.push_back (move (trim (a)));
+ trim (a);
+
+ if (a[0] == '!')
+ fail << "global override in package-specific configuration "
+ << "variable '" << a << "'";
+
+ cvs.push_back (move (a));
}
}
@@ -1516,6 +3569,14 @@ namespace bpkg
string () /* reason for "fetching ..." */);
}
+ // Now, as repo_configs is filled and the repositories are fetched mask
+ // the repositories, if any.
+ //
+ if (o.mask_repository_specified () || o.mask_repository_uuid_specified ())
+ rep_mask (o.mask_repository (),
+ o.mask_repository_uuid (),
+ current_configs);
+
// Expand the package specs into individual package args, parsing them
// into the package scheme, name, and version constraint components, and
// also saving associated options and configuration variables.
@@ -1537,6 +3598,12 @@ namespace bpkg
string value;
pkg_options options;
strings config_vars;
+
+ // If schema is sys then this member indicates whether the constraint
+ // came from the system package manager (not NULL) or user/fallback
+ // (NULL).
+ //
+ const system_package_status* system_status;
};
auto arg_parsed = [] (const pkg_arg& a) {return !a.name.empty ();};
@@ -1605,16 +3672,19 @@ namespace bpkg
const pkg_options& o (a.options);
- add_bool ("--keep-out", o.keep_out ());
- add_bool ("--disfigure", o.disfigure ());
- add_bool ("--upgrade", o.upgrade ());
- add_bool ("--patch", o.patch ());
- add_bool ("--immediate", o.immediate ());
- add_bool ("--recursive", o.recursive ());
- add_bool ("--upgrade-immediate", o.upgrade_immediate ());
- add_bool ("--upgrade-recursive", o.upgrade_recursive ());
- add_bool ("--patch-immediate", o.patch_immediate ());
- add_bool ("--patch-recursive", o.patch_recursive ());
+ add_bool ("--keep-out", o.keep_out ());
+ add_bool ("--disfigure", o.disfigure ());
+ add_bool ("--upgrade", o.upgrade ());
+ add_bool ("--patch", o.patch ());
+ add_bool ("--deorphan", o.deorphan ());
+ add_bool ("--immediate", o.immediate ());
+ add_bool ("--recursive", o.recursive ());
+ add_bool ("--upgrade-immediate", o.upgrade_immediate ());
+ add_bool ("--upgrade-recursive", o.upgrade_recursive ());
+ add_bool ("--patch-immediate", o.patch_immediate ());
+ add_bool ("--patch-recursive", o.patch_recursive ());
+ add_bool ("--deorphan-immediate", o.deorphan_immediate ());
+ add_bool ("--deorphan-recursive", o.deorphan_recursive ());
if (o.checkout_root_specified ())
add_string ("--checkout-root", o.checkout_root ().string ());
@@ -1652,23 +3722,141 @@ namespace bpkg
return r;
};
- // Add the system package authoritative information to the database's
- // system repository, unless it already contains authoritative information
- // for this package.
+ // Figure out the system package version unless explicitly specified and
+ // add the system package authoritative information to the database's
+ // system repository unless the database is NULL or it already contains
+ // authoritative information for this package. Return the figured out
+ // system package version as constraint.
//
// Note that it is assumed that all the possible duplicates are handled
// elsewhere/later.
//
- auto add_system_package = [] (database& db,
- const package_name& nm,
- const version& v)
+ auto add_system_package = [&o] (database* db,
+ const package_name& nm,
+ optional<version_constraint> vc,
+ const system_package_status* sps,
+ vector<shared_ptr<available_package>>* stubs)
+ -> pair<version_constraint, const system_package_status*>
{
- assert (db.system_repository);
+ if (!vc)
+ {
+ assert (sps == nullptr);
+
+ // See if we should query the system package manager.
+ //
+ if (!sys_pkg_mgr)
+ sys_pkg_mgr = o.sys_no_query ()
+ ? nullptr
+ : make_consumption_system_package_manager (o,
+ host_triplet,
+ o.sys_distribution (),
+ o.sys_architecture (),
+ o.sys_install (),
+ !o.sys_no_fetch (),
+ o.sys_yes (),
+ o.sys_sudo ());
+ if (*sys_pkg_mgr != nullptr)
+ {
+ system_package_manager& spm (**sys_pkg_mgr);
+
+ // First check the cache.
+ //
+ optional<const system_package_status*> os (spm.status (nm, nullptr));
+
+ available_packages aps;
+ if (!os)
+ {
+ // If no cache hit, then collect the available packages for the
+ // mapping information.
+ //
+ aps = find_available_all (current_configs, nm);
+
+ // If no source/stub for the package (and thus no mapping), issue
+ // diagnostics consistent with other such places unless explicitly
+ // allowed by the user.
+ //
+ if (aps.empty ())
+ {
+ if (!o.sys_no_stub ())
+ fail << "unknown package " << nm <<
+ info << "consider specifying --sys-no-stub or " << nm << "/*";
+
+ // Add the stub package to the imaginary system repository (like
+ // the user-specified case below).
+ //
+ if (stubs != nullptr)
+ stubs->push_back (make_shared<available_package> (nm));
+ }
+ }
+
+ // This covers both our diagnostics below as well as anything that
+ // might be issued by status().
+ //
+ auto df = make_diag_frame (
+ [&nm] (diag_record& dr)
+ {
+ dr << info << "specify " << nm << "/* if package is not "
+ << "installed with system package manager";
+
+ dr << info << "specify --sys-no-query to disable system "
+ << "package manager interactions";
+ });
- const system_package* sp (db.system_repository->find (nm));
+ if (!os)
+ {
+ os = spm.status (nm, &aps);
+ assert (os);
+ }
+
+ if ((sps = *os) != nullptr)
+ vc = version_constraint (sps->version);
+ else
+ {
+ diag_record dr (fail);
- if (sp == nullptr || !sp->authoritative)
- db.system_repository->insert (nm, v, true /* authoritative */);
+ dr << "no installed " << (o.sys_install () ? "or available " : "")
+ << "system package for " << nm;
+
+ if (!o.sys_install ())
+ dr << info << "specify --sys-install to try to install it";
+ }
+ }
+ else
+ vc = version_constraint (wildcard_version);
+ }
+ else
+ {
+ // The system package may only have an exact/wildcard version
+ // specified.
+ //
+ assert (vc->min_version == vc->max_version);
+
+ // For system packages not associated with a specific repository
+ // location add the stub package to the imaginary system repository
+ // (see below for details).
+ //
+ if (stubs != nullptr)
+ stubs->push_back (make_shared<available_package> (nm));
+ }
+
+ if (db != nullptr)
+ {
+ assert (db->system_repository);
+
+ const system_package* sp (db->system_repository->find (nm));
+
+ // Note that we don't check for the version match here since that's
+ // handled by check_dup() lambda at a later stage, which covers both
+ // db and no-db cases consistently.
+ //
+ if (sp == nullptr || !sp->authoritative)
+ db->system_repository->insert (nm,
+ *vc->min_version,
+ true /* authoritative */,
+ sps);
+ }
+
+ return make_pair (move (*vc), sps);
};
// Create the parsed package argument. Issue diagnostics and fail if the
@@ -1680,15 +3868,23 @@ namespace bpkg
package_name nm,
optional<version_constraint> vc,
pkg_options os,
- strings vs) -> pkg_arg
+ strings vs,
+ vector<shared_ptr<available_package>>* stubs = nullptr)
+ -> pkg_arg
{
assert (!vc || !vc->empty ()); // May not be empty if present.
if (db == nullptr)
assert (sc == package_scheme::sys && os.dependency ());
- pkg_arg r {
- db, sc, move (nm), move (vc), string (), move (os), move (vs)};
+ pkg_arg r {db,
+ sc,
+ move (nm),
+ move (vc),
+ string () /* value */,
+ move (os),
+ move (vs),
+ nullptr /* system_status */};
// Verify that the package database is specified in the multi-config
// mode, unless this is a system dependency package.
@@ -1707,17 +3903,16 @@ namespace bpkg
{
case package_scheme::sys:
{
- if (!r.constraint)
- r.constraint = version_constraint (wildcard_version);
-
- // The system package may only have an exact/wildcard version
- // specified.
- //
- assert (r.constraint->min_version == r.constraint->max_version);
+ assert (stubs != nullptr);
- if (db != nullptr)
- add_system_package (*db, r.name, *r.constraint->min_version);
+ auto sp (add_system_package (db,
+ r.name,
+ move (r.constraint),
+ nullptr /* system_package_status */,
+ stubs));
+ r.constraint = move (sp.first);
+ r.system_status = sp.second;
break;
}
case package_scheme::none: break; // Nothing to do.
@@ -1739,7 +3934,8 @@ namespace bpkg
nullopt /* constraint */,
move (v),
move (os),
- move (vs)};
+ move (vs),
+ nullptr /* system_status */};
};
vector<pkg_arg> pkg_args;
@@ -1802,13 +3998,6 @@ namespace bpkg
parse_package_version_constraint (
s, sys, version_flags (sc), version_only (sc)));
- // For system packages not associated with a specific repository
- // location add the stub package to the imaginary system
- // repository (see above for details).
- //
- if (sys && vc)
- stubs.push_back (make_shared<available_package> (n));
-
pkg_options& o (ps.options);
// Disregard the (main) database for a system dependency with
@@ -1825,7 +4014,8 @@ namespace bpkg
move (n),
move (vc),
move (o),
- move (ps.config_vars)));
+ move (ps.config_vars),
+ &stubs));
}
else // Add unparsed.
pkg_args.push_back (arg_raw (ps.db,
@@ -2059,7 +4249,8 @@ namespace bpkg
move (n),
move (vc),
ps.options,
- ps.config_vars));
+ ps.config_vars,
+ &stubs));
}
}
}
@@ -2081,6 +4272,32 @@ namespace bpkg
dependency_packages dep_pkgs;
recursive_packages rec_pkgs;
+ // Note that the command line adjustments which resolve the unsatisfied
+ // dependent issue (see unsatisfied_dependents for details) may
+ // potentially be sub-optimal, since we do not perform the full
+ // backtracking by trying all the possible adjustments and picking the
+ // most optimal combination. Instead, we keep collecting adjustments until
+ // either the package builds collection succeeds or there are no more
+ // adjustment combinations to try (and we don't try all of them). As a
+ // result we, for example, may end up with some redundant constraints on
+ // the command line just because the respective dependents have been
+ // evaluated first. Generally, dropping all the redundant adjustments can
+ // potentially be quite time-consuming, since we would need to try
+ // dropping all their possible combinations. We, however, will implement
+ // the refinement for only the common case (adjustments are independent),
+ // trying to drop just one adjustment per the refinement cycle iteration
+ // and wait and see how it goes.
+ //
+ cmdline_adjustments cmdline_adjs (hold_pkgs, dep_pkgs);
+
+ // If both are present, then we are in the command line adjustments
+ // refinement cycle, where cmdline_refine_adjustment is the adjustment
+ // being currently dropped and cmdline_refine_index is its index on the
+ // stack (as it appears at the beginning of the cycle).
+ //
+ optional<cmdline_adjustment> cmdline_refine_adjustment;
+ optional<size_t> cmdline_refine_index;
+
{
// Check if the package is a duplicate. Return true if it is but
// harmless.
@@ -2132,7 +4349,7 @@ namespace bpkg
!compare_options (a.options, pa.options) ||
a.config_vars != pa.config_vars))
fail << "duplicate package " << pa.name <<
- info << "first mentioned as " << arg_string (r.first->second) <<
+ info << "first mentioned as " << arg_string (a) <<
info << "second mentioned as " << arg_string (pa);
return !r.second;
@@ -2140,6 +4357,120 @@ namespace bpkg
transaction t (mdb);
+ // Return the available package that matches the specified orphan best
+ // (see evaluate_dependency() description for details). Also return the
+ // repository fragment the package comes from. Return a pair of NULLs if
+ // no suitable package has been found.
+ //
+ auto find_orphan_match =
+ [] (const shared_ptr<selected_package>& sp,
+ const lazy_shared_ptr<repository_fragment>& root)
+ {
+ using available = pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>>;
+
+ assert (sp != nullptr);
+
+ const package_name& n (sp->name);
+ const version& v (sp->version);
+ optional<version_constraint> vc {version_constraint (v)};
+
+ // Note that non-zero iteration makes a version non-standard, so we
+ // reset it to 0 to produce the patch/minor constraints.
+ //
+ version vr (v.epoch,
+ v.upstream,
+ v.release,
+ v.revision,
+ 0 /* iteration */);
+
+ optional<version_constraint> pc (
+ patch_constraint (n, vr, true /* quiet */));
+
+ optional<version_constraint> mc (
+ minor_constraint (n, vr, true /* quiet */));
+
+ // Note: explicit revision makes query_available() to always consider
+ // revisions (but not iterations) regardless of the revision argument
+ // value.
+ //
+ optional<version_constraint> verc {
+ version_constraint (version (v.epoch,
+ v.upstream,
+ v.release,
+ v.revision ? v.revision : 0,
+ 0 /* iteration */))};
+
+ optional<version_constraint> vlc {
+ version_constraint (version (v.epoch,
+ v.upstream,
+ v.release,
+ nullopt,
+ 0 /* iteration */))};
+
+ // Find the latest available non-stub package, optionally matching a
+ // constraint and considering revision. If a package is found, then
+ // cache it together with the repository fragment it comes from and
+ // return true.
+ //
+ available find_result;
+ const version* find_version (nullptr);
+ auto find = [&n,
+ &root,
+ &find_result,
+ &find_version] (const optional<version_constraint>& c,
+ bool revision = false) -> bool
+ {
+ available r (
+ find_available_one (n, c, root, false /* prereq */, revision));
+
+ const shared_ptr<available_package>& ap (r.first);
+
+ if (ap != nullptr && !ap->stub ())
+ {
+ find_result = move (r);
+ find_version = &find_result.first->version;
+ return true;
+ }
+ else
+ return false;
+ };
+
+ if (// Same version, revision, and iteration.
+ //
+ find (vc, true) ||
+ //
+ // Latest iteration of same version and revision.
+ //
+ find (verc) ||
+ //
+ // Later revision of same version.
+ //
+ (find (vlc) &&
+ find_version->compare (v,
+ false /* revision */,
+ true /* iteration */) > 0) ||
+ //
+ // Later patch of same version.
+ //
+ (pc && find (pc) &&
+ find_version->compare (v, true /* revision */) > 0) ||
+ //
+ // Later minor of same version.
+ //
+ (mc && find (mc) &&
+ find_version->compare (v, true /* revision */) > 0) ||
+ //
+ // Latest available version, including earlier.
+ //
+ find (nullopt))
+ {
+ return find_result;
+ }
+
+ return available ();
+ };
+
// Here is what happens here: for unparsed package args we are going to
// try and guess whether we are dealing with a package archive, package
// directory, or package name/version by first trying it as an archive,
@@ -2164,6 +4495,7 @@ namespace bpkg
//
lazy_shared_ptr<repository_fragment> af;
shared_ptr<available_package> ap;
+ bool existing (false); // True if build as an archive or directory.
if (!arg_parsed (pa))
{
@@ -2189,20 +4521,13 @@ namespace bpkg
false /* ignore_toolchain */,
false /* expand_values */,
true /* load_buildfiles */,
- true /* complete_depends */,
+ true /* complete_values */,
diag ? 2 : 1));
// This is a package archive.
//
l4 ([&]{trace << "archive '" << a << "': " << arg_string (pa);});
- // Supporting this would complicate things a bit, but we may add
- // support for it one day.
- //
- if (pa.options.dependency ())
- fail << "package archive '" << a
- << "' may not be built as a dependency";
-
pa = arg_package (pdb,
package_scheme::none,
m.name,
@@ -2213,6 +4538,9 @@ namespace bpkg
af = root;
ap = make_shared<available_package> (move (m));
ap->locations.push_back (package_location {root, move (a)});
+
+ existing_packages.push_back (make_pair (ref (*pdb), ap));
+ existing = true;
}
}
catch (const invalid_path&)
@@ -2257,7 +4585,11 @@ namespace bpkg
true /* load_buildfiles */,
[&o, &d, &pvi] (version& v)
{
- pvi = package_version (o, d);
+ // Note that we also query subprojects since the package
+ // information will be used for the subsequent
+ // package_iteration() call.
+ //
+ pvi = package_version (o, d, b_info_flags::subprojects);
if (pvi.version)
v = move (*pvi.version);
@@ -2269,13 +4601,6 @@ namespace bpkg
l4 ([&]{trace << "directory '" << d << "': "
<< arg_string (pa);});
- // Supporting this would complicate things a bit, but we may
- // add support for it one day.
- //
- if (pa.options.dependency ())
- fail << "package directory '" << d
- << "' may not be built as a dependency";
-
// Fix-up the package version to properly decide if we need to
// upgrade/downgrade the package.
//
@@ -2300,6 +4625,9 @@ namespace bpkg
ap = make_shared<available_package> (move (m));
af = root;
ap->locations.push_back (package_location {root, move (d)});
+
+ existing_packages.push_back (make_pair (ref (*pdb), ap));
+ existing = true;
}
}
catch (const invalid_path&)
@@ -2321,6 +4649,7 @@ namespace bpkg
//
shared_ptr<selected_package> sp;
bool patch (false);
+ bool deorphan (false);
if (ap == nullptr)
{
@@ -2360,12 +4689,13 @@ namespace bpkg
lazy_shared_ptr<repository_fragment> root (*pdb, empty_string);
- // Either get the user-specified version or the latest allowed
- // for a source code package. For a system package we will try
- // to find the available package that matches the user-specified
- // system version (preferable for the configuration negotiation
- // machinery) and, if fail, fallback to picking the latest one
- // just to make sure the package is recognized.
+ // Get the user-specified version, the latest allowed version,
+ // or the orphan best match for a source code package. For a
+ // system package we will try to find the available package that
+ // matches the user-specified system version (preferable for the
+ // configuration negotiation machinery) and, if fail, fallback
+ // to picking the latest one just to make sure the package is
+ // recognized.
//
optional<version_constraint> c;
@@ -2395,10 +4725,48 @@ namespace bpkg
else if (!sys || !wildcard (*pa.constraint))
c = pa.constraint;
- auto rp (find_available_one (pa.name, c, root));
+ if (pa.options.deorphan ())
+ {
+ if (!sys)
+ {
+ if (sp == nullptr)
+ sp = pdb->find<selected_package> (pa.name);
- if (rp.first == nullptr && sys && c)
- rp = find_available_one (pa.name, nullopt, root);
+ if (sp != nullptr && orphan_package (*pdb, sp))
+ deorphan = true;
+ }
+
+ // If the package is not an orphan, its version is not
+ // constrained and upgrade/patch is not requested, then just
+ // skip the package.
+ //
+ if (!deorphan &&
+ !pa.constraint &&
+ !pa.options.upgrade () &&
+ !pa.options.patch ())
+ {
+ ++i;
+ continue;
+ }
+ }
+
+ pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>> rp (
+ deorphan &&
+ !pa.constraint &&
+ !pa.options.upgrade () &&
+ !pa.options.patch ()
+ ? find_orphan_match (sp, root)
+ : find_available_one (pa.name, c, root));
+
+ if (rp.first == nullptr && sys)
+ {
+ available_packages aps (
+ find_available_all (repo_configs, pa.name));
+
+ if (!aps.empty ())
+ rp = move (aps.front ());
+ }
ap = move (rp.first);
af = move (rp.second);
@@ -2418,22 +4786,55 @@ namespace bpkg
continue;
// Save (both packages to hold and dependencies) as dependents for
- // recursive upgrade.
+ // recursive upgrade/deorphaning.
//
{
- optional<bool> u;
- optional<bool> r;
+ // Recursive/immediate upgrade/patch.
+ //
+ optional<bool> r; // true -- recursive, false -- immediate.
+ optional<bool> u; // true -- upgrade, false -- patch.
+
+ // Recursive/immediate deorphaning.
+ //
+ optional<bool> d; // true -- recursive, false -- immediate.
const auto& po (pa.options);
- if (po.upgrade_immediate ()) { u = true; r = false; }
- else if (po.upgrade_recursive ()) { u = true; r = true; }
- else if ( po.patch_immediate ()) { u = false; r = false; }
- else if ( po.patch_recursive ()) { u = false; r = true; }
- else if ( po.immediate ()) { u = po.upgrade (); r = false; }
- else if ( po.recursive ()) { u = po.upgrade (); r = true; }
+ // Note that, for example, --upgrade-immediate wins over the
+ // --upgrade --recursive options pair.
+ //
+ if (po.immediate ())
+ {
+ if (po.upgrade () || po.patch ())
+ {
+ r = false;
+ u = po.upgrade ();
+ }
- if (r)
+ if (po.deorphan ())
+ d = false;
+ }
+ else if (po.recursive ())
+ {
+ if (po.upgrade () || po.patch ())
+ {
+ r = true;
+ u = po.upgrade ();
+ }
+
+ if (po.deorphan ())
+ d = true;
+ }
+
+ if (po.upgrade_immediate ()) { u = true; r = false; }
+ else if (po.upgrade_recursive ()) { u = true; r = true; }
+ else if ( po.patch_immediate ()) { u = false; r = false; }
+ else if ( po.patch_recursive ()) { u = false; r = true; }
+
+ if (po.deorphan_immediate ()) { d = false; }
+ else if (po.deorphan_recursive ()) { d = true; }
+
+ if (r || d)
{
l4 ([&]{trace << "stash recursive package " << arg_string (pa);});
@@ -2442,7 +4843,9 @@ namespace bpkg
// configuration.
//
if (pdb != nullptr)
- rec_pkgs.push_back (recursive_package {*pdb, pa.name, *u, *r});
+ rec_pkgs.push_back (recursive_package {*pdb, pa.name,
+ r, u && *u,
+ d});
}
}
@@ -2454,52 +4857,70 @@ namespace bpkg
bool sys (arg_sys (pa));
- // Make sure that the package is known.
- //
- auto apr (find_available (repo_configs,
- pa.name,
- !sys ? pa.constraint : nullopt));
+ if (pdb != nullptr)
+ sp = pdb->find<selected_package> (pa.name);
- if (apr.empty ())
+ // Make sure that the package is known. Only allow to unhold an
+ // unknown orphaned selected package (with the view that there is
+ // a good chance it will get dropped; and if not, such an unhold
+ // should be harmless).
+ //
+ if (!existing &&
+ find_available (repo_configs,
+ pa.name,
+ !sys ? pa.constraint : nullopt).empty ())
{
- string n (arg_string (pa, false /* options */));
-
- diag_record dr (fail);
- dr << "unknown package " << n;
- if (sys)
+ // Don't fail if the selected package is held and satisfies the
+ // constraints, if specified. Note that we may still fail later
+ // with the "not available from its dependents' repositories"
+ // error if the dependency is requested to be deorphaned and all
+ // its dependents are orphaned.
+ //
+ if (!(sp != nullptr &&
+ sp->hold_package &&
+ (!pa.constraint || satisfies (sp->version, pa.constraint))))
{
- // Feels like we can't end up here if the version was specified
- // explicitly.
- //
- dr << info << "consider specifying " << n << "/*";
+ string n (arg_string (pa, false /* options */));
+
+ diag_record dr (fail);
+ dr << "unknown package " << n;
+ if (sys)
+ {
+ // Feels like we can't end up here if the version was specified
+ // explicitly.
+ //
+ dr << info << "consider specifying " << n << "/*";
+ }
+ else
+ check_any_available (repo_configs, t, &dr);
}
- else
- check_any_available (repo_configs, t, &dr);
}
if (pdb != nullptr)
- {
- // Save before the name move.
- //
- sp = pdb->find<selected_package> (pa.name);
-
pkg_confs.emplace_back (*pdb, pa.name);
- }
+
+ bool hold_version (pa.constraint.has_value ());
dep_pkgs.push_back (
dependency_package {pdb,
move (pa.name),
move (pa.constraint),
+ hold_version,
move (sp),
sys,
- pa.options.patch (),
+ existing,
+ (pa.options.upgrade () || pa.options.patch ()
+ ? pa.options.upgrade ()
+ : optional<bool> ()),
+ pa.options.deorphan (),
pa.options.keep_out (),
pa.options.disfigure (),
(pa.options.checkout_root_specified ()
? move (pa.options.checkout_root ())
: optional<dir_path> ()),
pa.options.checkout_purge (),
- move (pa.config_vars)});
+ move (pa.config_vars),
+ pa.system_status});
continue;
}
@@ -2559,17 +4980,18 @@ namespace bpkg
//
if (pa.constraint)
{
- for (;;)
+ for (;;) // Breakout loop.
{
if (ap != nullptr) // Must be that version, see above.
break;
// Otherwise, our only chance is that the already selected object
- // satisfies the version constraint.
+ // satisfies the version constraint, unless we are deorphaning.
//
- if (sp != nullptr &&
- !sp->system () &&
- satisfies (sp->version, pa.constraint))
+ if (sp != nullptr &&
+ !sp->system () &&
+ satisfies (sp->version, pa.constraint) &&
+ !deorphan)
break; // Derive ap from sp below.
found = false;
@@ -2589,14 +5011,17 @@ namespace bpkg
// we have a newer version, we treat it as an upgrade request;
// otherwise, why specify the package in the first place? We just
// need to check if what we already have is "better" (i.e.,
- // newer).
+ // newer), unless we are deorphaning.
//
- if (sp != nullptr && !sp->system () && ap->version < sp->version)
+ if (sp != nullptr &&
+ !sp->system () &&
+ ap->version < sp->version &&
+ !deorphan)
ap = nullptr; // Derive ap from sp below.
}
else
{
- if (sp == nullptr || sp->system ())
+ if (sp == nullptr || sp->system () || deorphan)
found = false;
// Otherwise, derive ap from sp below.
@@ -2673,8 +5098,16 @@ namespace bpkg
bool keep_out (pa.options.keep_out () &&
sp != nullptr && sp->external ());
+ bool replace ((existing && sp != nullptr) || deorphan);
+
// Finally add this package to the list.
//
+ optional<bool> upgrade (sp != nullptr &&
+ !pa.constraint &&
+ (pa.options.upgrade () || pa.options.patch ())
+ ? pa.options.upgrade ()
+ : optional<bool> ());
+
// @@ Pass pa.configure_only() when support for package-specific
// --configure-only is added.
//
@@ -2701,9 +5134,11 @@ namespace bpkg
: optional<dir_path> ()),
pa.options.checkout_purge (),
move (pa.config_vars),
- {package_key {mdb, ""}}, // Required by (command line).
+ upgrade,
+ deorphan,
+ {cmd_line}, // Required by (command line).
false, // Required by dependents.
- 0}; // State flags.
+ replace ? build_package::build_replace : uint16_t (0)};
l4 ([&]{trace << "stash held package "
<< p.available_name_version_db ();});
@@ -2715,7 +5150,7 @@ namespace bpkg
//
if (pa.constraint)
p.constraints.emplace_back (
- mdb, "command line", move (*pa.constraint));
+ move (*pa.constraint), cmd_line.db, cmd_line.name.string ());
pkg_confs.emplace_back (p.db, p.name ());
@@ -2730,7 +5165,7 @@ namespace bpkg
// command line option to enable this behavior.
//
if (hold_pkgs.empty () && dep_pkgs.empty () &&
- (o.upgrade () || o.patch ()))
+ (o.upgrade () || o.patch () || o.deorphan ()))
{
for (database& cdb: current_configs)
{
@@ -2764,7 +5199,26 @@ namespace bpkg
continue;
}
- auto apr (find_available_one (name, pc, root));
+ bool deorphan (false);
+
+ if (o.deorphan ())
+ {
+ // If the package is not an orphan and upgrade/patch is not
+ // requested, then just skip the package.
+ //
+ if (orphan_package (cdb, sp))
+ deorphan = true;
+ else if (!o.upgrade () && !o.patch ())
+ continue;
+ }
+
+ // In the deorphan mode with no upgrade/patch requested pick the
+ // version that matches the orphan best. Otherwise, pick the patch
+ // or the latest available version, as requested.
+ //
+ auto apr (deorphan && !o.upgrade () && !o.patch ()
+ ? find_orphan_match (sp, root)
+ : find_available_one (name, pc, root));
shared_ptr<available_package> ap (move (apr.first));
if (ap == nullptr || ap->stub ())
@@ -2772,11 +5226,13 @@ namespace bpkg
diag_record dr (fail);
dr << name << " is not available";
- if (ap != nullptr)
+ if (ap != nullptr) // Stub?
+ {
dr << " in source" <<
info << "consider building it as "
- << package_string (name, version (), true /* system */)
- << " if it is available from the system";
+ << package_string (name, version (), true /* system */)
+ << " if it is available from the system";
+ }
// Let's help the new user out here a bit.
//
@@ -2793,40 +5249,53 @@ namespace bpkg
//
build_package p {
build_package::build,
- cdb,
- move (sp),
- move (ap),
- move (apr.second),
- nullopt, // Dependencies.
- nullopt, // Dependencies alternatives.
- nullopt, // Package skeleton.
- nullopt, // Postponed dependency alternatives.
- false, // Recursive collection.
- true, // Hold package.
- false, // Hold version.
- {}, // Constraints.
- false, // System package.
- keep_out,
- o.disfigure (),
- false, // Configure-only.
- nullopt, // Checkout root.
- false, // Checkout purge.
- strings (), // Configuration variables.
- {package_key {mdb, ""}}, // Required by (command line).
- false, // Required by dependents.
- 0}; // State flags.
+ cdb,
+ move (sp),
+ move (ap),
+ move (apr.second),
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ true, // Hold package.
+ false, // Hold version.
+ {}, // Constraints.
+ false, // System package.
+ keep_out,
+ o.disfigure (),
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ (o.upgrade () || o.patch ()
+ ? o.upgrade ()
+ : optional<bool> ()),
+ deorphan,
+ {cmd_line}, // Required by (command line).
+ false, // Required by dependents.
+ deorphan ? build_package::build_replace : uint16_t (0)};
l4 ([&]{trace << "stash held package "
<< p.available_name_version_db ();});
hold_pkgs.push_back (move (p));
- // If there are also -i|-r, then we are also upgrading dependencies
- // of all held packages.
+ // If there are also -i|-r, then we are also upgrading and/or
+ // deorphaning dependencies of all held packages.
//
if (o.immediate () || o.recursive ())
- rec_pkgs.push_back (
- recursive_package {cdb, name, o.upgrade (), o.recursive ()});
+ {
+ rec_pkgs.push_back (recursive_package {
+ cdb, name,
+ (o.upgrade () || o.patch ()
+ ? o.recursive ()
+ : optional<bool> ()),
+ o.upgrade (),
+ (o.deorphan ()
+ ? o.recursive ()
+ : optional<bool> ())});
+ }
}
}
}
@@ -2888,6 +5357,9 @@ namespace bpkg
// dependencies to up/down-grade, and unused dependencies to drop. We call
// this the plan.
//
+ // Note: for the sake of brevity we also assume the package replacement
+ // wherever we mention the package up/down-grade in this description.
+ //
// The way we do it is tricky: we first create the plan based on build-to-
// holds (i.e., the user selected). Next, to decide whether we need to
// up/down-grade or drop any dependecies we need to take into account an
@@ -2926,6 +5398,11 @@ namespace bpkg
// grade order where any subsequent entry does not affect the decision of
// the previous ones.
//
+ // Note that we also need to rebuild the plan from scratch on adding a new
+ // up/down-grade/drop if any dependency configuration negotiation has been
+ // performed, since any package replacement may affect the already
+ // negotiated configurations.
+ //
// Package managers are an easy, already solved problem, right?
//
build_packages pkgs;
@@ -2940,13 +5417,17 @@ namespace bpkg
shared_ptr<available_package> available;
lazy_shared_ptr<bpkg::repository_fragment> repository_fragment;
- bool system;
+ bool system;
+ bool existing; // Build as an existing archive or directory.
+ optional<bool> upgrade;
+ bool deorphan;
};
vector<dep> deps;
+ existing_dependencies existing_deps;
+ deorphaned_dependencies deorphaned_deps;
replaced_versions replaced_vers;
postponed_dependencies postponed_deps;
- postponed_positions postponed_poss;
unacceptable_alternatives unacceptable_alts;
// Map the repointed dependents to the replacement flags (see
@@ -3014,12 +5495,12 @@ namespace bpkg
// during the package collection) because we want to enter them before
// collect_build_postponed() and they could be the dependents that have
// the config clauses. In a sense, change to replaced_vers,
- // postponed_deps, or postponed_poss maps should not affect the deps
+ // postponed_deps, or unacceptable_alts maps should not affect the deps
// list. But not the other way around: a dependency erased from the deps
// list could have caused an entry in the replaced_vers, postponed_deps,
- // and/or postponed_poss maps. And so we clean replaced_vers,
- // postponed_deps, and postponed_poss on scratch_exe (scratch during the
- // plan execution).
+ // and/or unacceptable_alts maps. And so we clean replaced_vers,
+ // postponed_deps, and unacceptable_alts on scratch_exe (scratch during
+ // the plan execution).
//
for (bool refine (true), scratch_exe (true), scratch_col (false);
refine; )
@@ -3133,8 +5614,17 @@ namespace bpkg
// Also, if a dependency package already has selected package that
// is held, then we need to unhold it.
//
- auto enter = [&mdb, &pkgs] (database& db, const dependency_package& p)
+ auto enter = [&pkgs, &cmd_line] (database& db,
+ const dependency_package& p)
{
+ // Note that we don't set the upgrade and deorphan flags based on
+ // the --upgrade, --patch, and --deorphan options since an option
+ // presense doesn't necessarily means that the respective flag needs
+ // to be set (the package may not be selected, may not be patchable
+ // and/or an orphan, etc). The proper flags will be provided by
+ // evaluate_dependency() if/when any upgrade/deorphan recommendation
+ // is given.
+ //
build_package bp {
nullopt, // Action.
db,
@@ -3147,7 +5637,7 @@ namespace bpkg
nullopt, // Postponed dependency alternatives.
false, // Recursive collection.
false, // Hold package.
- p.constraint.has_value (), // Hold version.
+ p.hold_version,
{}, // Constraints.
p.system,
p.keep_out,
@@ -3156,13 +5646,16 @@ namespace bpkg
p.checkout_root,
p.checkout_purge,
p.config_vars,
- {package_key {mdb, ""}}, // Required by (command line).
+ nullopt, // Upgrade.
+ false, // Deorphan.
+ {cmd_line}, // Required by (command line).
false, // Required by dependents.
0}; // State flags.
if (p.constraint)
- bp.constraints.emplace_back (
- mdb, "command line", *p.constraint);
+ bp.constraints.emplace_back (*p.constraint,
+ cmd_line.db,
+ cmd_line.name.string ());
pkgs.enter (p.name, move (bp));
};
@@ -3176,12 +5669,11 @@ namespace bpkg
// The system package may only have an exact/wildcard version
// specified.
//
- add_system_package (db,
+ add_system_package (&db,
p.name,
- (p.constraint
- ? *p.constraint->min_version
- : wildcard_version));
-
+ p.constraint,
+ p.system_status,
+ nullptr /* stubs */);
enter (db, p);
};
@@ -3228,10 +5720,13 @@ namespace bpkg
}
});
- postponed_packages postponed_repo;
- postponed_packages postponed_alts;
- postponed_configurations postponed_cfgs;
- strings postponed_cfgs_history;
+ postponed_packages postponed_repo;
+ postponed_packages postponed_alts;
+ postponed_packages postponed_recs;
+ postponed_existing_dependencies postponed_edeps;
+ postponed_configurations postponed_cfgs;
+ strings postponed_cfgs_history;
+ unsatisfied_dependents unsatisfied_depts;
try
{
@@ -3243,13 +5738,14 @@ namespace bpkg
{
replaced_vers.clear ();
postponed_deps.clear ();
- postponed_poss.clear ();
unacceptable_alts.clear ();
scratch_exe = false;
}
- else if (scratch_col)
+ else
{
+ assert (scratch_col); // See the scratch definition above.
+
// Reset to detect bogus entries.
//
for (auto& rv: replaced_vers)
@@ -3261,12 +5757,6 @@ namespace bpkg
pd.second.with_config = false;
}
- for (auto& pd: postponed_poss)
- {
- pd.second.skipped = false;
- pd.second.reevaluated = false;
- }
-
scratch_col = false;
}
@@ -3299,14 +5789,8 @@ namespace bpkg
// specify packages on the command line does not matter).
//
for (const build_package& p: hold_pkgs)
- pkgs.collect_build (o,
- p,
- find_prereq_database,
- rpt_depts,
- add_priv_cfg,
- true /* initial_collection */,
- replaced_vers,
- postponed_cfgs);
+ pkgs.collect_build (
+ o, p, replaced_vers, postponed_cfgs, unsatisfied_depts);
// Collect all the prerequisites of the user selection.
//
@@ -3319,26 +5803,7 @@ namespace bpkg
auto i (postponed_deps.find (pk));
- if (i == postponed_deps.end ())
- {
- pkgs.collect_build_prerequisites (
- o,
- p.db,
- p.name (),
- find_prereq_database,
- rpt_depts,
- add_priv_cfg,
- true /* initial_collection */,
- replaced_vers,
- postponed_repo,
- postponed_alts,
- 0 /* max_alt_index */,
- postponed_deps,
- postponed_cfgs,
- postponed_poss,
- unacceptable_alts);
- }
- else
+ if (i != postponed_deps.end ())
{
// Even though the user selection may have a configuration, we
// treat it as a dependent without any configuration because
@@ -3349,6 +5814,37 @@ namespace bpkg
l5 ([&]{trace << "dep-postpone user-specified " << pk;});
}
+ else
+ {
+ const postponed_configuration* pcfg (
+ postponed_cfgs.find_dependency (pk));
+
+ if (pcfg != nullptr)
+ {
+ l5 ([&]{trace << "dep-postpone user-specified " << pk
+ << " since already in cluster " << *pcfg;});
+ }
+ else
+ {
+ pkgs.collect_build_prerequisites (
+ o,
+ p.db,
+ p.name (),
+ find_prereq_database,
+ add_priv_cfg,
+ rpt_depts,
+ replaced_vers,
+ postponed_repo,
+ postponed_alts,
+ 0 /* max_alt_index */,
+ postponed_recs,
+ postponed_edeps,
+ postponed_deps,
+ postponed_cfgs,
+ unacceptable_alts,
+ unsatisfied_depts);
+ }
+ }
}
// Note that we need to collect unheld after prerequisites, not to
@@ -3387,10 +5883,12 @@ namespace bpkg
replaced_vers,
postponed_repo,
postponed_alts,
+ postponed_recs,
+ postponed_edeps,
postponed_deps,
postponed_cfgs,
- postponed_poss,
unacceptable_alts,
+ unsatisfied_depts,
find_prereq_database,
add_priv_cfg);
}
@@ -3427,7 +5925,7 @@ namespace bpkg
// Marking upgraded dependencies as "required by command line"
// may seem redundant as they should already be pre-entered as
// such (see above). But remember dependencies upgraded with
- // -i|-r? Note that the required_by data member should never be
+ // -i|-r? Note that the required_by data member should never be
// empty, as it is used in prompts/diagnostics.
//
build_package p {
@@ -3451,67 +5949,104 @@ namespace bpkg
nullopt, // Checkout root.
false, // Checkout purge.
strings (), // Configuration variables.
- {package_key {mdb, ""}}, // Required by (command line).
+ d.upgrade,
+ d.deorphan,
+ {cmd_line}, // Required by (command line).
false, // Required by dependents.
- 0}; // State flags.
+ (d.existing || d.deorphan
+ ? build_package::build_replace
+ : uint16_t (0))};
- build_package_refs dep_chain;
+ package_key pk {ddb, d.name};
- // Note: recursive.
+ // Similar to the user-selected packages, collect non-
+ // recursively the dependencies for which recursive collection
+ // is postponed (see above for details).
//
- pkgs.collect_build (o,
- move (p),
- find_prereq_database,
- rpt_depts,
- add_priv_cfg,
- true /* initial_collection */,
- replaced_vers,
- postponed_cfgs,
- &dep_chain,
- &postponed_repo,
- &postponed_alts,
- &postponed_deps,
- &postponed_poss,
- &unacceptable_alts);
- }
- }
+ auto i (postponed_deps.find (pk));
+ if (i != postponed_deps.end ())
+ {
+ i->second.wout_config = true;
- // Erase the bogus postponements and re-collect from scratch, if any
- // (see postponed_dependencies for details).
- //
- // Note that we used to re-collect such postponements in-place but
- // re-doing from scratch feels more correct (i.e., we may end up
- // doing it earlier which will affect dependency alternatives).
- //
- postponed_deps.cancel_bogus (trace, true /* initial_collection */);
+ // Note: not recursive.
+ //
+ pkgs.collect_build (
+ o, move (p), replaced_vers, postponed_cfgs, unsatisfied_depts);
- // Now remove all the dependencies postponed during the initial
- // collection since all this information is already in
- // postponed_cfgs.
- //
- for (auto i (postponed_deps.begin ()); i != postponed_deps.end (); )
- {
- if (i->second.initial_collection)
- i = postponed_deps.erase (i);
- else
- ++i;
+ l5 ([&]{trace << "dep-postpone user-specified dependency "
+ << pk;});
+ }
+ else
+ {
+ const postponed_configuration* pcfg (
+ postponed_cfgs.find_dependency (pk));
+
+ if (pcfg != nullptr)
+ {
+ // Note: not recursive.
+ //
+ pkgs.collect_build (o,
+ move (p),
+ replaced_vers,
+ postponed_cfgs,
+ unsatisfied_depts);
+
+ l5 ([&]{trace << "dep-postpone user-specified dependency "
+ << pk << " since already in cluster "
+ << *pcfg;});
+ }
+ else
+ {
+ build_package_refs dep_chain;
+
+ // Note: recursive.
+ //
+ pkgs.collect_build (o,
+ move (p),
+ replaced_vers,
+ postponed_cfgs,
+ unsatisfied_depts,
+ &dep_chain,
+ find_prereq_database,
+ add_priv_cfg,
+ &rpt_depts,
+ &postponed_repo,
+ &postponed_alts,
+ &postponed_recs,
+ &postponed_edeps,
+ &postponed_deps,
+ &unacceptable_alts);
+ }
+ }
+ }
}
// Handle the (combined) postponed collection.
//
- if (!postponed_repo.empty () ||
- !postponed_alts.empty () ||
- postponed_deps.has_bogus () ||
+ if (find_if (postponed_recs.begin (), postponed_recs.end (),
+ [] (const build_package* p)
+ {
+ // Note that we check for the dependencies presence
+ // rather than for the recursive_collection flag
+ // (see collect_build_postponed() for details).
+ //
+ return !p->dependencies;
+ }) != postponed_recs.end () ||
+ !postponed_repo.empty () ||
+ !postponed_alts.empty () ||
+ postponed_deps.has_bogus () ||
!postponed_cfgs.empty ())
pkgs.collect_build_postponed (o,
replaced_vers,
postponed_repo,
postponed_alts,
+ postponed_recs,
+ postponed_edeps,
postponed_deps,
postponed_cfgs,
postponed_cfgs_history,
- postponed_poss,
unacceptable_alts,
+ unsatisfied_depts,
find_prereq_database,
rpt_depts,
add_priv_cfg);
@@ -3520,12 +6055,6 @@ namespace bpkg
// (see replaced_versions for details).
//
replaced_vers.cancel_bogus (trace, true /* scratch */);
-
- // Erase the bogus existing dependent re-evaluation postponements
- // and re-collect from scratch, if any (see postponed_positions for
- // details).
- //
- postponed_poss.cancel_bogus (trace);
}
catch (const scratch_collection& e)
{
@@ -3556,6 +6085,9 @@ namespace bpkg
continue;
}
+ set<package_key> depts (
+ pkgs.collect_dependents (rpt_depts, unsatisfied_depts));
+
// Now that we have collected all the package versions that we need to
// build, arrange them in the "dependency order", that is, with every
// package on the list only possibly depending on the ones after
@@ -3566,29 +6098,33 @@ namespace bpkg
// dependencies between the specified packages).
//
// The order of dependency upgrades/downgrades/drops is not really
- // deterministic. We, however, do them before hold_pkgs so that they
- // appear (e.g., on the plan) last.
+ // deterministic. We, however, do upgrades/downgrades before hold_pkgs
+ // so that they appear (e.g., on the plan) after the packages being
+ // built to hold. We handle drops last, though, so that the unused
+ // packages are likely get purged before the package fetches, so that
+ // the disk space they occupy can be reused.
//
for (const dep& d: deps)
- pkgs.order (d.db,
- d.name,
- nullopt /* buildtime */,
- find_prereq_database,
- false /* reorder */);
+ {
+ if (d.available != nullptr)
+ pkgs.order (d.db,
+ d.name,
+ find_prereq_database,
+ false /* reorder */);
+ }
for (const build_package& p: reverse_iterate (hold_pkgs))
- pkgs.order (p.db,
- p.name (),
- nullopt /* buildtime */,
- find_prereq_database);
+ pkgs.order (p.db, p.name (), find_prereq_database);
for (const auto& rd: rpt_depts)
pkgs.order (rd.first.db,
rd.first.name,
- nullopt /* buildtime */,
find_prereq_database,
- false /* reorder */);
+ false /* reorder */);
+ // Order the existing dependents which have participated in
+ // negotiation of the configuration of their dependencies.
+ //
for (const postponed_configuration& cfg: postponed_cfgs)
{
for (const auto& d: cfg.dependents)
@@ -3596,23 +6132,27 @@ namespace bpkg
if (d.second.existing)
{
const package_key& p (d.first);
-
- pkgs.order (p.db,
- p.name,
- nullopt /* buildtime */,
- find_prereq_database);
+ pkgs.order (p.db, p.name, find_prereq_database);
}
}
}
- // Collect and order all the dependents that we will need to
- // reconfigure because of the up/down-grades of packages that are now
- // on the list.
+ // Order the existing dependents whose dependencies are being
+ // up/down-graded or reconfigured.
//
- pkgs.collect_order_dependents (rpt_depts);
+ for (const package_key& p: depts)
+ pkgs.order (p.db, p.name, find_prereq_database, false /* reorder */);
- // And, finally, make sure all the packages that we need to unhold
- // are on the list.
+ // Order the re-collected packages (deviated dependents, etc).
+ //
+ for (build_package* p: postponed_recs)
+ {
+ assert (p->recursive_collection);
+
+ pkgs.order (p->db, p->name (), find_prereq_database);
+ }
+
+ // Make sure all the packages that we need to unhold are on the list.
//
for (const dependency_package& p: dep_pkgs)
{
@@ -3626,9 +6166,8 @@ namespace bpkg
if (sp != nullptr && sp->hold_package)
pkgs.order (db,
p.name,
- nullopt /* buildtime */,
find_prereq_database,
- false /* reorder */);
+ false /* reorder */);
};
if (p.db != nullptr)
@@ -3642,6 +6181,43 @@ namespace bpkg
}
}
+ // And, finally, order the package drops.
+ //
+ for (const dep& d: deps)
+ {
+ if (d.available == nullptr)
+ pkgs.order (d.db,
+ d.name,
+ find_prereq_database,
+ false /* reorder */);
+ }
+
+ // Make sure all the postponed dependencies of existing dependents
+ // have been collected and fail if that's not the case.
+ //
+ for (const auto& pd: postponed_edeps)
+ {
+ const build_package* p (pkgs.entered_build (pd.first));
+ assert (p != nullptr && p->available != nullptr);
+
+ if (!p->recursive_collection)
+ {
+ // Feels like this shouldn't happen but who knows.
+ //
+ diag_record dr (fail);
+ dr << "package " << p->available_name_version_db () << " is not "
+ << "built due to its configured dependents deviation in "
+ << "dependency resolution" <<
+ info << "deviated dependents:";
+
+ for (const package_key& d: pd.second)
+ dr << ' ' << d;
+
+ dr << info << "please report in "
+ << "https://github.com/build2/build2/issues/302";
+ }
+ }
+
#ifndef NDEBUG
pkgs.verify_ordering ();
#endif
@@ -3690,7 +6266,7 @@ namespace bpkg
changed = execute_plan (o,
bl,
- true /* simulate */,
+ &unsatisfied_depts,
find_prereq_database);
if (changed)
@@ -3714,20 +6290,31 @@ namespace bpkg
// value covers both the "no change is required" and the "no
// recommendation available" cases.
//
- auto eval_dep = [&dep_pkgs, &rec_pkgs, &o] (
- database& db,
- const shared_ptr<selected_package>& sp,
- bool ignore_unsatisfiable = true) -> optional<evaluate_result>
+ auto eval_dep = [&dep_pkgs,
+ &rec_pkgs,
+ &o,
+ &existing_deps,
+ &deorphaned_deps,
+ &pkgs,
+ cache = upgrade_dependencies_cache {}] (
+ database& db,
+ const shared_ptr<selected_package>& sp,
+ bool ignore_unsatisfiable = true) mutable
+ -> optional<evaluate_result>
{
optional<evaluate_result> r;
// See if there is an optional dependency upgrade recommendation.
//
if (!sp->hold_package)
- r = evaluate_dependency (db,
+ r = evaluate_dependency (o,
+ db,
sp,
dep_pkgs,
o.no_move (),
+ existing_deps,
+ deorphaned_deps,
+ pkgs,
ignore_unsatisfiable);
// If none, then see for the recursive dependency upgrade
@@ -3737,7 +6324,15 @@ namespace bpkg
// configured as such for a reason.
//
if (!r && !sp->system () && !rec_pkgs.empty ())
- r = evaluate_recursive (db, sp, rec_pkgs, ignore_unsatisfiable);
+ r = evaluate_recursive (o,
+ db,
+ sp,
+ rec_pkgs,
+ existing_deps,
+ deorphaned_deps,
+ pkgs,
+ ignore_unsatisfiable,
+ cache);
// Translate the "no change" result to nullopt.
//
@@ -3772,11 +6367,12 @@ namespace bpkg
bool s (false);
database& db (i->db);
+ const package_name& nm (i->name);
// Here we scratch if evaluate changed its mind or if the resulting
// version doesn't match what we expect it to be.
//
- if (auto sp = db.find<selected_package> (i->name))
+ if (auto sp = db.find<selected_package> (nm))
{
const version& dv (target_version (db, i->available, i->system));
@@ -3792,12 +6388,25 @@ namespace bpkg
if (s)
{
scratch_exe = true; // Rebuild the plan from scratch.
+
+ package_key pk (db, nm);
+
+ auto j (find (existing_deps.begin (), existing_deps.end (), pk));
+ if (j != existing_deps.end ())
+ existing_deps.erase (j);
+
+ deorphaned_deps.erase (pk);
+
i = deps.erase (i);
}
else
++i;
}
+ if (scratch_exe)
+ l5 ([&]{trace << "one of dependency evaluation decisions has "
+ << "changed, re-collecting from scratch";});
+
// If the execute_plan() call was noop, there are no user expectations
// regarding any dependency, and no upgrade is requested, then the
// only possible refinement outcome can be recommendations to drop
@@ -3825,8 +6434,13 @@ namespace bpkg
// make sure that the unsatisfiable dependency, if left, is
// reported.
//
- auto need_refinement = [&eval_dep, &deps, &rec_pkgs, &dep_dbs, &o] (
- bool diag = false) -> bool
+ auto need_refinement = [&eval_dep,
+ &deps,
+ &rec_pkgs,
+ &dep_dbs,
+ &existing_deps,
+ &deorphaned_deps,
+ &o] (bool diag = false) -> bool
{
// Examine the new dependency set for any up/down-grade/drops.
//
@@ -3857,11 +6471,25 @@ namespace bpkg
continue;
if (!diag)
+ {
deps.push_back (dep {er->db,
sp->name,
move (er->available),
move (er->repository_fragment),
- er->system});
+ er->system,
+ er->existing,
+ er->upgrade,
+ er->orphan.has_value ()});
+
+ if (er->existing)
+ existing_deps.emplace_back (er->db, sp->name);
+
+ if (er->orphan)
+ {
+ deorphaned_deps[package_key (er->db, sp->name)] =
+ move (*er->orphan);
+ }
+ }
r = true;
}
@@ -3873,8 +6501,19 @@ namespace bpkg
refine = need_refinement ();
+ // If no further refinement is necessary, then perform the
+ // diagnostics run. Otherwise, if any dependency configuration
+ // negotiation has been performed during the current plan refinement
+ // iteration, then rebuild the plan from scratch (see above for
+ // details). Also rebuild it from from scratch if any unsatisfied
+ // dependents have been ignored, since their unsatisfied constraints
+ // are now added to the dependencies' build_package::constraints
+ // lists.
+ //
if (!refine)
need_refinement (true /* diag */);
+ else if (!postponed_cfgs.empty () || !unsatisfied_depts.empty ())
+ scratch_exe = true;
}
// Note that we prevent building multiple instances of the same
@@ -3970,10 +6609,10 @@ namespace bpkg
// that the build-time dependency configuration type (host or
// build2) differs from the dependent configuration type (target
// is a common case) and doesn't work well, for example, for the
- // self-hosted configurations. For them it can fail
- // erroneously. We can potentially fix that by additionally
- // storing the build-time flag for a prerequisite. However, let's
- // first see if it ever becomes a problem.
+ // self-hosted configurations. For them it can fail erroneously.
+ // We can potentially fix that by additionally storing the
+ // build-time flag for a prerequisite. However, let's first see if
+ // it ever becomes a problem.
//
prerequisites r;
const package_prerequisites& prereqs (sp->prerequisites);
@@ -4257,6 +6896,190 @@ namespace bpkg
t.commit ();
}
+
+ if (!refine)
+ {
+ // Cleanup the package build collecting state, preparing for the
+ // re-collection from the very beginning.
+ //
+ auto prepare_recollect = [&refine,
+ &scratch_exe,
+ &deps,
+ &existing_deps,
+ &deorphaned_deps] ()
+ {
+ refine = true;
+ scratch_exe = true;
+
+ deps.clear ();
+ existing_deps.clear ();
+ deorphaned_deps.clear ();
+ };
+
+ // Issue diagnostics and fail if any existing dependents are not
+ // satisfied with their dependencies.
+ //
+ // But first, try to resolve the first encountered unsatisfied
+ // constraint by replacing the collected unsatisfactory dependency
+ // or some of its dependents with some other available package
+ // version. This version, while not being the best possible choice,
+ // must be satisfactory for all its new and existing dependents. If
+ // succeed, punch the replacement version into the command line and
+ // recollect from the very beginning (see unsatisfied_dependents for
+ // details).
+ //
+ if (!unsatisfied_depts.empty ())
+ {
+ if (!cmdline_refine_index) // Not command line adjustments refinement?
+ {
+ const unsatisfied_dependent& dpt (unsatisfied_depts.front ());
+
+ assert (!dpt.ignored_constraints.empty ());
+
+ const ignored_constraint& ic (dpt.ignored_constraints.front ());
+
+ const build_package* p (pkgs.entered_build (ic.dependency));
+ assert (p != nullptr); // The dependency must be collected.
+
+ l5 ([&]{trace << "try to replace unsatisfactory dependency "
+ << p->available_name_version_db () << " with some "
+ << "other version";});
+
+ optional<cmdline_adjustment> a;
+ vector<package_key> unsatisfied_dpts;
+ set<const build_package*> visited_dpts;
+
+ if ((a = try_replace_dependency (o,
+ *p,
+ pkgs,
+ hold_pkgs,
+ dep_pkgs,
+ cmdline_adjs,
+ unsatisfied_dpts,
+ "unsatisfactory dependency")) ||
+ (a = try_replace_dependent (o,
+ *p,
+ &ic.unsatisfied_constraints,
+ pkgs,
+ cmdline_adjs,
+ unsatisfied_dpts,
+ hold_pkgs,
+ dep_pkgs,
+ visited_dpts)) ||
+ !cmdline_adjs.empty ())
+ {
+ if (a)
+ {
+ cmdline_adjs.push (move (*a));
+ }
+ else
+ {
+ cmdline_adjustment a (cmdline_adjs.pop ());
+
+ l5 ([&]{trace << "cannot replace any package, rolling back "
+ << "latest command line adjustment ("
+ << cmdline_adjs.to_string (a) << ')';});
+ }
+
+ prepare_recollect ();
+ }
+ else
+ unsatisfied_depts.diag (pkgs); // Issue the diagnostics and fail.
+ }
+ else // We are in the command line adjustments refinement cycle.
+ {
+ // Since we have failed to collect, then the currently dropped
+ // command line adjustment is essential. Thus, push it back to
+ // the stack, drop the next one, and retry. If this is the last
+ // adjustment in the stack, then we assume that no further
+ // refinement is possible and we just recollect, assuming that
+ // this recollection will be successful.
+ //
+ assert (cmdline_refine_adjustment); // Wouldn't be here otherwise.
+
+ l5 ([&]{trace << "attempt to refine command line adjustments by "
+ << "rolling back adjustment "
+ << cmdline_adjs.to_string (
+ *cmdline_refine_adjustment)
+ << " failed, pushing it back";});
+
+ cmdline_adjs.push (move (*cmdline_refine_adjustment));
+
+ // Index of the being previously dropped adjustment must be
+ // valid.
+ //
+ assert (*cmdline_refine_index != cmdline_adjs.size ());
+
+ if (++(*cmdline_refine_index) != cmdline_adjs.size ())
+ {
+ cmdline_refine_adjustment = cmdline_adjs.pop (true /* front */);
+
+ l5 ([&]{trace << "continue with command line adjustments "
+ << "refinement cycle by rolling back adjustment "
+ << cmdline_adjs.to_string (
+ *cmdline_refine_adjustment);});
+ }
+ else
+ {
+ cmdline_refine_adjustment = nullopt;
+
+ l5 ([&]{trace << "cannot further refine command line "
+ << "adjustments, performing final collection";});
+ }
+
+ prepare_recollect ();
+ }
+ }
+ //
+ // If the collection was successful, then see if we still need to
+ // perform the command line adjustments refinement.
+ //
+ else if (cmdline_adjs.tried () &&
+ (!cmdline_refine_index ||
+ *cmdline_refine_index != cmdline_adjs.size ()))
+ {
+ // If some command line adjustment is currently being dropped,
+ // that means that this adjustment is redundant.
+ //
+ bool initial (!cmdline_refine_index);
+
+ if (!initial)
+ {
+ assert (cmdline_refine_adjustment);
+
+ l5 ([&]{trace << "command line adjustment "
+ << cmdline_adjs.to_string (
+ *cmdline_refine_adjustment)
+ << " is redundant, dropping it";});
+
+ cmdline_refine_adjustment = nullopt;
+ cmdline_refine_index = nullopt;
+ }
+
+ // We cannot remove all the adjustments during the refinement.
+ // Otherwise, we shouldn't be failing in the first place.
+ //
+ assert (!cmdline_adjs.empty ());
+
+ // If there is just a single adjustment left, then there is
+ // nothing to refine anymore.
+ //
+ if (cmdline_adjs.size () != 1)
+ {
+ cmdline_refine_adjustment = cmdline_adjs.pop (true /* front */);
+ cmdline_refine_index = 0;
+
+ l5 ([&]{trace << (initial ? "start" : "re-start") << " command "
+ << "line adjustments refinement cycle by rolling "
+ << "back first adjustment ("
+ << cmdline_adjs.to_string (
+ *cmdline_refine_adjustment)
+ << ')';});
+
+ prepare_recollect ();
+ }
+ }
+ }
}
}
@@ -4274,10 +7097,11 @@ namespace bpkg
bool update_dependents (false);
// We need the plan and to ask for the user's confirmation only if some
- // implicit action (such as building prerequisite or reconfiguring
- // dependent package) is to be taken or there is a selected package which
- // version must be changed. But if the user explicitly requested it with
- // --plan, then we print it as long as it is not empty.
+ // implicit action (such as building prerequisite, reconfiguring dependent
+ // package, or installing system/distribution packages) is to be taken or
+ // there is a selected package which version must be changed. But if the
+ // user explicitly requested it with --plan, then we print it as long as
+ // it is not empty.
//
string plan;
sha256 csum;
@@ -4288,6 +7112,31 @@ namespace bpkg
o.plan_specified () ||
o.rebuild_checksum_specified ())
{
+ // Map the main system/distribution packages that need to be installed
+ // to the system packages which caused their installation (see
+ // build_package::system_install() for details).
+ //
+ using package_names = vector<reference_wrapper<const package_name>>;
+ using system_map = map<string, package_names>;
+
+ system_map sys_map;
+
+ // Iterate in the reverse order as we will do for printing the action
+ // lines. This way a sys-install action line will be printed right
+ // before the bpkg action line of a package which appears first in the
+ // sys-install action's 'required by' list.
+ //
+ for (const build_package& p: reverse_iterate (pkgs))
+ {
+ if (const system_package_status* s = p.system_install ())
+ {
+ package_names& ps (sys_map[s->system_name]);
+
+ if (find (ps.begin (), ps.end (), p.name ()) == ps.end ())
+ ps.push_back (p.name ());
+ }
+ }
+
// Start the transaction since we may query available packages for
// skeleton initializations.
//
@@ -4295,200 +7144,262 @@ namespace bpkg
bool first (true); // First entry in the plan.
- for (build_package& p: reverse_iterate (pkgs))
+ // Print the bpkg package action lines.
+ //
+ // Also print the sys-install action lines for system/distribution
+ // packages which require installation by the system package manager.
+ // Print them before the respective system package action lines, but
+ // only once per (main) system/distribution package. For example:
+ //
+ // sys-install libssl1.1/1.1.1l (required by sys:libssl, sys:libcrypto)
+ // configure sys:libssl/1.1.1 (required by foo)
+ // configure sys:libcrypto/1.1.1 (required by bar)
+ //
+ for (auto i (pkgs.rbegin ()); i != pkgs.rend (); )
{
+ build_package& p (*i);
assert (p.action);
- database& pdb (p.db);
- const shared_ptr<selected_package>& sp (p.selected);
-
string act;
- if (*p.action == build_package::drop)
+ const system_package_status* s;
+ system_map::iterator j;
+
+ if ((s = p.system_install ()) != nullptr &&
+ (j = sys_map.find (s->system_name)) != sys_map.end ())
{
- act = "drop " + sp->string (pdb) + " (unused)";
+ act = "sys-install ";
+ act += s->system_name;
+ act += '/';
+ act += s->system_version;
+ act += " (required by ";
+
+ bool first (true);
+ for (const package_name& n: j->second)
+ {
+ if (first)
+ first = false;
+ else
+ act += ", ";
+
+ act += "sys:";
+ act += n.string ();
+ }
+
+ act += ')';
+
need_prompt = true;
+
+ // Make sure that we print this sys-install action just once.
+ //
+ sys_map.erase (j);
+
+ // Note that we don't increment i in order to re-iterate this pkgs
+ // entry.
}
else
{
- // Print configuration variables.
- //
- // The idea here is to only print configuration for those packages
- // for which we call pkg_configure*() in execute_plan().
- //
- package_skeleton* cfg (nullptr);
+ ++i;
- string cause;
- if (*p.action == build_package::adjust)
- {
- assert (sp != nullptr && (p.reconfigure () || p.unhold ()));
+ database& pdb (p.db);
+ const shared_ptr<selected_package>& sp (p.selected);
- // This is a dependent needing reconfiguration.
+ if (*p.action == build_package::drop)
+ {
+ act = "drop " + sp->string (pdb) + " (unused)";
+ need_prompt = true;
+ }
+ else
+ {
+ // Print configuration variables.
//
- // This is an implicit reconfiguration which requires the plan to
- // be printed. Will flag that later when composing the list of
- // prerequisites.
+ // The idea here is to only print configuration for those packages
+ // for which we call pkg_configure*() in execute_plan().
//
- if (p.reconfigure ())
- {
- act = "reconfigure";
- cause = "dependent of";
+ package_skeleton* cfg (nullptr);
- if (!o.configure_only ())
- update_dependents = true;
- }
-
- // This is a held package needing unhold.
- //
- if (p.unhold ())
+ string cause;
+ if (*p.action == build_package::adjust)
{
- if (act.empty ())
- act = "unhold";
- else
- act += "/unhold";
- }
+ assert (sp != nullptr && (p.reconfigure () || p.unhold ()));
- act += ' ' + sp->name.string ();
-
- const string& s (pdb.string);
- if (!s.empty ())
- act += ' ' + s;
+ // This is a dependent needing reconfiguration.
+ //
+ // This is an implicit reconfiguration which requires the plan
+ // to be printed. Will flag that later when composing the list
+ // of prerequisites.
+ //
+ if (p.reconfigure ())
+ {
+ act = "reconfigure";
+ cause = "dependent of";
- // This is an adjustment and so there is no available package
- // specified for the build package object and thus the skeleton
- // cannot be present.
- //
- assert (p.available == nullptr && !p.skeleton);
+ if (!o.configure_only ())
+ update_dependents = true;
+ }
- // We shouldn't be printing configurations for plain unholds.
- //
- if (p.reconfigure ())
- {
- // Since there is no available package specified we need to find
- // it (or create a transient one).
+ // This is a held package needing unhold.
//
- cfg = &p.init_skeleton (o, find_available (o, pdb, sp));
- }
- }
- else
- {
- assert (p.available != nullptr); // This is a package build.
+ if (p.unhold ())
+ {
+ if (act.empty ())
+ act = "unhold";
+ else
+ act += "/unhold";
+ }
- // Even if we already have this package selected, we have to
- // make sure it is configured and updated.
- //
- if (sp == nullptr)
- {
- act = p.system ? "configure" : "new";
+ act += ' ' + sp->name.string ();
+
+ const string& s (pdb.string);
+ if (!s.empty ())
+ act += ' ' + s;
- // For a new non-system package the skeleton must already be
- // initialized.
+ // This is an adjustment and so there is no available package
+ // specified for the build package object and thus the skeleton
+ // cannot be present.
//
- assert (p.system || p.skeleton.has_value ());
+ assert (p.available == nullptr && !p.skeleton);
- // Initialize the skeleton if it is not initialized yet.
+ // We shouldn't be printing configurations for plain unholds.
//
- cfg = &(p.skeleton ? *p.skeleton : p.init_skeleton (o));
+ if (p.reconfigure ())
+ {
+ // Since there is no available package specified we need to
+ // find it (or create a transient one).
+ //
+ cfg = &p.init_skeleton (o,
+ true /* load_old_dependent_config */,
+ find_available (o, pdb, sp));
+ }
}
- else if (sp->version == p.available_version ())
+ else
{
- // If this package is already configured and is not part of the
- // user selection (or we are only configuring), then there is
- // nothing we will be explicitly doing with it (it might still
- // get updated indirectly as part of the user selection update).
- //
- if (!p.reconfigure () &&
- sp->state == package_state::configured &&
- (!p.user_selection () ||
- o.configure_only () ||
- p.configure_only ()))
- continue;
+ assert (p.available != nullptr); // This is a package build.
- act = p.system
- ? "reconfigure"
- : (p.reconfigure ()
- ? (o.configure_only () || p.configure_only ()
- ? "reconfigure"
- : "reconfigure/update")
- : "update");
+ bool replace (p.replace ());
- if (p.reconfigure ())
+ // Even if we already have this package selected, we have to
+ // make sure it is configured and updated.
+ //
+ if (sp == nullptr)
{
+ act = p.system ? "configure" : "new";
+
+ // For a new non-system package the skeleton must already be
+ // initialized.
+ //
+ assert (p.system || p.skeleton.has_value ());
+
// Initialize the skeleton if it is not initialized yet.
//
cfg = &(p.skeleton ? *p.skeleton : p.init_skeleton (o));
}
- }
- else
- {
- act = p.system
- ? "reconfigure"
- : sp->version < p.available_version ()
- ? "upgrade"
- : "downgrade";
-
- // For a non-system package up/downgrade the skeleton must
- // already be initialized.
- //
- assert (p.system || p.skeleton.has_value ());
+ else if (sp->version == p.available_version ())
+ {
+ // If this package is already configured and is not part of
+ // the user selection (or we are only configuring), then there
+ // is nothing we will be explicitly doing with it (it might
+ // still get updated indirectly as part of the user selection
+ // update).
+ //
+ if (!p.reconfigure () &&
+ sp->state == package_state::configured &&
+ (!p.user_selection () ||
+ o.configure_only () ||
+ p.configure_only ()))
+ continue;
- // Initialize the skeleton if it is not initialized yet.
- //
- cfg = &(p.skeleton ? *p.skeleton : p.init_skeleton (o));
+ act = p.system
+ ? "reconfigure"
+ : (p.reconfigure ()
+ ? (o.configure_only () || p.configure_only ()
+ ? (replace ? "replace" : "reconfigure")
+ : (replace ? "replace/update" : "reconfigure/update"))
+ : "update");
- need_prompt = true;
- }
+ if (p.reconfigure ())
+ {
+ // Initialize the skeleton if it is not initialized yet.
+ //
+ cfg = &(p.skeleton ? *p.skeleton : p.init_skeleton (o));
+ }
+ }
+ else
+ {
+ act += p.system
+ ? "reconfigure"
+ : (sp->version < p.available_version ()
+ ? (replace ? "replace/upgrade" : "upgrade")
+ : (replace ? "replace/downgrade" : "downgrade"));
+
+ // For a non-system package up/downgrade the skeleton must
+ // already be initialized.
+ //
+ assert (p.system || p.skeleton.has_value ());
- if (p.unhold ())
- act += "/unhold";
+ // Initialize the skeleton if it is not initialized yet.
+ //
+ cfg = &(p.skeleton ? *p.skeleton : p.init_skeleton (o));
- act += ' ' + p.available_name_version_db ();
- cause = p.required_by_dependents ? "required by" : "dependent of";
+ need_prompt = true;
+ }
- if (p.configure_only ())
- update_dependents = true;
- }
+ if (p.unhold ())
+ act += "/unhold";
- // Also list dependents for the newly built user-selected
- // dependencies.
- //
- bool us (p.user_selection ());
- string rb;
- if (!us || (!p.user_selection (hold_pkgs) && sp == nullptr))
- {
- // Note: if we are ever tempted to truncate this, watch out for
- // the --rebuild-checksum functionality which uses this. But then
- // it's not clear this information is actually important: can a
- // dependent-dependency structure change without any of the
- // package versions changing? Doesn't feel like it should.
+ act += ' ' + p.available_name_version_db ();
+ cause = p.required_by_dependents ? "required by" : "dependent of";
+
+ if (p.configure_only ())
+ update_dependents = true;
+ }
+
+ // Also list dependents for the newly built user-selected
+ // dependencies.
//
- for (const package_key& pk: p.required_by)
+ bool us (p.user_selection ());
+ string rb;
+ if (!us || (!p.user_selection (hold_pkgs) && sp == nullptr))
{
- // Skip the command-line dependent.
+ // Note: if we are ever tempted to truncate this, watch out for
+ // the --rebuild-checksum functionality which uses this. But
+ // then it's not clear this information is actually important:
+ // can a dependent-dependency structure change without any of
+ // the package versions changing? Doesn't feel like it should.
//
- if (!pk.name.empty ())
- rb += (rb.empty () ? " " : ", ") + pk.string ();
+ for (const package_version_key& pvk: p.required_by)
+ {
+ // Skip the command-line, etc dependents and don't print the
+ // package version (which is not always available; see
+ // build_package::required_by for details).
+ //
+ if (pvk.version) // Is it a real package?
+ {
+ rb += (rb.empty () ? " " : ", ") +
+ pvk.string (true /* ignore_version */);
+ }
+ }
+
+ // If not user-selected, then there should be another (implicit)
+ // reason for the action.
+ //
+ assert (!rb.empty ());
}
- // If not user-selected, then there should be another (implicit)
- // reason for the action.
- //
- assert (!rb.empty ());
- }
+ if (!rb.empty ())
+ act += " (" + cause + rb + ')';
- if (!rb.empty ())
- act += " (" + cause + rb + ')';
+ if (cfg != nullptr && !cfg->empty_print ())
+ {
+ ostringstream os;
+ cfg->print_config (os, o.print_only () ? " " : " ");
+ act += '\n';
+ act += os.str ();
+ }
- if (cfg != nullptr && !cfg->empty_print ())
- {
- ostringstream os;
- cfg->print_config (os, o.print_only () ? " " : " ");
- act += '\n';
- act += os.str ();
+ if (!us)
+ need_prompt = true;
}
-
- if (!us)
- need_prompt = true;
}
if (first)
@@ -4550,13 +7461,14 @@ namespace bpkg
// Ok, we have "all systems go". The overall action plan is as follows.
//
- // 1. disfigure up/down-graded, reconfigured [left to right]
- // 2. purge up/down-graded [right to left]
- // 3.a fetch/unpack new, up/down-graded
- // 3.b checkout new, up/down-graded
- // 4. configure all
- // 5. unhold unheld
- // 6. build user selection [right to left]
+ // 1. sys-install not installed system/distribution
+ // 2. disfigure up/down-graded, reconfigured [left to right]
+ // 3. purge up/down-graded [right to left]
+ // 4.a fetch/unpack new, up/down-graded, replaced
+ // 4.b checkout new, up/down-graded, replaced
+ // 5. configure all
+ // 6. unhold unheld
+ // 7. build user selection [right to left]
//
// Note that for some actions, e.g., purge or fetch, the order is not
// really important. We will, however, do it right to left since that
@@ -4572,7 +7484,7 @@ namespace bpkg
//
bool noop (!execute_plan (o,
pkgs,
- false /* simulate */,
+ nullptr /* simulate */,
find_prereq_database));
if (o.configure_only ())
@@ -4621,10 +7533,15 @@ namespace bpkg
database& db (p.db);
+ // Note: don't update the re-evaluated and re-collected dependents
+ // unless they are reconfigured.
+ //
if ((*p.action == build_package::adjust && p.reconfigure ()) ||
(*p.action == build_package::build &&
- (p.flags & (build_package::build_repoint |
- build_package::build_reevaluate)) != 0))
+ ((p.flags & build_package::build_repoint) != 0 ||
+ ((p.flags & (build_package::build_reevaluate |
+ build_package::build_recollect)) != 0 &&
+ p.reconfigure ()))))
upkgs.push_back (pkg_command_vars {db.config_orig,
!multi_config () && db.main (),
p.selected,
@@ -4647,13 +7564,16 @@ namespace bpkg
static bool
execute_plan (const pkg_build_options& o,
build_package_list& build_pkgs,
- bool simulate,
+ unsatisfied_dependents* simulate,
const function<find_database_function>& fdb)
{
tracer trace ("execute_plan");
l4 ([&]{trace << "simulate: " << (simulate ? "yes" : "no");});
+ // If unsatisfied dependents are specified then we are in the simulation
+ // mode and thus simulate can be used as bool.
+
bool r (false);
uint16_t verb (!simulate ? bpkg::verb : 0);
@@ -4664,6 +7584,40 @@ namespace bpkg
size_t prog_i, prog_n, prog_percent;
+ // sys-install
+ //
+ // Install the system/distribution packages required by the respective
+ // system packages (see build_package::system_install() for details).
+ //
+ if (!simulate && o.sys_install ())
+ {
+ // Collect the names of all the system packages being managed by the
+ // system package manager (as opposed to user/fallback), suppressing
+ // duplicates.
+ //
+ vector<package_name> ps;
+
+ for (build_package& p: build_pkgs)
+ {
+ if (p.system_status () &&
+ find (ps.begin (), ps.end (), p.name ()) == ps.end ())
+ {
+ ps.push_back (p.name ());
+ }
+ }
+
+ // Install the system/distribution packages.
+ //
+ if (!ps.empty ())
+ {
+ // Otherwise, we wouldn't get any package statuses.
+ //
+ assert (sys_pkg_mgr && *sys_pkg_mgr != nullptr);
+
+ (*sys_pkg_mgr)->install (ps);
+ }
+ }
+
// disfigure
//
// Note: similar code in pkg-drop.
@@ -4690,10 +7644,9 @@ namespace bpkg
// On the package reconfiguration we will try to resolve dependencies to
// the same prerequisites (see pkg_configure() for details). For that, we
- // will save prerequisites before disfiguring the dependents. Note,
- // though, that this is not required for dependents with the collected
- // prerequisites builds since the dependency alternatives are already
- // selected for them.
+ // will save prerequisites before disfiguring a package. Note, though,
+ // that this is not required for the recursively collected packages since
+ // the dependency alternatives are already selected for them.
//
map<const build_package*, vector<package_name>> previous_prerequisites;
@@ -4707,6 +7660,8 @@ namespace bpkg
database& pdb (p.db);
shared_ptr<selected_package>& sp (p.selected);
+ assert (sp != nullptr); // Shouldn't be here otherwise.
+
// Each package is disfigured in its own transaction, so that we
// always leave the configuration in a valid state.
//
@@ -4718,7 +7673,7 @@ namespace bpkg
bool external (false);
if (!simulate)
{
- external = sp != nullptr && sp->external () && p.external ();
+ external = (sp->external () && p.external ());
// Reset the keep_out flag if the package being unpacked is not
// external.
@@ -4727,31 +7682,62 @@ namespace bpkg
p.keep_out = false;
}
- if (*p.action != build_package::drop &&
- !p.dependencies &&
- !sp->prerequisites.empty ())
+ // Save prerequisites before disfiguring the package.
+ //
+ // Note that we add the prerequisites list to the map regardless if
+ // there are any prerequisites or not to, in particular, indicate the
+ // package reconfiguration mode to the subsequent
+ // pkg_configure_prerequisites() call (see the function documentation
+ // for details).
+ //
+ if (*p.action != build_package::drop && !p.dependencies && !p.system)
{
vector<package_name>& ps (previous_prerequisites[&p]);
- ps.reserve (sp->prerequisites.size ());
+ if (!sp->prerequisites.empty ())
+ {
+ ps.reserve (sp->prerequisites.size ());
- for (const auto& pp: sp->prerequisites)
- ps.push_back (pp.first.object_id ());
+ for (const auto& pp: sp->prerequisites)
+ ps.push_back (pp.first.object_id ());
+ }
}
// For an external package being replaced with another external, keep
// the configuration unless requested not to with --disfigure.
//
- // Note that for other cases the preservation of the configuration is
- // still a @@ TODO (the idea is to use our config.config.{save,load}
- // machinery). Also see "parallel" logic in package_skeleton.
+ bool disfigure (p.disfigure || !external);
+
+ // If the skeleton was not initialized yet (this is an existing package
+ // reconfiguration and no configuration was printed as a part of the
+ // plan, etc), then initialize it now. Whether the skeleton is newly
+ // initialized or not, make sure that the current configuration is
+ // loaded, unless the package project is not being disfigured.
//
+ if (*p.action != build_package::drop && !p.system)
+ {
+ if (!p.skeleton)
+ {
+ // If there is no available package specified for the build package
+ // object, then we need to find it (or create a transient one).
+ //
+ p.init_skeleton (o,
+ true /* load_old_dependent_config */,
+ (p.available == nullptr
+ ? find_available (o, pdb, sp)
+ : nullptr));
+ }
+
+ if (disfigure)
+ p.skeleton->load_old_config ();
+ }
+
// Commits the transaction.
//
pkg_disfigure (o, pdb, t,
sp,
!p.keep_out /* clean */,
- p.disfigure || !external /* disfigure */,
+ disfigure,
simulate);
r = true;
@@ -4886,9 +7872,11 @@ namespace bpkg
}
// Fetch or checkout if this is a new package or if we are
- // up/down-grading.
+ // up/down-grading or replacing.
//
- if (sp == nullptr || sp->version != p.available_version ())
+ if (sp == nullptr ||
+ sp->version != p.available_version () ||
+ p.replace ())
{
sp = nullptr; // For the directory case below.
@@ -4910,19 +7898,22 @@ namespace bpkg
for (const package_location& l: ap->locations)
{
- const repository_location& rl (
- l.repository_fragment.load ()->location);
-
- if (!basis || rl.local ()) // First or local?
+ if (!rep_masked_fragment (l.repository_fragment))
{
- basis = rl.basis ();
+ const repository_location& rl (
+ l.repository_fragment.load ()->location);
- if (rl.directory_based ())
- break;
+ if (!basis || rl.local ()) // First or local?
+ {
+ basis = rl.basis ();
+
+ if (rl.directory_based ())
+ break;
+ }
}
}
- assert (basis);
+ assert (basis); // Shouldn't be here otherwise.
// All calls commit the transaction.
//
@@ -5049,7 +8040,7 @@ namespace bpkg
// Commits the transaction.
//
- sp = pkg_unpack (o, pdb, af.database (), t, ap->id.name, simulate);
+ sp = pkg_unpack (o, pdb, t, ap->id.name, simulate);
if (result)
text << "unpacked " << *sp << pdb;
@@ -5100,14 +8091,51 @@ namespace bpkg
return true;
};
- if (progress)
+ // On the first pass collect all the build_package's to be configured and
+ // calculate their configure_prerequisites_result's.
+ //
+ struct configure_package
{
- prog_i = 0;
- prog_n = static_cast<size_t> (count_if (build_pkgs.begin (),
- build_pkgs.end (),
- configure_pred));
- prog_percent = 100;
- }
+ reference_wrapper<build_package> pkg;
+
+ // These are unused for system packages.
+ //
+ configure_prerequisites_result res;
+ build2::variable_overrides ovrs;
+ };
+ vector<configure_package> configure_packages;
+ configure_packages.reserve (build_pkgs.size ());
+
+ // While at it also collect global configuration variable overrides from
+ // each configure_prerequisites_result::config_variables and merge them
+ // into configure_global_vars.
+ //
+ // @@ TODO: Note that the current global override semantics is quite
+ // broken in that we don't force reconfiguration of all the packages.
+ //
+#ifndef BPKG_OUTPROC_CONFIGURE
+ strings configure_global_vars;
+#endif
+
+ // Return the "would be" state of packages that would be configured
+ // by this stage.
+ //
+ function<find_package_state_function> configured_state (
+ [&configure_packages] (const shared_ptr<selected_package>& sp)
+ -> optional<pair<package_state, package_substate>>
+ {
+ for (const configure_package& cp: configure_packages)
+ {
+ const build_package& p (cp.pkg);
+
+ if (p.selected == sp)
+ return make_pair (
+ package_state::configured,
+ p.system ? package_substate::system : package_substate::none);
+ }
+
+ return nullopt;
+ });
for (build_package& p: reverse_iterate (build_pkgs))
{
@@ -5119,7 +8147,7 @@ namespace bpkg
shared_ptr<selected_package>& sp (p.selected);
const shared_ptr<available_package>& ap (p.available);
- // Configure the package.
+ // Collect the package.
//
// At this stage the package is either selected, in which case it's a
// source code one, or just available, in which case it is a system
@@ -5131,7 +8159,6 @@ namespace bpkg
assert (sp != nullptr || p.system);
database& pdb (p.db);
-
transaction t (pdb, !simulate /* start */);
// Show how we got here if things go wrong, for example selecting a
@@ -5145,137 +8172,319 @@ namespace bpkg
info << "while configuring " << p.name () << p.db;
}));
- auto prereqs = [&p, &previous_prerequisites] ()
- {
- auto i (previous_prerequisites.find (&p));
- return i != previous_prerequisites.end () ? &i->second : nullptr;
- };
-
- // Note that pkg_configure() commits the transaction.
- //
+ configure_prerequisites_result cpr;
if (p.system)
{
+ // We have no choice but to configure system packages on the first
+ // pass since otherwise there will be no selected package for
+ // pkg_configure_prerequisites() to find. Luckily they have no
+ // dependencies and so can be configured in any order. We will print
+ // their progress/result on the second pass in the proper order.
+ //
+ // Note: commits the transaction.
+ //
sp = pkg_configure_system (ap->id.name,
p.available_version (),
pdb,
t);
}
- else if (ap != nullptr)
+ else
{
- assert (*p.action == build_package::build);
-
- // If the package prerequisites builds are collected, then use the
- // resulting package skeleton and the pre-selected dependency
- // alternatives.
+ // Should only be called for packages whose prerequisites are saved.
//
- // Note that we may not collect the package prerequisites builds if
- // the package is already configured but we still need to reconfigure
- // it due, for example, to an upgrade of its dependency. In this case
- // we pass to pkg_configure() the newly created package skeleton which
- // contains the package configuration variables specified on the
- // command line but (naturally) no reflection configuration variables.
- // Note, however, that in this case pkg_configure() call will evaluate
- // the reflect clauses itself and so the proper reflection variables
- // will still end up in the package configuration.
+ auto prereqs = [&p, &previous_prerequisites] ()
+ {
+ auto i (previous_prerequisites.find (&p));
+ assert (i != previous_prerequisites.end ());
+ return &i->second;
+ };
+
+ // In the simulation mode unconstrain all the unsatisfactory
+ // dependencies, if any, while configuring the dependent (see
+ // build_packages::collect_dependents() for details).
//
- // @@ Note that if we ever allow the user to override the alternative
- // selection, this will break (and also if the user re-configures
- // the package manually). Maybe that a good reason not to allow
- // this? Or we could store this information in the database.
+ // Note: must be called at most once.
//
- if (p.dependencies)
+ auto unconstrain_deps = [simulate,
+ &p,
+ &trace,
+ deps = vector<package_key> ()] () mutable
{
- assert (p.skeleton);
+ if (simulate)
+ {
+ unsatisfied_dependent* ud (
+ simulate->find_dependent (package_key (p.db, p.name ())));
- pkg_configure (o,
- pdb,
- t,
- sp,
- *p.dependencies,
- &*p.alternatives,
- move (*p.skeleton),
- nullptr /* previous_prerequisites */,
- p.disfigure,
- simulate,
- fdb);
+ if (ud != nullptr)
+ {
+ assert (deps.empty ());
+
+ deps.reserve (ud->ignored_constraints.size ());
+
+ for (const auto& c: ud->ignored_constraints)
+ {
+ l5 ([&]{trace << "while configuring dependent " << p.name ()
+ << p.db << " in simulation mode unconstrain ("
+ << c.dependency << ' ' << c.constraint << ')';});
+
+ deps.emplace_back (c.dependency);
+ }
+ }
+ }
+
+ return !deps.empty () ? &deps : nullptr;
+ };
+
+ if (ap != nullptr)
+ {
+ assert (*p.action == build_package::build);
+
+ // If the package prerequisites builds are collected, then use the
+ // resulting package skeleton and the pre-selected dependency
+ // alternatives.
+ //
+ // Note that we may not collect the package prerequisites builds if
+ // the package is already configured but we still need to
+ // reconfigure it due, for example, to an upgrade of its dependency.
+ // In this case we pass to pkg_configure() the newly created package
+ // skeleton which contains the package configuration variables
+ // specified on the command line but (naturally) no reflection
+ // configuration variables. Note, however, that in this case
+ // pkg_configure() call will evaluate the reflect clauses itself and
+ // so the proper reflection variables will still end up in the
+ // package configuration.
+ //
+ // @@ Note that if we ever allow the user to override the
+ // alternative selection, this will break (and also if the user
+ // re-configures the package manually). Maybe that a good reason
+ // not to allow this? Or we could store this information in the
+ // database.
+ //
+ if (p.dependencies)
+ {
+ assert (p.skeleton);
+
+ cpr = pkg_configure_prerequisites (o,
+ pdb,
+ t,
+ *p.dependencies,
+ &*p.alternatives,
+ move (*p.skeleton),
+ nullptr /* prev_prerequisites */,
+ simulate,
+ fdb,
+ configured_state,
+ unconstrain_deps ());
+ }
+ else
+ {
+ assert (p.skeleton); // Must be initialized before disfiguring.
+
+ cpr = pkg_configure_prerequisites (o,
+ pdb,
+ t,
+ ap->dependencies,
+ nullptr /* alternatives */,
+ move (*p.skeleton),
+ prereqs (),
+ simulate,
+ fdb,
+ configured_state,
+ unconstrain_deps ());
+ }
}
- else
+ else // Existing dependent.
{
- assert (sp != nullptr); // See above.
+ // This is an adjustment of a dependent which cannot be system
+ // (otherwise it wouldn't be a dependent) and cannot become system
+ // (otherwise it would be a build).
+ //
+ assert (*p.action == build_package::adjust && !sp->system ());
- // Note that the skeleton can be present if, for example, this is a
- // dependency which configuration has been negotiated but it is not
- // collected recursively since it has no buildfile clauses.
+ // Must be in the unpacked state since it was disfigured on the
+ // first pass (see above).
//
- if (!p.skeleton)
- p.init_skeleton (o);
+ assert (sp->state == package_state::unpacked);
- pkg_configure (o,
- pdb,
- t,
- sp,
- ap->dependencies,
- nullptr /* alternatives */,
- move (*p.skeleton),
- prereqs (),
- p.disfigure,
- simulate,
- fdb);
+ // The skeleton must be initialized before disfiguring and the
+ // package can't be system.
+ //
+ assert (p.skeleton && p.skeleton->available != nullptr);
+
+ const dependencies& deps (p.skeleton->available->dependencies);
+
+ // @@ Note that on reconfiguration the dependent looses the
+ // potential configuration variables specified by the user on
+ // some previous build, which can be quite surprising. Should we
+ // store this information in the database?
+ //
+ // Note: this now works for external packages via package
+ // skeleton (which extracts user configuration).
+ //
+ cpr = pkg_configure_prerequisites (o,
+ pdb,
+ t,
+ deps,
+ nullptr /* alternatives */,
+ move (*p.skeleton),
+ prereqs (),
+ simulate,
+ fdb,
+ configured_state,
+ unconstrain_deps ());
+ }
+
+ t.commit ();
+
+ if (verb >= 5 && !simulate && !cpr.config_variables.empty ())
+ {
+ diag_record dr (trace);
+
+ dr << sp->name << pdb << " configuration variables:";
+
+ for (const string& cv: cpr.config_variables)
+ dr << "\n " << cv;
+ }
+
+ if (!simulate)
+ {
+#ifndef BPKG_OUTPROC_CONFIGURE
+ auto& gvs (configure_global_vars);
+
+ // Note that we keep global overrides in cpr.config_variables for
+ // diagnostics and skip them in var_override_function below.
+ //
+ for (const string& v: cpr.config_variables)
+ {
+ // Each package should have exactly the same set of global
+ // overrides by construction since we don't allow package-
+ // specific global overrides.
+ //
+ if (v[0] == '!')
+ {
+ if (find (gvs.begin (), gvs.end (), v) == gvs.end ())
+ gvs.push_back (v);
+ }
+ }
+#endif
+ // Add config.config.disfigure unless already disfigured (see the
+ // high-level pkg_configure() version for background).
+ //
+ if (ap == nullptr || !p.disfigure)
+ {
+ cpr.config_variables.push_back (
+ "config.config.disfigure='config." + sp->name.variable () + "**'");
+ }
}
}
- else // Dependent.
- {
- // This is an adjustment of a dependent which cannot be system
- // (otherwise it wouldn't be a dependent) and cannot become system
- // (otherwise it would be a build).
- //
- assert (*p.action == build_package::adjust &&
- !p.system &&
- !sp->system ());
- // Must be in the unpacked state since it was disfigured on the first
- // pass (see above).
- //
- assert (sp->state == package_state::unpacked);
+ configure_packages.push_back (configure_package {p, move (cpr), {}});
+ }
- // Initialize the skeleton if it is not initialized yet.
- //
- // Note that the skeleton can only be present here if it was
- // initialized during the preparation of the plan and so this plan
- // execution is not simulated (see above for details).
- //
- // Also note that there is no available package specified for the
- // build package object here and so we need to find it (or create a
- // transient one).
- //
- assert (p.available == nullptr && (!p.skeleton || !simulate));
+ // Reuse the build state to avoid reloading the dependencies over and over
+ // again. This is a valid optimization since we are configuring in the
+ // dependency-dependent order.
+ //
+ unique_ptr<build2::context> configure_ctx;
- if (!p.skeleton)
- p.init_skeleton (o, find_available (o, pdb, sp));
+#ifndef BPKG_OUTPROC_CONFIGURE
+ if (!simulate)
+ {
+ using build2::context;
+ using build2::variable_override;
- assert (p.skeleton->available != nullptr); // Can't be system.
+ function<context::var_override_function> vof (
+ [&configure_packages] (context& ctx, size_t& i)
+ {
+ for (configure_package& cp: configure_packages)
+ {
+ for (const string& v: cp.res.config_variables)
+ {
+ if (v[0] == '!') // Skip global overrides (see above).
+ continue;
- const dependencies& deps (p.skeleton->available->dependencies);
+ pair<char, variable_override> p (
+ ctx.parse_variable_override (v, i++, false /* buildspec */));
- // @@ Note that on reconfiguration the dependent looses the potential
- // configuration variables specified by the user on some previous
- // build, which can be quite surprising. Should we store this
- // information in the database?
+ variable_override& vo (p.second);
+
+ // @@ TODO: put absolute scope overrides into global_vars.
+ //
+ assert (!(p.first == '!' || (vo.dir && vo.dir->absolute ())));
+
+ cp.ovrs.push_back (move (vo));
+ }
+ }
+ });
+
+ configure_ctx = pkg_configure_context (
+ o, move (configure_global_vars), vof);
+
+ // Only global in configure_global_vars.
+ //
+ assert (configure_ctx->var_overrides.empty ());
+ }
+#endif
+
+ if (progress)
+ {
+ prog_i = 0;
+ prog_n = configure_packages.size ();
+ prog_percent = 100;
+ }
+
+ for (configure_package& cp: configure_packages)
+ {
+ build_package& p (cp.pkg);
+
+ const shared_ptr<selected_package>& sp (p.selected);
+
+ // Configure the package (system already configured).
+ //
+ // NOTE: remember to update the preparation of the plan to be presented
+ // to the user if changing anything here.
+ //
+ database& pdb (p.db);
+
+ if (!p.system)
+ {
+ const shared_ptr<available_package>& ap (p.available);
+
+ transaction t (pdb, !simulate /* start */);
+
+ // Show how we got here if things go wrong.
//
- // I believe this now works for external packages via package
- // skeleton (which extracts user configuration).
+ auto g (
+ make_exception_guard (
+ [&p] ()
+ {
+ info << "while configuring " << p.name () << p.db;
+ }));
+
+ // Note that pkg_configure() commits the transaction.
//
- pkg_configure (o,
- pdb,
- t,
- sp,
- deps,
- nullptr /* alternatives */,
- move (*p.skeleton),
- prereqs (),
- false /* disfigured */,
- simulate,
- fdb);
+ if (ap != nullptr)
+ {
+ pkg_configure (o,
+ pdb,
+ t,
+ sp,
+ move (cp.res),
+ configure_ctx,
+ cp.ovrs,
+ simulate);
+ }
+ else // Dependent.
+ {
+ pkg_configure (o,
+ pdb,
+ t,
+ sp,
+ move (cp.res),
+ configure_ctx,
+ cp.ovrs,
+ simulate);
+ }
}
r = true;
@@ -5300,6 +8509,10 @@ namespace bpkg
}
}
+#ifndef BPKG_OUTPROC_CONFIGURE
+ configure_ctx.reset (); // Free.
+#endif
+
// Clear the progress if shown.
//
if (progress)
diff --git a/bpkg/pkg-checkout.cxx b/bpkg/pkg-checkout.cxx
index b4d93f0..81efdc2 100644
--- a/bpkg/pkg-checkout.cxx
+++ b/bpkg/pkg-checkout.cxx
@@ -10,12 +10,12 @@
#include <bpkg/package-odb.hxx>
#include <bpkg/database.hxx>
#include <bpkg/checksum.hxx>
+#include <bpkg/rep-mask.hxx>
#include <bpkg/diagnostics.hxx>
#include <bpkg/manifest-utility.hxx>
#include <bpkg/pkg-purge.hxx>
#include <bpkg/pkg-verify.hxx>
-#include <bpkg/pkg-configure.hxx>
using namespace std;
using namespace butl;
@@ -133,7 +133,7 @@ namespace bpkg
check_any_available (rdb, t);
- // Note that here we compare including the revision (see pkg-fetch()
+ // Note that here we compare including the revision (see pkg_fetch()
// implementation for more details).
//
shared_ptr<available_package> ap (
@@ -149,14 +149,17 @@ namespace bpkg
for (const package_location& l: ap->locations)
{
- const repository_location& rl (l.repository_fragment.load ()->location);
-
- if (rl.version_control_based () && (pl == nullptr || rl.local ()))
+ if (!rep_masked_fragment (l.repository_fragment))
{
- pl = &l;
+ const repository_location& rl (l.repository_fragment.load ()->location);
+
+ if (rl.version_control_based () && (pl == nullptr || rl.local ()))
+ {
+ pl = &l;
- if (rl.local ())
- break;
+ if (rl.local ())
+ break;
+ }
}
}
@@ -171,9 +174,6 @@ namespace bpkg
const repository_location& rl (pl->repository_fragment->location);
auto_rmdir rmd;
- optional<string> mc;
- optional<string> bc;
-
const dir_path& ord (output_root ? *output_root : c);
dir_path d (ord / dir_path (n.string () + '-' + v.string ()));
@@ -313,21 +313,6 @@ namespace bpkg
"!config.dist.bootstrap=true",
"config.dist.root='" + ord.representation () + '\'',
bspec);
-
- mc = package_checksum (o, d, nullptr /* package_info */);
-
- // Calculate the buildfiles checksum if the package has any buildfile
- // clauses in the dependencies.
- //
- // Note that the available package already has all the buildfiles
- // loaded.
- //
- if ((p != nullptr && p->manifest_checksum == mc)
- ? p->buildfiles_checksum.has_value ()
- : has_buildfile_clause (ap->dependencies))
- bc = package_buildfiles_checksum (ap->bootstrap_build,
- ap->root_build,
- ap->buildfiles);
}
if (p != nullptr)
@@ -361,13 +346,16 @@ namespace bpkg
if (p != nullptr)
{
+ // Note: we can be replacing an external package and thus we reset the
+ // manifest/subprojects and buildfiles checksums.
+ //
p->version = move (v);
p->state = package_state::unpacked;
p->repository_fragment = rl;
p->src_root = move (d);
p->purge_src = purge;
- p->manifest_checksum = move (mc);
- p->buildfiles_checksum = move (bc);
+ p->manifest_checksum = nullopt;
+ p->buildfiles_checksum = nullopt;
pdb.update (p);
}
@@ -387,8 +375,8 @@ namespace bpkg
false,
move (d), // Source root.
purge, // Purge directory.
- move (mc),
- move (bc),
+ nullopt, // No manifest/subprojects checksum.
+ nullopt, // No buildfiles checksum.
nullopt, // No output directory yet.
{}}); // No prerequisites captured yet.
diff --git a/bpkg/pkg-command.cxx b/bpkg/pkg-command.cxx
index 5788e11..20e5230 100644
--- a/bpkg/pkg-command.cxx
+++ b/bpkg/pkg-command.cxx
@@ -5,6 +5,9 @@
#include <libbutl/path-pattern.hxx>
+#include <libbuild2/file.hxx>
+#include <libbuild2/context.hxx>
+
#include <bpkg/package.hxx>
#include <bpkg/package-odb.hxx>
#include <bpkg/database.hxx>
@@ -54,6 +57,8 @@ namespace bpkg
}
};
+ unique_ptr<build2::context> ctx; // Create lazily.
+
for (const pkg_command_vars& pv: ps)
{
if (!pv.vars.empty () || pv.cwd)
@@ -74,12 +79,49 @@ namespace bpkg
const shared_ptr<selected_package>& p (pv.pkg);
- assert (p->state == package_state::configured);
- assert (p->out_root); // Should be present since configured.
+ assert (p->state == package_state::configured &&
+ p->substate != package_substate::system);
+ assert (p->out_root &&
+ p->src_root); // Should be present since configured, not system.
dir_path out_root (p->effective_out_root (pv.config_orig));
l4 ([&]{trace << p->name << " out_root: " << out_root;});
+ // Figure out if the source directory is forwarded to this out_root. If
+ // it is, then we need to build via src_root. Failed that, backlinks
+ // won't be created.
+ //
+ if (*p->out_root != *p->src_root)
+ {
+ dir_path src_root (p->effective_src_root (pv.config_orig));
+
+ // For us to switch to src_root, it should not only be configured as
+ // forwarded, but also be forwarded to our out_root. So we actually
+ // need to first check if the build/bootstrap/out-root.build (or its
+ // alt naming equivalent) exists and, if so, extract the out_root
+ // value and compare it to ours. This is all done by bootstrap_fwd()
+ // from libbuild2 so seeing that we act as a special build system
+ // driver, we might as well use that. Note that this could potentially
+ // be improved by only creating context if the file exists.
+ //
+ try
+ {
+ if (ctx == nullptr)
+ ctx.reset (new build2::context ());
+
+ optional<bool> altn;
+ if (build2::bootstrap_fwd (*ctx, src_root, altn) == out_root)
+ {
+ out_root = move (src_root);
+ l4 ([&]{trace << p->name << " src_root: " << out_root;});
+ }
+ }
+ catch (const build2::failed&)
+ {
+ throw failed (); // Assume the diagnostics has already been issued.
+ }
+ }
+
if (bspec.back () != '(')
bspec += ' ';
diff --git a/bpkg/pkg-configure.cxx b/bpkg/pkg-configure.cxx
index 20a2567..eb5b85b 100644
--- a/bpkg/pkg-configure.cxx
+++ b/bpkg/pkg-configure.cxx
@@ -3,6 +3,17 @@
#include <bpkg/pkg-configure.hxx>
+#include <libbuild2/types.hxx>
+#include <libbuild2/utility.hxx>
+#include <libbuild2/diagnostics.hxx>
+
+#include <libbuild2/file.hxx>
+#include <libbuild2/scope.hxx>
+#include <libbuild2/operation.hxx>
+#include <libbuild2/config/operation.hxx>
+
+#include <bpkg/bpkg.hxx> // build2_init(), etc
+
#include <bpkg/package.hxx>
#include <bpkg/package-odb.hxx>
#include <bpkg/database.hxx>
@@ -19,32 +30,9 @@ using namespace butl;
namespace bpkg
{
- // Given dependencies of a package, return its prerequisite packages,
- // configuration variables that resulted from selection of these
- // prerequisites (import, reflection, etc), and sources of the configuration
- // variables resulted from evaluating the reflect clauses. See
- // pkg_configure() for the semantics of the dependency list. Fail if for
- // some of the dependency alternative lists there is no satisfactory
- // alternative (all its dependencies are configured, satisfy the respective
- // constraints, etc).
- //
- struct configure_prerequisites_result
- {
- package_prerequisites prerequisites;
- strings config_variables; // Note: name and value.
-
- // Only contains sources of configuration variables collected using the
- // package skeleton, excluding those user-specified variables which are
- // not the project variables for the specified package (module
- // configuration variables, etc). Thus, it is not parallel to the
- // config_variables member.
- //
- vector<config_variable> config_sources; // Note: name and source.
- };
+ static optional<version_constraint> absent_constraint;
- // Note: loads selected packages.
- //
- static configure_prerequisites_result
+ configure_prerequisites_result
pkg_configure_prerequisites (const common_options& o,
database& db,
transaction&,
@@ -53,16 +41,94 @@ namespace bpkg
package_skeleton&& ps,
const vector<package_name>* prev_prereqs,
bool simulate,
- const function<find_database_function>& fdb)
+ const function<find_database_function>& fdb,
+ const function<find_package_state_function>& fps,
+ const vector<package_key>* unconstrain_deps)
{
+ tracer trace ("pkg_configure_prerequisites");
+
+ // Unconstraining dependencies are only allowed in the simulation mode.
+ //
+ assert (unconstrain_deps == nullptr || simulate);
+
+ // No use case for both being specified.
+ //
+ assert (alts == nullptr || prev_prereqs == nullptr);
+
+ tracer_guard tg (db, trace);
+
package_prerequisites prereqs;
+ vector<size_t> dep_alts;
strings vars;
+ // Notes on the buildfile clauses evaluation:
+ //
+ // - In the manual configuration mode (alts == NULL, prev_prereqs == NULL)
+ // we always evaluate the enable and reflect clauses. We, however, fail
+ // if any of the prefer or require clauses are specified in any of the
+ // enabled dependency alternatives, assuming that this package didn't
+ // negotiate its preferences/requirements for the dependency
+ // configurations.
+ //
+ // Note that evaluating the require and prefer clauses in this case is
+ // meaningless since we don't reconfigure the dependencies nor negotiate
+ // configurations with other dependents. What we should probably do is
+ // load configurations of the dependencies and use them while evaluating
+ // the dependent's enable and reflect clauses as we go along. Probably
+ // we should still evaluate the accept clauses to make sure that the
+ // dependency is configured acceptably for the dependent.
+ //
+ // - In the pre-selected alternatives mode (alts != NULL, prev_prereqs ==
+ // NULL) we don't evaluate the enable, prefer, and require clauses since
+ // they have already been evaluated as a part of the dependency
+ // alternatives selection and the dependency configurations negotiation.
+ // We, however always evaluate the reflect clauses.
+ //
+ // - In the reconfiguration mode (prev_prereqs != NULL, alts == NULL) we
+ // don't evaluate the prefer and require clauses, assuming that was done
+ // on some previous pkg-build run when this package and its dependencies
+ // have been configured. But because of this we may not evaluate the
+ // enable and reflect clauses which refer to dependency configuration
+ // variables. If such clauses are present, then this is considered an
+ // implementation error since such packages should be handled in the
+ // above pre-selected alternatives mode.
+ //
+ bool manual (alts == nullptr && prev_prereqs == nullptr);
+
+ // In the reconfiguration mode keep track of configuration variable
+ // prefixes (in the 'config.<dependency>.' form) for dependencies in the
+ // selected alternatives with the prefer or require clauses specified and
+ // fail if any enable or reflect clause refers to them.
+ //
+ // Note that the enable and reflect clauses may only refer to dependency
+ // configuration variables of already selected alternatives with the
+ // prefer or require clauses specified.
+ //
+ vector<string> banned_var_prefixes;
+
+ auto verify_banned_vars = [&ps,
+ &banned_var_prefixes] (const string& clause,
+ const char* what)
+ {
+ for (const string& p: banned_var_prefixes)
+ {
+ if (clause.find (p) != string::npos)
+ {
+ fail << "unable to reconfigure dependent " << ps.package.name
+ << " with " << what << " clause that refers to dependency "
+ << "configuration variables" <<
+ info << "please report in https://github.com/build2/build2/issues/302";
+ }
+ }
+ };
+
// Alternatives argument must be parallel to the dependencies argument if
// specified.
//
assert (alts == nullptr || alts->size () == deps.size ());
+ dep_alts.reserve (deps.size ());
+
for (size_t di (0); di != deps.size (); ++di)
{
// Skip the toolchain build-time dependencies and dependencies without
@@ -71,45 +137,51 @@ namespace bpkg
const dependency_alternatives_ex& das (deps[di]);
if (das.empty ())
+ {
+ dep_alts.push_back (0);
continue;
+ }
small_vector<pair<reference_wrapper<const dependency_alternative>,
size_t>,
2> edas;
- // If the dependency alternatives are not pre-selected, then evaluate
- // the enable clauses.
- //
- // Note that evaluating the require and prefer clauses in this case is
- // meaningless since we don't reconfigure the dependencies nor negotiate
- // configurations with other dependents. What we should probably do is
- // load configurations of the dependencies and use them while evaluating
- // the dependent's enable and reflect clauses as we go along. Probably
- // we should still evaluate the accept clauses to make sure that the
- // dependency is configured acceptably for the dependent. For now we
- // fail and will support this maybe later.
- //
if (alts == nullptr)
{
if (toolchain_buildtime_dependency (o, das, &ps.package.name))
+ {
+ dep_alts.push_back (0);
continue;
+ }
for (size_t i (0); i != das.size (); ++i)
{
const dependency_alternative& da (das[i]);
- if (!da.enable || ps.evaluate_enable (*da.enable, make_pair (di, i)))
+ // Evaluate the dependency alternative enable clause, if present,
+ // unless it refers to any banned variables in which case we fail.
+ //
+ if (da.enable)
{
- if (da.prefer || da.require)
- fail << "manual configuration of dependents with prefer or "
- << "require clauses is not yet supported";
+ if (!banned_var_prefixes.empty ())
+ verify_banned_vars (*da.enable, "enable");
- edas.push_back (make_pair (ref (da), i));
+ if (!ps.evaluate_enable (*da.enable, make_pair (di, i)))
+ continue;
}
+
+ if (manual && (da.prefer || da.require))
+ fail << "manual configuration of dependents with prefer or "
+ << "require clauses is not yet supported";
+
+ edas.push_back (make_pair (ref (da), i));
}
if (edas.empty ())
+ {
+ dep_alts.push_back (0);
continue;
+ }
}
else
{
@@ -130,13 +202,16 @@ namespace bpkg
// the "make dependency decisions" mode and select the alternative
// regardless of the former prerequisites.
//
+ assert (!edas.empty ());
+
for (const vector<package_name>* pps (prev_prereqs);;)
{
- bool satisfied (false);
+ const pair<reference_wrapper<const dependency_alternative>,
+ size_t>* selected_alt (nullptr);
+
for (const auto& eda: edas)
{
const dependency_alternative& da (eda.first);
- size_t dai (eda.second);
// Cache the selected packages which correspond to the alternative
// dependencies, pairing them with the respective constraints. If
@@ -167,9 +242,31 @@ namespace bpkg
const shared_ptr<selected_package>& dp (spd.first);
- if (dp == nullptr ||
- dp->state != package_state::configured ||
- !satisfies (dp->version, d.constraint) ||
+ if (dp == nullptr)
+ break;
+
+ database& pdb (*spd.second);
+
+ optional<pair<package_state, package_substate>> dps;
+ if (fps != nullptr)
+ dps = fps (dp);
+
+ const optional<version_constraint>* dc (&d.constraint);
+
+ // Unconstrain this dependency, if requested.
+ //
+ if (unconstrain_deps != nullptr)
+ {
+ const vector<package_key>& uds (*unconstrain_deps);
+ if (find (uds.begin (), uds.end (), package_key (pdb, n)) !=
+ uds.end ())
+ {
+ dc = &absent_constraint;
+ }
+ }
+
+ if ((dps ? dps->first : dp->state) != package_state::configured ||
+ !satisfies (dp->version, *dc) ||
(pps != nullptr &&
find (pps->begin (), pps->end (), dp->name) == pps->end ()))
break;
@@ -177,13 +274,9 @@ namespace bpkg
// See the package_prerequisites definition for details on
// creating the map keys with the database passed.
//
- bool conf (da.prefer || da.require);
-
prerequisites.emplace_back (
- lazy_shared_ptr<selected_package> (*spd.second, dp),
- prerequisite_info {d.constraint,
- make_pair (conf ? di + 1 : 0,
- conf ? dai + 1 : 0)});
+ lazy_shared_ptr<selected_package> (pdb, dp),
+ prerequisite_info {*dc});
}
// Try the next alternative if there are unresolved dependencies for
@@ -222,15 +315,6 @@ namespace bpkg
if (s2 && !s1)
c1 = c2;
-
- // Keep position of the first dependency alternative with a
- // configuration clause.
- //
- pair<size_t, size_t>& p1 (p.first->second.config_position);
- pair<size_t, size_t> p2 (pi.config_position);
-
- if (p1.first == 0 && p2.first != 0)
- p1 = p2;
}
// If the prerequisite is configured in the linked configuration,
@@ -244,7 +328,13 @@ namespace bpkg
{
shared_ptr<selected_package> sp (pr.first.load ());
- if (!sp->system ())
+ optional<pair<package_state, package_substate>> ps;
+ if (fps != nullptr)
+ ps = fps (sp);
+
+ if (ps
+ ? ps->second != package_substate::system
+ : !sp->system ())
{
// @@ Note that this doesn't work for build2 modules that
// require bootstrap. For their dependents we need to
@@ -263,7 +353,45 @@ namespace bpkg
// Also note that such modules are marked with `requires:
// bootstrap` in their manifest.
//
- dir_path od (sp->effective_out_root (pdb.config));
+ // Note that we currently don't support global overrides
+ // in the shared build2 context (but could probably do,
+ // if necessary).
+ //
+
+ dir_path od;
+ if (ps)
+ {
+ // There is no out_root for a would-be configured package.
+ // So we calculate it like in pkg_configure() below (yeah,
+ // it's an ugly hack).
+ //
+ od = sp->external ()
+ ? pdb.config / dir_path (sp->name.string ())
+ : pdb.config / dir_path (sp->name.string () + '-' +
+ sp->version.string ());
+ }
+ else
+ od = sp->effective_out_root (pdb.config);
+
+ // We tried to use global overrides to recreate the original
+ // behavior of not warning about unused config.import.*
+ // variables (achived via the config.config.persist value in
+ // amalgamation). Even though it's probably misguided (we
+ // don't actually save the unused values anywhere, just
+ // don't warn about them).
+ //
+ // Can we somehow cause a clash, say if the same package
+ // comes from different configurations? Yeah, we probably
+ // can. So could add it as undermined (?), detect a clash,
+ // and "fallforward" to the correct behavior.
+ //
+ // But we can clash with an absent value -- that is, we
+ // force importing from a wrong configuration where without
+ // any import things would have been found in the same
+ // amalgamation. Maybe we could detect that (no import
+ // for the same package -- but it could be for a package
+ // we are not configuring).
+ //
vars.push_back ("config.import." + sp->name.variable () +
"='" + od.representation () + '\'');
}
@@ -271,12 +399,7 @@ namespace bpkg
}
}
- // Evaluate the dependency alternative reflect clause, if present.
- //
- if (da.reflect)
- ps.evaluate_reflect (*da.reflect, make_pair (di, dai));
-
- satisfied = true;
+ selected_alt = &eda;
break;
}
@@ -284,7 +407,7 @@ namespace bpkg
// "recreate dependency decisions" mode. In the latter case fall back
// to the "make dependency decisions" mode and retry.
//
- if (!satisfied)
+ if (selected_alt == nullptr)
{
if (pps != nullptr)
{
@@ -295,6 +418,38 @@ namespace bpkg
fail << "unable to satisfy dependency on " << das;
}
+ const dependency_alternative& da (selected_alt->first);
+
+ // In the reconfiguration mode ban the usage of the selected
+ // alternative dependency configuration variables in the subsequent
+ // enable and reflect clauses, unless we are also unconstraining
+ // dependencies (which indicates it's a relaxed mode that precedes
+ // a drop or failure with better diagnostics).
+ //
+ if (alts == nullptr && !manual &&
+ unconstrain_deps == nullptr &&
+ (da.prefer || da.require))
+ {
+ for (const dependency& d: da)
+ banned_var_prefixes.push_back (
+ "config." + d.name.variable () + '.');
+ }
+
+ // Evaluate the selected dependency alternative reflect clause, if
+ // present, unless it refers to any banned variables in which case we
+ // fail.
+ //
+ if (da.reflect)
+ {
+ if (!banned_var_prefixes.empty ())
+ verify_banned_vars (*da.reflect, "reflect");
+
+ ps.evaluate_reflect (*da.reflect,
+ make_pair (di, selected_alt->second));
+ }
+
+ dep_alts.push_back (selected_alt->second + 1);
+
// The dependency alternative is selected and its dependencies are
// resolved to the selected packages. So proceed to the next depends
// value.
@@ -303,13 +458,20 @@ namespace bpkg
}
}
+ // Make sure we didn't miss any selected dependency alternative.
+ //
+ assert (dep_alts.size () == deps.size ());
+
// Add the rest of the configuration variables (user overrides, reflects,
// etc) as well as their sources.
//
vector<config_variable> srcs;
+ string checksum;
if (!simulate)
{
+ checksum = ps.config_checksum ();
+
pair<strings, vector<config_variable>> rvs (move (ps).collect_config ());
strings& vs (rvs.first);
@@ -330,8 +492,78 @@ namespace bpkg
}
return configure_prerequisites_result {move (prereqs),
+ move (dep_alts),
move (vars),
- move (srcs)};
+ move (srcs),
+ move (checksum)};
+ }
+
+
+ unique_ptr<build2::context>
+ pkg_configure_context (
+ const common_options& o,
+ strings&& cmd_vars,
+ const function<build2::context::var_override_function>& var_ovr_func)
+ {
+ using namespace build2;
+
+ // Initialize the build system.
+ //
+ // Note that this takes into account --build-option and default options
+ // files (which may have global overrides and which end up in
+ // build2_cmd_vars).
+ //
+ if (!build2_sched.started ())
+ build2_init (o);
+
+ // Re-tune the scheduler for parallel execution (see build2_init()
+ // for details).
+ //
+ if (build2_sched.tuned ())
+ build2_sched.tune (0);
+
+ auto merge_cmd_vars = [&cmd_vars] () -> const strings&
+ {
+ if (cmd_vars.empty ())
+ return build2_cmd_vars;
+
+ if (!build2_cmd_vars.empty ())
+ cmd_vars.insert (cmd_vars.begin (),
+ build2_cmd_vars.begin (), build2_cmd_vars.end ());
+
+ return cmd_vars;
+ };
+
+ // Shouldn't we shared the module context with package skeleton
+ // contexts? Maybe we don't have to since we don't build modules in
+ // them concurrently (in a sence, we didn't share it when we were
+ // invoking the build system driver).
+ //
+ unique_ptr<context> ctx (
+ new context (build2_sched,
+ build2_mutexes,
+ build2_fcache,
+ nullopt /* match_only */,
+ false /* no_external_modules */,
+ false /* dry_run */,
+ false /* no_diag_buffer */,
+ false /* keep_going */,
+ merge_cmd_vars (),
+ context::reserves {
+ 30000 /* targets */,
+ 1100 /* variables */},
+ nullptr /* module_context */,
+ nullptr /* inherited_mudules_lock */,
+ var_ovr_func));
+
+ // Set the current meta-operation once per context so that we don't reset
+ // ctx->current_on. Note that this function also sets ctx->current_mname
+ // and var_build_meta_operation on global scope.
+ //
+ ctx->current_meta_operation (config::mo_configure);
+ ctx->current_oname = string (); // default
+
+ return ctx;
}
void
@@ -339,13 +571,15 @@ namespace bpkg
database& db,
transaction& t,
const shared_ptr<selected_package>& p,
- const dependencies& deps,
- const vector<size_t>* alts,
- package_skeleton&& ps,
- const vector<package_name>* pps,
- bool disfigured,
- bool simulate,
- const function<find_database_function>& fdb)
+ configure_prerequisites_result&& cpr,
+#ifndef BPKG_OUTPROC_CONFIGURE
+ const unique_ptr<build2::context>& pctx,
+ const build2::variable_overrides& ovrs,
+#else
+ const unique_ptr<build2::context>&,
+ const build2::variable_overrides&, // Still in cpr.config_variables.
+#endif
+ bool simulate)
{
tracer trace ("pkg_configure");
@@ -354,11 +588,18 @@ namespace bpkg
tracer_guard tg (db, trace);
- const dir_path& c (db.config_orig);
+#ifndef BPKG_OUTPROC_CONFIGURE
+ const dir_path& c (db.config); // Absolute.
+#else
+ const dir_path& c (db.config_orig); // Relative.
+#endif
+
dir_path src_root (p->effective_src_root (c));
// Calculate package's out_root.
//
+ // Note: see a version of this in pkg_configure_prerequisites().
+ //
dir_path out_root (
p->external ()
? c / dir_path (p->name.string ())
@@ -367,26 +608,31 @@ namespace bpkg
l4 ([&]{trace << "src_root: " << src_root << ", "
<< "out_root: " << out_root;});
- // Verify all our prerequisites are configured and populate the
- // prerequisites list.
- //
- assert (p->prerequisites.empty ());
-
- configure_prerequisites_result cpr (
- pkg_configure_prerequisites (o,
- db,
- t,
- deps,
- alts,
- move (ps),
- pps,
- simulate,
- fdb));
+ assert (p->prerequisites.empty () && p->dependency_alternatives.empty ());
p->prerequisites = move (cpr.prerequisites);
+ p->dependency_alternatives = move (cpr.dependency_alternatives);
+
+ // Mark the section as loaded, so dependency alternatives are updated.
+ //
+ p->dependency_alternatives_section.load ();
+ // Configure.
+ //
if (!simulate)
{
+ // Original implementation that runs the standard build system driver.
+ //
+ // Note that the semantics doesn't match 100%. In particular, in the
+ // in-process implementation we enter overrides with global visibility
+ // in each project instead of the amalgamation (which is probably more
+ // accurate, since we don't re-configure the amalgamation nor some
+ // dependencies which could be affected by such overrides). In a sense,
+ // we enter them as if they were specified with the special .../ scope
+ // (but not with the % project visibility -- they must still be visible
+ // in subprojects).
+ //
+#ifdef BPKG_OUTPROC_CONFIGURE
// Form the buildspec.
//
string bspec;
@@ -402,46 +648,211 @@ namespace bpkg
l4 ([&]{trace << "buildspec: " << bspec;});
- // Unless this package has been completely disfigured, disfigure all the
- // package configuration variables to reset all the old values to
- // defaults (all the new user/dependent/reflec values, including old
- // user, are returned by collect_config() and specified as overrides).
- // Note that this semantics must be consistent with how we load things
- // in the package skeleton during configuration negotiation.
- //
- // Note also that this means we don't really use the dependent and
- // reflect sources that we save in the database. But let's keep them
- // for the completeness of information (maybe could be useful during
- // configuration reset or some such).
+ try
+ {
+ run_b (o, verb_b::quiet, cpr.config_variables, bspec);
+ }
+ catch (const failed&)
+ {
+ // See below for comments.
+ //
+ p->out_root = out_root.leaf ();
+ p->state = package_state::broken;
+ pkg_disfigure (o, db, t, p, true, true, false);
+ throw;
+ }
+#else
+ // Print the out-process command line in the verbose mode.
//
- string dvar;
- if (!disfigured)
+ if (verb >= 2)
{
- // Note: must be quoted to preserve the pattern.
+ string bspec;
+
+ // Use path representation to get canonical trailing slash.
//
- dvar = "config.config.disfigure='config.";
- dvar += p->name.variable ();
- dvar += "**'";
+ if (src_root == out_root)
+ bspec = "configure('" + out_root.representation () + "')";
+ else
+ bspec = "configure('" +
+ src_root.representation () + "'@'" +
+ out_root.representation () + "')";
+
+ print_b (o, verb_b::quiet, cpr.config_variables, bspec);
}
- // Configure.
- //
try
{
- run_b (o,
- verb_b::quiet,
- cpr.config_variables,
- (!dvar.empty () ? dvar.c_str () : nullptr),
- bspec);
+ // Note: no bpkg::failed should be thrown from this block.
+ //
+ using namespace build2;
+ using build2::fail;
+ using build2::info;
+ using build2::endf;
+ using build2::location;
+
+ // The build2_init() function initializes the build system verbosity
+ // as if running with verb_b::normal while we need verb_b::quiet. So
+ // we temporarily adjust the build2 verbosity (see map_verb_b() for
+ // details).
+ //
+ auto verbg (make_guard ([ov = build2::verb] () {build2::verb = ov;}));
+ if (bpkg::verb == 1)
+ build2::verb = 0;
+
+ context& ctx (*pctx);
+
+ // Bootstrap and load the project.
+ //
+ // Note: in many ways similar to package_skeleton code.
+ //
+ scope& rs (*create_root (ctx, out_root, src_root)->second.front ());
+
+ // If we are configuring in the dependency order (as we should), then
+ // it feels like the only situation where we can end up with an
+ // already bootstrapped project is an unspecified dependency. Note
+ // that this is a hard fail since it would have been loaded without
+ // the proper configuration.
+ //
+ if (bootstrapped (rs))
+ {
+ fail << p->name << db << " loaded ahead of its dependents" <<
+ info << "likely unspecified dependency on package " << p->name;
+ }
+
+ optional<bool> altn;
+ value& v (bootstrap_out (rs, altn));
+
+ if (!v)
+ v = src_root;
+ else
+ {
+ dir_path& p (cast<dir_path> (v));
+
+ if (src_root != p)
+ {
+ // @@ Fuzzy if need this or can do as package skeleton (seeing
+ // that we know we are re-configuring).
+ //
+ ctx.new_src_root = src_root;
+ ctx.old_src_root = move (p);
+ p = src_root;
+ }
+ }
+
+ setup_root (rs, false /* forwarded */);
+
+ // Note: we already know our amalgamation.
+ //
+ bootstrap_pre (rs, altn);
+ bootstrap_src (rs, altn,
+ c.relative (out_root) /* amalgamation */,
+ true /* subprojects */);
+
+ create_bootstrap_outer (rs, true /* subprojects */);
+ bootstrap_post (rs);
+
+ values mparams;
+ const meta_operation_info& mif (config::mo_configure);
+ const operation_info& oif (op_default);
+
+ // Skip configure_pre() and configure_operation_pre() calls since we
+ // don't pass any parameteres and pass default operation. We also know
+ // that op_default has no pre/post operations, naturally.
+
+ // Find the root buildfile. Note that the implied buildfile logic does
+ // not apply (our target is the project root directory).
+ //
+ optional<path> bf (find_buildfile (src_root, src_root, altn));
+
+ if (!bf)
+ fail << "no buildfile in " << src_root;
+
+ // Enter project-wide overrides.
+ //
+ // Note that the use of the root scope as amalgamation makes sure
+ // scenarious like below work correctly (see above for background).
+ //
+ // bpkg create -d cfg cc config.cc.coptions=-Wall
+ // bpkg build { config.cc.coptions+=-g }+ libfoo
+ // { config.cc.coptions+=-O }+ libbar
+ //
+ ctx.enter_project_overrides (rs, out_root, ovrs, &rs);
+
+ // The goal here is to be more or less semantically equivalent to
+ // configuring several projects at once. Except that here we have
+ // interleaving load/match instead of first all load then all
+ // match. But presumably this shouldn't be a problem (we can already
+ // have match interrupted by load and the "island append" requirement
+ // should hold here as well).
+ //
+ // Note that either way we will be potentially re-matching the same
+ // dependency targets multiple times (see build2::configure_execute()
+ // for details).
+ //
+ const path_name bsn ("<buildspec>");
+ const location loc (bsn, 0, 0);
+
+ // out_root/dir{./}
+ //
+ target_key tk {
+ &dir::static_type,
+ &out_root,
+ &empty_dir_path,
+ &empty_string,
+ nullopt};
+
+ action_targets tgs;
+ mif.load (mparams, rs, *bf, out_root, src_root, loc);
+ mif.search (mparams, rs, rs, *bf, tk, loc, tgs);
+
+ ctx.current_operation (oif, nullptr);
+ action a (ctx.current_action ());
+
+ mif.match (mparams, a, tgs, 2 /* diag */, true /* progress */);
+ mif.execute (mparams, a, tgs, 2 /* diag */, true /* progress */);
+
+ // Note: no operation_post/meta_operation_post for configure.
+
+ // Here is a tricky part: if this is a normal package, then it will be
+ // discovered as a subproject of the bpkg configuration when we load
+ // it for the first time (because they are all unpacked). However, if
+ // this is a package with src_root!=out_root (such as an external
+ // package or a package with a custom checkout_root) then there could
+ // be no out_root directory for it in the bpkg configuration yet. As a
+ // result, we need to manually add it as a newly discovered
+ // subproject.
+ //
+ if (!rs.out_eq_src ())
+ {
+ scope* as (rs.parent_scope ()->root_scope ());
+ assert (as != nullptr); // No bpkg configuration?
+
+ // Kept NULL if there are no subprojects, so we may need to
+ // initialize it (see build2::bootstrap_src() for details).
+ //
+ subprojects* sp (*as->root_extra->subprojects);
+ if (sp == nullptr)
+ {
+ value& v (as->vars.assign (*ctx.var_subprojects));
+ v = subprojects {};
+ sp = *(as->root_extra->subprojects = &cast<subprojects> (v));
+ }
+
+ const project_name& n (**rs.root_extra->project);
+
+ if (sp->find (n) == sp->end ())
+ sp->emplace (n, out_root.leaf ());
+ }
}
- catch (const failed&)
+ catch (const build2::failed&)
{
+ // Assume the diagnostics has already been issued.
+
// If we failed to configure the package, make sure we revert
// it back to the unpacked state by running disfigure (it is
// valid to run disfigure on an un-configured build). And if
// disfigure fails as well, then the package will be set into
// the broken state.
- //
// Indicate to pkg_disfigure() we are partially configured.
//
@@ -455,10 +866,14 @@ namespace bpkg
true /* clean */,
true /* disfigure */,
false /* simulate */);
- throw;
+
+
+ throw bpkg::failed ();
}
+#endif
p->config_variables = move (cpr.config_sources);
+ p->config_checksum = move (cpr.config_checksum);
}
p->out_root = out_root.leaf ();
@@ -468,6 +883,73 @@ namespace bpkg
t.commit ();
}
+ void
+ pkg_configure (const common_options& o,
+ database& db,
+ transaction& t,
+ const shared_ptr<selected_package>& p,
+ const dependencies& deps,
+ const vector<size_t>* alts,
+ package_skeleton&& ps,
+ const vector<package_name>* pps,
+ bool disfigured,
+ bool simulate,
+ const function<find_database_function>& fdb)
+ {
+ configure_prerequisites_result cpr (
+ pkg_configure_prerequisites (o,
+ db,
+ t,
+ deps,
+ alts,
+ move (ps),
+ pps,
+ simulate,
+ fdb,
+ nullptr));
+
+ if (!simulate)
+ {
+ // Unless this package has been completely disfigured, disfigure all the
+ // package configuration variables to reset all the old values to
+ // defaults (all the new user/dependent/reflec values, including old
+ // user, are returned by collect_config() and specified as overrides).
+ // Note that this semantics must be consistent with how we load things
+ // in the package skeleton during configuration negotiation.
+ //
+ // Note also that this means we don't really use the dependent and
+ // reflect sources that we save in the database. But let's keep them
+ // for the completeness of information (maybe could be useful during
+ // configuration reset or some such).
+ //
+ if (!disfigured)
+ {
+ // Note: must be quoted to preserve the pattern.
+ //
+ cpr.config_variables.push_back (
+ "config.config.disfigure='config." + p->name.variable () + "**'");
+ }
+ }
+
+ unique_ptr<build2::context> ctx;
+
+#ifndef BPKG_OUTPROC_CONFIGURE
+ if (!simulate)
+ ctx = pkg_configure_context (o, move (cpr.config_variables));
+#endif
+
+ pkg_configure (o,
+ db,
+ t,
+ p,
+ move (cpr),
+ ctx,
+ (ctx != nullptr
+ ? ctx->var_overrides
+ : build2::variable_overrides {}),
+ simulate);
+ }
+
shared_ptr<selected_package>
pkg_configure_system (const package_name& n,
const version& v,
@@ -626,7 +1108,11 @@ namespace bpkg
false /* disfigure */,
&p->config_variables,
move (src_root),
- move (out_root)),
+ move (out_root),
+ nullopt /* old_src_root */,
+ nullopt /* old_out_root */,
+ package_skeleton::load_config_user |
+ package_skeleton::load_config_dependent),
nullptr /* prerequisites */,
false /* disfigured */,
false /* simulate */);
diff --git a/bpkg/pkg-configure.hxx b/bpkg/pkg-configure.hxx
index 16ed96f..cd74786 100644
--- a/bpkg/pkg-configure.hxx
+++ b/bpkg/pkg-configure.hxx
@@ -7,6 +7,9 @@
#include <libbpkg/manifest.hxx> // version
#include <libbpkg/package-name.hxx>
+#include <libbuild2/context.hxx>
+#include <libbuild2/variable.hxx> // variable_overrides
+
#include <bpkg/types.hxx>
#include <bpkg/forward.hxx> // transaction, selected_package
#include <bpkg/utility.hxx>
@@ -21,6 +24,14 @@ namespace bpkg
int
pkg_configure (const pkg_configure_options&, cli::scanner& args);
+ // Configure a system package and commit the transaction.
+ //
+ shared_ptr<selected_package>
+ pkg_configure_system (const package_name&,
+ const version&,
+ database&,
+ transaction&);
+
// The custom search function. If specified, it is called by pkg_configure()
// to obtain the database to search for the prerequisite in, instead of
// searching for it in the linked databases, recursively. If the function
@@ -31,7 +42,14 @@ namespace bpkg
const package_name&,
bool buildtime);
- // Configure the package, update its state, and commit the transaction.
+ // Given dependencies of a package, return its prerequisite packages,
+ // 1-based indexes of the selected dependency alternatives (0 for toolchain
+ // build-time dependencies, etc), configuration variables that resulted from
+ // selection of these prerequisites (import, reflection, etc), and sources
+ // of the configuration variables resulted from evaluating the reflect
+ // clauses. Fail if for some of the dependency alternative lists there is no
+ // satisfactory alternative (all its dependencies are configured, satisfy
+ // the respective constraints, etc).
//
// The package dependency constraints are expected to be complete.
//
@@ -44,12 +62,120 @@ namespace bpkg
// be parallel to the dependencies argument and specify indexes of the
// selected alternatives.
//
- // If prerequisites corresponding to the previous configured state of the
- // package are specified, then for each depends value try to select an
- // alternative where dependencies all belong to this list (the "recreate
+ // If the dependency alternatives are not pre-selected (alternatives ==
+ // NULL), then for each depends value select the first satisfactory
+ // alternative encountered. If, however, prerequisites corresponding to the
+ // previous configured state of the package are specified
+ // (prev_prerequisites != NULL), then for each depends value try to select
+ // an alternative where dependencies all belong to this list (the "recreate
// dependency decisions" mode). Failed that, select an alternative as if no
// prerequisites are specified (the "make dependency decisions" mode).
//
+ // Note that there are actually 3 possible use cases for
+ // pkg_configure_prerequisites():
+ //
+ // - The package is being configured manually. In this case its dependency
+ // alternatives are not pre-selected and there is no information about its
+ // previous configured state (alternatives == NULL, prev_prerequisites ==
+ // NULL).
+ //
+ // - The package is being built, upgraded, or re-evaluated. In this case its
+ // dependency alternatives are pre-selected, their enable, prefer, and
+ // require clauses are evaluated, and there is no need in the previous
+ // configured state information (alternatives != NULL, prev_prerequisites
+ // == NULL).
+ //
+ // - The package is being reconfigured for a reason other than any of the
+ // mentioned above (dependency up/down-grade/reconfiguration, deorphaning,
+ // pkg-build --disfigure is specified, etc). In this case its dependency
+ // alternatives are not pre-selected but the previous configured state
+ // information is provided (alternatives == NULL, prev_prerequisites !=
+ // NULL).
+ //
+ // - There are no use cases when both dependency alternatives are
+ // pre-selected and the previous configured state information needs to be
+ // provided. Thus, alternatives and prev_prerequisites must never be both
+ // NULL.
+ //
+ // Optionally, remove constraints from the specified dependencies
+ // (unconstrain_deps). Only allowed in the simulation mode.
+ //
+ struct configure_prerequisites_result
+ {
+ package_prerequisites prerequisites;
+ vector<size_t> dependency_alternatives;
+ strings config_variables; // Note: name and value.
+
+ // Only contains sources of configuration variables collected using the
+ // package skeleton, excluding those user-specified variables which are
+ // not the project variables for the specified package (module
+ // configuration variables, etc). Thus, it is not parallel to the
+ // config_variables member.
+ //
+ vector<config_variable> config_sources; // Note: name and source.
+
+ // SHA256 checksum of variables (names and values) referred to by the
+ // config_sources member.
+ //
+ string config_checksum;
+ };
+
+ // Return the "would be" state for packages that would be configured
+ // by this stage.
+ //
+ using find_package_state_function =
+ optional<pair<package_state, package_substate>> (
+ const shared_ptr<selected_package>&);
+
+ // Note: loads selected packages.
+ //
+ configure_prerequisites_result
+ pkg_configure_prerequisites (
+ const common_options&,
+ database&,
+ transaction&,
+ const dependencies&,
+ const vector<size_t>* alternatives,
+ package_skeleton&&,
+ const vector<package_name>* prev_prerequisites,
+ bool simulate,
+ const function<find_database_function>&,
+ const function<find_package_state_function>&,
+ const vector<package_key>* unconstrain_deps = nullptr);
+
+ // Configure the package, update its state, and commit the transaction.
+ //
+ // This is a lower-level version meant for sharing the same build context
+ // to configure multiple packages (in the dependency order).
+ //
+ // Note: variable_overrides must include config.config.disfigure, if
+ // required.
+ //
+ // Note: expects all the non-external packages to be configured to be
+ // already unpacked (for subproject discovery).
+ //
+ void
+ pkg_configure (const common_options&,
+ database&,
+ transaction&,
+ const shared_ptr<selected_package>&,
+ configure_prerequisites_result&&,
+ const unique_ptr<build2::context>&,
+ const build2::variable_overrides&,
+ bool simulate);
+
+ // Create a build context suitable for configuring packages.
+ //
+ unique_ptr<build2::context>
+ pkg_configure_context (
+ const common_options&,
+ strings&& cmd_vars,
+ const function<build2::context::var_override_function>& = nullptr);
+
+ // This is a higher-level version meant for configuring a single package.
+ //
+ // Note: loads selected packages.
+ //
void
pkg_configure (const common_options&,
database&,
@@ -58,18 +184,10 @@ namespace bpkg
const dependencies&,
const vector<size_t>* alternatives,
package_skeleton&&,
- const vector<package_name>* prerequisites,
+ const vector<package_name>* prev_prerequisites,
bool disfigured,
bool simulate,
const function<find_database_function>& = {});
-
- // Configure a system package and commit the transaction.
- //
- shared_ptr<selected_package>
- pkg_configure_system (const package_name&,
- const version&,
- database&,
- transaction&);
}
#endif // BPKG_PKG_CONFIGURE_HXX
diff --git a/bpkg/pkg-disfigure.cxx b/bpkg/pkg-disfigure.cxx
index 690c3e1..2239314 100644
--- a/bpkg/pkg-disfigure.cxx
+++ b/bpkg/pkg-disfigure.cxx
@@ -72,6 +72,11 @@ namespace bpkg
// Since we are no longer configured, clear the prerequisites list.
//
p->prerequisites.clear ();
+ p->dependency_alternatives.clear ();
+
+ // Mark the section as loaded, so dependency alternatives are updated.
+ //
+ p->dependency_alternatives_section.load ();
assert (p->src_root); // Must be set since unpacked.
assert (p->out_root); // Must be set since configured.
@@ -200,7 +205,10 @@ namespace bpkg
}
if (disfigure)
+ {
p->config_variables.clear ();
+ p->config_checksum.clear ();
+ }
}
p->out_root = nullopt;
diff --git a/bpkg/pkg-drop.cli b/bpkg/pkg-drop.cli
index 7c2b0bd..75ee04d 100644
--- a/bpkg/pkg-drop.cli
+++ b/bpkg/pkg-drop.cli
@@ -81,6 +81,13 @@ namespace bpkg
"Issue an error if attempting to drop dependent packages."
}
+ uint16_t --dependent-exit
+ {
+ "<code>",
+ "Silently exit with the specified error code if attempting to drop
+ dependent packages."
+ }
+
bool --disfigure-only
{
"Disfigure all the packages but don't purge."
diff --git a/bpkg/pkg-drop.cxx b/bpkg/pkg-drop.cxx
index 7def795..d8fa4ea 100644
--- a/bpkg/pkg-drop.cxx
+++ b/bpkg/pkg-drop.cxx
@@ -51,23 +51,23 @@ namespace bpkg
};
using dependent_names = vector<dependent_name>;
- // A "dependency-ordered" list of packages and their prerequisites.
- // That is, every package on the list only possibly depending on the
- // ones after it. In a nutshell, the usage is as follows: we first add
- // the packages specified by the user (the "user selection"). We then
- // collect all the dependent packages of the user selection, if any.
- // These will either have to be dropped as well or we cannot continue.
- // If the user gave the go ahead to drop the dependents, then, for our
- // purposes, this list of dependents can from now own be treated as if
- // it was a part of the user selection. The next step is to collect all
- // the non-held prerequisites of the user selection with the goal of
- // figuring out which ones will no longer be needed and offering to
- // drop them as well. This part is a bit tricky and has to be done in
- // three steps: We first collect all the prerequisites that we could
- // possibly be dropping. We then order all the packages. And, finally,
- // we filter out prerequisites that we cannot drop. See the comment to
- // the call to collect_prerequisites() for details on why it has to be
- // done this way.
+ // A "dependency-ordered" list of packages and their prerequisites. That is,
+ // every package on the list only possibly depending on the ones after it.
+ // In a nutshell, the usage is as follows: we first add the packages
+ // specified by the user (the "user selection"). We then collect all the
+ // dependent packages of the user selection, if any. These will either have
+ // to be dropped as well or we cannot continue and need to either issue
+ // diagnostics and fail or exit with the specified (via --dependent-exit)
+ // code. If the user gave the go ahead to drop the dependents, then, for our
+ // purposes, this list of dependents can from now own be treated as if it
+ // was a part of the user selection. The next step is to collect all the
+ // non-held prerequisites of the user selection with the goal of figuring
+ // out which ones will no longer be needed and offering to drop them as
+ // well. This part is a bit tricky and has to be done in three steps: We
+ // first collect all the prerequisites that we could possibly be dropping.
+ // We then order all the packages. And, finally, we filter out prerequisites
+ // that we cannot drop. See the comment to the call to
+ // collect_prerequisites() for details on why it has to be done this way.
//
struct drop_packages: list<reference_wrapper<drop_package>>
{
@@ -520,6 +520,16 @@ namespace bpkg
dr << fail << "both --drop-dependent and --keep-dependent|-K "
<< "specified";
}
+ else if (o.drop_dependent () && o.dependent_exit_specified ())
+ {
+ dr << fail << "both --drop-dependent and --dependent-exit "
+ << "specified";
+ }
+ else if (o.keep_dependent () && o.dependent_exit_specified ())
+ {
+ dr << fail << "both --keep-dependent|-K and --dependent-exit "
+ << "specified";
+ }
else if (o.all ())
{
if (o.all_pattern_specified ())
@@ -632,11 +642,18 @@ namespace bpkg
// The next step is to see if there are any dependents that are not
// already on the list. We will either have to drop those as well or
- // abort.
+ // issue diagnostics and fail or silently indicate that with an exit
+ // code.
//
dependent_names dnames (pkgs.collect_dependents ());
if (!dnames.empty () && !o.drop_dependent ())
{
+ if (o.dependent_exit_specified ())
+ {
+ t.commit ();
+ return o.dependent_exit ();
+ }
+
{
diag_record dr;
diff --git a/bpkg/pkg-fetch.cxx b/bpkg/pkg-fetch.cxx
index 50f0937..837c968 100644
--- a/bpkg/pkg-fetch.cxx
+++ b/bpkg/pkg-fetch.cxx
@@ -10,6 +10,7 @@
#include <bpkg/package-odb.hxx>
#include <bpkg/checksum.hxx>
#include <bpkg/database.hxx>
+#include <bpkg/rep-mask.hxx>
#include <bpkg/diagnostics.hxx>
#include <bpkg/manifest-utility.hxx>
@@ -43,17 +44,24 @@ namespace bpkg
//
normalize (a, "archive");
+ // Only purge the existing archive if its path differs from the new path.
+ //
+ shared_ptr<selected_package> p (db.find<selected_package> (n));
+
+ bool purge_archive (p != nullptr &&
+ p->archive &&
+ p->effective_archive (db.config) != a);
+
if (a.sub (db.config))
a = a.leaf (db.config);
- shared_ptr<selected_package> p (db.find<selected_package> (n));
if (p != nullptr)
{
// Clean up the source directory and archive of the package we are
- // replacing. Once this is done, there is no going back. If things
- // go badly, we can't simply abort the transaction.
+ // replacing. Once this is done, there is no going back. If things go
+ // badly, we can't simply abort the transaction.
//
- pkg_purge_fs (db, t, p, simulate);
+ pkg_purge_fs (db, t, p, simulate, purge_archive);
// Note that if the package name spelling changed then we need to update
// it, to make sure that the subsequent commands don't fail and the
@@ -196,6 +204,8 @@ namespace bpkg
bool replace,
bool simulate)
{
+ assert (session::has_current ());
+
tracer trace ("pkg_fetch");
tracer_guard tg (pdb, trace); // NOTE: sets tracer for the whole cluster.
@@ -224,14 +234,17 @@ namespace bpkg
for (const package_location& l: ap->locations)
{
- const repository_location& rl (l.repository_fragment.load ()->location);
-
- if (rl.archive_based () && (pl == nullptr || rl.local ()))
+ if (!rep_masked_fragment (l.repository_fragment))
{
- pl = &l;
+ const repository_location& rl (l.repository_fragment.load ()->location);
- if (rl.local ())
- break;
+ if (rl.archive_based () && (pl == nullptr || rl.local ()))
+ {
+ pl = &l;
+
+ if (rl.local ())
+ break;
+ }
}
}
@@ -244,10 +257,76 @@ namespace bpkg
<< "from " << pl->repository_fragment->name;
auto_rmfile arm;
- path a (pdb.config_orig / pl->location.leaf ());
+ path an (pl->location.leaf ());
+ path a (pdb.config_orig / an);
+
+ // Note that in the replace mode we first fetch the new package version
+ // archive and then update the existing selected package object, dropping
+ // the previous package version archive, if present. This way we, in
+ // particular, keep the existing selected package/archive intact if the
+ // fetch operation fails. However, this approach requires to handle
+ // re-fetching (potentially from a different repository) of the same
+ // package version specially.
+ //
+ // Specifically, if we need to overwrite the package archive file, then we
+ // stash the existing archive in the temporary directory and remove it on
+ // success. On failure, we try to move the stashed archive to the original
+ // place. Failed that either, we mark the package as broken.
+ //
+ // (If you are wondering why don't we instead always fetch into a
+ // temporary file, the answer is Windows, where moving a newly created
+ // file may not succeed because it is being scanned by Windows Defender
+ // or some such.)
+ //
+ auto_rmfile earm;
+ shared_ptr<selected_package> sp;
+
+ auto g (
+ make_exception_guard (
+ [&arm, &a, &earm, &sp, &pdb, &t] ()
+ {
+ // Restore stashed archive.
+ //
+ if (!earm.path.empty () && exists (earm.path))
+ {
+ if (mv (earm.path, a, true /* ignore_error */))
+ {
+ earm.cancel ();
+ arm.cancel (); // Note: may not be armed yet, which is ok.
+ }
+ //
+ // Note: can already be marked as broken by pkg_purge_fs().
+ //
+ else if (sp->state != package_state::broken)
+ {
+ sp->state = package_state::broken;
+ pdb.update (sp);
+ t.commit ();
+
+ // Here we assume that mv() has already issued the diagnostics.
+ //
+ info << "package " << sp->name << pdb << " is now broken; "
+ << "use 'pkg-purge --force' to remove";
+ }
+ }
+ }));
if (!simulate)
{
+ // Stash the existing package archive if it needs to be overwritten (see
+ // above for details).
+ //
+ // Note: compare the archive absolute paths.
+ //
+ if (replace &&
+ (sp = pdb.find<selected_package> (n)) != nullptr &&
+ sp->archive &&
+ sp->effective_archive (pdb.config) == pdb.config / an)
+ {
+ earm = tmp_file (pdb.config_orig, n.string () + '-' + v.string ());
+ mv (a, earm.path);
+ }
+
pkg_fetch_archive (
co, pl->repository_fragment->location, pl->location, a);
diff --git a/bpkg/pkg-fetch.hxx b/bpkg/pkg-fetch.hxx
index 5d698d5..8607178 100644
--- a/bpkg/pkg-fetch.hxx
+++ b/bpkg/pkg-fetch.hxx
@@ -37,6 +37,8 @@ namespace bpkg
// Note that both package and repository information configurations need to
// be passed.
//
+ // Also note that it should be called in session.
+ //
shared_ptr<selected_package>
pkg_fetch (const common_options&,
database& pdb,
diff --git a/bpkg/pkg-install.hxx b/bpkg/pkg-install.hxx
index 3898c1a..3f257f0 100644
--- a/bpkg/pkg-install.hxx
+++ b/bpkg/pkg-install.hxx
@@ -5,7 +5,6 @@
#define BPKG_PKG_INSTALL_HXX
#include <bpkg/types.hxx>
-#include <bpkg/forward.hxx> // selected_package
#include <bpkg/utility.hxx>
#include <bpkg/pkg-command.hxx>
diff --git a/bpkg/pkg-purge.cxx b/bpkg/pkg-purge.cxx
index 4fe040e..e031b6a 100644
--- a/bpkg/pkg-purge.cxx
+++ b/bpkg/pkg-purge.cxx
@@ -50,6 +50,7 @@ namespace bpkg
//
p->src_root = nullopt;
p->manifest_checksum = nullopt;
+ p->buildfiles_checksum = nullopt;
if (archive)
{
@@ -57,7 +58,7 @@ namespace bpkg
{
if (!simulate)
{
- path a (p->archive->absolute () ? *p->archive : c / *p->archive);
+ path a (p->effective_archive (c));
if (exists (a))
rm (a);
@@ -191,7 +192,7 @@ namespace bpkg
if (p->purge_archive)
{
- path a (p->archive->absolute () ? *p->archive : c / *p->archive);
+ path a (p->effective_archive (c));
if (exists (a))
fail << "archive file of broken package " << n << " still exists" <<
diff --git a/bpkg/pkg-status.cli b/bpkg/pkg-status.cli
index 59319bf..084b7a3 100644
--- a/bpkg/pkg-status.cli
+++ b/bpkg/pkg-status.cli
@@ -218,7 +218,7 @@ namespace bpkg
]
\
- See the JSON OUTPUT section in \l{bdep-common-options(1)} for details on
+ See the JSON OUTPUT section in \l{bpkg-common-options(1)} for details on
the overall properties of this format and the semantics of the
\cb{struct} serialization.
diff --git a/bpkg/pkg-uninstall.hxx b/bpkg/pkg-uninstall.hxx
index c3df29a..6024fe1 100644
--- a/bpkg/pkg-uninstall.hxx
+++ b/bpkg/pkg-uninstall.hxx
@@ -5,7 +5,6 @@
#define BPKG_PKG_UNINSTALL_HXX
#include <bpkg/types.hxx>
-#include <bpkg/forward.hxx> // selected_package
#include <bpkg/utility.hxx>
#include <bpkg/pkg-command.hxx>
diff --git a/bpkg/pkg-unpack.cxx b/bpkg/pkg-unpack.cxx
index 48a64ea..22ff02f 100644
--- a/bpkg/pkg-unpack.cxx
+++ b/bpkg/pkg-unpack.cxx
@@ -10,6 +10,7 @@
#include <bpkg/package-odb.hxx>
#include <bpkg/database.hxx>
#include <bpkg/checksum.hxx>
+#include <bpkg/rep-mask.hxx>
#include <bpkg/diagnostics.hxx>
#include <bpkg/manifest-utility.hxx>
@@ -162,7 +163,10 @@ namespace bpkg
optional<string> mc;
optional<string> bc;
- if (!simulate)
+ // Only calculate the manifest/subprojects and buildfiles checksums for
+ // external packages (see selected_package::external() for details).
+ //
+ if (!simulate && (rl.empty () || rl.directory_based ()))
{
mc = package_checksum (o, d, pi);
@@ -221,7 +225,11 @@ namespace bpkg
false /* load_buildfiles */,
[&o, &d, &pvi] (version& v)
{
- pvi = package_version (o, d);
+ // Note that we also query subprojects since the package
+ // information will be used for the subsequent
+ // package_iteration() call.
+ //
+ pvi = package_version (o, d, b_info_flags::subprojects);
if (pvi.version)
v = move (*pvi.version);
@@ -281,7 +289,7 @@ namespace bpkg
check_any_available (rdb, t);
- // Note that here we compare including the revision (see pkg-fetch()
+ // Note that here we compare including the revision (see pkg_fetch()
// implementation for more details).
//
shared_ptr<available_package> ap (
@@ -297,7 +305,8 @@ namespace bpkg
for (const package_location& l: ap->locations)
{
- if (l.repository_fragment.load ()->location.directory_based ())
+ if (!rep_masked_fragment (l.repository_fragment) &&
+ l.repository_fragment.load ()->location.directory_based ())
{
pl = &l;
break;
@@ -330,7 +339,6 @@ namespace bpkg
shared_ptr<selected_package>
pkg_unpack (const common_options& co,
database& db,
- database& rdb,
transaction& t,
const package_name& name,
bool simulate)
@@ -363,19 +371,17 @@ namespace bpkg
dir_path d (c / dir_path (n.string () + '-' + v.string ()));
- if (exists (d))
- fail << "package directory " << d << " already exists";
-
auto_rmdir arm;
- optional<string> mc;
- optional<string> bc;
if (!simulate)
{
+ if (exists (d))
+ fail << "package directory " << d << " already exists";
+
// If the archive path is not absolute, then it must be relative
// to the configuration.
//
- path a (p->archive->absolute () ? *p->archive : c / *p->archive);
+ path a (p->effective_archive (c));
l4 ([&]{trace << "archive: " << a;});
@@ -398,62 +404,11 @@ namespace bpkg
{
fail << "unable to extract " << a << " to " << c << ": " << e;
}
-
- mc = package_checksum (co, d, nullptr /* package_info */);
-
- // Calculate the buildfiles checksum if the package has any buildfile
- // clauses in the dependencies.
- //
- // Note that we may not have the available package (e.g., fetched as an
- // existing package archive rather than from an archive repository), in
- // which case we need to parse the manifest to retrieve the
- // dependencies. This is unfortunate, but is probably not a big deal
- // performance-wise given that this is not too common and we are running
- // an archive unpacking process anyway.
- //
- shared_ptr<available_package> ap (
- rdb.find<available_package> (available_package_id (n, v)));
-
- if (ap != nullptr)
- {
- // Note that the available package already has all the buildfiles
- // loaded.
- //
- if (has_buildfile_clause (ap->dependencies))
- bc = package_buildfiles_checksum (ap->bootstrap_build,
- ap->root_build,
- ap->buildfiles);
- }
- else
- {
- // Note that we don't need to translate the package version here since
- // the manifest comes from an archive and so has a proper version
- // already.
- //
- package_manifest m (
- pkg_verify (co,
- d,
- true /* ignore_unknown */,
- false /* ignore_toolchain */,
- false /* load_buildfiles */,
- function<package_manifest::translate_function> ()));
-
- if (has_buildfile_clause (m.dependencies))
- bc = package_buildfiles_checksum (m.bootstrap_build,
- m.root_build,
- m.buildfiles,
- d,
- m.buildfile_paths,
- m.alt_naming);
- }
}
p->src_root = d.leaf (); // For now assuming to be in configuration.
p->purge_src = true;
- p->manifest_checksum = move (mc);
- p->buildfiles_checksum = move (bc);
-
p->state = package_state::unpacked;
db.update (p);
@@ -518,7 +473,6 @@ namespace bpkg
p = v.empty ()
? pkg_unpack (o,
db /* pdb */,
- db /* rdb */,
t,
n,
false /* simulate */)
diff --git a/bpkg/pkg-unpack.hxx b/bpkg/pkg-unpack.hxx
index 99d74e0..7394732 100644
--- a/bpkg/pkg-unpack.hxx
+++ b/bpkg/pkg-unpack.hxx
@@ -32,13 +32,9 @@ namespace bpkg
// Unpack the fetched package and commit the transaction.
//
- // Note that both package and repository information configurations need to
- // be passed.
- //
shared_ptr<selected_package>
pkg_unpack (const common_options&,
- database& pdb,
- database& rdb,
+ database&,
transaction&,
const package_name&,
bool simulate);
diff --git a/bpkg/pkg-update.hxx b/bpkg/pkg-update.hxx
index 3a2df8c..cac7651 100644
--- a/bpkg/pkg-update.hxx
+++ b/bpkg/pkg-update.hxx
@@ -5,7 +5,6 @@
#define BPKG_PKG_UPDATE_HXX
#include <bpkg/types.hxx>
-#include <bpkg/forward.hxx> // selected_package
#include <bpkg/utility.hxx>
#include <bpkg/pkg-command.hxx>
diff --git a/bpkg/pkg-verify.cxx b/bpkg/pkg-verify.cxx
index 0541f1b..d48c5b7 100644
--- a/bpkg/pkg-verify.cxx
+++ b/bpkg/pkg-verify.cxx
@@ -566,7 +566,7 @@ namespace bpkg
o.ignore_unknown () /* ignore_toolchain */,
o.deep () /* expand_values */,
o.deep () /* load_buildfiles */,
- o.deep () /* complete_depends */,
+ o.deep () /* complete_values */,
o.silent () ? 0 : 2));
if (o.manifest ())
diff --git a/bpkg/pkg-verify.hxx b/bpkg/pkg-verify.hxx
index 631f0be..0609844 100644
--- a/bpkg/pkg-verify.hxx
+++ b/bpkg/pkg-verify.hxx
@@ -26,7 +26,7 @@ namespace bpkg
// description-type value to the effective description type (see
// libbpkg/manifest.hxx), load the bootstrap, root, and config/*.build
// buildfiles into the respective *-build values, and complete the
- // dependency constraints.
+ // manifest values (depends, <distribution>-version, etc).
//
// Throw not_package (derived from failed) if this doesn't look like a
// package. Throw plain failed if this does looks like a package but
@@ -47,7 +47,7 @@ namespace bpkg
bool ignore_toolchain,
bool expand_values,
bool load_buildfiles,
- bool complete_depends = true,
+ bool complete_values = true,
int diag_level = 2);
// Similar to the above but verifies that a source directory is a valid
diff --git a/bpkg/rep-create.cxx b/bpkg/rep-create.cxx
index 6c95679..9b9bdeb 100644
--- a/bpkg/rep-create.cxx
+++ b/bpkg/rep-create.cxx
@@ -24,7 +24,7 @@ using namespace butl;
namespace bpkg
{
- struct package_version_key
+ struct package_name_version
{
package_name name;
bpkg::version version;
@@ -34,20 +34,20 @@ namespace bpkg
// revision.
//
bool
- operator< (const package_version_key& y) const
+ operator< (const package_name_version& y) const
{
int r (name.compare (y.name));
return r < 0 || (r == 0 && version.compare (y.version, true) < 0);
}
};
- struct package_version_data
+ struct package_data
{
path archive;
package_manifest manifest;
};
- using package_map = map<package_version_key, package_version_data>;
+ using package_map = map<package_name_version, package_data>;
static void
collect (const rep_create_options& o,
@@ -58,7 +58,7 @@ namespace bpkg
{
tracer trace ("collect");
- for (const dir_entry& de: dir_iterator (d, false /* ignore_dangling */))
+ for (const dir_entry& de: dir_iterator (d, dir_iterator::no_follow))
{
path p (de.path ());
@@ -116,8 +116,8 @@ namespace bpkg
//
m.location = a.leaf (root);
- package_version_key k {m.name, m.version}; // Argument evaluation order.
- auto r (map.emplace (move (k), package_version_data {a, move (m)}));
+ package_name_version k {m.name, m.version}; // Argument evaluation order.
+ auto r (map.emplace (move (k), package_data {a, move (m)}));
// Diagnose duplicates.
//
diff --git a/bpkg/rep-fetch.cxx b/bpkg/rep-fetch.cxx
index 30c429f..d02a064 100644
--- a/bpkg/rep-fetch.cxx
+++ b/bpkg/rep-fetch.cxx
@@ -314,7 +314,10 @@ namespace bpkg
if (bs &&
r.build2_dependency &&
!satisfy_build2 (co, *r.build2_dependency))
+ {
bs = false;
+ pds.clear (); // Won't now be used.
+ }
nvs.push_back (move (r));
}
@@ -328,11 +331,20 @@ namespace bpkg
}
mfs.push_back (move (f));
- pds.push_back (move (d));
+
+ if (bs)
+ pds.push_back (move (d));
}
+ // Note that for the directory-based repositories we also query
+ // subprojects since the package information will be used for the
+ // subsequent package_iteration() call (see below).
+ //
if (bs)
- pvs = package_versions (co, pds);
+ pvs = package_versions (co, pds,
+ (rl.directory_based ()
+ ? b_info_flags::subprojects
+ : b_info_flags::none));
}
// Parse package manifests, fixing up their versions.
@@ -474,25 +486,35 @@ namespace bpkg
// Load *-file values.
//
- m.load_files (
- [ev, &rd, &rl, &pl]
- (const string& n, const path& p) -> optional<string>
- {
- // Always expand the build-file values.
- //
- if (ev || n == "build-file")
+ try
+ {
+ m.load_files (
+ [ev, &rd, &rl, &pl]
+ (const string& n, const path& p) -> optional<string>
{
- return read_package_file (p,
- n,
- pl,
- rd,
- rl,
- empty_string /* fragment */);
- }
- else
- return nullopt;
- },
- iu);
+ // Always expand the build-file values.
+ //
+ if (ev || n == "build-file")
+ {
+ return read_package_file (p,
+ n,
+ pl,
+ rd,
+ rl,
+ empty_string /* fragment */);
+ }
+ else
+ return nullopt;
+ },
+ iu);
+ }
+ catch (const manifest_parsing& e)
+ {
+ diag_record dr (fail);
+ dr << e << info;
+ print_package_info (dr, pl, rl, nullopt /* fragment */);
+ dr << endf;
+ }
// Load the bootstrap, root, and config/*.build buildfiles into the
// respective *-build values, if requested and if they are not already
@@ -672,38 +694,49 @@ namespace bpkg
// Load *-file values.
//
- m.load_files (
- [ev, &td, &rl, &pl, &fr, &checkout_submodules]
- (const string& n, const path& p) -> optional<string>
- {
- // Always expand the build-file values.
- //
- if (ev || n == "build-file")
+ try
+ {
+ m.load_files (
+ [ev, &td, &rl, &pl, &fr, &checkout_submodules]
+ (const string& n, const path& p) -> optional<string>
{
- // Check out submodules if the referenced file doesn't exist.
+ // Always expand the build-file values.
//
- // Note that this doesn't work for symlinks on Windows where
- // git normally creates filesystem-agnostic symlinks that are
- // indistinguishable from regular files (see fixup_worktree()
- // for details). It seems like the only way to deal with that
- // is to unconditionally checkout submodules on Windows. Let's
- // not pessimize things for now (if someone really wants this
- // to work, they can always enable real symlinks in git).
- //
- if (!exists (td / pl / p))
- checkout_submodules ();
-
- return read_package_file (p,
- n,
- pl,
- td,
- rl,
- fr.friendly_name);
- }
- else
- return nullopt;
- },
- iu);
+ if (ev || n == "build-file")
+ {
+ // Check out submodules if the referenced file doesn't exist.
+ //
+ // Note that this doesn't work for symlinks on Windows where
+ // git normally creates filesystem-agnostic symlinks that
+ // are indistinguishable from regular files (see
+ // fixup_worktree() for details). It seems like the only way
+ // to deal with that is to unconditionally checkout
+ // submodules on Windows. Let's not pessimize things for now
+ // (if someone really wants this to work, they can always
+ // enable real symlinks in git).
+ //
+ if (!exists (td / pl / p))
+ checkout_submodules ();
+
+ return read_package_file (p,
+ n,
+ pl,
+ td,
+ rl,
+ fr.friendly_name);
+ }
+ else
+ return nullopt;
+ },
+ iu);
+ }
+ catch (const manifest_parsing& e)
+ {
+ diag_record dr (fail);
+ dr << e << info;
+ print_package_info (dr, pl, rl, fr.friendly_name);
+ dr << endf;
+ }
// Load the bootstrap, root, and config/*.build buildfiles into the
// respective *-build values, if requested and if they are not
@@ -1082,12 +1115,6 @@ namespace bpkg
//
if (rl.directory_based ())
{
- // Wouldn't be here otherwise. Note that rep_fetch_data is retrieved
- // by rep_fetch() with false passed as the ignore_toolchain argument
- // (see rep_fetch() for more details).
- //
- assert (!pis.empty ());
-
// Note that we can't check if the external package of this upstream
// version and revision is already available in the configuration
// until we fetch all the repositories, as some of the available
@@ -1101,7 +1128,7 @@ namespace bpkg
path_cast<dir_path> (rl.path () / *pm.location),
pm.name,
pm.version,
- &pis[i],
+ !pis.empty () ? &pis[i] : nullptr,
false /* check_external */));
if (v)
@@ -1286,6 +1313,12 @@ namespace bpkg
// repository fragments list, as well as its prerequisite and complement
// repository sets.
//
+ // Note that we do this in the forward compatible manner ignoring
+ // unrecognized manifest values and unsatisfied build2 toolchain
+ // constraints in the package manifests. This approach allows older
+ // toolchains to work with newer repositories, successfully building the
+ // toolchain-satisfied packages and only failing for unsatisfied ones.
+ //
rep_fetch_data rfd (
rep_fetch (co,
&db.config_orig,
@@ -1293,7 +1326,7 @@ namespace bpkg
rl,
dependent_trust,
true /* ignore_unknow */,
- false /* ignore_toolchain */,
+ true /* ignore_toolchain */,
false /* expand_values */,
true /* load_buildfiles */));
@@ -1584,12 +1617,17 @@ namespace bpkg
{
dependencies& ds (at.package->dependencies);
- // Note that the special test dependencies entry is always the last
- // one, if present.
+ // Note that there is only one special test dependencies entry in
+ // the test package.
//
- assert (!ds.empty () && ds.back ().type);
-
- ds.pop_back ();
+ for (auto i (ds.begin ()), e (ds.end ()); i != e; ++i)
+ {
+ if (i->type)
+ {
+ ds.erase (i);
+ break;
+ }
+ }
db.update (at.package);
}
@@ -1598,16 +1636,25 @@ namespace bpkg
// Go through the available packages that have external tests and add
// them as the special test dependencies to these test packages.
//
+ // Note that not being able to resolve the test package for a main
+ // package is not an error, since the test package absence doesn't
+ // affect the main package building and internal testing. Dropping of an
+ // external test package from a repository may, however, be intentional.
+ // Think of a private repository crafted as a subset of some public
+ // repository with the external examples packages omitted.
+ //
for (const auto& am: db.query<available_main> ())
{
const shared_ptr<available_package>& p (am.package);
+ const package_name& n (p->id.name);
+ const version& v (p->version);
vector<shared_ptr<repository_fragment>> rfs;
for (const package_location& pl: p->locations)
rfs.push_back (pl.repository_fragment.load ());
- bool module (build2_module (p->id.name));
+ bool module (build2_module (n));
for (const test_dependency& td: p->tests)
{
@@ -1617,7 +1664,7 @@ namespace bpkg
if (module && !td.buildtime)
fail << "run-time " << td.type << ' ' << td.name << " for build "
<< "system module "
- << package_string (p->id.name, p->version) <<
+ << package_string (n, v) <<
info << "build system modules cannot have run-time " << td.type;
vector<pair<shared_ptr<available_package>,
@@ -1635,11 +1682,12 @@ namespace bpkg
dependencies& ds (tp->dependencies);
- if (ds.empty () || !ds.back ().type)
- ds.push_back (dependency_alternatives_ex (td.type,
- td.buildtime));
-
- dependency_alternatives_ex& das (ds.back ());
+ // Find the special test dependencies entry, if already present.
+ //
+ auto b (ds.begin ());
+ auto e (ds.end ());
+ auto oi (b); // Old entry location.
+ for (; oi != e && !oi->type; ++oi) ;
// Note that since we store all the primary packages as
// alternative dependencies (which must be all of the same
@@ -1650,12 +1698,10 @@ namespace bpkg
// `== <version>` constraints (see below), so we can use min
// version of such a constraint as the primary package version.
//
- if (das.buildtime != td.buildtime)
+ if (oi != e && oi->buildtime != td.buildtime)
{
- // Could only be empty if we just added it, which cannot be the
- // case since the build-time flag differs.
- //
- assert (!das.empty ());
+ dependency_alternatives_ex& das (*oi);
+ assert (!das.empty ()); // Cannot be empty if present.
const dependency_alternative& da (das[0]);
@@ -1671,19 +1717,87 @@ namespace bpkg
<< package_string (da[0].name,
*da[0].constraint->min_version) <<
info << (td.buildtime ? "build-time for " : "run-time for ")
- << package_string (p->id.name, p->version);
+ << package_string (n, v);
}
- dependency_alternative da (nullopt /* enable */,
+ // Find the (new) location for the special test dependencies entry.
+ //
+ // Note that if the entry is already present, it can only be moved
+ // towards the end of the list.
+ //
+ auto ni (e);
+
+ // First, find the last depends clause that explicitly specifies
+ // this main package but goes after the special entry current
+ // location, if present. Note that we only consider clauses with
+ // the matching buildtime flag.
+ //
+ for (auto i (oi != e ? oi + 1 : b); i != e; ++i)
+ {
+ const dependency_alternatives_ex& das (*i);
+ if (das.buildtime == td.buildtime)
+ {
+ bool specifies (false);
+
+ for (const dependency_alternative& da: das)
+ {
+ for (const dependency& d: da)
+ {
+ if (d.name == n)
+ {
+ specifies = true;
+ break;
+ }
+ }
+
+ if (specifies)
+ break;
+ }
+
+ if (specifies)
+ ni = i;
+ }
+ }
+
+ // Now, set ni to refer to the special test dependencies entry,
+ // moving or creating one, if required.
+ //
+ if (oi != e) // The entry already exists?
+ {
+ if (ni != e) // Move the entry to the new location?
+ {
+ // Move the [oi + 1, ni] range 1 position to the left and
+ // move the *oi element to the now vacant ni slot.
+ //
+ rotate (oi, oi + 1, ni + 1);
+ }
+ else
+ ni = oi; // Leave the entry at the old location.
+ }
+ else // The entry doesn't exist.
+ {
+ if (ni != e) // Create the entry right after ni?
+ ++ni;
+ else
+ ni = b; // Create the entry at the beginning of the list.
+
+ ni = ds.emplace (ni, td.type, td.buildtime); // Create the entry.
+ }
+
+ // Finally, add the new dependency alternative to the special
+ // entry.
+ //
+ dependency_alternative da (td.enable,
td.reflect,
nullopt /* prefer */,
nullopt /* accept */,
nullopt /* require */);
- da.push_back (
- dependency {p->id.name, version_constraint (p->version)});
+ da.push_back (dependency {n, version_constraint (v)});
+
+ assert (ni != ds.end ()); // Must be deduced by now.
- das.push_back (move (da));
+ ni->push_back (move (da));
db.update (tp);
}
diff --git a/bpkg/rep-mask.cxx b/bpkg/rep-mask.cxx
new file mode 100644
index 0000000..d7f9c6a
--- /dev/null
+++ b/bpkg/rep-mask.cxx
@@ -0,0 +1,368 @@
+// file : bpkg/rep-mask.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <bpkg/rep-mask.hxx>
+
+#include <bpkg/package.hxx>
+#include <bpkg/package-odb.hxx>
+#include <bpkg/database.hxx>
+#include <bpkg/diagnostics.hxx>
+#include <bpkg/package-query.hxx> // repo_configs
+#include <bpkg/manifest-utility.hxx> // repository_name()
+
+using namespace std;
+using namespace butl;
+
+namespace bpkg
+{
+ static optional<database_map<strings>> unmasked_repositories;
+ static optional<database_map<strings>> unmasked_repository_fragments;
+
+ // Note: defined in rep-remove.cxx.
+ //
+ void
+ rep_remove (database&,
+ transaction&,
+ const shared_ptr<repository>&,
+ bool mask);
+
+ // The overall plan is as follows:
+ //
+ // - Start the transaction.
+ //
+ // - Remove all the specified repositories recursively in all the
+ // configurations specified by repo_configs (repos) and/or configurations
+ // specified explicitly via UUIDs (config_uuid_repos).
+ //
+ // - Collect the remaining repositories and repository fragments as unmasked.
+ //
+ // - Rollback the transaction.
+ //
+ // Later on, the rep_masked*() functions will refer to the configuration-
+ // specific unmasked repositories and repository fragments lists to decide
+ // if the repository/fragment is masked or not in the specific configuration.
+ //
+ void
+ rep_mask (const strings& repos,
+ const strings& config_uuid_repos,
+ linked_databases& current_configs)
+ {
+ tracer trace ("rep_mask");
+
+ assert (!repo_configs.empty ());
+
+ database& mdb (repo_configs.front ());
+ tracer_guard tg (mdb, trace);
+
+ // Temporary "suspend" session before modifying the database.
+ //
+ session* sess (session::current_pointer ());
+ if (sess != nullptr)
+ session::reset_current ();
+
+ vector<lazy_weak_ptr<repository>> rs;
+ vector<bool> found_repos (repos.size(), false);
+
+ transaction t (mdb);
+
+ // Add a repository from a database, suppressing duplicates.
+ //
+ auto add_repo = [&rs] (database& db, shared_ptr<repository>&& r)
+ {
+ if (find_if (rs.begin (), rs.end (),
+ [&db, &r] (const lazy_weak_ptr<repository>& lr)
+ {
+ return lr.database () == db && lr.object_id () == r->name;
+ }) == rs.end ())
+ rs.emplace_back (db, move (r));
+ };
+
+ // Collect the repositories masked in all configurations.
+ //
+ for (database& db: repo_configs)
+ {
+ for (size_t i (0); i != repos.size (); ++i)
+ {
+ // Add a repository, suppressing duplicates, and mark it as found.
+ //
+ auto add = [&db,
+ &found_repos, i,
+ &add_repo] (shared_ptr<repository>&& r)
+ {
+ add_repo (db, move (r));
+ found_repos[i] = true;
+ };
+
+ const string& rp (repos[i]);
+
+ if (repository_name (rp))
+ {
+ if (shared_ptr<repository> r = db.find<repository> (rp))
+ add (move (r));
+ }
+ else
+ {
+ using query = query<repository>;
+
+ // Verify that the repository URL is not misspelled or empty.
+ //
+ try
+ {
+ repository_url u (rp);
+ assert (!u.empty ());
+ }
+ catch (const invalid_argument& e)
+ {
+ fail << "repository '" << rp << "' cannot be masked: "
+ << "invalid repository location: " << e;
+ }
+
+ for (shared_ptr<repository> r:
+ pointer_result (
+ db.query<repository> (query::location.url == rp)))
+ add (move (r));
+ }
+ }
+ }
+
+ // Fail if any of the specified repositories is not found in any database.
+ //
+ for (size_t i (0); i != repos.size (); ++i)
+ {
+ if (!found_repos[i])
+ fail << "repository '" << repos[i] << "' cannot be masked: not found";
+ }
+
+ // Collect the repositories masked in specific configurations.
+ //
+ for (const string& cr: config_uuid_repos)
+ {
+ auto bad = [&cr] (const string& d)
+ {
+ fail << "configuration repository '" << cr << "' cannot be masked: "
+ << d;
+ };
+
+ size_t p (cr.find ('='));
+
+ if (p == string::npos)
+ bad ("missing '='");
+
+ uuid uid;
+ string uid_str (cr, 0, p);
+
+ try
+ {
+ uid = uuid (uid_str);
+ }
+ catch (const invalid_argument& e)
+ {
+ bad ("invalid configuration uuid '" + uid_str + "': " + e.what ());
+ }
+
+ database* db (nullptr);
+
+ for (database& cdb: current_configs)
+ {
+ if ((db = cdb.try_find_dependency_config (uid)) != nullptr)
+ break;
+ }
+
+ if (db == nullptr)
+ bad ("no configuration with uuid " + uid.string () +
+ " is linked with " +
+ (current_configs.size () == 1
+ ? mdb.config_orig.representation ()
+ : "specified current configurations"));
+
+ string rp (cr, p + 1);
+
+ if (repository_name (rp))
+ {
+ if (shared_ptr<repository> r = db->find<repository> (rp))
+ add_repo (*db, move (r));
+ else
+ bad ("repository name '" + rp + "' not found in configuration " +
+ uid.string ());
+ }
+ else
+ {
+ using query = query<repository>;
+
+ // Verify that the repository URL is not misspelled or empty.
+ //
+ try
+ {
+ repository_url u (rp);
+ assert (!u.empty ());
+ }
+ catch (const invalid_argument& e)
+ {
+ bad ("invalid repository location '" + rp + "': " + e.what ());
+ }
+
+ bool found (false);
+ for (shared_ptr<repository> r:
+ pointer_result (
+ db->query<repository> (query::location.url == rp)))
+ {
+ add_repo (*db, move (r));
+ found = true;
+ }
+
+ if (!found)
+ bad ("repository location '" + rp + "' not found in configuration " +
+ uid.string ());
+ }
+ }
+
+ // First, remove the repository references from the dependent repository
+ // fragments. Note that rep_remove() removes the dangling repositories.
+ //
+ // Note that for efficiency we un-reference all the repositories before
+ // starting to delete them.
+ //
+ for (const lazy_weak_ptr<repository>& r: rs)
+ {
+ database& db (r.database ());
+ const string& nm (r.object_id ());
+
+ // Remove from complements of the dependents.
+ //
+ for (const auto& rf: db.query<repository_complement_dependent> (
+ query<repository_complement_dependent>::complement::name == nm))
+ {
+ const shared_ptr<repository_fragment>& f (rf);
+ repository_fragment::dependencies& cs (f->complements);
+
+ auto i (cs.find (r));
+ assert (i != cs.end ());
+
+ cs.erase (i);
+ db.update (f);
+ }
+
+ // Remove from prerequisites of the dependents.
+ //
+ for (const auto& rf:
+ db.query<repository_prerequisite_dependent> (
+ query<repository_prerequisite_dependent>::prerequisite::name ==
+ nm))
+ {
+ const shared_ptr<repository_fragment>& f (rf);
+ repository_fragment::dependencies& ps (f->prerequisites);
+
+ auto i (ps.find (r));
+ assert (i != ps.end ());
+
+ ps.erase (i);
+ db.update (f);
+ }
+ }
+
+ // Remove the now dangling repositories.
+ //
+ for (const lazy_weak_ptr<repository>& r: rs)
+ rep_remove (r.database (), t, r.load (), true /* mask */);
+
+ // Collect the repositories and fragments which have remained after the
+ // removal.
+ //
+ unmasked_repositories = database_map<strings> ();
+ unmasked_repository_fragments = database_map<strings> ();
+
+ for (database& db: repo_configs)
+ {
+ // Add the repository location canonical name to the database-specific
+ // unmasked repositories or repository fragments lists. Note that
+ // repository location is used only for tracing.
+ //
+ auto add = [&db, &trace] (string&& n,
+ database_map<strings>& m,
+ const repository_location& loc,
+ const char* what)
+ {
+ auto i (m.find (db));
+ if (i == m.end ())
+ i = m.insert (db, strings ()).first;
+
+ l4 ([&]{trace << "unmasked " << what << ": '" << n
+ << "' '" << loc.url () << "'" << db;});
+
+ i->second.push_back (move (n));
+ };
+
+ for (shared_ptr<repository> r: pointer_result (db.query<repository> ()))
+ add (move (r->name),
+ *unmasked_repositories,
+ r->location,
+ "repository");
+
+ for (shared_ptr<repository_fragment> f:
+ pointer_result (db.query<repository_fragment> ()))
+ add (move (f->name),
+ *unmasked_repository_fragments,
+ f->location,
+ "repository fragment");
+ }
+
+ // Rollback the transaction and restore the session, if present.
+ //
+ t.rollback ();
+
+ if (sess != nullptr)
+ session::current_pointer (sess);
+ }
+
+ static inline bool
+ masked (database& db,
+ const string& name,
+ const optional<database_map<strings>>& m)
+ {
+ if (!m)
+ return false;
+
+ auto i (m->find (db));
+ if (i != m->end ())
+ {
+ const strings& ns (i->second);
+ return find (ns.begin (), ns.end (), name) == ns.end ();
+ }
+
+ return true;
+ }
+
+ bool
+ rep_masked (database& db, const shared_ptr<repository>& r)
+ {
+ return masked (db, r->name, unmasked_repositories);
+ }
+
+ bool
+ rep_masked (const lazy_weak_ptr<repository>& r)
+ {
+ // Should not be transient.
+ //
+ assert (!(r.lock ().get_eager () != nullptr && !r.loaded ()));
+
+ return masked (r.database (), r.object_id (), unmasked_repositories);
+ }
+
+ bool
+ rep_masked_fragment (database& db, const shared_ptr<repository_fragment>& f)
+ {
+ return masked (db, f->name, unmasked_repository_fragments);
+ }
+
+ bool
+ rep_masked_fragment (const lazy_shared_ptr<repository_fragment>& f)
+ {
+ // Should not be transient.
+ //
+ assert (!(f.get_eager () != nullptr && !f.loaded ()));
+
+ return masked (f.database (),
+ f.object_id (),
+ unmasked_repository_fragments);
+ }
+}
diff --git a/bpkg/rep-mask.hxx b/bpkg/rep-mask.hxx
new file mode 100644
index 0000000..2185af2
--- /dev/null
+++ b/bpkg/rep-mask.hxx
@@ -0,0 +1,73 @@
+// file : bpkg/rep-mask.hxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BPKG_REP_MASK_HXX
+#define BPKG_REP_MASK_HXX
+
+#include <bpkg/types.hxx>
+#include <bpkg/forward.hxx> // database, repository
+#include <bpkg/utility.hxx>
+
+namespace bpkg
+{
+ // Note: not a command (at least not yet).
+ //
+ // Mask repositories to pretend they don't exist in the configurations that
+ // are used as the repository information sources (repo_configs;
+ // repositories argument) and/or specific configurations
+ // (config_uuid_repositories argument). Also mask their complement and
+ // prerequisite repositories, recursively, excluding those which are
+ // complements and/or prerequisites of other unmasked repositories. The
+ // repositories can be specified either as repository location canonical
+ // names or URLs. Issue diagnostics and fail if any of the specified
+ // repositories don't exist in any configuration.
+ //
+ // Notes:
+ //
+ // - The current configurations are only used to resolve the configuration
+ // UUIDs, if any.
+ //
+ // - A repository may end up being masked in one configuration but not in
+ // another.
+ //
+ // - Using a canonical name potentially masks repositories with different
+ // URLs in different configurations (think of local and remote pkg
+ // repository locations).
+ //
+ // - Using a URL potentially masks repositories with different canonical
+ // names in the same configuration (think of directory and local git
+ // repository locations).
+ //
+ // NOTE: repo_configs needs to be filled prior to the function call.
+ //
+ void
+ rep_mask (const strings& repositories, // <rep>
+ const strings& config_uuid_repositories, // <config-uuid>=<rep>
+ linked_databases& current_configs);
+
+ // Return true if a repository is masked in the specified configuration.
+ //
+ bool
+ rep_masked (database&, const shared_ptr<repository>&);
+
+ // Note: the argument must refer to a persistent object which incorporates
+ // the configuration information (database).
+ //
+ bool
+ rep_masked (const lazy_weak_ptr<repository>&);
+
+ // Return true if a repository fragment in the specified configuration
+ // belongs to the masked repositories only and is therefore masked (see
+ // package.hxx for the fragment/repository relationship details).
+ //
+ bool
+ rep_masked_fragment (database&, const shared_ptr<repository_fragment>&);
+
+ // Note: the argument must refer to a persistent object which incorporates
+ // the configuration information (database).
+ //
+ bool
+ rep_masked_fragment (const lazy_shared_ptr<repository_fragment>&);
+}
+
+#endif // BPKG_REP_MASK_HXX
diff --git a/bpkg/rep-remove.cxx b/bpkg/rep-remove.cxx
index 26d5725..ad10f56 100644
--- a/bpkg/rep-remove.cxx
+++ b/bpkg/rep-remove.cxx
@@ -143,8 +143,20 @@ namespace bpkg
rm_r (td, true /* dir_itself */, 3, rm_error_mode::warn);
}
+ static void
+ rep_remove_fragment (database&,
+ transaction&,
+ const shared_ptr<repository_fragment>&,
+ bool mask);
+
+ // In the mask repositories mode don't cleanup the repository state in the
+ // filesystem (see rep-mask.hxx for the details on repository masking).
+ //
void
- rep_remove (database& db, transaction& t, const shared_ptr<repository>& r)
+ rep_remove (database& db,
+ transaction& t,
+ const shared_ptr<repository>& r,
+ bool mask)
{
assert (!r->name.empty ()); // Can't be the root repository.
@@ -164,7 +176,7 @@ namespace bpkg
// Remove dangling repository fragments.
//
for (const repository::fragment_type& fr: r->fragments)
- rep_remove_fragment (db, t, fr.fragment.load ());
+ rep_remove_fragment (db, t, fr.fragment.load (), mask);
// If there are no repositories stayed in the database then no repository
// fragments should stay either.
@@ -172,8 +184,8 @@ namespace bpkg
if (db.query_value<repository_count> () == 0)
assert (db.query_value<repository_fragment_count> () == 0);
- // Cleanup the repository state if present and there are no more
- // repositories referring this state.
+ // Unless in the mask repositories mode, cleanup the repository state if
+ // present and there are no more repositories referring this state.
//
// Note that this step is irreversible on failure. If something goes wrong
// we will end up with a state-less fetched repository and the
@@ -184,44 +196,58 @@ namespace bpkg
// then remove them after committing the transaction. Though, we still may
// fail in the middle due to the filesystem error.
//
- dir_path d (repository_state (r->location));
-
- if (!d.empty ())
+ if (!mask)
{
- dir_path sd (db.config_orig / repos_dir / d);
+ dir_path d (repository_state (r->location));
- if (exists (sd))
+ if (!d.empty ())
{
- // There is no way to get the list of repositories that share this
- // state other than traversing all repositories of this type.
- //
- bool rm (true);
-
- using query = query<repository>;
+ dir_path sd (db.config_orig / repos_dir / d);
- for (shared_ptr<repository> rp:
- pointer_result (
- db.query<repository> (
- query::name != "" &&
- query::location.type == to_string (r->location.type ()))))
+ if (exists (sd))
{
- if (repository_state (rp->location) == d)
+ // There is no way to get the list of repositories that share this
+ // state other than traversing all repositories of this type.
+ //
+ bool rm (true);
+
+ using query = query<repository>;
+
+ for (shared_ptr<repository> rp:
+ pointer_result (
+ db.query<repository> (
+ query::name != "" &&
+ query::location.type == to_string (r->location.type ()))))
{
- rm = false;
- break;
+ if (repository_state (rp->location) == d)
+ {
+ rm = false;
+ break;
+ }
}
- }
- if (rm)
- rmdir (db.config_orig, sd);
+ if (rm)
+ rmdir (db.config_orig, sd);
+ }
}
}
}
void
+ rep_remove (database& db, transaction& t, const shared_ptr<repository>& r)
+ {
+ rep_remove (db, t, r, false /* mask */);
+ }
+
+ // In the mask repositories mode don't remove the repository fragment from
+ // locations of the available packages it contains (see rep-mask.hxx for the
+ // details on repository masking).
+ //
+ static void
rep_remove_fragment (database& db,
transaction& t,
- const shared_ptr<repository_fragment>& rf)
+ const shared_ptr<repository_fragment>& rf,
+ bool mask)
{
tracer trace ("rep_remove_fragment");
@@ -235,11 +261,12 @@ namespace bpkg
"fragment=" + query::_val (rf->name)) != 0)
return;
- // Remove the repository fragment from locations of the available packages
- // it contains. Note that this must be done before the repository fragment
- // removal.
+ // Unless in the mask repositories mode, remove the repository fragment
+ // from locations of the available packages it contains. Note that this
+ // must be done before the repository fragment removal.
//
- rep_remove_package_locations (db, t, rf->name);
+ if (!mask)
+ rep_remove_package_locations (db, t, rf->name);
// Remove the repository fragment.
//
@@ -255,8 +282,8 @@ namespace bpkg
//
if (db.query_value<repository_fragment_count> () == 0)
{
- assert (db.query_value<repository_count> () == 0);
- assert (db.query_value<available_package_count> () == 0);
+ assert (db.query_value<repository_count> () == 0);
+ assert (mask || db.query_value<available_package_count> () == 0);
}
// Remove dangling complements and prerequisites.
@@ -264,10 +291,10 @@ namespace bpkg
// Prior to removing a prerequisite/complement we need to make sure it
// still exists, which may not be the case due to the dependency cycle.
//
- auto remove = [&db, &t] (const lazy_weak_ptr<repository>& rp)
+ auto remove = [&db, &t, mask] (const lazy_weak_ptr<repository>& rp)
{
if (shared_ptr<repository> r = db.find<repository> (rp.object_id ()))
- rep_remove (db, t, r);
+ rep_remove (db, t, r, mask);
};
for (const lazy_weak_ptr<repository>& cr: rf->complements)
@@ -284,6 +311,14 @@ namespace bpkg
}
void
+ rep_remove_fragment (database& db,
+ transaction& t,
+ const shared_ptr<repository_fragment>& rf)
+ {
+ return rep_remove_fragment (db, t, rf, false /* mask */);
+ }
+
+ void
rep_remove_clean (const common_options& o, database& db, bool quiet)
{
tracer trace ("rep_remove_clean");
@@ -336,7 +371,7 @@ namespace bpkg
try
{
- for (const dir_entry& de: dir_iterator (rd, false /* ignore_dangling */))
+ for (const dir_entry& de: dir_iterator (rd, dir_iterator::no_follow))
{
if (de.ltype () == entry_type::directory)
rmdir (db.config_orig, rd / path_cast<dir_path> (de.path ()));
diff --git a/bpkg/repository-types.cli b/bpkg/repository-types.cli
index 21ddaf9..1692a13 100644
--- a/bpkg/repository-types.cli
+++ b/bpkg/repository-types.cli
@@ -189,7 +189,9 @@ that they support fetching minimal history for tags and branches and may or
may not support this for commit ids depending on the server configuration.
Note, however, that unlike for \cb{http(s)://}, for these protocols \cb{bpkg}
does not try to sense if fetching unadvertised commits is allowed and always
-assumes that it is not.
+assumes that it is not. Also note that the sensed or assumed protocol
+capabilities can be overridden for a \cb{git} repository URL prefix using the
+\cb{--git-capabilities} option (\l{bpkg-common-options(1)}).
Based on this information, to achieve optimal results the recommended protocol
for remote repositories is smart \cb{https://}. Additionally, if you are
diff --git a/bpkg/satisfaction.cxx b/bpkg/satisfaction.cxx
index cbcb5a0..4229004 100644
--- a/bpkg/satisfaction.cxx
+++ b/bpkg/satisfaction.cxx
@@ -34,13 +34,19 @@ namespace bpkg
//
if (c.min_version)
{
- int i (ev.compare (*c.min_version, !c.min_version->revision));
+ int i (ev.compare (*c.min_version,
+ !c.min_version->revision,
+ true /* ignore_iteration */));
+
s = c.min_open ? i > 0 : i >= 0;
}
if (s && c.max_version)
{
- int i (ev.compare (*c.max_version, !c.max_version->revision));
+ int i (ev.compare (*c.max_version,
+ !c.max_version->revision,
+ true /* ignore_iteration */));
+
s = c.max_open ? i < 0 : i <= 0;
}
@@ -85,7 +91,10 @@ namespace bpkg
version lv (norm (*l.min_version, true /* min */, l.min_open));
version rv (norm (*r.min_version, true /* min */, r.min_open));
- int i (lv.compare (rv, false /* ignore_revision */));
+ int i (lv.compare (rv,
+ false /* ignore_revision */,
+ true /* ignore_iteration */));
+
if (l.min_open)
// Doesn't matter if r is min_open or not.
//
@@ -108,7 +117,10 @@ namespace bpkg
version lv (norm (*l.max_version, false /* min */, l.max_open));
version rv (norm (*r.max_version, false /* min */, r.max_open));
- int i (lv.compare (rv, false /* ignore_revision */));
+ int i (lv.compare (rv,
+ false /* ignore_revision */,
+ true /* ignore_iteration */));
+
if (l.max_open)
// Doesn't matter if r is max_open or not.
//
diff --git a/bpkg/satisfaction.hxx b/bpkg/satisfaction.hxx
index 8df4580..174e375 100644
--- a/bpkg/satisfaction.hxx
+++ b/bpkg/satisfaction.hxx
@@ -12,8 +12,13 @@
namespace bpkg
{
- // Note: all of the following functions expect the package version
- // constraints to be complete.
+ // Notes:
+ //
+ // - All of the following functions expect the package version constraints
+ // to be complete.
+ //
+ // - The version iterations are ignored on version comparisons.
+ //
// Return true if version satisfies the constraint.
//
diff --git a/bpkg/system-package-manager-archive.cxx b/bpkg/system-package-manager-archive.cxx
new file mode 100644
index 0000000..d46e6d6
--- /dev/null
+++ b/bpkg/system-package-manager-archive.cxx
@@ -0,0 +1,794 @@
+// file : bpkg/system-package-manager-archive.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <bpkg/system-package-manager-archive.hxx>
+
+#include <map>
+
+#include <bpkg/diagnostics.hxx>
+
+#include <bpkg/pkg-bindist-options.hxx>
+
+using namespace butl;
+
+namespace bpkg
+{
+ system_package_manager_archive::
+ system_package_manager_archive (bpkg::os_release&& osr,
+ const target_triplet& h,
+ string a,
+ optional<bool> progress,
+ const pkg_bindist_options* options)
+ : system_package_manager (move (osr), h, "", progress), ops (options)
+ {
+ if (!a.empty ())
+ {
+ assert (ops != nullptr);
+
+ try
+ {
+ target = target_triplet (a);
+ }
+ catch (const invalid_argument& e)
+ {
+ fail << "invalid --architecture target triplet value '" << a << "': "
+ << e;
+ }
+
+ if (!ops->os_release_id_specified ())
+ fail << "--architecture requires explict --os-release-id";
+
+ if (!ops->archive_install_root_specified () &&
+ !ops->archive_install_config ())
+ fail << "--architecture requires explict --archive-install-root";
+ }
+ else
+ target = host;
+
+ arch = target.string (); // Set since queried (e.g., JSON value).
+ }
+
+ // env --chdir=<root> tar|zip ... <base>.<ext> <base>
+ //
+ // Return the archive file path.
+ //
+ static path
+ archive (const dir_path& root,
+ const string& base,
+ const string& e /* ext */)
+ {
+ // NOTE: similar code in build2 (libbuild2/dist/operation.cxx).
+
+ path an (base + '.' + e);
+ path ap (root / an);
+
+ // Use zip for .zip archives. Also recognize and handle a few well-known
+ // tar.xx cases (in case tar doesn't support -a or has other issues like
+ // MSYS). Everything else goes to tar in the auto-compress mode (-a).
+ //
+ // Note also that we pass the archive path as name (an) instead of path
+ // (ap) since we are running from the root directory (see below).
+ //
+ cstrings args;
+
+ // Separate compressor (gzip, xz, etc) state.
+ //
+ size_t i (0); // Command line start or 0 if not used.
+ auto_rmfile out_rm; // Output file cleanup (must come first).
+ auto_fd out_fd; // Output file.
+
+ if (e == "zip")
+ {
+ // On Windows we use libarchive's bsdtar (zip is an MSYS executable).
+ //
+ // While not explicitly stated, the compression-level option works
+ // for zip archives.
+ //
+#ifdef _WIN32
+ args = {"bsdtar",
+ "-a", // -a with the .zip extension seems to be the only way.
+ "--options=compression-level=9",
+ "-cf", an.string ().c_str (),
+ base.c_str (),
+ nullptr};
+#else
+ args = {"zip",
+ "-9",
+ "-rq", an.string ().c_str (),
+ base.c_str (),
+ nullptr};
+#endif
+ }
+ else
+ {
+ // On Windows we use libarchive's bsdtar with auto-compression (tar
+ // itself and quite a few compressors are MSYS executables).
+ //
+ // OpenBSD tar does not support --format but it appear ustar is the
+ // default (while this is not said explicitly in tar(1), it is said in
+ // pax(1) and confirmed on the mailing list). Nor does it support -a, at
+ // least as of 7.1 but we will let this play out naturally, in case this
+ // support gets added.
+ //
+ // Note also that in the future we may switch to libarchive in order to
+ // generate reproducible archives.
+ //
+ const char* l (nullptr); // Compression level (option).
+
+#ifdef _WIN32
+ args = {"bsdtar", "--format", "ustar"};
+
+ if (e == "tar.gz" || e == "tar.xz")
+ l = "--options=compression-level=9";
+#else
+ args = {"tar"
+#ifndef __OpenBSD__
+ , "--format", "ustar"
+#endif
+ };
+
+ // For gzip it's a good idea to use -9 by default. While for xz, -9 is
+ // not recommended as the default due to memory requirements, in our
+ // case (large binary archives on development machines), this is
+ // unlikely to be an issue.
+ //
+ // Note also that the compression level can be altered via the GZIP
+ // (GZIP_OPT also seems to work) and XZ_OPT environment variables,
+ // respectively.
+ //
+ const char* c (nullptr);
+
+ if (e == "tar.gz") { c = "gzip"; l = "-9"; }
+ else if (e == "tar.xz")
+ {
+ // At least as of Mac OS 13 and Xcode 15, there is no standalone xz
+ // utility but tar seem to be capable of producing .tar.xz.
+ //
+#ifdef __APPLE__
+ l = "--options=compression-level=9";
+#else
+ c = "xz"; l = "-9";
+#endif
+ }
+
+ if (c != nullptr)
+ {
+ args.push_back ("-cf");
+ args.push_back ("-");
+ args.push_back (base.c_str ());
+ args.push_back (nullptr); i = args.size ();
+ args.push_back (c);
+ if (l != nullptr)
+ args.push_back (l);
+ args.push_back (nullptr);
+ args.push_back (nullptr); // Pipe end.
+
+ try
+ {
+ out_fd = fdopen (ap,
+ fdopen_mode::out | fdopen_mode::binary |
+ fdopen_mode::truncate | fdopen_mode::create);
+ out_rm = auto_rmfile (ap);
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to open " << ap << ": " << e;
+ }
+ }
+ else
+#endif
+ {
+ if (e != "tar")
+ {
+ args.push_back ("-a");
+ if (l != nullptr)
+ args.push_back (l);
+ }
+
+ args.push_back ("-cf");
+ args.push_back (an.string ().c_str ());
+ args.push_back (base.c_str ());
+ args.push_back (nullptr);
+ }
+ }
+
+ size_t what (0); // Failed program name index in args.
+ try
+ {
+ process_path app; // Archiver path.
+ process_path cpp; // Compressor path.
+
+ app = process::path_search (args[what = 0]);
+
+ if (i != 0)
+ cpp = process::path_search (args[what = i]);
+
+ // Change the archiver's working directory to root.
+ //
+ process_env ape (app, root);
+
+ // Note: print the command line unless quiet similar to other package
+ // manager implementations.
+ //
+ if (verb >= 1)
+ print_process (ape, args);
+
+ what = 0;
+ process apr (app,
+ args.data (), // No auto-pipe.
+ 0 /* stdin */,
+ (i != 0 ? -1 : 1) /* stdout */,
+ 2 /* stderr */,
+ ape.cwd->string ().c_str (),
+ ape.vars);
+
+ // Start the compressor if required.
+ //
+ process cpr;
+ if (i != 0)
+ {
+ what = i;
+ cpr = process (cpp,
+ args.data () + i,
+ apr.in_ofd.get () /* stdin */,
+ out_fd.get () /* stdout */,
+ 2 /* stderr */);
+
+ cpr.in_ofd.reset (); // Close the archiver's stdout on our side.
+ }
+
+ // Delay throwing until we diagnose both ends of the pipe.
+ //
+ bool fail (false);
+
+ what = 0;
+ if (!apr.wait ())
+ {
+ diag_record dr (error);
+ dr << args[0] << " exited with non-zero code";
+
+ if (verb == 0)
+ {
+ info << "command line: ";
+ print_process (dr, ape, args.data ());
+ }
+
+ fail = true;
+ }
+
+ if (i != 0)
+ {
+ what = i;
+ if (!cpr.wait ())
+ {
+ diag_record dr (error);
+ dr << args[i] << " exited with non-zero code";
+
+ if (verb == 0)
+ {
+ info << "command line: ";
+ print_process (dr, args.data () + i);
+ }
+
+ fail = true;
+ }
+ }
+
+ if (fail)
+ throw failed ();
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[what] << ": " << e;
+
+ if (e.child)
+ exit (1);
+
+ throw failed ();
+ }
+
+ out_rm.cancel ();
+ return ap;
+ }
+
+ // NOTE: THE BELOW DESCRIPTION IS ALSO REWORDED IN BPKG-PKG-BINDIST(1).
+ //
+ // The overall plan is to invoke the build system and install all the
+ // packages directly from their bpkg locations into the binary package
+ // directory as a chroot. Then tar/zip this directory to produce one or more
+ // binary package archives.
+ //
+ auto system_package_manager_archive::
+ generate (const packages& pkgs,
+ const packages& deps,
+ const strings& vars,
+ const dir_path& /*cfg_dir*/,
+ const package_manifest& pm,
+ const string& pt,
+ const small_vector<language, 1>& langs,
+ optional<bool> recursive_full,
+ bool first) -> binary_files
+ {
+ tracer trace ("system_package_manager_archive::generate");
+
+ assert (!langs.empty ()); // Should be effective.
+
+ // We require explicit output root.
+ //
+ if (!ops->output_root_specified ())
+ fail << "output root directory must be specified explicitly with "
+ << "--output-root|-o";
+
+ const dir_path& out (ops->output_root ()); // Cannot be empty.
+
+ const shared_ptr<selected_package>& sp (pkgs.front ().selected);
+ const package_name& pn (sp->name);
+ const version& pv (sp->version);
+
+ // Use version without iteration in paths, etc.
+ //
+ string pvs (pv.string (false /* ignore_revision */,
+ true /* ignore_iteration */));
+
+ bool lib (pt == "lib");
+ bool priv (ops->private_ ()); // Private installation.
+
+ // Return true if this package uses the specified language, only as
+ // interface language if intf_only is true.
+ //
+ auto lang = [&langs] (const char* n, bool intf_only = false) -> bool
+ {
+ return find_if (langs.begin (), langs.end (),
+ [n, intf_only] (const language& l)
+ {
+ return (!intf_only || !l.impl) && l.name == n;
+ }) != langs.end ();
+ };
+
+ bool lang_c (lang ("c"));
+ bool lang_cxx (lang ("c++"));
+ bool lang_cc (lang ("cc"));
+
+ if (verb >= 3)
+ {
+ auto print_status = [] (diag_record& dr, const selected_package& p)
+ {
+ dr << (p.substate == package_substate::system ? "sys:" : "")
+ << p.name << ' ' << p.version;
+ };
+
+ {
+ diag_record dr (trace);
+ dr << "package: " ;
+ print_status (dr, *sp);
+ }
+
+ for (const package& p: deps)
+ {
+ diag_record dr (trace);
+ dr << "dependency: ";
+ print_status (dr, *p.selected);
+ }
+ }
+
+ // Should we override config.install.* or just use whatever configured
+ // (sans the root)? While using whatever configure seemed like a good idea
+ // at first, it's also a good idea to have the ability to tweak the
+ // installation directory structure on the per-platform basis (like, say,
+ // lib/libexec split or pkgconfig/ location on FreeBSD; in a sense, the
+ // user may choose to install to /usr and it would be good if things ended
+ // up in the expected places -- this is still a @@ TODO).
+ //
+ // So unless instructed otherwise with --archive-install-config, we
+ // override every config.install.* variable in order not to pick anything
+ // configured. Note that we add some more in the command line below.
+ //
+ // We make use of the <project> substitution since in the recursive mode
+ // we may be installing multiple projects. Note that the <private>
+ // directory component is automatically removed if this functionality is
+ // not enabled.
+ //
+ bool ovr_install (!ops->archive_install_config ());
+
+ strings config;
+ {
+ const string& c (target.class_);
+
+ dir_path root;
+ if (ops->archive_install_root_specified ())
+ {
+ // If specified, we override it even with --archive-install-config.
+ //
+ root = ops->archive_install_root (); // Cannot be empty.
+ }
+ else if (ovr_install)
+ {
+ if (c == "windows")
+ {
+ // Using C:\<project>\ looks like the best we can do (if the
+ // installation is not relocatable, at least related packages will
+ // be grouped together).
+ //
+ root = dir_path ("C:\\" + pm.effective_project ().string ());
+ }
+ else
+ root = dir_path ("/usr/local");
+ }
+
+ auto add = [&config] (auto&& v)
+ {
+ config.push_back (string ("config.install.") + v);
+ };
+
+ if (!root.empty ())
+ add ("root='" + root.representation () + '\'');
+
+ if (ovr_install)
+ {
+ add ("data_root=root/");
+ add ("exec_root=root/");
+
+ add ("bin=exec_root/bin/");
+ add ("sbin=exec_root/sbin/");
+
+ add ("lib=exec_root/lib/<private>/");
+ add ("libexec=exec_root/libexec/<private>/<project>/");
+ add ("pkgconfig=lib/pkgconfig/");
+
+ add ("etc=data_root/etc/");
+ add ("include=data_root/include/<private>/");
+ add ("include_arch=include/");
+ add ("share=data_root/share/");
+ add ("data=share/<private>/<project>/");
+ add ("buildfile=share/build2/export/<project>/");
+
+ add ("doc=share/doc/<private>/<project>/");
+ add ("legal=doc/");
+ add ("man=share/man/");
+ add ("man1=man/man1/");
+ add ("man2=man/man2/");
+ add ("man3=man/man3/");
+ add ("man4=man/man4/");
+ add ("man5=man/man5/");
+ add ("man6=man/man6/");
+ add ("man7=man/man7/");
+ add ("man8=man/man8/");
+
+ add ("private=" + (priv ? pn.string () : "[null]"));
+
+ // If this is a C-based language, add rpath for private installation,
+ // unless targeting Windows.
+ //
+ if (priv && (lang_c || lang_cxx || lang_cc) && c != "windows")
+ {
+ dir_path l ((dir_path (root) /= "lib") /= pn.string ());
+ config.push_back ("config.bin.rpath='" + l.representation () + '\'');
+ }
+ }
+ }
+
+ // Add user-specified configuration variables last to allow them to
+ // override anything.
+ //
+ for (const string& v: vars)
+ config.push_back (v);
+
+ // Note that we can use weak install scope for the auto recursive mode
+ // since we know dependencies cannot be spread over multiple linked
+ // configurations.
+ //
+ string scope (!recursive_full || *recursive_full ? "project" : "weak");
+
+ // The plan is to create the archive directory (with the same name as the
+ // archive base; we call it "destination directory") inside the output
+ // directory and then tar/zip it up placing the resulting archives next to
+ // it.
+ //
+ // Let's require clean output directory to keep things simple.
+ //
+ // Also, by default, we are going to keep all the intermediate files on
+ // failure for troubleshooting.
+ //
+ if (first && exists (out) && !empty (out))
+ {
+ if (!ops->wipe_output ())
+ fail << "output root directory " << out << " is not empty" <<
+ info << "use --wipe-output to clean it up but be careful";
+
+ rm_r (out, false);
+ }
+
+ // NOTE: THE BELOW DESCRIPTION IS ALSO REWORDED IN BPKG-PKG-BINDIST(1).
+ //
+ // Our archive directory/file base have the following form:
+ //
+ // <package>-<version>-<build_metadata>
+ //
+ // Where <build_metadata> in turn has the following form (unless overriden
+ // with --archive-build-mata):
+ //
+ // <cpu>-<os>[-<langrt>...]
+ //
+ // For example:
+ //
+ // hello-1.2.3-x86_64-windows10
+ // libhello-1.2.3-x86_64-windows10-msvc17.4
+ // libhello-1.2.3-x86_64-debian11-gcc12-rust1.62
+ //
+ bool md_s (ops->archive_build_meta_specified ());
+ const string& md (ops->archive_build_meta ());
+
+ bool md_f (false);
+ bool md_b (false);
+ if (md_s && !md.empty ())
+ {
+ md_f = md.front () == '+';
+ md_b = md.back () == '+';
+
+ if (md_f && md_b) // Note: covers just `+`.
+ fail << "invalid build metadata '" << md << "'";
+ }
+
+ vector<reference_wrapper<const pair<const string, string>>> langrt;
+ if (!md_s || md_f || md_b)
+ {
+ // First collect the interface languages and then add implementation.
+ // This way if different languages map to the same runtimes (e.g., C and
+ // C++ mapped to gcc12), then we will always prefer the interface
+ // version over the implementation (which could be different, for
+ // example, libstdc++6 vs libstdc++-12-dev; but it's not clear how this
+ // will be specified, won't they end up with different names as opposed
+ // to gcc6 and gcc12 -- still fuzzy/unclear).
+ //
+ // @@ We will need to split id and version to be able to pick the
+ // highest version.
+ //
+ // @@ Maybe we should just do "soft" version like in <distribution>?
+ //
+ // Note that we allow multiple values for the same language to support
+ // cases like --archive-lang cc=gcc12 --archive-lang cc=g++12. But
+ // we treat an empty value as a request to clear all the previous
+ // entries.
+ //
+
+ auto find = [] (const std::multimap<string, string>& m, const string& n)
+ {
+ auto p (m.equal_range (n));
+
+ if (p.first == p.second)
+ {
+ // If no mapping for c/c++, fallback to cc.
+ //
+ if (n == "c" || n == "c++")
+ p = m.equal_range ("cc");
+ }
+
+ return p;
+ };
+
+ // We don't want to clear entries specified with --*-lang with an empty
+ // value specified with --*-lang-impl.
+ //
+ size_t clear_limit (0);
+
+ auto add = [&langrt, &clear_limit] (const pair<const string, string>& p)
+ {
+ // Suppress duplicates.
+ //
+ if (!p.second.empty ())
+ {
+ if (find_if (langrt.begin (), langrt.end (),
+ [&p] (const pair<const string, string>& x)
+ {
+ // @@ TODO: keep highest version.
+ return p.second == x.second;
+ }) == langrt.end ())
+ {
+ langrt.push_back (p);
+ }
+ }
+ else if (clear_limit != langrt.size ())
+ {
+ for (auto i (langrt.begin () + clear_limit); i != langrt.end (); )
+ {
+ if (i->get ().first == p.first)
+ i = langrt.erase (i);
+ else
+ ++i;
+ }
+ }
+ };
+
+ auto& implm (ops->archive_lang_impl ());
+
+ // The interface/implementation distinction is only relevant to
+ // libraries. For everything else we treat all the languages as
+ // implementation.
+ //
+ if (lib)
+ {
+ auto& intfm (ops->archive_lang ());
+
+ for (const language& l: langs)
+ {
+ if (l.impl)
+ continue;
+
+ auto p (find (intfm, l.name));
+
+ if (p.first == p.second)
+ p = find (implm, l.name);
+
+ if (p.first == p.second)
+ fail << "no runtime mapping for language " << l.name <<
+ info << "consider specifying with --archive-lang[-impl]" <<
+ info << "or alternatively specify --archive-build-meta";
+
+ for (auto i (p.first); i != p.second; ++i)
+ add (*i);
+ }
+
+ clear_limit = langrt.size ();
+ }
+
+ for (const language& l: langs)
+ {
+ if (lib && !l.impl)
+ continue;
+
+ auto p (find (implm, l.name));
+
+ if (p.first == p.second)
+ continue; // Unimportant.
+
+ for (auto i (p.first); i != p.second; ++i)
+ add (*i);
+ }
+ }
+
+ // If there is no split, reduce to empty key and empty filter.
+ //
+ binary_files r;
+ for (const pair<const string, string>& kf:
+ ops->archive_split_specified ()
+ ? ops->archive_split ()
+ : std::map<string, string> {{string (), string ()}})
+ {
+ string sys_name (pn.string ());
+
+ if (!kf.first.empty ())
+ sys_name += '-' + kf.first;
+
+ string base (sys_name);
+
+ base += '-' + pvs;
+
+ if (md_s && !(md_f || md_b))
+ {
+ if (!md.empty ())
+ base += '-' + md;
+ }
+ else
+ {
+ if (md_b)
+ {
+ base += '-';
+ base.append (md, 0, md.size () - 1);
+ }
+
+ if (!ops->archive_no_cpu ())
+ base += '-' + target.cpu;
+
+ if (!ops->archive_no_os ())
+ base += '-' + os_release.name_id + os_release.version_id;
+
+ for (const pair<const string, string>& p: langrt)
+ base += '-' + p.second;
+
+ if (md_f)
+ {
+ base += '-';
+ base.append (md, 1, md.size () - 1);
+ }
+ }
+
+ dir_path dst (out / dir_path (base));
+ mk_p (dst);
+
+ // Install.
+ //
+ // In a sense, this is a special version of pkg-install.
+ //
+ {
+ strings dirs;
+ for (const package& p: pkgs)
+ dirs.push_back (p.out_root.representation ());
+
+ string filter;
+ if (!kf.second.empty ())
+ filter = "config.install.filter=" + kf.second;
+
+ run_b (*ops,
+ verb_b::normal,
+ (ops->jobs_specified ()
+ ? strings ({"--jobs", to_string (ops->jobs ())})
+ : strings ()),
+ "config.install.chroot='" + dst.representation () + '\'',
+ (ovr_install ? "config.install.sudo=[null]" : nullptr),
+ (!filter.empty () ? filter.c_str () : nullptr),
+ config,
+ "!config.install.scope=" + scope,
+ "install:",
+ dirs);
+
+ // @@ TODO: call install.json? Or manifest-install.json. Place in
+ // data/ (would need support in build2 to use install.* values)?
+ //
+#if 0
+ args.push_back ("!config.install.manifest=-");
+#endif
+ }
+
+ if (ops->archive_prepare_only ())
+ {
+ if (verb >= 1)
+ text << "prepared " << dst;
+
+ continue;
+ }
+
+ // Create the archive.
+ //
+ // Should the default archive type be based on host or target? I guess
+ // that depends on where the result will be unpacked, and it feels like
+ // target is more likely.
+ //
+ // @@ What about the ownerhip of the resulting file in the archive?
+ // We don't do anything for source archives, not sure why we should
+ // do something here.
+ //
+ for (string t: (ops->archive_type_specified ()
+ ? ops->archive_type ()
+ : strings {target.class_ == "windows" ? "zip" : "tar.xz"}))
+ {
+ // Help the user out if the extension is specified with the leading
+ // dot.
+ //
+ if (t.size () > 1 && t.front () == '.')
+ t.erase (0, 1);
+
+ path f (archive (out, base, t));
+
+ // Using archive type as file type seems appropriate. Add key before
+ // the archive type, if any.
+ //
+ if (!kf.first.empty ())
+ t = kf.first + '.' + t;
+
+ r.push_back (binary_file {move (t), move (f), sys_name});
+ }
+
+ // Cleanup intermediate files unless requested not to.
+ //
+ if (!ops->keep_output ())
+ {
+ rm_r (dst);
+ }
+ }
+
+ return r;
+ }
+
+ optional<const system_package_status*> system_package_manager_archive::
+ status (const package_name&, const available_packages*)
+ {
+ assert (false);
+ return nullopt;
+ }
+
+ void system_package_manager_archive::
+ install (const vector<package_name>&)
+ {
+ assert (false);
+ }
+}
diff --git a/bpkg/system-package-manager-archive.hxx b/bpkg/system-package-manager-archive.hxx
new file mode 100644
index 0000000..01c4a2a
--- /dev/null
+++ b/bpkg/system-package-manager-archive.hxx
@@ -0,0 +1,55 @@
+// file : bpkg/system-package-manager-archive.hxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BPKG_SYSTEM_PACKAGE_MANAGER_ARCHIVE_HXX
+#define BPKG_SYSTEM_PACKAGE_MANAGER_ARCHIVE_HXX
+
+#include <bpkg/types.hxx>
+#include <bpkg/utility.hxx>
+
+#include <bpkg/system-package-manager.hxx>
+
+namespace bpkg
+{
+ // The system package manager implementation for the installation archive
+ // packages, production only.
+ //
+ class system_package_manager_archive: public system_package_manager
+ {
+ public:
+ virtual binary_files
+ generate (const packages&,
+ const packages&,
+ const strings&,
+ const dir_path&,
+ const package_manifest&,
+ const string&,
+ const small_vector<language, 1>&,
+ optional<bool>,
+ bool) override;
+
+ virtual optional<const system_package_status*>
+ status (const package_name&, const available_packages*) override;
+
+ virtual void
+ install (const vector<package_name>&) override;
+
+ public:
+ // Note: options can only be NULL when testing functions that don't need
+ // them.
+ //
+ system_package_manager_archive (bpkg::os_release&&,
+ const target_triplet& host,
+ string arch,
+ optional<bool> progress,
+ const pkg_bindist_options*);
+
+ protected:
+ // Only for production.
+ //
+ const pkg_bindist_options* ops = nullptr;
+ target_triplet target;
+ };
+}
+
+#endif // BPKG_SYSTEM_PACKAGE_MANAGER_ARCHIVE_HXX
diff --git a/bpkg/system-package-manager-debian.cxx b/bpkg/system-package-manager-debian.cxx
new file mode 100644
index 0000000..8b27e37
--- /dev/null
+++ b/bpkg/system-package-manager-debian.cxx
@@ -0,0 +1,3616 @@
+// file : bpkg/system-package-manager-debian.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <bpkg/system-package-manager-debian.hxx>
+
+#include <locale>
+
+#include <libbutl/timestamp.hxx>
+#include <libbutl/filesystem.hxx> // permissions
+
+#include <bpkg/diagnostics.hxx>
+
+#include <bpkg/pkg-bindist-options.hxx>
+
+using namespace butl;
+
+namespace bpkg
+{
+ using package_status = system_package_status_debian;
+
+ // Translate host CPU to Debian package architecture.
+ //
+ string system_package_manager_debian::
+ arch_from_target (const target_triplet& h)
+ {
+ const string& c (h.cpu);
+ return
+ c == "x86_64" ? "amd64" :
+ c == "aarch64" ? "arm64" :
+ c == "i386" || c == "i486" || c == "i586" || c == "i686" ? "i386" :
+ c;
+ }
+
+ // Parse the debian-name (or alike) value. The first argument is the package
+ // type.
+ //
+ // Note that for now we treat all the packages from the non-main groups as
+ // extras omitting the -common package (assuming it's pulled by the main
+ // package) as well as -doc and -dbg unless requested with the
+ // extra_{doc,dbg} arguments.
+ //
+ package_status system_package_manager_debian::
+ parse_name_value (const string& pt,
+ const string& nv,
+ bool extra_doc,
+ bool extra_dbg)
+ {
+ auto split = [] (const string& s, char d) -> strings
+ {
+ strings r;
+ for (size_t b (0), e (0); next_word (s, b, e, d); )
+ r.push_back (string (s, b, e - b));
+ return r;
+ };
+
+ auto suffix = [] (const string& n, const string& s) -> bool
+ {
+ size_t nn (n.size ());
+ size_t sn (s.size ());
+ return nn > sn && n.compare (nn - sn, sn, s) == 0;
+ };
+
+ auto parse_group = [&split, &suffix] (const string& g, const string* pt)
+ {
+ strings ns (split (g, ' '));
+
+ if (ns.empty ())
+ fail << "empty package group";
+
+ package_status r;
+
+ // Handle the "dev instead of main" special case for libraries.
+ //
+ // Check that the following name does not end with -dev. This will be
+ // the only way to disambiguate the case where the library name happens
+ // to end with -dev (e.g., libfoo-dev libfoo-dev-dev).
+ //
+ {
+ string& m (ns[0]);
+
+ if (pt != nullptr &&
+ *pt == "lib" &&
+ suffix (m, "-dev") &&
+ !(ns.size () > 1 && suffix (ns[1], "-dev")))
+ {
+ r = package_status ("", move (m));
+ }
+ else
+ r = package_status (move (m));
+ }
+
+ // Handle the rest.
+ //
+ for (size_t i (1); i != ns.size (); ++i)
+ {
+ string& n (ns[i]);
+
+ const char* w;
+ if (string* v = (suffix (n, (w = "-dev")) ? &r.dev :
+ suffix (n, (w = "-doc")) ? &r.doc :
+ suffix (n, (w = "-dbg")) ? &r.dbg :
+ suffix (n, (w = "-common")) ? &r.common : nullptr))
+ {
+ if (!v->empty ())
+ fail << "multiple " << w << " package names in '" << g << "'" <<
+ info << "did you forget to separate package groups with comma?";
+
+ *v = move (n);
+ }
+ else
+ r.extras.push_back (move (n));
+ }
+
+ return r;
+ };
+
+ strings gs (split (nv, ','));
+ assert (!gs.empty ()); // *-name value cannot be empty.
+
+ package_status r;
+ for (size_t i (0); i != gs.size (); ++i)
+ {
+ if (i == 0) // Main group.
+ r = parse_group (gs[i], &pt);
+ else
+ {
+ package_status g (parse_group (gs[i], nullptr));
+
+ if (!g.main.empty ()) r.extras.push_back (move (g.main));
+ if (!g.dev.empty ()) r.extras.push_back (move (g.dev));
+ if (!g.doc.empty () && extra_doc) r.extras.push_back (move (g.doc));
+ if (!g.dbg.empty () && extra_dbg) r.extras.push_back (move (g.dbg));
+ if (!g.common.empty () && false) r.extras.push_back (move (g.common));
+ if (!g.extras.empty ()) r.extras.insert (
+ r.extras.end (),
+ make_move_iterator (g.extras.begin ()),
+ make_move_iterator (g.extras.end ()));
+ }
+ }
+
+ return r;
+ }
+
+ // Attempt to determine the main package name from its -dev package based on
+ // the extracted Depends value. Return empty string if unable to.
+ //
+ string system_package_manager_debian::
+ main_from_dev (const string& dev_name,
+ const string& dev_ver,
+ const string& depends)
+ {
+ // The format of the Depends value is a comma-seperated list of dependency
+ // expressions. For example:
+ //
+ // Depends: libssl3 (= 3.0.7-1), libc6 (>= 2.34), libfoo | libbar
+ //
+ // For the main package we look for a dependency in the form:
+ //
+ // <dev-stem>* (= <dev-ver>)
+ //
+ // Usually it is the first one.
+ //
+ string dev_stem (dev_name, 0, dev_name.rfind ("-dev"));
+
+ string r;
+ for (size_t b (0), e (0); next_word (depends, b, e, ','); )
+ {
+ string d (depends, b, e - b);
+ trim (d);
+
+ size_t p (d.find (' '));
+ if (p != string::npos)
+ {
+ if (d.compare (0, dev_stem.size (), dev_stem) == 0) // <dev-stem>*
+ {
+ size_t q (d.find ('(', p + 1));
+ if (q != string::npos && d.back () == ')') // (...)
+ {
+ if (d[q + 1] == '=' && d[q + 2] == ' ') // Equal.
+ {
+ string v (d, q + 3, d.size () - q - 3 - 1);
+ trim (v);
+
+ if (v == dev_ver)
+ {
+ r.assign (d, 0, p);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return r;
+ }
+
+ // Do we use apt or apt-get? From apt(8):
+ //
+ // "The apt(8) commandline is designed as an end-user tool and it may change
+ // behavior between versions. [...]
+ //
+ // All features of apt(8) are available in dedicated APT tools like
+ // apt-get(8) and apt-cache(8) as well. [...] So you should prefer using
+ // these commands (potentially with some additional options enabled) in
+ // your scripts as they keep backward compatibility as much as possible."
+ //
+ // Note also that for some reason both apt-cache and apt-get exit with 100
+ // code on error.
+ //
+ static process_path apt_cache_path;
+ static process_path apt_get_path;
+ static process_path sudo_path;
+
+ // Obtain the installed and candidate versions for the specified list of
+ // Debian packages by executing `apt-cache policy`.
+ //
+ // If the n argument is not 0, then only query the first n packages.
+ //
+ void system_package_manager_debian::
+ apt_cache_policy (vector<package_policy>& pps, size_t n)
+ {
+ if (n == 0)
+ n = pps.size ();
+
+ assert (n != 0 && n <= pps.size ());
+
+ // The --quiet option makes sure we don't get a noice (N) printed to
+ // stderr if the package is unknown. It does not appear to affect error
+ // diagnostics (try temporarily renaming /var/lib/dpkg/status).
+ //
+ cstrings args {"apt-cache", "policy", "--quiet"};
+
+ for (size_t i (0); i != n; ++i)
+ {
+ package_policy& pp (pps[i]);
+
+ const string& n (pp.name);
+ assert (!n.empty ());
+
+ pp.installed_version.clear ();
+ pp.candidate_version.clear ();
+
+ args.push_back (n.c_str ());
+ }
+
+ args.push_back (nullptr);
+
+ // Run with the C locale to make sure there is no localization. Note that
+ // this is not without potential drawbacks, see Debian bug #643787. But
+ // for now it seems to work and feels like the least of two potential
+ // evils.
+ //
+ const char* evars[] = {"LC_ALL=C", nullptr};
+
+ try
+ {
+ if (apt_cache_path.empty () && !simulate_)
+ apt_cache_path = process::path_search (args[0], false /* init */);
+
+ process_env pe (apt_cache_path, evars);
+
+ if (verb >= 3)
+ print_process (pe, args);
+
+ // Redirect stdout to a pipe. For good measure also redirect stdin to
+ // /dev/null to make sure there are no prompts of any kind.
+ //
+ process pr;
+ if (!simulate_)
+ pr = process (apt_cache_path,
+ args,
+ -2 /* stdin */,
+ -1 /* stdout */,
+ 2 /* stderr */,
+ nullptr /* cwd */,
+ evars);
+ else
+ {
+ strings k;
+ for (size_t i (0); i != n; ++i)
+ k.push_back (pps[i].name);
+
+ const path* f (nullptr);
+ if (installed_)
+ {
+ auto i (simulate_->apt_cache_policy_installed_.find (k));
+ if (i != simulate_->apt_cache_policy_installed_.end ())
+ f = &i->second;
+ }
+ if (f == nullptr && fetched_)
+ {
+ auto i (simulate_->apt_cache_policy_fetched_.find (k));
+ if (i != simulate_->apt_cache_policy_fetched_.end ())
+ f = &i->second;
+ }
+ if (f == nullptr)
+ {
+ auto i (simulate_->apt_cache_policy_.find (k));
+ if (i != simulate_->apt_cache_policy_.end ())
+ f = &i->second;
+ }
+
+ diag_record dr (text);
+ print_process (dr, pe, args);
+ dr << " <" << (f == nullptr || f->empty () ? "/dev/null" : f->string ());
+
+ pr = process (process_exit (0));
+ pr.in_ofd = f == nullptr || f->empty ()
+ ? fdopen_null ()
+ : (f->string () == "-"
+ ? fddup (stdin_fd ())
+ : fdopen (*f, fdopen_mode::in));
+ }
+
+ try
+ {
+ ifdstream is (move (pr.in_ofd), fdstream_mode::skip, ifdstream::badbit);
+
+ // The output of `apt-cache policy <pkg1> <pkg2> ...` are blocks of
+ // lines in the following form:
+ //
+ // <pkg1>:
+ // Installed: 1.2.3-1
+ // Candidate: 1.3.0-2
+ // Version table:
+ // <...>
+ // <pkg2>:
+ // Installed: (none)
+ // Candidate: 1.3.0+dfsg-2+b1
+ // Version table:
+ // <...>
+ //
+ // Where <...> are further lines indented with at least one space. If
+ // a package is unknown, then the entire block (including the first
+ // <pkg>: line) is omitted. The blocks appear in the same order as
+ // packages on the command line and multiple entries for the same
+ // package result in multiple corresponding blocks. It looks like
+ // there should be not blank lines but who really knows.
+ //
+ // Note also that if Installed version is not (none), then the
+ // Candidate version will be that version of better.
+ //
+ {
+ auto df = make_diag_frame (
+ [&pe, &args] (diag_record& dr)
+ {
+ dr << info << "while parsing output of ";
+ print_process (dr, pe, args);
+ });
+
+ size_t i (0);
+
+ string l;
+ for (getline (is, l); !eof (is); )
+ {
+ // Parse the first line of the block.
+ //
+ if (l.empty () || l.front () == ' ' || l.back () != ':')
+ fail << "expected package name instead of '" << l << "'";
+
+ l.pop_back ();
+
+ // Skip until this package.
+ //
+ for (; i != n && pps[i].name != l; ++i) ;
+
+ if (i == n)
+ fail << "unexpected package name '" << l << "'";
+
+ package_policy& pp (pps[i]);
+
+ auto parse_version = [&l] (const string& n) -> string
+ {
+ size_t s (n.size ());
+
+ if (l[0] == ' ' &&
+ l[1] == ' ' &&
+ l.compare (2, s, n) == 0 &&
+ l[2 + s] == ':')
+ {
+ string v (l, 2 + s + 1);
+ trim (v);
+
+ if (!v.empty ())
+ return v == "(none)" ? string () : move (v);
+ }
+
+ fail << "invalid " << n << " version line '" << l << "'" << endf;
+ };
+
+ // Get the installed version line.
+ //
+ if (eof (getline (is, l)))
+ fail << "expected Installed version line after package name";
+
+ pp.installed_version = parse_version ("Installed");
+
+ // Get the candidate version line.
+ //
+ if (eof (getline (is, l)))
+ fail << "expected Candidate version line after Installed version";
+
+ pp.candidate_version = parse_version ("Candidate");
+
+ // Candidate should fallback to Installed.
+ //
+ assert (pp.installed_version.empty () ||
+ !pp.candidate_version.empty ());
+
+ // Skip the rest of the indented lines (or blanks, just in case).
+ //
+ while (!eof (getline (is, l)) && (l.empty () || l.front () == ' ')) ;
+ }
+ }
+
+ is.close ();
+ }
+ catch (const io_error& e)
+ {
+ if (pr.wait ())
+ fail << "unable to read " << args[0] << " policy output: " << e;
+
+ // Fall through.
+ }
+
+ if (!pr.wait ())
+ {
+ diag_record dr (fail);
+ dr << args[0] << " policy exited with non-zero code";
+
+ if (verb < 3)
+ {
+ dr << info << "command line: ";
+ print_process (dr, pe, args);
+ }
+ }
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e;
+
+ if (e.child)
+ exit (1);
+
+ throw failed ();
+ }
+ }
+
+ // Execute `apt-cache show` and return the Depends value, if any, for the
+ // specified package and version. Fail if either package or version is
+ // unknown.
+ //
+ string system_package_manager_debian::
+ apt_cache_show (const string& name, const string& ver)
+ {
+ assert (!name.empty () && !ver.empty ());
+
+ string spec (name + '=' + ver);
+
+ // In particular, --quiet makes sure we don't get noices (N) printed to
+ // stderr. It does not appear to affect error diagnostics (try showing
+ // information for an unknown package).
+ //
+ const char* args[] = {
+ "apt-cache", "show", "--quiet", spec.c_str (), nullptr};
+
+ // Note that for this command there seems to be no need to run with the C
+ // locale since the output is presumably not localizable. But let's do it
+ // for good measure and also seeing that we try to backfit some
+ // diagnostics into apt-cache (see no_version below).
+ //
+ const char* evars[] = {"LC_ALL=C", nullptr};
+
+ string r;
+ try
+ {
+ if (apt_cache_path.empty () && !simulate_)
+ apt_cache_path = process::path_search (args[0], false /* init */);
+
+ process_env pe (apt_cache_path, evars);
+
+ if (verb >= 3)
+ print_process (pe, args);
+
+ // Redirect stdout to a pipe. For good measure also redirect stdin to
+ // /dev/null to make sure there are no prompts of any kind.
+ //
+ process pr;
+ if (!simulate_)
+ pr = process (apt_cache_path,
+ args,
+ -2 /* stdin */,
+ -1 /* stdout */,
+ 2 /* stderr */,
+ nullptr /* cwd */,
+ evars);
+ else
+ {
+ pair<string, string> k (name, ver);
+
+ const path* f (nullptr);
+ if (fetched_)
+ {
+ auto i (simulate_->apt_cache_show_fetched_.find (k));
+ if (i != simulate_->apt_cache_show_fetched_.end ())
+ f = &i->second;
+ }
+ if (f == nullptr)
+ {
+ auto i (simulate_->apt_cache_show_.find (k));
+ if (i != simulate_->apt_cache_show_.end ())
+ f = &i->second;
+ }
+
+ diag_record dr (text);
+ print_process (dr, pe, args);
+ dr << " <" << (f == nullptr || f->empty () ? "/dev/null" : f->string ());
+
+ if (f == nullptr || f->empty ())
+ {
+ text << "E: No packages found";
+ pr = process (process_exit (100));
+ }
+ else
+ {
+ pr = process (process_exit (0));
+ pr.in_ofd = f->string () == "-"
+ ? fddup (stdin_fd ())
+ : fdopen (*f, fdopen_mode::in);
+ }
+ }
+
+ bool no_version (false);
+ try
+ {
+ ifdstream is (move (pr.in_ofd), fdstream_mode::skip, ifdstream::badbit);
+
+ // The output of `apt-cache show <pkg>=<ver>` appears to be a single
+ // Debian control file in the RFC 822 encoding followed by a blank
+ // line. See deb822(5) for details. Here is a representative example:
+ //
+ // Package: libcurl4
+ // Version: 7.85.0-1
+ // Depends: libbrotli1 (>= 0.6.0), libc6 (>= 2.34), ...
+ // Description-en: easy-to-use client-side URL transfer library
+ // libcurl is an easy-to-use client-side URL transfer library.
+ //
+ // Note that if the package is unknown, then we get an error but if
+ // the version is unknown, we get no output (and a note if running
+ // without --quiet).
+ //
+ string l;
+ if (eof (getline (is, l)))
+ {
+ // The unknown version case. Issue diagnostics consistent with the
+ // unknown package case, at least for the English locale.
+ //
+ text << "E: No package version found";
+ no_version = true;
+ }
+ else
+ {
+ auto df = make_diag_frame (
+ [&pe, &args] (diag_record& dr)
+ {
+ dr << info << "while parsing output of ";
+ print_process (dr, pe, args);
+ });
+
+ do
+ {
+ // This line should be the start of a field unless it's a comment
+ // or the terminating blank line. According to deb822(5), there
+ // can be no leading whitespaces before `#`.
+ //
+ if (l.empty ())
+ break;
+
+ if (l[0] == '#')
+ {
+ getline (is, l);
+ continue;
+ }
+
+ size_t p (l.find (':'));
+
+ if (p == string::npos)
+ fail << "expected field name instead of '" << l << "'";
+
+ // Extract the field name. Note that field names are case-
+ // insensitive.
+ //
+ string n (l, 0, p);
+ trim (n);
+
+ // Extract the field value.
+ //
+ string v (l, p + 1);
+ trim (v);
+
+ // If we have more lines see if the following line is part of this
+ // value.
+ //
+ while (!eof (getline (is, l)) && (l[0] == ' ' || l[0] == '\t'))
+ {
+ // This can either be a "folded" or a "multiline" field and
+ // which one it is depends on the field semantics. Here we only
+ // care about Depends and so treat them all as folded (it's
+ // unclear whether Depends must be a simple field).
+ //
+ trim (l);
+ v += ' ';
+ v += l;
+ }
+
+ // See if this is a field of interest.
+ //
+ if (icasecmp (n, "Package") == 0)
+ {
+ assert (v == name); // Sanity check.
+ }
+ else if (icasecmp (n, "Version") == 0)
+ {
+ assert (v == ver); // Sanity check.
+ }
+ else if (icasecmp (n, "Depends") == 0)
+ {
+ r = move (v);
+
+ // Let's not waste time reading any further.
+ //
+ break;
+ }
+ }
+ while (!eof (is));
+ }
+
+ is.close ();
+ }
+ catch (const io_error& e)
+ {
+ if (pr.wait ())
+ fail << "unable to read " << args[0] << " show output: " << e;
+
+ // Fall through.
+ }
+
+ if (!pr.wait () || no_version)
+ {
+ diag_record dr (fail);
+ dr << args[0] << " show exited with non-zero code";
+
+ if (verb < 3)
+ {
+ dr << info << "command line: ";
+ print_process (dr, pe, args);
+ }
+ }
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e;
+
+ if (e.child)
+ exit (1);
+
+ throw failed ();
+ }
+
+ return r;
+ }
+
+ // Prepare the common `apt-get <command>` options.
+ //
+ pair<cstrings, const process_path&> system_package_manager_debian::
+ apt_get_common (const char* command, strings& args_storage)
+ {
+ // Pre-allocate the required number of entries in the arguments storage.
+ //
+ if (fetch_timeout_)
+ args_storage.reserve (1);
+
+ cstrings args;
+
+ if (!sudo_.empty ())
+ args.push_back (sudo_.c_str ());
+
+ args.push_back ("apt-get");
+ args.push_back (command);
+
+ // Map our verbosity/progress to apt-get --quiet[=<level>]. The levels
+ // appear to have the following behavior:
+ //
+ // 1 -- shows URL being downloaded but no percentage progress is shown.
+ //
+ // 2 -- only shows diagnostics (implies --assume-yes which cannot be
+ // overriden with --assume-no).
+ //
+ // It also appears to automatically use level 1 if stderr is not a
+ // terminal. This can be overrident with --quiet=0.
+ //
+ // Note also that --show-progress does not apply to apt-get update. For
+ // apt-get install it shows additionally progress during unpacking which
+ // looks quite odd.
+ //
+ if (progress_ && *progress_)
+ {
+ args.push_back ("--quiet=0");
+ }
+ else if (verb == 0)
+ {
+ // Only use level 2 if assuming yes.
+ //
+ args.push_back (yes_ ? "--quiet=2" : "--quiet");
+ }
+ else if (progress_ && !*progress_)
+ {
+ args.push_back ("--quiet");
+ }
+
+ if (yes_)
+ {
+ args.push_back ("--assume-yes");
+ }
+ else if (!stderr_term)
+ {
+ // Suppress any prompts if stderr is not a terminal for good measure.
+ //
+ args.push_back ("--assume-no");
+ }
+
+ // Add the network operations timeout options, if requested.
+ //
+ if (fetch_timeout_)
+ {
+ args.push_back ("-o");
+
+ args_storage.push_back (
+ "Acquire::http::Timeout=" + to_string (*fetch_timeout_));
+
+ args.push_back (args_storage.back ().c_str ());
+ }
+
+ try
+ {
+ const process_path* pp (nullptr);
+
+ if (!sudo_.empty ())
+ {
+ if (sudo_path.empty () && !simulate_)
+ sudo_path = process::path_search (args[0], false /* init */);
+
+ pp = &sudo_path;
+ }
+ else
+ {
+ if (apt_get_path.empty () && !simulate_)
+ apt_get_path = process::path_search (args[0], false /* init */);
+
+ pp = &apt_get_path;
+ }
+
+ return pair<cstrings, const process_path&> (move (args), *pp);
+ }
+ catch (const process_error& e)
+ {
+ fail << "unable to execute " << args[0] << ": " << e << endf;
+ }
+ }
+
+ // Execute `apt-get update` to update the package index.
+ //
+ void system_package_manager_debian::
+ apt_get_update ()
+ {
+ strings args_storage;
+ pair<cstrings, const process_path&> args_pp (
+ apt_get_common ("update", args_storage));
+
+ cstrings& args (args_pp.first);
+ const process_path& pp (args_pp.second);
+
+ args.push_back (nullptr);
+
+ try
+ {
+ if (verb >= 2)
+ print_process (args);
+ else if (verb == 1)
+ text << "updating " << os_release.name_id << " package index...";
+
+ process pr;
+ if (!simulate_)
+ {
+ // Redirect stdout to stderr since apt-get prints some of its
+ // diagnostics to stdout.
+ //
+ pr = process (pp, args, 0 /* stdin */, 2 /* stdout */);
+ }
+ else
+ {
+ print_process (args);
+ pr = process (process_exit (simulate_->apt_get_update_fail_ ? 100 : 0));
+ }
+
+ if (!pr.wait ())
+ {
+ diag_record dr (fail);
+ dr << "apt-get update exited with non-zero code";
+
+ if (verb < 2)
+ {
+ dr << info << "command line: ";
+ print_process (dr, args);
+ }
+ }
+
+ if (verb == 1)
+ text << "updated " << os_release.name_id << " package index";
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e;
+
+ if (e.child)
+ exit (1);
+
+ throw failed ();
+ }
+ }
+
+ // Execute `apt-get install` to install the specified packages/versions
+ // (e.g., libfoo or libfoo=1.2.3).
+ //
+ void system_package_manager_debian::
+ apt_get_install (const strings& pkgs)
+ {
+ assert (!pkgs.empty ());
+
+ strings args_storage;
+ pair<cstrings, const process_path&> args_pp (
+ apt_get_common ("install", args_storage));
+
+ cstrings& args (args_pp.first);
+ const process_path& pp (args_pp.second);
+
+ for (const string& p: pkgs)
+ args.push_back (p.c_str ());
+
+ args.push_back (nullptr);
+
+ try
+ {
+ if (verb >= 2)
+ print_process (args);
+ else if (verb == 1)
+ text << "installing " << os_release.name_id << " packages...";
+
+ process pr;
+ if (!simulate_)
+ {
+ // Redirect stdout to stderr since apt-get prints some of its
+ // diagnostics to stdout.
+ //
+ pr = process (pp, args, 0 /* stdin */, 2 /* stdout */);
+ }
+ else
+ {
+ print_process (args);
+ pr = process (process_exit (simulate_->apt_get_install_fail_ ? 100 : 0));
+ }
+
+ if (!pr.wait ())
+ {
+ diag_record dr (fail);
+ dr << "apt-get install exited with non-zero code";
+
+ if (verb < 2)
+ {
+ dr << info << "command line: ";
+ print_process (dr, args);
+ }
+
+ dr << info << "consider resolving the issue manually and retrying "
+ << "the bpkg command";
+ }
+
+ if (verb == 1)
+ text << "installed " << os_release.name_id << " packages";
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e;
+
+ if (e.child)
+ exit (1);
+
+ throw failed ();
+ }
+ }
+
+ optional<const system_package_status*> system_package_manager_debian::
+ status (const package_name& pn, const available_packages* aps)
+ {
+ // First check the cache.
+ //
+ {
+ auto i (status_cache_.find (pn));
+
+ if (i != status_cache_.end ())
+ return i->second ? &*i->second : nullptr;
+
+ if (aps == nullptr)
+ return nullopt;
+ }
+
+ optional<package_status> r (status (pn, *aps));
+
+ // Cache.
+ //
+ auto i (status_cache_.emplace (pn, move (r)).first);
+ return i->second ? &*i->second : nullptr;
+ }
+
+ optional<package_status> system_package_manager_debian::
+ status (const package_name& pn, const available_packages& aps)
+ {
+ tracer trace ("system_package_manager_debian::status");
+
+ // For now we ignore -doc and -dbg package components (but we may want to
+ // have options controlling this later). Note also that we assume -common
+ // is pulled automatically by the main package so we ignore it as well
+ // (see equivalent logic in parse_name_value()).
+ //
+ bool need_doc (false);
+ bool need_dbg (false);
+
+ vector<package_status> candidates;
+
+ // Translate our package name to the Debian package names.
+ //
+ {
+ auto df = make_diag_frame (
+ [this, &pn] (diag_record& dr)
+ {
+ dr << info << "while mapping " << pn << " to "
+ << os_release.name_id << " package name";
+ });
+
+ // Without explicit type, the best we can do in trying to detect whether
+ // this is a library is to check for the lib prefix. Libraries without
+ // the lib prefix and non-libraries with the lib prefix (both of which
+ // we do not recomment) will have to provide a manual mapping (or
+ // explicit type).
+ //
+ // Note that using the first (latest) available package as a source of
+ // type information seems like a reasonable choice.
+ //
+ const string& pt (!aps.empty ()
+ ? aps.front ().first->effective_type ()
+ : package_manifest::effective_type (nullopt, pn));
+
+ strings ns;
+ if (!aps.empty ())
+ ns = system_package_names (aps,
+ os_release.name_id,
+ os_release.version_id,
+ os_release.like_ids,
+ true /* native */);
+ if (ns.empty ())
+ {
+ // Attempt to automatically translate our package name (see above for
+ // details).
+ //
+ const string& n (pn.string ());
+
+ if (pt == "lib")
+ {
+ // Keep the main package name empty as an indication that it is to
+ // be discovered.
+ //
+ // @@ It seems that quite often the header-only library -dev package
+ // name doesn't start with 'lib'. Here are some randomly chosen
+ // packages: libeigen3-dev, libmdds-dev, rapidjson-dev, etl-dev,
+ // seqan-dev, catch2. Should we implement the fallback similar to
+ // the Fedora implementation? Maybe one day.
+ //
+ candidates.push_back (package_status ("", n + "-dev"));
+ }
+ else
+ candidates.push_back (package_status (n));
+ }
+ else
+ {
+ // Parse each manual mapping.
+ //
+ for (const string& n: ns)
+ {
+ package_status s (parse_name_value (pt, n, need_doc, need_dbg));
+
+ // Suppress duplicates for good measure based on the main package
+ // name (and falling back to -dev if empty).
+ //
+ auto i (find_if (candidates.begin (), candidates.end (),
+ [&s] (const package_status& x)
+ {
+ // Note that it's possible for one mapping to be
+ // specified as -dev only while the other as main
+ // and -dev.
+ //
+ return s.main.empty () || x.main.empty ()
+ ? s.dev == x.dev
+ : s.main == x.main;
+ }));
+ if (i == candidates.end ())
+ candidates.push_back (move (s));
+ else
+ {
+ // Should we verify the rest matches for good measure? But what if
+ // we need to override, as in:
+ //
+ // debian_10-name: libcurl4 libcurl4-openssl-dev
+ // debian_9-name: libcurl4 libcurl4-dev
+ //
+ // Note that for this to work we must get debian_10 values before
+ // debian_9, which is the semantics guaranteed by
+ // system_package_names().
+ }
+ }
+ }
+ }
+
+ // Guess unknown main package given the -dev package and its version.
+ // Failed that, assume the package to be a binless library and leave the
+ // main member of the package_status object empty.
+ //
+ auto guess_main = [this, &trace] (package_status& s, const string& ver)
+ {
+ string depends (apt_cache_show (s.dev, ver));
+
+ s.main = main_from_dev (s.dev, ver, depends);
+
+ if (s.main.empty ())
+ {
+ l4 ([&]{trace << "unable to guess main package for " << s.dev << ' '
+ << ver << ", Depends value: " << depends;});
+ }
+ };
+
+ // Calculate the package status from individual package components.
+ // Return nullopt if there is a component without installed or candidate
+ // version (which means the package cannot be installed).
+ //
+ // The main argument specifies the size of the main group. Only components
+ // from this group are considered for partially_installed determination.
+ //
+ // @@ TODO: we should probably prioritize partially installed with fully
+ // installed main group. Add almost_installed next to partially_installed?
+ //
+ using status_type = package_status::status_type;
+
+ auto status = [] (const vector<package_policy>& pps, size_t main)
+ -> optional<status_type>
+ {
+ bool i (false), u (false);
+
+ for (size_t j (0); j != pps.size (); ++j)
+ {
+ const package_policy& pp (pps[j]);
+
+ if (pp.installed_version.empty ())
+ {
+ if (pp.candidate_version.empty ())
+ return nullopt;
+
+ u = true;
+ }
+ else if (j < main)
+ i = true;
+ }
+
+ return (!u ? package_status::installed :
+ !i ? package_status::not_installed :
+ package_status::partially_installed);
+ };
+
+ // First look for an already fully installed package.
+ //
+ optional<package_status> r;
+
+ {
+ diag_record dr; // Ambiguity diagnostics.
+
+ for (package_status& ps: candidates)
+ {
+ vector<package_policy>& pps (ps.package_policies);
+
+ if (!ps.main.empty ()) pps.emplace_back (ps.main);
+ if (!ps.dev.empty ()) pps.emplace_back (ps.dev);
+ if (!ps.doc.empty () && need_doc) pps.emplace_back (ps.doc);
+ if (!ps.dbg.empty () && need_dbg) pps.emplace_back (ps.dbg);
+ if (!ps.common.empty () && false) pps.emplace_back (ps.common);
+ ps.package_policies_main = pps.size ();
+ for (const string& n: ps.extras) pps.emplace_back (n);
+
+ apt_cache_policy (pps);
+
+ // Handle the unknown main package.
+ //
+ if (ps.main.empty ())
+ {
+ const package_policy& dev (pps.front ());
+
+ // Note that at this stage we can only use the installed -dev
+ // package (since the candidate version may change after fetch).
+ //
+ if (dev.installed_version.empty ())
+ continue;
+
+ guess_main (ps, dev.installed_version);
+
+ if (!ps.main.empty ()) // Not a binless library?
+ {
+ pps.emplace (pps.begin (), ps.main);
+ ps.package_policies_main++;
+ apt_cache_policy (pps, 1);
+ }
+ }
+
+ optional<status_type> s (status (pps, ps.package_policies_main));
+
+ if (!s || *s != package_status::installed)
+ continue;
+
+ const package_policy& main (pps.front ()); // Main/dev.
+
+ ps.status = *s;
+ ps.system_name = main.name;
+ ps.system_version = main.installed_version;
+
+ if (!r)
+ {
+ r = move (ps);
+ continue;
+ }
+
+ if (dr.empty ())
+ {
+ dr << fail << "multiple installed " << os_release.name_id
+ << " packages for " << pn <<
+ info << "candidate: " << r->system_name << ' ' << r->system_version;
+ }
+
+ dr << info << "candidate: " << ps.system_name << ' '
+ << ps.system_version;
+ }
+
+ if (!dr.empty ())
+ dr << info << "consider specifying the desired version manually";
+ }
+
+ // Next look for available versions if we are allowed to install. Indicate
+ // the non-installable candidates by setting both their main and -dev
+ // package names to empty strings.
+ //
+ if (!r && install_)
+ {
+ // If we weren't instructed to fetch or we already fetched, then we
+ // don't need to re-run apt_cache_policy().
+ //
+ bool requery;
+ if ((requery = fetch_ && !fetched_))
+ {
+ apt_get_update ();
+ fetched_ = true;
+ }
+
+ {
+ diag_record dr; // Ambiguity diagnostics.
+
+ for (package_status& ps: candidates)
+ {
+ vector<package_policy>& pps (ps.package_policies);
+
+ if (requery)
+ apt_cache_policy (pps);
+
+ // Handle the unknown main package.
+ //
+ if (ps.main.empty ())
+ {
+ const package_policy& dev (pps.front ());
+
+ // Note that this time we use the candidate version.
+ //
+ if (dev.candidate_version.empty ())
+ {
+ // Not installable.
+ //
+ ps.dev.clear ();
+ continue;
+ }
+
+ guess_main (ps, dev.candidate_version);
+
+ if (!ps.main.empty ()) // Not a binless library?
+ {
+ pps.emplace (pps.begin (), ps.main);
+ ps.package_policies_main++;
+ apt_cache_policy (pps, 1);
+ }
+ }
+
+ optional<status_type> s (status (pps, ps.package_policies_main));
+
+ if (!s)
+ {
+ // Not installable.
+ //
+ ps.main.clear ();
+ ps.dev.clear ();
+ continue;
+ }
+
+ assert (*s != package_status::installed); // Sanity check.
+
+ const package_policy& main (pps.front ()); // Main/dev.
+
+ // Note that if we are installing something for this main package,
+ // then we always go for the candidate version even though it may
+ // have an installed version that may be good enough (especially if
+ // what we are installing are extras). The reason is that it may as
+ // well not be good enough (especially if we are installing the -dev
+ // package) and there is no straightforward way to change our mind.
+ //
+ ps.status = *s;
+ ps.system_name = main.name;
+ ps.system_version = main.candidate_version;
+
+ // Prefer partially installed to not installed. This makes detecting
+ // ambiguity a bit trickier so we handle partially installed here
+ // and not installed in a separate loop below.
+ //
+ if (ps.status != package_status::partially_installed)
+ continue;
+
+ if (!r)
+ {
+ r = move (ps);
+ continue;
+ }
+
+ auto print_missing = [&dr] (const package_status& s)
+ {
+ for (const package_policy& pp: s.package_policies)
+ if (pp.installed_version.empty ())
+ dr << ' ' << pp.name;
+ };
+
+ if (dr.empty ())
+ {
+ dr << fail << "multiple partially installed "
+ << os_release.name_id << " packages for " << pn;
+
+ dr << info << "candidate: " << r->system_name << ' '
+ << r->system_version << ", missing components:";
+ print_missing (*r);
+ }
+
+ dr << info << "candidate: " << ps.system_name << ' '
+ << ps.system_version << ", missing components:";
+ print_missing (ps);
+ }
+
+ if (!dr.empty ())
+ dr << info << "consider fully installing the desired package "
+ << "manually and retrying the bpkg command";
+ }
+
+ if (!r)
+ {
+ diag_record dr; // Ambiguity diagnostics.
+
+ for (package_status& ps: candidates)
+ {
+ if (ps.main.empty () && ps.dev.empty ()) // Not installable?
+ continue;
+
+ assert (ps.status == package_status::not_installed); // Sanity check.
+
+ if (!r)
+ {
+ r = move (ps);
+ continue;
+ }
+
+ if (dr.empty ())
+ {
+ dr << fail << "multiple available " << os_release.name_id
+ << " packages for " << pn <<
+ info << "candidate: " << r->system_name << ' '
+ << r->system_version;
+ }
+
+ dr << info << "candidate: " << ps.system_name << ' '
+ << ps.system_version;
+ }
+
+ if (!dr.empty ())
+ dr << info << "consider installing the desired package manually and "
+ << "retrying the bpkg command";
+ }
+ }
+
+ if (r)
+ {
+ // Map the Debian version to the bpkg version. But first strip the
+ // revision from Debian version ([<epoch>:]<upstream>[-<revision>]), if
+ // any.
+ //
+ // Note that according to deb-version(5), <upstream> may contain `:`/`-`
+ // but in these cases <epoch>/<revision> must be specified explicitly,
+ // respectively.
+ //
+ string sv (r->system_version, 0, r->system_version.rfind ('-'));
+
+ // Debian package versions sometimes include metadata introduced with
+ // the `+` character that established relationships between Debian and
+ // upstream packages, backports, and some other murky stuff (see Debian
+ // Policy with a strong cup of coffee for details). Normally such
+ // metadata is included in the revision, as in, for example,
+ // 1.4.0-1+deb10u1. However, sometimes you see it included in the
+ // version directly, as in, for example: 3.2.4+debian-1 (see Debian bug
+ // 542288 for a potential explanation; might need to refill you cup).
+ //
+ // Since our upstream version may not contain `+`, it feels reasonable
+ // to remove such metadata. What's less clear is whether we should do
+ // the same before trying the to-downstream mapping. In fact, it's
+ // possible `+` belongs to the upstream version rather than Debian
+ // metadata or that there are both (there is also no guarantee that
+ // Debian metadata may not contain multiple `+`). So what we are going
+ // to do is try the mapping with more and more `+` components stripped
+ // (naturally ending up with all of them stripped for the fallback
+ // below).
+ //
+ optional<version> v;
+ for (size_t p (sv.size ()); p != string::npos; p = sv.rfind ('+'))
+ {
+ sv.resize (p);
+
+ if (!aps.empty ())
+ {
+ v = downstream_package_version (sv,
+ aps,
+ os_release.name_id,
+ os_release.version_id,
+ os_release.like_ids);
+ if (v)
+ break;
+ }
+ }
+
+ if (!v)
+ {
+ // Fallback to using system version as downstream version. But first
+ // strip the epoch, if any. Also convert the potential pre-release
+ // separator to the bpkg version pre-release separator.
+ //
+ size_t p (sv.find (':'));
+ if (p != string::npos)
+ sv.erase (0, p + 1);
+
+ // Consider the first '~' character as a pre-release separator. Note
+ // that if there are more of them, then we will fail since '~' is an
+ // invalid character for bpkg version.
+ //
+ p = sv.find ('~');
+ if (p != string::npos)
+ sv[p] = '-';
+
+ try
+ {
+ v = version (sv);
+ }
+ catch (const invalid_argument& e)
+ {
+ fail << "unable to map " << os_release.name_id << " package "
+ << r->system_name << " version " << sv << " to bpkg package "
+ << pn << " version" <<
+ info << os_release.name_id << " version is not a valid bpkg "
+ << "version: " << e.what () <<
+ info << "consider specifying explicit mapping in " << pn
+ << " package manifest";
+ }
+ }
+
+ r->version = move (*v);
+ }
+
+ return r;
+ }
+
+ void system_package_manager_debian::
+ install (const vector<package_name>& pns)
+ {
+ assert (!pns.empty ());
+
+ assert (install_ && !installed_);
+ installed_ = true;
+
+ // Collect and merge all the Debian packages/versions for the specified
+ // bpkg packages.
+ //
+ struct package
+ {
+ string name;
+ string version; // Empty if unspecified.
+ };
+ vector<package> pkgs;
+
+ for (const package_name& pn: pns)
+ {
+ auto it (status_cache_.find (pn));
+ assert (it != status_cache_.end () && it->second);
+
+ const package_status& ps (*it->second);
+
+ // At first it may seem we don't need to do anything for already fully
+ // installed packages. But it's possible some of them were automatically
+ // installed, meaning that they can be automatically removed if they no
+ // longer have any dependents (see apt-mark(8) for details). Which in
+ // turn means that things may behave differently depending on whether
+ // we've installed a package ourselves or if it was already installed.
+ // So instead we are going to also pass the already fully installed
+ // packages which will make sure they are all set to manually installed.
+ // But we must be careful not to force their upgrade. To achieve this
+ // we will specify the installed version as the desired version.
+ //
+ // Note also that for partially/not installed we don't specify the
+ // version, expecting the candidate version to be installed.
+ //
+ bool fi (ps.status == package_status::installed);
+
+ for (const package_policy& pp: ps.package_policies)
+ {
+ string n (pp.name);
+ string v (fi ? pp.installed_version : string ());
+
+ auto i (find_if (pkgs.begin (), pkgs.end (),
+ [&n] (const package& p)
+ {
+ return p.name == n;
+ }));
+
+ if (i != pkgs.end ())
+ {
+ if (i->version.empty ())
+ i->version = move (v);
+ else
+ // Feels like this cannot happen since we always use the installed
+ // version of the package.
+ //
+ assert (i->version == v);
+ }
+ else
+ pkgs.push_back (package {move (n), move (v)});
+ }
+ }
+
+ // Install.
+ //
+ {
+ // Convert to the `apt-get install` <pkg>[=<ver>] form.
+ //
+ strings specs;
+ specs.reserve (pkgs.size ());
+ for (const package& p: pkgs)
+ {
+ string s (p.name);
+ if (!p.version.empty ())
+ {
+ s += '=';
+ s += p.version;
+ }
+ specs.push_back (move (s));
+ }
+
+ apt_get_install (specs);
+ }
+
+ // Verify that versions we have promised in status() match what actually
+ // got installed.
+ //
+ {
+ vector<package_policy> pps;
+
+ // Here we just check the main package component of each package.
+ //
+ for (const package_name& pn: pns)
+ {
+ const package_status& ps (*status_cache_.find (pn)->second);
+
+ if (find_if (pps.begin (), pps.end (),
+ [&ps] (const package_policy& pp)
+ {
+ return pp.name == ps.system_name;
+ }) == pps.end ())
+ {
+ pps.push_back (package_policy (ps.system_name));
+ }
+ }
+
+ apt_cache_policy (pps);
+
+ for (const package_name& pn: pns)
+ {
+ const package_status& ps (*status_cache_.find (pn)->second);
+
+ auto i (find_if (pps.begin (), pps.end (),
+ [&ps] (const package_policy& pp)
+ {
+ return pp.name == ps.system_name;
+ }));
+ assert (i != pps.end ());
+
+ const package_policy& pp (*i);
+
+ if (pp.installed_version != ps.system_version)
+ {
+ fail << "unexpected " << os_release.name_id << " package version "
+ << "for " << ps.system_name <<
+ info << "expected: " << ps.system_version <<
+ info << "installed: " << pp.installed_version <<
+ info << "consider retrying the bpkg command";
+ }
+ }
+ }
+ }
+
+ // Map non-system bpkg package to system package name(s) and version.
+ //
+ // This is used both to map the package being generated and its
+ // dependencies. What should we do with extras returned in package_status?
+ // We can't really generate any of them (which files would we place in
+ // them?) nor can we list them as dependencies (we don't know their system
+ // versions). So it feels like the only sensible choice is to ignore extras.
+ //
+ // In a sense, we have a parallel arrangement going on here: binary packages
+ // that we generate don't have extras (i.e., they include everything
+ // necessary in the "standard" packages from the main group) and when we
+ // punch a system dependency based on a non-system bpkg package, we assume
+ // it was generated by us and thus doesn't have any extras. Or, to put it
+ // another way, if you want the system dependency to refer to a "native"
+ // system package with extras you need to configure it as a system bpkg
+ // package.
+ //
+ // In fact, this extends to package names. For example, unless custom
+ // mapping is specified, we will generate libsqlite3 and libsqlite3-dev
+ // while native names are libsqlite3-0 and libsqlite3-dev. While this
+ // duality is not ideal, presumably we will normally only be producing our
+ // binary packages if there are no suitable native packages. And for a few
+ // exceptions (e.g., our package is "better" in some way, such as configured
+ // differently or fixes a critical bug), we will just have to provide
+ // appropriate manual mapping that makes sure the names match (the extras is
+ // still a potential problem though -- we will only have them as
+ // dependencies if we build against a native system package; maybe we can
+ // add them manually with an option).
+ //
+ package_status system_package_manager_debian::
+ map_package (const package_name& pn,
+ const version& pv,
+ const available_packages& aps,
+ const optional<string>& build_metadata) const
+ {
+ // We should only have one available package corresponding to this package
+ // name/version.
+ //
+ assert (aps.size () == 1);
+
+ const shared_ptr<available_package>& ap (aps.front ().first);
+ const lazy_shared_ptr<repository_fragment>& rf (aps.front ().second);
+
+ // Without explicit type, the best we can do in trying to detect whether
+ // this is a library is to check for the lib prefix. Libraries without the
+ // lib prefix and non-libraries with the lib prefix (both of which we do
+ // not recomment) will have to provide a manual mapping (or explicit
+ // type).
+ //
+ const string& pt (ap->effective_type ());
+
+ strings ns (system_package_names (aps,
+ os_release.name_id,
+ os_release.version_id,
+ os_release.like_ids,
+ false /* native */));
+ package_status r;
+ if (ns.empty ())
+ {
+ // Automatically translate our package name similar to the consumption
+ // case above. Except here we don't attempt to deduce main from -dev,
+ // naturally.
+ //
+ const string& n (pn.string ());
+
+ if (pt == "lib")
+ r = package_status (n, n + "-dev");
+ else
+ r = package_status (n);
+ }
+ else
+ {
+ // Even though we only pass one available package, we may still end up
+ // with multiple mappings. In this case we take the first, per the
+ // documentation.
+ //
+ r = parse_name_value (pt,
+ ns.front (),
+ false /* need_doc */,
+ false /* need_dbg */);
+
+ // If this is -dev without main, then derive main by stripping the -dev
+ // suffix. This feels tighter than just using the bpkg package name.
+ //
+ if (r.main.empty ())
+ {
+ assert (!r.dev.empty ());
+ r.main.assign (r.dev, 0, r.dev.size () - 4);
+ }
+ }
+
+ // Map the version.
+ //
+ // NOTE: THE BELOW DESCRIPTION IS ALSO REPRODUCED IN THE BPKG MANUAL.
+ //
+ // To recap, a Debian package version has the following form:
+ //
+ // [<epoch>:]<upstream>[-<revision>]
+ //
+ // For details on the ordering semantics, see the Version control file
+ // field documentation in the Debian Policy Manual. While overall
+ // unsurprising, one notable exception is `~`, which sorts before anything
+ // else and is commonly used for upstream pre-releases. For example,
+ // 1.0~beta1~svn1245 sorts earlier than 1.0~beta1, which sorts earlier
+ // than 1.0.
+ //
+ // There are also various special version conventions (such as all the
+ // revision components in 1.4-5+deb10u1~bpo9u1) but they all appear to
+ // express relationships between native packages and/or their upstream and
+ // thus do not apply to our case.
+ //
+ // Ok, so how do we map our version to that? To recap, the bpkg version
+ // has the following form:
+ //
+ // [+<epoch>-]<upstream>[-<prerel>][+<revision>]
+ //
+ // Let's start with the case where neither distribution nor upstream
+ // version is specified and we need to derive everything from the bpkg
+ // version.
+ //
+ // <epoch>
+ //
+ // On one hand, if we keep the epoch, it won't necessarily match
+ // Debian's native package epoch. But on the other it will allow our
+ // binary packages from different epochs to co-exist. Seeing that this
+ // can be easily overridden with a custom distribution version, let's
+ // keep it.
+ //
+ // Note that while the Debian start/default epoch is 0, ours is 1 (we
+ // use the 0 epoch for stub packages). So we will need to shift this
+ // value range.
+ //
+ //
+ // <upstream>[-<prerel>]
+ //
+ // Our upstream version maps naturally to Debian's. That is, our
+ // upstream version format/semantics is a subset of Debian's.
+ //
+ // If this is a pre-release, then we could fail (that is, don't allow
+ // pre-releases) but then we won't be able to test on pre-release
+ // packages, for example, to make sure the name mapping is correct.
+ // Plus sometimes it's useful to publish pre-releases. We could ignore
+ // it, but then such packages will be indistinguishable from each other
+ // and the final release, which is not ideal. On the other hand, Debian
+ // has the mechanism (`~`) which is essentially meant for this, so let's
+ // use it. We will use <prerel> as is since its format is the same as
+ // upstream and thus should map naturally.
+ //
+ //
+ // <revision>
+ //
+ // Similar to epoch, our revision won't necessarily match Debian's
+ // native package revision. But on the other hand it will allow us to
+ // establish a correspondence between source and binary packages. Plus,
+ // upgrades between binary package revisions will be handled naturally.
+ // Seeing that we allow overriding the revision with a custom
+ // distribution version (see below), let's keep it.
+ //
+ // Note also that both Debian and our revision start/default is 0.
+ // However, it is Debian's convention to start revision from 1. But it
+ // doesn't seem worth it for us to do any shifting here and so we will
+ // use our revision as is.
+ //
+ // Another related question is whether we should also include some
+ // metadata that identifies the distribution and its version that this
+ // package is for. The strongest precedent here is probably Ubuntu's
+ // PPA. While there doesn't appear to be a consistent approach, one can
+ // often see versions like these:
+ //
+ // 2.1.0-1~ppa0~ubuntu14.04.1,
+ // 1.4-5-1.2.1~ubuntu20.04.1~ppa1
+ // 22.12.2-0ubuntu1~ubuntu23.04~ppa1
+ //
+ // Seeing that this is a non-sortable component (what in semver would be
+ // called "build metadata"), using `~` is probably not the worst choice.
+ //
+ // So we follow this lead and add the ~<name_id><version_id> component
+ // to revision. Note that this also means we will have to make the 0
+ // revision explicit. For example:
+ //
+ // 1.2.3-1~debian10
+ // 1.2.3-0~ubuntu20.04
+ //
+ // The next case to consider is when we have the upstream version
+ // (upstream-version manifest value). After some rumination it feels
+ // correct to use it in place of the <epoch>-<upstream> components in the
+ // above mapping (upstream version itself cannot have epoch). In other
+ // words, we will add the pre-release and revision components from the
+ // bpkg version. If this is not the desired semantics, then it can always
+ // be overrided with the distribution version.
+ //
+ // Finally, we have the distribution version. The Debian <epoch> and
+ // <upstream> components are straightforward: they should be specified by
+ // the distribution version as required. This leaves pre-release and
+ // revision. It feels like in most cases we would want these copied over
+ // from the bpkg version automatically -- it's too tedious and error-
+ // prone to maintain them manually. However, we want the user to have the
+ // full override ability. So instead, if empty revision is specified, as
+ // in 1.2.3-, then we automatically add the bpkg revision. Similarly, if
+ // empty pre-release is specified, as in 1.2.3~, then we add the bpkg
+ // pre-release. To add both automatically, we would specify 1.2.3~- (other
+ // combinations are 1.2.3~b.1- and 1.2.3~-1).
+ //
+ // Note also that per the Debian version specification, if upstream
+ // contains `:` and/or `-`, then epoch and/or revision must be specified
+ // explicitly, respectively. Note that the bpkg upstream version may not
+ // contain either.
+ //
+ string& sv (r.system_version);
+
+ bool no_build_metadata (build_metadata && build_metadata->empty ());
+
+ if (optional<string> ov = system_package_version (ap,
+ rf,
+ os_release.name_id,
+ os_release.version_id,
+ os_release.like_ids))
+ {
+ string& dv (*ov);
+ size_t n (dv.size ());
+
+ // Find the revision and pre-release positions, if any.
+ //
+ size_t rp (dv.rfind ('-'));
+ size_t pp (dv.rfind ('~', rp));
+
+ // Copy over the [<epoch>:]<upstream> part.
+ //
+ sv.assign (dv, 0, pp < rp ? pp : rp);
+
+ // Add pre-release copying over the bpkg version value if empty.
+ //
+ if (pp != string::npos)
+ {
+ if (size_t pn = (rp != string::npos ? rp : n) - (pp + 1))
+ {
+ sv.append (dv, pp, pn + 1);
+ }
+ else
+ {
+ if (pv.release)
+ {
+ assert (!pv.release->empty ()); // Cannot be earliest special.
+ sv += '~';
+ sv += *pv.release;
+ }
+ }
+ }
+
+ // Add revision copying over the bpkg version value if empty.
+ //
+ // Omit the default -0 revision if we have no build metadata.
+ //
+ if (rp != string::npos)
+ {
+ if (size_t rn = n - (rp + 1))
+ {
+ sv.append (dv, rp, rn + 1);
+ }
+ else if (pv.revision || !no_build_metadata)
+ {
+ sv += '-';
+ sv += to_string (pv.revision ? *pv.revision : 0);
+ }
+ }
+ else if (!no_build_metadata)
+ sv += "-0"; // Default revision (for build metadata; see below).
+ }
+ else
+ {
+ if (ap->upstream_version)
+ {
+ const string& uv (*ap->upstream_version);
+
+ // Add explicit epoch if upstream contains `:`.
+ //
+ // Note that we don't need to worry about `-` since we always add
+ // revision (see below).
+ //
+ if (uv.find (':') != string::npos)
+ sv = "0:";
+
+ sv += uv;
+ }
+ else
+ {
+ // Add epoch unless maps to 0.
+ //
+ assert (pv.epoch != 0); // Cannot be a stub.
+ if (pv.epoch != 1)
+ {
+ sv = to_string (pv.epoch - 1);
+ sv += ':';
+ }
+
+ sv += pv.upstream;
+ }
+
+ // Add pre-release.
+ //
+ if (pv.release)
+ {
+ assert (!pv.release->empty ()); // Cannot be earliest special.
+ sv += '~';
+ sv += *pv.release;
+ }
+
+ // Add revision.
+ //
+ if (pv.revision || !no_build_metadata)
+ {
+ sv += '-';
+ sv += to_string (pv.revision ? *pv.revision : 0);
+ }
+ }
+
+ // Add build matadata.
+ //
+ if (!no_build_metadata)
+ {
+ sv += '~';
+
+ if (!build_metadata)
+ {
+ sv += os_release.name_id;
+ sv += os_release.version_id; // Could be empty.
+ }
+ else
+ {
+ const string& md (*build_metadata);
+
+ bool f (md.front () == '+');
+ bool b (md.back () == '+');
+
+ if (f && b) // Note: covers just `+`.
+ fail << "invalid build metadata '" << md << "'";
+
+ if (f || b)
+ {
+ if (b)
+ sv.append (md, 0, md.size () - 1);
+
+ sv += os_release.name_id;
+ sv += os_release.version_id;
+
+ if (f)
+ sv.append (md, 1, md.size () - 1);
+ }
+ else
+ sv += md;
+ }
+ }
+
+ return r;
+ }
+
+ // Some background on creating Debian packages (for a bit more detailed
+ // overview see the Debian Packaging Tutorial).
+ //
+ // A binary Debian package (.deb) is an ar archive which itself contains a
+ // few tar archives normally compressed with gz or xz. So it's possible to
+ // create the package completely manually without using any of the Debian
+ // tools and while some implementations (for example, cargo-deb) do it this
+ // way, we are not going to go this route because it does not scale well to
+ // more complex packages which may require additional functionality (such as
+ // managing systemd files) and which is covered by the Debian tools (for an
+ // example of where this leads, see the partial debhelper re-implementation
+ // in cargo-deb). Another issues with this approach is that it's not
+ // amenable to customizations, at least not in a way familiar to Debian
+ // users.
+ //
+ // At the lowest level of the Debian tools for creating packages sits the
+ // dpkg-deb --build|-b command (also accessible as dpkg --build|-b). Given a
+ // directory with all the binary package contents (including the package
+ // metadata, such as the control file, in the debian/ subdirectory) this
+ // command will pack everything up into a .deb file. While an improvement
+ // over the fully manual packaging, this approach has essentially the same
+ // drawbacks. In particular, this command generates a single package which
+ // means we will have to manually sort out things into -dev, -doc, etc.
+ //
+ // Next up the stack is dpkg-buildpackage. This tool expects the package to
+ // follow the Debian way of packaging, that is, to provide the debian/rules
+ // makefile with a number of required targets which it then invokes to
+ // build, install, and pack a package from source (and sometime during this
+ // process it calls dpkg-deb --build). The dpkg-buildpackage(1) man page has
+ // an overview of all the steps that this command performs and it is the
+ // recommended, lower-level, way to build packages on Debian.
+ //
+ // At the top of the stack sits debuild which calls dpkg-buildpackage, then
+ // lintian, and finally design (though signing can also be performed by
+ // dpkg-buildpackage itself).
+ //
+ // Based on this our plan is to use dpkg-buildpackage which brings us to the
+ // Debian way of packaging with debian/rules at its core. As it turns out,
+ // it can also be implemented in a number of alternative ways. So let's
+ // discuss those.
+ //
+ // As mentioned earlier, debian/rules is a makefile that is expected to
+ // provide a number of targets, such as build, install, etc. And
+ // theoretically these targets can be implemented completely manually. In
+ // practice, however, the Debian way is to use the debhelper(1) packaging
+ // helper tools. For example, there are helpers for stripping binaries,
+ // compressing man pages, fixing permissions, and managing systemd files.
+ //
+ // While debhelper tools definitely simplify debian/rules, there is often
+ // still a lot of boilerplate code. So second-level helpers are often used,
+ // with the dominant option being the dh(1) command sequencer (there is also
+ // CDBS but it appears to be fading into obsolescence).
+ //
+ // Based on that our options appear to be classic debhelper and dh. Looking
+ // at the statistics, it's clear that the majority of packages (including
+ // fairly complex ones) tend to prefer dh and there is no reason for us to
+ // try to buck this trend.
+ //
+ // NOTE: THE BELOW DESCRIPTION IS ALSO REWORDED IN BPKG-PKG-BINDIST(1).
+ //
+ // So, to sum up, the plan is to produce debian/rules that uses the dh
+ // command sequencer and then invoke dpkg-buildpackage to produce the binary
+ // package from that. While this approach is normally used to build things
+ // from source, it feels like we should be able to pretend that we are.
+ // Specifially, we can override the install target to invoke the build
+ // system and install all the packages directly from their bpkg locations.
+ //
+ // Note that the -dbgsym packages are generated by default and all we need
+ // to do from our side is to compile with debug information (-g), failed
+ // which we get a warning from debhelper.
+ //
+ // Note: this setup requires dpkg-dev (or build-essential) and debhelper
+ // packages.
+ //
+ auto system_package_manager_debian::
+ generate (const packages& pkgs,
+ const packages& deps,
+ const strings& vars,
+ const dir_path& cfg_dir,
+ const package_manifest& pm,
+ const string& pt,
+ const small_vector<language, 1>& langs,
+ optional<bool> recursive_full,
+ bool first) -> binary_files
+ {
+ tracer trace ("system_package_manager_debian::generate");
+
+ assert (!langs.empty ()); // Should be effective.
+
+ // We require explicit output root.
+ //
+ if (!ops_->output_root_specified ())
+ fail << "output root directory must be specified explicitly with "
+ << "--output-root|-o";
+
+ const dir_path& out (ops_->output_root ()); // Cannot be empty.
+
+ optional<string> build_metadata;
+ if (ops_->debian_build_meta_specified ())
+ build_metadata = ops_->debian_build_meta ();
+
+ const shared_ptr<selected_package>& sp (pkgs.front ().selected);
+ const package_name& pn (sp->name);
+ const version& pv (sp->version);
+
+ // Use version without iteration in paths, etc (`#` breaks dpkg
+ // machinery).
+ //
+ string pvs (pv.string (false /* ignore_revision */,
+ true /* ignore_iteration */));
+
+ const available_packages& aps (pkgs.front ().available);
+
+ bool lib (pt == "lib");
+ bool priv (ops_->private_ ()); // Private installation.
+
+ // For now we only know how to handle libraries with C-common interface
+ // languages. But we allow other implementation languages.
+ //
+ if (lib)
+ {
+ for (const language& l: langs)
+ if (!l.impl && l.name != "c" && l.name != "c++" && l.name != "cc")
+ fail << l.name << " libraries are not yet supported";
+ }
+
+ // Return true if this package uses the specified language, only as
+ // interface language if intf_only is true.
+ //
+ auto lang = [&langs] (const char* n, bool intf_only = false) -> bool
+ {
+ return find_if (langs.begin (), langs.end (),
+ [n, intf_only] (const language& l)
+ {
+ return (!intf_only || !l.impl) && l.name == n;
+ }) != langs.end ();
+ };
+
+ // As a first step, figure out the system names and version of the package
+ // we are generating and all the dependencies, diagnosing anything fishy.
+ // If the main package is not present for a dependency, then set the main
+ // package name to an empty string.
+ //
+ // Note that there should be no duplicate dependencies and we can sidestep
+ // the status cache.
+ //
+ package_status st (map_package (pn, pv, aps, build_metadata));
+
+ vector<package_status> sdeps;
+ sdeps.reserve (deps.size ());
+ for (const package& p: deps)
+ {
+ const shared_ptr<selected_package>& sp (p.selected);
+ const available_packages& aps (p.available);
+
+ package_status s;
+ if (sp->substate == package_substate::system)
+ {
+ // Note that for a system dependency the main package name is already
+ // empty if it is not present in the distribution.
+ //
+ optional<package_status> os (status (sp->name, aps));
+
+ if (!os || os->status != package_status::installed)
+ fail << os_release.name_id << " package for " << sp->name
+ << " system package is no longer installed";
+
+ // For good measure verify the mapped back version still matches
+ // configured. Note that besides the normal case (queried by the
+ // system package manager), it could have also been specified by the
+ // user as an actual version or a wildcard. Ignoring this check for a
+ // wildcard feels consistent with the overall semantics.
+ //
+ if (sp->version != wildcard_version && sp->version != os->version)
+ {
+ fail << "current " << os_release.name_id << " package version for "
+ << sp->name << " system package does not match configured" <<
+ info << "configured version: " << sp->version <<
+ info << "current version: " << os->version << " ("
+ << os->system_version << ')';
+ }
+
+ s = move (*os);
+ }
+ else
+ {
+ s = map_package (sp->name, sp->version, aps, build_metadata);
+
+ // Set the main package name to an empty string if we wouldn't be
+ // generating the main package for this dependency (binless library
+ // without the -common package).
+ //
+ assert (aps.size () == 1);
+
+ const optional<string>& t (aps.front ().first->type);
+
+ if (s.common.empty () &&
+ package_manifest::effective_type (t, sp->name) == "lib")
+ {
+ strings sos (package_manifest::effective_type_sub_options (t));
+
+ if (find (sos.begin (), sos.end (), "binless") != sos.end ())
+ s.main.clear ();
+ }
+ }
+
+ sdeps.push_back (move (s));
+ }
+
+ if (!st.dbg.empty ())
+ fail << "generation of obsolete manual -dbg packages not supported" <<
+ info << "use automatic -dbgsym packages instead";
+
+ // We override every config.install.* variable in order not to pick
+ // anything configured. Note that we add some more in the rules file
+ // below.
+ //
+ // We make use of the <project> substitution since in the recursive mode
+ // we may be installing multiple projects. Note that the <private>
+ // directory component is automatically removed if this functionality is
+ // not enabled. One side-effect of using <project> is that we will be
+ // using the bpkg package name instead of the main Debian package name.
+ // But perhaps that's correct: on Debian it's usually the source package
+ // name, which is the same. To keep things consistent we use the bpkg
+ // package name for <private> as well.
+ //
+ // Note that some libraries have what looks like architecture-specific
+ // configuration files in /usr/include/$(DEB_HOST_MULTIARCH)/ which is
+ // what we use for our config.install.include_arch location.
+ //
+ // Note: we need to quote values that contain `$` so that they don't get
+ // expanded as build2 variables in the installed_entries() call.
+ //
+ // NOTE: make sure to update .install files below if changing anything
+ // here.
+ //
+ strings config {
+ "config.install.root=/usr/",
+ "config.install.data_root=root/",
+ "config.install.exec_root=root/",
+
+ "config.install.bin=exec_root/bin/",
+ "config.install.sbin=exec_root/sbin/",
+
+ // On Debian shared libraries should not be executable. Also,
+ // libexec/ is the same as lib/ (note that executables that get
+ // installed there will still have the executable bit set).
+ //
+ "config.install.lib='exec_root/lib/$(DEB_HOST_MULTIARCH)/<private>/'",
+ "config.install.lib.mode=644",
+ "config.install.libexec=lib/<project>/",
+ "config.install.pkgconfig=lib/pkgconfig/",
+
+ "config.install.etc=/etc/",
+ "config.install.include=data_root/include/<private>/",
+ "config.install.include_arch='data_root/include/$(DEB_HOST_MULTIARCH)/<private>/'",
+ "config.install.share=data_root/share/",
+ "config.install.data=share/<private>/<project>/",
+ "config.install.buildfile=share/build2/export/<project>/",
+
+ "config.install.doc=share/doc/<private>/<project>/",
+ "config.install.legal=doc/",
+ "config.install.man=share/man/",
+ "config.install.man1=man/man1/",
+ "config.install.man2=man/man2/",
+ "config.install.man3=man/man3/",
+ "config.install.man4=man/man4/",
+ "config.install.man5=man/man5/",
+ "config.install.man6=man/man6/",
+ "config.install.man7=man/man7/",
+ "config.install.man8=man/man8/"};
+
+ config.push_back ("config.install.private=" +
+ (priv ? pn.string () : "[null]"));
+
+ // Add user-specified configuration variables last to allow them to
+ // override anything.
+ //
+ for (const string& v: vars)
+ config.push_back (v);
+
+ // Note that we can use weak install scope for the auto recursive mode
+ // since we know dependencies cannot be spread over multiple linked
+ // configurations.
+ //
+ string scope (!recursive_full || *recursive_full ? "project" : "weak");
+
+ // Get the map of files that will end up in the binary packages.
+ //
+ // Note that we are passing quoted values with $(DEB_HOST_MULTIARCH) which
+ // will be treated literally.
+ //
+ installed_entry_map ies (installed_entries (*ops_, pkgs, config, scope));
+
+ if (ies.empty ())
+ fail << "specified package(s) do not install any files";
+
+ if (verb >= 4)
+ {
+ for (const auto& p: ies)
+ {
+ diag_record dr (trace);
+ dr << "installed entry: " << p.first;
+
+ if (p.second.target != nullptr)
+ dr << " -> " << p.second.target->first; // Symlink.
+ else
+ dr << ' ' << p.second.mode;
+ }
+ }
+
+ // Installed entry directories for sorting out which files belong where.
+ //
+ // Let's tighten things up and only look in <private>/ (if specified) to
+ // make sure there is nothing stray.
+ //
+ string pd (priv ? pn.string () + '/' : "");
+
+ // NOTE: keep consistent with the config.install.* values above.
+ //
+ // We put exported buildfiles into the main package, which makes sense
+ // after some meditation: they normally contain rules and are bundled
+ // either with a tool (say, thrift), a module (say, libbuild2-thrift), or
+ // an add-on package (say, thrift-build2).
+ //
+ dir_path bindir ("/usr/bin/");
+ dir_path sbindir ("/usr/sbin/");
+ dir_path etcdir ("/etc/");
+ dir_path incdir ("/usr/include/" + pd);
+ dir_path incarchdir ("/usr/include/$(DEB_HOST_MULTIARCH)/" + pd);
+ //dir_path bfdir ("/usr/share/build2/export/");
+ dir_path libdir ("/usr/lib/$(DEB_HOST_MULTIARCH)/" + pd);
+ dir_path pkgdir (libdir / dir_path ("pkgconfig"));
+ dir_path sharedir ("/usr/share/" + pd);
+ dir_path docdir ("/usr/share/doc/" + pd);
+ dir_path mandir ("/usr/share/man/");
+
+ // As an optimization, don't generate the main and -dbgsym packages for a
+ // binless library unless it also specifies the -common package.
+ //
+ // If this is a binless library, then verify that it doesn't install any
+ // executable, library, or configuration files. Also verify that it has
+ // the -dev package.
+ //
+ bool binless (false);
+
+ if (lib)
+ {
+ assert (aps.size () == 1);
+
+ const shared_ptr<available_package>& ap (aps.front ().first);
+ strings sos (package_manifest::effective_type_sub_options (ap->type));
+
+ if (find (sos.begin (), sos.end (), "binless") != sos.end ())
+ {
+ // Verify installed files.
+ //
+ auto bad_install = [&pn, &pv] (const string& w)
+ {
+ fail << "binless library " << pn << ' ' << pv << " installs " << w;
+ };
+
+ auto verify_not_installed = [&ies, &bad_install] (const dir_path& d)
+ {
+ auto p (ies.find_sub (d));
+ if (p.first != p.second)
+ bad_install (p.first->first.string ());
+ };
+
+ verify_not_installed (bindir);
+ verify_not_installed (sbindir);
+
+ // It would probably be better not to fail here but generate the main
+ // package instead (as we do if the -common package is also being
+ // generated). Then, however, it would not be easy to detect if a
+ // dependency has the main package or not (see sdeps initialization
+ // for details).
+ //
+ verify_not_installed (etcdir);
+
+ for (auto p (ies.find_sub (libdir)); p.first != p.second; ++p.first)
+ {
+ const path& f (p.first->first);
+
+ if (!f.sub (pkgdir))
+ bad_install (f.string ());
+ }
+
+ // Verify packages.
+ //
+ if (st.dev.empty ())
+ fail << "binless library " << pn << ' ' << pv << " doesn't have "
+ << os_release.name_id << " -dev package";
+
+ binless = true;
+ }
+ }
+
+ bool gen_main (!binless || !st.common.empty ());
+
+ // If we don't generate the main package (and thus the -common package),
+ // then fail if there are any data files installed. It would probably be
+ // better not to fail but generate the main package instead in this
+ // case. Then, however, it would not be easy to detect if a dependency has
+ // the main package or not.
+ //
+ if (!gen_main)
+ {
+ // Note: covers bfdir.
+ //
+ for (auto p (ies.find_sub (sharedir)); p.first != p.second; ++p.first)
+ {
+ const path& f (p.first->first);
+
+ if (!f.sub (docdir) && !f.sub (mandir))
+ {
+ fail << "binless library " << pn << ' ' << pv << " installs " << f <<
+ info << "consider specifying -common package in explicit "
+ << os_release.name_id << " name mapping in package manifest";
+ }
+ }
+ }
+
+ if (verb >= 3)
+ {
+ auto print_status = [] (diag_record& dr,
+ const package_status& s,
+ const string& main)
+ {
+ dr << (main.empty () ? "" : " ") << main
+ << (s.dev.empty () ? "" : " ") << s.dev
+ << (s.doc.empty () ? "" : " ") << s.doc
+ << (s.dbg.empty () ? "" : " ") << s.dbg
+ << (s.common.empty () ? "" : " ") << s.common
+ << ' ' << s.system_version;
+ };
+
+ {
+ diag_record dr (trace);
+ dr << "package:";
+ print_status (dr, st, gen_main ? st.main : empty_string);
+ }
+
+ for (const package_status& st: sdeps)
+ {
+ diag_record dr (trace);
+ dr << "dependency:";
+ print_status (dr, st, st.main);
+ }
+ }
+
+ // Start assembling the package "source" directory.
+ //
+ // It's hard to predict all the files that will be generated (and
+ // potentially read), so we will just require a clean output directory.
+ //
+ // Also, by default, we are going to keep all the intermediate files on
+ // failure for troubleshooting.
+ //
+ if (first && exists (out) && !empty (out))
+ {
+ if (!ops_->wipe_output ())
+ fail << "output root directory " << out << " is not empty" <<
+ info << "use --wipe-output to clean it up but be careful";
+
+ rm_r (out, false);
+ }
+
+ // Normally the source directory is called <name>-<upstream-version>
+ // (e.g., as unpacked from the source archive).
+ //
+ dir_path src (out / dir_path (pn.string () + '-' + pvs));
+ dir_path deb (src / dir_path ("debian"));
+ mk_p (deb);
+
+ // The control file.
+ //
+ // See the "Control files and their fields" chapter in the Debian Policy
+ // Manual for details (for example, which fields are mandatory).
+ //
+ // Note that we try to do a reasonably thorough job (e.g., filling in
+ // sections, etc) with the view that this can be used as a starting point
+ // for manual packaging (and perhaps we could add a mode for this in the
+ // future, call it "starting point" mode).
+ //
+ // Also note that this file supports variable substitutions (for example,
+ // ${binary:Version}) as described in deb-substvars(5). While we could do
+ // without, it is widely used in manual packages so we do the same. Note,
+ // however, that we don't use the shlibs:Depends/misc:Depends mechanism
+ // (which automatically detects dependencies) since we have an accurate
+ // set and some of them may not be system packages.
+ //
+ string homepage (pm.package_url ? pm.package_url->string () :
+ pm.url ? pm.url->string () :
+ string ());
+
+ string maintainer;
+ if (ops_->debian_maintainer_specified ())
+ maintainer = ops_->debian_maintainer ();
+ else
+ {
+ const email* e (pm.package_email ? &*pm.package_email :
+ pm.email ? &*pm.email :
+ nullptr);
+
+ if (e == nullptr)
+ fail << "unable to determine package maintainer from manifest" <<
+ info << "specify explicitly with --debian-maintainer";
+
+ // In certain places (e.g., changelog), Debian expect this to be in the
+ // `John Doe <john@example.org>` form while we often specify just the
+ // email address (e.g., to the mailing list). Try to detect such a case
+ // and complete it to the desired format.
+ //
+ if (e->find (' ') == string::npos && e->find ('@') != string::npos)
+ {
+ // Try to use comment as name, if any.
+ //
+ if (!e->comment.empty ())
+ maintainer = e->comment;
+ else
+ maintainer = pn.string () + " package maintainer";
+
+ maintainer += " <" + *e + '>';
+ }
+ else
+ maintainer = *e;
+ }
+
+ path ctrl (deb / "control");
+ try
+ {
+ ofdstream os (ctrl);
+
+ // First comes the general (source package) stanza.
+ //
+ // Note that the Priority semantics is not the same as our priority.
+ // Rather it should reflect the overall importance of the package. Our
+ // priority is more appropriately mapped to urgency in the changelog.
+ //
+ // If this is not a library, then by default we assume its some kind of
+ // a development tool and use the devel section.
+ //
+ // Note also that we require the debhelper compatibility level 13 which
+ // has more advanced features that we rely on. Such as:
+ //
+ // - Variable substitutions in the debhelper config files.
+ //
+ string section (
+ ops_->debian_section_specified () ? ops_->debian_section () :
+ lib ? "libs" :
+ "devel");
+
+ string priority (
+ ops_->debian_priority_specified () ? ops_->debian_priority () :
+ "optional");
+
+ os << "Source: " << pn << '\n'
+ << "Section: " << section << '\n'
+ << "Priority: " << priority << '\n'
+ << "Maintainer: " << maintainer << '\n'
+ << "Standards-Version: " << "4.6.2" << '\n'
+ << "Build-Depends: " << "debhelper-compat (= 13)" << '\n'
+ << "Rules-Requires-Root: " << "no" << '\n';
+ if (!homepage.empty ())
+ os << "Homepage: " << homepage << '\n';
+ if (pm.src_url)
+ os << "Vcs-Browser: " << pm.src_url->string () << '\n';
+
+ // Then we have one or more binary package stanzas.
+ //
+ // Note that values from the source package stanza (such as Section,
+ // Priority) are used as defaults for the binary packages.
+ //
+ // We cannot easily detect architecture-independent packages (think
+ // libbutl.bash) and providing an option feels like the best we can do.
+ // Note that the value `any` means architecture-dependent while `all`
+ // means architecture-independent.
+ //
+ // The Multi-Arch hint can be `same` or `foreign`. The former means that
+ // a separate copy of the package may be installed for each architecture
+ // (e.g., library) while the latter -- that a single copy may be used by
+ // all architectures (e.g., executable, -doc, -common). Note that for
+ // some murky reasons Multi-Arch:foreign needs to be explicitly
+ // specified for Architecture:all.
+ //
+ // The Description field is quite messy: it requires both the short
+ // description (our summary) as a first line and a long description (our
+ // description) as the following lines in the multiline format.
+ // Converting our description to the Debian format is not going to be
+ // easy: it can be arbitrarily long and may not even be plain text (it's
+ // commonly the contents of the README.md file). So for now we fake it
+ // with a description of the package component. Note also that
+ // traditionally the Description field comes last.
+ //
+ string arch (ops_->debian_architecture_specified ()
+ ? ops_->debian_architecture ()
+ : "any");
+
+ string march (arch == "all" || !lib ? "foreign" : "same");
+
+ if (gen_main)
+ {
+ string depends;
+
+ auto add_depends = [&depends] (const string& v)
+ {
+ if (!depends.empty ())
+ depends += ", ";
+
+ depends += v;
+ };
+
+ if (!st.common.empty ())
+ add_depends (st.common + " (= ${binary:Version})");
+
+ for (const package_status& st: sdeps)
+ {
+ // Note that the constraints will include build metadata (e.g.,
+ // ~debian10). While it may be tempting to strip it, we cannot since
+ // the order is inverse. We could just make it empty `~`, though
+ // that will look a bit strange. But keeping it shouldn't cause any
+ // issues. Also note that the build metadata is part of the revision
+ // so we could strip the whole thing.
+ //
+ if (!st.main.empty ())
+ add_depends (st.main + " (>= " + st.system_version + ')');
+ }
+
+ if (ops_->debian_main_langdep_specified ())
+ {
+ if (!ops_->debian_main_langdep ().empty ())
+ {
+ if (!depends.empty ())
+ depends += ", ";
+
+ depends += ops_->debian_main_langdep ();
+ }
+ }
+ else
+ {
+ // Note that we are not going to add dependencies on libcN
+ // (currently libc6) or libstdc++N (currently libstdc++6) because
+ // it's not easy to determine N and they both are normally part of
+ // the base system.
+ //
+ // What about other language runtimes? Well, it doesn't seem like we
+ // can deduce those automatically so we will either have to add ad
+ // hoc support or the user will have to provide them manually with
+ // --debian-main-depends.
+ }
+
+ if (!ops_->debian_main_extradep ().empty ())
+ {
+ if (!depends.empty ())
+ depends += ", ";
+
+ depends += ops_->debian_main_extradep ();
+ }
+
+ os << '\n'
+ << "Package: " << st.main << '\n'
+ << "Architecture: " << arch << '\n'
+ << "Multi-Arch: " << march << '\n';
+ if (!depends.empty ())
+ os << "Depends: " << depends << '\n';
+ os << "Description: " << pm.summary << '\n'
+ << " This package contains the runtime files." << '\n';
+ }
+
+ if (!st.dev.empty ())
+ {
+ string depends (gen_main ? st.main + " (= ${binary:Version})" : "");
+
+ auto add_depends = [&depends] (const string& v)
+ {
+ if (!depends.empty ())
+ depends += ", ";
+
+ depends += v;
+ };
+
+ for (const package_status& st: sdeps)
+ {
+ // Doesn't look like we can distinguish between interface and
+ // implementation dependencies here. So better to over- than
+ // under-specify.
+ //
+ if (!st.dev.empty ())
+ add_depends (st.dev + " (>= " + st.system_version + ')');
+ }
+
+ if (ops_->debian_dev_langdep_specified ())
+ {
+ if (!ops_->debian_dev_langdep ().empty ())
+ {
+ add_depends (ops_->debian_dev_langdep ());
+ }
+ }
+ else
+ {
+ // Add dependency on libcN-dev and libstdc++-N-dev.
+ //
+ // Note: libcN-dev provides libc-dev and libstdc++N-dev provides
+ // libstdc++-dev. While it would be better to depend on the exact
+ // versions, determining N is not easy (and in case of listdc++
+ // there could be multiple installed at the same time).
+ //
+ // Note that we haven't seen just libc-dev in any native packages,
+ // it's always either libc6-dev or libc6-dev|libc-dev. So we will
+ // see how it goes.
+ //
+ // If this is an undetermined C-common library, we assume it may be
+ // C++ (better to over- than under-specify).
+ //
+ bool cc (lang ("cc", true));
+ if (cc || (cc = lang ("c++", true))) add_depends ("libstdc++-dev");
+ if (cc || (cc = lang ("c", true))) add_depends ("libc-dev");
+ }
+
+ if (!ops_->debian_dev_extradep ().empty ())
+ {
+ add_depends (ops_->debian_dev_extradep ());
+ }
+
+ // Feels like the architecture should be the same as for the main
+ // package.
+ //
+ os << '\n'
+ << "Package: " << st.dev << '\n'
+ << "Section: " << (lib ? "libdevel" : "devel") << '\n'
+ << "Architecture: " << arch << '\n'
+ << "Multi-Arch: " << march << '\n';
+ if (!st.doc.empty ())
+ os << "Suggests: " << st.doc << '\n';
+ if (!depends.empty ())
+ os << "Depends: " << depends << '\n';
+ os << "Description: " << pm.summary << '\n'
+ << " This package contains the development files." << '\n';
+ }
+
+ if (!st.doc.empty ())
+ {
+ os << '\n'
+ << "Package: " << st.doc << '\n'
+ << "Section: " << "doc" << '\n'
+ << "Architecture: " << "all" << '\n'
+ << "Multi-Arch: " << "foreign" << '\n'
+ << "Description: " << pm.summary << '\n'
+ << " This package contains the documentation." << '\n';
+ }
+
+ // Keep this in case we want to support it in the "starting point" mode.
+ //
+ if (!st.dbg.empty () && !binless)
+ {
+ string depends (st.main + " (= ${binary:Version})");
+
+ os << '\n'
+ << "Package: " << st.dbg << '\n'
+ << "Section: " << "debug" << '\n'
+ << "Priority: " << "extra" << '\n'
+ << "Architecture: " << arch << '\n'
+ << "Multi-Arch: " << march << '\n';
+ if (!depends.empty ())
+ os << "Depends: " << depends << '\n';
+ os << "Description: " << pm.summary << '\n'
+ << " This package contains the debugging information." << '\n';
+ }
+
+ if (!st.common.empty ())
+ {
+ // Generally, this package is not necessarily architecture-independent
+ // (for example, it could contain something shared between multiple
+ // binary packages produced from the same source package rather than
+ // something shared between all the architectures of a binary
+ // package). But seeing that we always generate one binary package,
+ // for us it only makes sense as architecture-independent.
+ //
+ // It's also not clear what dependencies we can deduce for this
+ // package. Assuming that it depends on all the dependency -common
+ // packages is probably unreasonable.
+ //
+ os << '\n'
+ << "Package: " << st.common << '\n'
+ << "Architecture: " << "all" << '\n'
+ << "Multi-Arch: " << "foreign" << '\n'
+ << "Description: " << pm.summary << '\n'
+ << " This package contains the architecture-independent files." << '\n';
+ }
+
+ os.close ();
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to write to " << ctrl << ": " << e;
+ }
+
+ // The changelog file.
+ //
+ // See the "Debian changelog" section in the Debian Policy Manual for
+ // details.
+ //
+ // In particular, this is the sole source of the package version.
+ //
+ timestamp now (system_clock::now ());
+
+ path chlog (deb / "changelog");
+ try
+ {
+ ofdstream os (chlog);
+
+ // The first line has the following format:
+ //
+ // <src-package> (<version>) <distribution>; urgency=<urgency>
+ //
+ // Note that <distribution> doesn't end up in the binary package.
+ // Normally all Debian packages start in unstable or experimental.
+ //
+ string urgency;
+ switch (pm.priority ? pm.priority->value : priority::low)
+ {
+ case priority::low: urgency = "low"; break;
+ case priority::medium: urgency = "medium"; break;
+ case priority::high: urgency = "high"; break;
+ case priority::security: urgency = "critical"; break;
+ }
+
+ os << pn << " (" << st.system_version << ") "
+ << (pv.release ? "experimental" : "unstable") << "; "
+ << "urgency=" << urgency << '\n';
+
+ // Next we have a bunch of "change details" lines that start with `*`
+ // indented with two spaces. They are traditionally seperated from the
+ // first and last lines with blank lines.
+ //
+ os << '\n'
+ << " * New bpkg package release " << pvs << '.' << '\n'
+ << '\n';
+
+ // The last line is the "maintainer signoff" and has the following
+ // form:
+ //
+ // -- <name> <email> <date>
+ //
+ // The <date> component shall have the following form in the English
+ // locale (Mon, Jan, etc):
+ //
+ // <day-of-week>, <dd> <month> <yyyy> <hh>:<mm>:<ss> +<zzzz>
+ //
+ os << " -- " << maintainer << " ";
+ std::locale l (os.imbue (std::locale ("C")));
+ to_stream (os,
+ now,
+ "%a, %d %b %Y %T %z",
+ false /* special */,
+ true /* local */);
+ os.imbue (l);
+ os << '\n';
+
+ os.close ();
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to write to " << chlog << ": " << e;
+ }
+
+ // The copyright file.
+ //
+ // See the "Machine-readable debian/copyright file" document for
+ // details.
+ //
+ // Note that while not entirely clear, it looks like there should be at
+ // least one Files stanza.
+ //
+ // Note also that there is currently no way for us to get accurate
+ // copyright information.
+ //
+ // @@ TODO: Strictly speaking, in the recursive mode, we should collect
+ // licenses of all the dependencies we are bundling.
+ //
+ path copyr (deb / "copyright");
+ try
+ {
+ ofdstream os (copyr);
+
+ string license;
+ for (const licenses& ls: pm.license_alternatives)
+ {
+ if (!license.empty ())
+ license += " or ";
+
+ for (auto b (ls.begin ()), i (b); i != ls.end (); ++i)
+ {
+ if (i != b)
+ license += " and ";
+
+ license += *i;
+ }
+ }
+
+ os << "Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/" << '\n'
+ << "Upstream-Name: " << pn << '\n'
+ << "Upstream-Contact: " << maintainer << '\n';
+ if (!homepage.empty ())
+ os << "Source: " << homepage << '\n';
+ os << "License: " << license << '\n'
+ << "Comment: See accompanying files for exact copyright information" << '\n'
+ << " and full license text(s)." << '\n';
+
+ // Note that for licenses mentioned in the Files stanza we either have
+ // to provide the license text(s) inline or as separate License stanzas.
+ //
+ os << '\n'
+ << "Files: *" << '\n'
+ << "Copyright: ";
+ to_stream (os, now, "%Y", false /* special */, true /* local */);
+ os << " the " << pn << " authors (see accompanying files for details)" << '\n'
+ << "License: " << license << '\n'
+ << " See accompanying files for full license text(s)." << '\n';
+
+ os.close ();
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to write to " << copyr << ": " << e;
+ }
+
+ // The source/format file.
+ //
+ dir_path deb_src (deb / dir_path ("source"));
+ mk (deb_src);
+
+ path format (deb_src / "format");
+ try
+ {
+ ofdstream os (format);
+ os << "3.0 (quilt)\n";
+ os.close ();
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to write to " << format << ": " << e;
+ }
+
+ // The rules makefile. Note that it must be executable.
+ //
+ // This file is executed by dpkg-buildpackage(1) which expects it to
+ // provide the following "API" make targets:
+ //
+ // clean
+ //
+ // build -- configure and build for all package
+ // build-arch -- configure and build for Architecture:any packages
+ // build-indep -- configure and build for Architecture:all packages
+ //
+ // binary -- make all binary packages
+ // binary-arch -- make Architecture:any binary packages
+ // binary-indep -- make Architecture:all binary packages
+ //
+ // The dh command sequencer provides the standard implementation of these
+ // API targets with the following customization point targets (for an
+ // overview of dh, start with the slides from the "Not Your Grandpa's
+ // Debhelper" presentation at DebConf 9 followed by the dh(1) man page):
+ //
+ // override_dh_auto_configure # ./configure --prefix=/usr
+ // override_dh_auto_build # make
+ // override_dh_auto_test # make test
+ // override_dh_auto_install # make install
+ // override_dh_auto_clean # make distclean
+ //
+ // Note that pretty much any dh_xxx command invoked by dh in order to
+ // implement the API targets can be customized with the corresponding
+ // override_dh_xxx target. To see what commands are executed for an API
+ // target, run `dh <target> --no-act`.
+ //
+ path rules (deb / "rules");
+ try
+ {
+ bool lang_c (lang ("c"));
+ bool lang_cxx (lang ("c++"));
+ bool lang_cc (lang ("cc"));
+
+ // See fdopen() for details (umask, etc).
+ //
+ permissions ps (permissions::ru | permissions::wu | permissions::xu |
+ permissions::rg | permissions::wg | permissions::xg |
+ permissions::ro | permissions::wo | permissions::xo);
+ ofdstream os (fdopen (rules,
+ fdopen_mode::out | fdopen_mode::create,
+ ps));
+
+ os << "#!/usr/bin/make -f\n"
+ << "# -*- makefile -*-\n"
+ << '\n';
+
+ // See debhelper(7) for details on these.
+ //
+ // Note that there is also the DEB_BUILD_OPTIONS=terse option. Perhaps
+ // for the "starting point" mode we should base DH_* values as well as
+ // the build system verbosity below on that value. See debian/rules in
+ // upstream mariadb for what looks like a sensible setup.
+ //
+ if (verb == 0)
+ os << "export DH_QUIET := 1\n"
+ << '\n';
+ else if (verb == 1)
+ os << "# Uncomment this to turn on verbose mode.\n"
+ << "#export DH_VERBOSE := 1\n"
+ << '\n';
+ else
+ os << "export DH_VERBOSE := 1\n"
+ << '\n';
+
+ // We could have instead called dpkg-architecture directly but seeing
+ // that we are also include buildflags.mk below, might as well use
+ // architecture.mk (in the packages that we sampled you see both
+ // approaches). Note that these come in the dpkg-dev package, the same
+ // as dpkg-buildpackage.
+ //
+ os << "# DEB_HOST_* (DEB_HOST_MULTIARCH, etc)" << '\n'
+ << "#" << '\n'
+ << "include /usr/share/dpkg/architecture.mk" << '\n'
+ << '\n';
+
+ if (ops_->debian_buildflags () != "ignore")
+ {
+ // While we could have called dpkg-buildflags directly, including
+ // buildflags.mk instead appears to be the standard practice.
+ //
+ // Note that theses flags are not limited to C-based languages (for
+ // example, they also cover Assembler, Fortran, and potentially others
+ // in the future).
+ //
+ string mo; // Include leading space if not empty.
+ if (ops_->debian_maint_option_specified ())
+ {
+ for (const string& o: ops_->debian_maint_option ())
+ {
+ if (!o.empty ())
+ {
+ mo += ' ';
+ mo += o;
+ }
+ }
+ }
+ else
+ mo = " hardening=+all";
+
+ os << "# *FLAGS (CFLAGS, CXXFLAGS, etc)" << '\n'
+ << "#" << '\n'
+ << "export DEB_BUILD_MAINT_OPTIONS :=" << mo << '\n'
+ << "include /usr/share/dpkg/buildflags.mk" << '\n'
+ << '\n';
+
+ if (!binless)
+ {
+ // Fixup -ffile-prefix-map option (if specified) which is used to
+ // strip source file path prefix in debug information (besides other
+ // places). By default it points to the source directory. We change
+ // it to point to the bpkg configuration directory. Note that this
+ // won't work for external packages with source out of configuration
+ // (e.g., managed by bdep).
+ //
+ if (lang_c || lang_cc)
+ {
+ // @@ TODO: OBJCFLAGS.
+
+ os << "CFLAGS := $(patsubst -ffile-prefix-map=%,-ffile-prefix-map="
+ << cfg_dir.string () << "=.,$(CFLAGS))" << '\n'
+ << '\n';
+ }
+
+ if (lang_cxx || lang_cc)
+ {
+ // @@ TODO: OBJCXXFLAGS.
+
+ os << "CXXFLAGS := $(patsubst -ffile-prefix-map=%,-ffile-prefix-map="
+ << cfg_dir.string () << "=.,$(CXXFLAGS))" << '\n'
+ << '\n';
+ }
+ }
+ }
+
+ // For a binless library the -dbgsym package is not supposed to be
+ // generated. Thus, we disable its automatic generation by adding the
+ // noautodbgsym flag to the DEB_BUILD_OPTIONS variable.
+ //
+ // This doesn't seem to be necessary (probably because there is no
+ // .so/.a).
+ //
+#if 0
+ if (binless)
+ os << "export DEB_BUILD_OPTIONS += noautodbgsym" << '\n'
+ << '\n';
+#endif
+
+ // The debian/tmp/ subdirectory appears to be the canonical destination
+ // directory (see dh_auto_install(1) for details).
+ //
+ os << "DESTDIR := $(CURDIR)/debian/tmp" << '\n'
+ << '\n';
+
+ // Let's use absolute path to the build system driver in case we are
+ // invoked with altered environment or some such.
+ //
+ // See --jobs documentation in dpkg-buildpackage(1) for details on
+ // parallel=N.
+ //
+ // Note: should be consistent with the invocation in installed_entries()
+ // above.
+ //
+ cstrings verb_args; string verb_arg;
+ map_verb_b (*ops_, verb_b::normal, verb_args, verb_arg);
+
+ os << "b := " << search_b (*ops_).effect_string ();
+ for (const char* o: verb_args) os << ' ' << o;
+ for (const string& o: ops_->build_option ()) os << ' ' << o;
+ os << '\n'
+ << '\n'
+ << "parallel := $(filter parallel=%,$(DEB_BUILD_OPTIONS))" << '\n'
+ << "ifneq ($(parallel),)" << '\n'
+ << " parallel := $(patsubst parallel=%,%,$(parallel))" << '\n'
+ << " ifeq ($(parallel),1)" << '\n'
+ << " b += --serial-stop" << '\n'
+ << " else" << '\n'
+ << " b += --jobs=$(parallel)" << '\n'
+ << " endif" << '\n'
+ << "endif" << '\n'
+ << '\n';
+
+ // Configuration variables.
+ //
+ // Note: we need to quote values that contain `<>`, `[]`, since they
+ // will be passed through shell. For simplicity, let's just quote
+ // everything.
+ //
+ os << "config := config.install.chroot='$(DESTDIR)/'" << '\n'
+ << "config += config.install.sudo='[null]'" << '\n';
+
+ // If this is a C-based language, add rpath for private installation.
+ //
+ if (priv && (lang_c || lang_cxx || lang_cc))
+ os << "config += config.bin.rpath='/usr/lib/$(DEB_HOST_MULTIARCH)/"
+ << pn << "/'" << '\n';
+
+ // Add build flags.
+ //
+ if (ops_->debian_buildflags () != "ignore")
+ {
+ const string& m (ops_->debian_buildflags ());
+
+ string o (m == "assign" ? "=" :
+ m == "append" ? "+=" :
+ m == "prepend" ? "=+" : "");
+
+ if (o.empty ())
+ fail << "unknown --debian-buildflags option value '" << m << "'";
+
+ // Note that config.cc.* doesn't play well with the append/prepend
+ // modes because the orders are:
+ //
+ // x.poptions cc.poptions
+ // cc.coptions x.coptions
+ // cc.loptions x.loptions
+ //
+ // Oh, well, hopefully it will be close enough for most cases.
+ //
+ // Note also that there are compiler mode options that are not
+ // overridden.
+ //
+ if (o == "=" && (lang_c || lang_cxx || lang_cc))
+ {
+ os << "config += config.cc.poptions='[null]'" << '\n'
+ << "config += config.cc.coptions='[null]'" << '\n'
+ << "config += config.cc.loptions='[null]'" << '\n';
+ }
+
+ if (lang_c || lang_cc)
+ {
+ // @@ TODO: OBJCFLAGS (we currently don't have separate options).
+ // Also see -ffile-prefix-map fixup above.
+
+ os << "config += config.c.poptions" << o << "'$(CPPFLAGS)'" << '\n'
+ << "config += config.c.coptions" << o << "'$(CFLAGS)'" << '\n'
+ << "config += config.c.loptions" << o << "'$(LDFLAGS)'" << '\n';
+ }
+
+ if (lang_cxx || lang_cc)
+ {
+ // @@ TODO: OBJCXXFLAGS (we currently don't have separate options).
+ // Also see -ffile-prefix-map fixup above.
+
+ os << "config += config.cxx.poptions" << o << "'$(CPPFLAGS)'" << '\n'
+ << "config += config.cxx.coptions" << o << "'$(CXXFLAGS)'" << '\n'
+ << "config += config.cxx.loptions" << o << "'$(LDFLAGS)'" << '\n';
+ }
+
+ // @@ TODO: ASFLAGS (when we have assembler support).
+ }
+
+ // Keep last to allow user-specified configuration variables to override
+ // anything.
+ //
+ for (const string& c: config)
+ {
+ // Quote the value unless already quoted (see above). Presense of
+ // potentially-quoted user variables complicates things a bit (can
+ // be partially quoted, double-quoted, etc).
+ //
+ size_t p (c.find_first_of ("=+ \t")); // End of name.
+ if (p != string::npos)
+ {
+ p = c.find_first_not_of ("=+ \t", p); // Beginning of value.
+ if (p != string::npos)
+ {
+ if (c.find_first_of ("'\"", p) == string::npos) // Not quoted.
+ {
+ os << "config += " << string (c, 0, p) << '\''
+ << string (c, p) << "'\n";
+ continue;
+ }
+ }
+ }
+
+ os << "config += " << c << '\n';
+ }
+
+ os << '\n';
+
+ // List of packages we need to install.
+ //
+ for (auto b (pkgs.begin ()), i (b); i != pkgs.end (); ++i)
+ {
+ os << "packages" << (i == b ? " := " : " += ")
+ << i->out_root.representation () << '\n';
+ }
+ os << '\n';
+
+ // Default to the dh command sequencer.
+ //
+ // Note that passing --buildsystem=none doesn't seem to make any
+ // difference (other than add some noise).
+ //
+ os << "%:\n"
+ << '\t' << "dh $@" << '\n'
+ << '\n';
+
+ // Override dh_auto_configure.
+ //
+ os << "# Everything is already configured.\n"
+ << "#\n"
+ << "override_dh_auto_configure:\n"
+ << '\n';
+
+ // Override dh_auto_build.
+ //
+ os << "override_dh_auto_build:\n"
+ << '\t' << "$b $(config) update-for-install: $(packages)" << '\n'
+ << '\n';
+
+ // Override dh_auto_test.
+ //
+ // Note that running tests after update-for-install may cause rebuild
+ // (e.g., relinking without rpath, etc) before tests and again before
+ // install. So doesn't seem worth the trouble.
+ //
+ os << "# Assume any testing has already been done.\n"
+ << "#\n"
+ << "override_dh_auto_test:\n"
+ << '\n';
+
+ // Override dh_auto_install.
+ //
+ os << "override_dh_auto_install:\n"
+ << '\t' << "$b $(config) '!config.install.scope=" << scope << "' "
+ << "install: $(packages)" << '\n'
+ << '\n';
+
+ // Override dh_auto_clean.
+ //
+ os << "# This is not a real source directory so nothing to clean.\n"
+ << "#\n"
+ << "override_dh_auto_clean:\n"
+ << '\n';
+
+ // Override dh_shlibdeps.
+ //
+ // Failed that we get a warning about calculated ${shlibs:Depends} being
+ // unused.
+ //
+ // Note that there is also dh_makeshlibs which is invoked just before
+ // but we shouldn't override it because (quoting its man page): "It will
+ // also ensure that ldconfig is invoked during install and removal when
+ // it finds shared libraries."
+ //
+ os << "# Disable dh_shlibdeps since we don't use ${shlibs:Depends}.\n"
+ << "#\n"
+ << "override_dh_shlibdeps:\n"
+ << '\n';
+
+ os.close ();
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to write to " << rules << ": " << e;
+ }
+
+ // Generate the dh_install (.install) config files for each package in
+ // order to sort out which files belong where.
+ //
+ // For documentation of the config file format see debhelper(1) and
+ // dh_install(1). But the summary is:
+ //
+ // - Supports only simple wildcards (?, *, [...]; no recursive/**).
+ // - But can install whole directories recursively.
+ // - An entry that doesn't match anything is an error (say, /usr/sbin/*).
+ // - Supports variable substitutions (${...}; since compat level 13).
+ //
+ // Keep in mind that wherever there is <project> in the config.install.*
+ // variable, we can end up with multiple different directories (bundled
+ // packages).
+ //
+ path main_install;
+ path dev_install;
+ path doc_install;
+ path dbg_install;
+ path common_install;
+
+ const path* cur_install (nullptr); // File being opened/written to.
+ try
+ {
+ ofdstream main_os;
+ ofdstream dev_os;
+ ofdstream doc_os;
+ ofdstream dbg_os;
+ ofdstream com_os;
+
+ pair<path&, ofdstream&> main (main_install, main_os);
+ pair<path&, ofdstream&> dev (dev_install, dev_os);
+ pair<path&, ofdstream&> doc (doc_install, doc_os);
+ pair<path&, ofdstream&> dbg (dbg_install, dbg_os);
+ pair<path&, ofdstream&> com (common_install, com_os);
+
+ auto open = [&deb, &cur_install] (pair<path&, ofdstream&>& os,
+ const string& n)
+ {
+ if (!n.empty ())
+ {
+ cur_install = &(os.first = deb / (n + ".install"));
+ os.second.open (os.first);
+ }
+ };
+
+ open (main, gen_main ? st.main : empty_string);
+ open (dev, st.dev);
+ open (doc, st.doc);
+ open (dbg, st.dbg);
+ open (com, st.common);
+
+ auto is_open = [] (pair<path&, ofdstream&>& os)
+ {
+ return os.second.is_open ();
+ };
+
+ auto add = [&cur_install] (pair<path&, ofdstream&>& os, const path& p)
+ {
+ // Strip root.
+ //
+ string s (p.leaf (p.root_directory ()).string ());
+
+ // Replace () with {}.
+ //
+ for (char& c: s)
+ {
+ if (c == '(') c = '{';
+ if (c == ')') c = '}';
+ }
+
+ cur_install = &os.first;
+ os.second << s << '\n';
+ };
+
+ // The main package contains everything that doesn't go to another
+ // packages.
+ //
+ if (gen_main)
+ {
+ if (ies.contains_sub (bindir)) add (main, bindir / "*");
+ if (ies.contains_sub (sbindir)) add (main, sbindir / "*");
+
+ // This could potentially go to -common but it could also be target-
+ // specific, who knows. So let's keep it in main for now.
+ //
+ if (ies.contains_sub (etcdir)) add (main, etcdir / "*");
+ }
+
+ if (!is_open (dev))
+ {
+ assert (gen_main); // Shouldn't be here otherwise.
+
+ if (ies.contains_sub (incdir)) add (main, incdir / "*");
+ if (ies.contains_sub (incarchdir)) add (main, incarchdir / "*");
+ if (ies.contains_sub (libdir)) add (main, libdir / "*");
+ }
+ else
+ {
+ if (ies.contains_sub (incdir)) add (dev, incdir / "*");
+ if (ies.contains_sub (incarchdir)) add (dev, incarchdir / "*");
+
+ // Ok, time for things to get hairy: we need to split the contents
+ // of lib/ into the main and -dev packages. The -dev package should
+ // contain three things:
+ //
+ // 1. Static libraries (.a).
+ // 2. Non-versioned shared library symlinks (.so).
+ // 3. Contents of the pkgconfig/ subdirectory.
+ //
+ // Everything else should go into the main package. In particular, we
+ // assume any subdirectories other than pkgconfig/ are the libexec
+ // stuff or similar.
+ //
+ // The (2) case (shared library) is tricky. Here we can have three
+ // plausible arrangements:
+ //
+ // A. Portably-versioned library:
+ //
+ // libfoo-1.2.so
+ // libfoo.so -> libfoo-1.2.so
+ //
+ // B. Natively-versioned library:
+ //
+ // libfoo.so.1.2.3
+ // libfoo.so.1.2 -> libfoo.so.1.2.3
+ // libfoo.so.1 -> libfoo.so.1.2
+ // libfoo.so -> libfoo.so.1
+ //
+ // C. Non-versioned library:
+ //
+ // libfoo.so
+ //
+ // Note that in the (C) case the library should go into the main
+ // package. Based on this, the criteria appears to be straightforward:
+ // the extension is .so and it's a symlink. For good measure we also
+ // check that there is the `lib` prefix (plugins, etc).
+ //
+ for (auto p (ies.find_sub (libdir)); p.first != p.second; )
+ {
+ const path& f (p.first->first);
+ const installed_entry& ie ((p.first++)->second);
+
+ path l (f.leaf (libdir));
+
+ if (l.simple ())
+ {
+ assert (gen_main); // Shouldn't be here otherwise.
+
+ string e (l.extension ());
+ const string& n (l.string ());
+
+ bool d (n.size () > 3 && n.compare (0, 3, "lib") == 0 &&
+ ((e == "a" ) ||
+ (e == "so" && ie.target != nullptr)));
+
+ add (d ? dev : main, libdir / l);
+ }
+ else
+ {
+ // Let's keep things tidy and use a wildcard rather than listing
+ // all the entries in subdirectories verbatim.
+ //
+ dir_path d (libdir / dir_path (*l.begin ()));
+
+ // Can only be a subdirectory of pkgdir/ if the main package is
+ // not being generated.
+ //
+ assert (d == pkgdir || gen_main);
+
+ add (d == pkgdir ? dev : main, d / "*");
+
+ // Skip all the other entries in this subdirectory (in the prefix
+ // map they will all be in a contiguous range).
+ //
+ while (p.first != p.second && p.first->first.sub (d))
+ ++p.first;
+ }
+ }
+ }
+
+ // We cannot just do usr/share/* since it will clash with doc/ and man/
+ // below. So we have to list all the top-level entries in usr/share/
+ // that are not doc/ or man/.
+ //
+ if (gen_main)
+ {
+ // Note: covers bfdir.
+ //
+ for (auto p (ies.find_sub (sharedir)); p.first != p.second; )
+ {
+ const path& f ((p.first++)->first);
+
+ if (f.sub (docdir) || f.sub (mandir))
+ continue;
+
+ path l (f.leaf (sharedir));
+
+ if (l.simple ())
+ add (is_open (com) ? com : main, sharedir / l);
+ else
+ {
+ // Let's keep things tidy and use a wildcard rather than listing
+ // all the entries in subdirectories verbatim.
+ //
+ dir_path d (sharedir / dir_path (*l.begin ()));
+
+ add (is_open (com) ? com : main, d / "*");
+
+ // Skip all the other entries in this subdirectory (in the prefix
+ // map they will all be in a contiguous range).
+ //
+ while (p.first != p.second && p.first->first.sub (d))
+ ++p.first;
+ }
+ }
+ }
+
+ // Should we put the documentation into -common if there is no -doc?
+ // While there doesn't seem to be anything explicit in the policy, there
+ // are packages that do it this way (e.g., libao, libaudit). And the
+ // same logic seems to apply to -dev (e.g., zlib).
+ //
+ {
+ auto& os (is_open (doc) ? doc :
+ is_open (com) ? com :
+ is_open (dev) ? dev :
+ main);
+
+ // We can only add doc files to the main or -common packages if we
+ // generate the main package.
+ //
+ assert ((&os != &main && &os != &com) || gen_main);
+
+ if (ies.contains_sub (docdir)) add (os, docdir / "*");
+ if (ies.contains_sub (mandir)) add (os, mandir / "*");
+ }
+
+ // Close.
+ //
+ auto close = [&cur_install] (pair<path&, ofdstream&>& os)
+ {
+ if (os.second.is_open ())
+ {
+ cur_install = &os.first;
+ os.second.close ();
+ }
+ };
+
+ close (main);
+ close (dev);
+ close (doc);
+ close (dbg);
+ close (com);
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to write to " << *cur_install << ": " << e;
+ }
+
+ // Run dpkg-buildpackage.
+ //
+ // Note that there doesn't seem to be any way to control its verbosity or
+ // progress.
+ //
+ // Note also that dpkg-buildpackage causes recompilation on every run by
+ // changing the SOURCE_DATE_EPOCH environment variable (which we track for
+ // changes since it affects GCC). Note that since we don't have this
+ // SOURCE_DATE_EPOCH during dry-run caused by installed_entries(), there
+ // would be a recompilation even if the value weren't changing.
+ //
+ cstrings args {
+ "dpkg-buildpackage",
+ "--build=binary", // Only build binary packages.
+ "--no-sign", // Do not sign anything.
+ "--target-arch", arch.c_str ()};
+
+ // Pass our --jobs value, if any.
+ //
+ string jobs_arg;
+ if (size_t n = ops_->jobs_specified () ? ops_->jobs () : 0)
+ {
+ // Note: only accepts the --jobs=N form.
+ //
+ args.push_back ((jobs_arg = "--jobs=" + to_string (n)).c_str ());
+ }
+
+ // Pass any additional options specified by the user.
+ //
+ for (const string& o: ops_->debian_build_option ())
+ args.push_back (o.c_str ());
+
+ args.push_back (nullptr);
+
+ if (ops_->debian_prepare_only ())
+ {
+ if (verb >= 1)
+ {
+ diag_record dr (text);
+
+ dr << "prepared " << src <<
+ text << "command line: ";
+
+ print_process (dr, args);
+ }
+
+ return binary_files {};
+ }
+
+ try
+ {
+ process_path pp (process::path_search (args[0]));
+ process_env pe (pp, src /* cwd */);
+
+ // There is going to be quite a bit of diagnostics so print the command
+ // line unless quiet.
+ //
+ if (verb >= 1)
+ print_process (pe, args);
+
+ // Redirect stdout to stderr since half of dpkg-buildpackage diagnostics
+ // goes there. For good measure also redirect stdin to /dev/null to make
+ // sure there are no prompts of any kind.
+ //
+ process pr (pp,
+ args,
+ -2 /* stdin */,
+ 2 /* stdout */,
+ 2 /* stderr */,
+ pe.cwd->string ().c_str (),
+ pe.vars);
+
+ if (!pr.wait ())
+ {
+ // Let's repeat the command line even if it was printed at the
+ // beginning to save the user a rummage through the logs.
+ //
+ diag_record dr (fail);
+ dr << args[0] << " exited with non-zero code" <<
+ info << "command line: "; print_process (dr, pe, args);
+ }
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e;
+
+ if (e.child)
+ exit (1);
+
+ throw failed ();
+ }
+
+ // Cleanup intermediate files unless requested not to.
+ //
+ if (!ops_->keep_output ())
+ {
+ rm_r (src);
+ }
+
+ // Collect and return the binary package paths.
+ //
+ binary_files r;
+ r.system_version = st.system_version;
+
+ auto add = [&out, &r] (const string& f,
+ const char* t,
+ const string& n,
+ bool opt = false)
+ {
+ path p (out / f);
+
+ if (exists (p))
+ r.push_back (binary_file {t, move (p), n});
+ else if (!opt)
+ fail << "expected output file " << f << " does not exist";
+ };
+
+ // The resulting .deb file names have the <name>_<version>_<arch>.deb
+ // form. If the package is architecture-independent, then <arch> is the
+ // special `all` value.
+ //
+ const string& v (st.system_version);
+ const string& a (arch);
+
+ if (gen_main)
+ add (st.main + '_' + v + '_' + a + ".deb", "main.deb", st.main);
+
+ if (!binless)
+ add (st.main + "-dbgsym_" + v + '_' + a + ".deb",
+ "dbgsym.deb",
+ st.main + "-dbgsym",
+ true);
+
+ if (!st.dev.empty ())
+ add (st.dev + '_' + v + '_' + a + ".deb", "dev.deb", st.dev);
+
+ if (!st.doc.empty ())
+ add (st.doc + '_' + v + "_all.deb", "doc.deb", st.doc);
+
+ if (!st.common.empty ())
+ add (st.common + '_' + v + "_all.deb", "common.deb", st.common);
+
+ // Besides the binary packages (.deb) we also get the .buildinfo and
+ // .changes files, which could be useful. Note that their names are based
+ // on the source package name.
+ //
+ add (pn.string () + '_' + v + '_' + a + ".buildinfo", "buildinfo", "");
+ add (pn.string () + '_' + v + '_' + a + ".changes", "changes", "");
+
+ return r;
+ }
+}
diff --git a/bpkg/system-package-manager-debian.hxx b/bpkg/system-package-manager-debian.hxx
new file mode 100644
index 0000000..336f7a7
--- /dev/null
+++ b/bpkg/system-package-manager-debian.hxx
@@ -0,0 +1,271 @@
+// file : bpkg/system-package-manager-debian.hxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BPKG_SYSTEM_PACKAGE_MANAGER_DEBIAN_HXX
+#define BPKG_SYSTEM_PACKAGE_MANAGER_DEBIAN_HXX
+
+#include <map>
+
+#include <bpkg/types.hxx>
+#include <bpkg/utility.hxx>
+
+#include <bpkg/system-package-manager.hxx>
+
+namespace bpkg
+{
+ // The system package manager implementation for Debian and alike (Ubuntu,
+ // etc) using the apt frontend (specifically, apt-get and apt-cache) for
+ // consumption and the dpkg-buildpackage/debhelper/dh tooling for
+ // production.
+ //
+ // NOTE: THE BELOW DESCRIPTION IS ALSO REPRODUCED IN THE BPKG MANUAL.
+ //
+ // For background, a library in Debian is normally split up into several
+ // packages: the shared library package (e.g., libfoo1 where 1 is the ABI
+ // version), the development files package (e.g., libfoo-dev), the
+ // documentation files package (e.g., libfoo-doc), the debug symbols package
+ // (e.g., libfoo1-dbg), and the (usually) architecture-independent files
+ // (e.g., libfoo1-common). All the packages except -dev are optional and
+ // there is quite a bit of variability here. Here are a few examples:
+ //
+ // libsqlite3-0 libsqlite3-dev
+ //
+ // libssl1.1 libssl-dev libssl-doc
+ // libssl3 libssl-dev libssl-doc
+ //
+ // libcurl4 libcurl4-openssl-dev libcurl4-doc
+ // libcurl3-gnutls libcurl4-gnutls-dev libcurl4-doc (yes, 3 and 4)
+ //
+ // Note that while most library package names in Debian start with lib (per
+ // the policy), there are exceptions (e.g., zlib1g zlib1g-dev). The
+ // header-only library package names may or may not start with lib and end
+ // with -dev (e.g., libeigen3-dev, rapidjson-dev, catch2).
+ //
+ // Also note that manual -dbg packages are obsolete in favor of automatic
+ // -dbgsym packages from Debian 9. So while we support -dbg for consumption,
+ // we only generate -dbgsym.
+ //
+ // Based on that, it seems our best bet when trying to automatically map our
+ // library package name to Debian package names is to go for the -dev
+ // package first and figure out the shared library package from that based
+ // on the fact that the -dev package should have the == dependency on the
+ // shared library package with the same version and its name should normally
+ // start with the -dev package's stem.
+ //
+ // For executable packages there is normally no -dev packages but -dbg,
+ // -doc, and -common are plausible.
+ //
+ // The format of the debian-name (or alike) manifest value is a comma-
+ // separated list of one or more package groups:
+ //
+ // <package-group> [, <package-group>...]
+ //
+ // Where each <package-group> is the space-separated list of one or more
+ // package names:
+ //
+ // <package-name> [ <package-name>...]
+ //
+ // All the packages in the group should be "package components" (for the
+ // lack of a better term) of the same "logical package", such as -dev, -doc,
+ // -common packages. They normally have the same version.
+ //
+ // The first group is called the main group and the first package in the
+ // group is called the main package. Note that all the groups are consumed
+ // (installed) but only the main group is produced (packaged).
+ //
+ // We allow/recommend specifying the -dev package instead of the main
+ // package for libraries (the bpkg package name starts with lib), seeing
+ // that we are capable of detecting the main package automatically. If the
+ // library name happens to end with -dev (which poses an ambiguity), then
+ // the -dev package should be specified explicitly as the second package to
+ // disambiguate this situation (if a non-library name happened to start with
+ // lib and end with -dev, well, you are out of luck, I guess).
+ //
+ // Note also that for now we treat all the packages from the non-main groups
+ // as extras but in the future we may decide to sort them out like the main
+ // group (see parse_name_value() for details).
+ //
+ // The Debian package version has the [<epoch>:]<upstream>[-<revision>] form
+ // (see deb-version(5) for details). If no explicit mapping to the bpkg
+ // version is specified with the debian-to-downstream-version (or alike)
+ // manifest values or none match, then we fallback to using the <upstream>
+ // part as the bpkg version. If explicit mapping is specified, then we match
+ // it against the [<epoch>:]<upstream> parts ignoring <revision>.
+ //
+ struct system_package_status_debian: system_package_status
+ {
+ string main;
+ string dev;
+ string doc;
+ string dbg;
+ string common;
+ strings extras;
+
+ // The `apt-cache policy` output.
+ //
+ struct package_policy
+ {
+ string name;
+ string installed_version; // Empty if none.
+ string candidate_version; // Empty if none and no installed_version.
+
+ explicit
+ package_policy (string n): name (move (n)) {}
+ };
+
+ vector<package_policy> package_policies;
+ size_t package_policies_main = 0; // Size of the main group.
+
+ explicit
+ system_package_status_debian (string m, string d = {})
+ : main (move (m)), dev (move (d))
+ {
+ assert (!main.empty () || !dev.empty ());
+ }
+
+ system_package_status_debian () = default;
+ };
+
+ class system_package_manager_debian: public system_package_manager
+ {
+ public:
+ virtual optional<const system_package_status*>
+ status (const package_name&, const available_packages*) override;
+
+ virtual void
+ install (const vector<package_name>&) override;
+
+ virtual binary_files
+ generate (const packages&,
+ const packages&,
+ const strings&,
+ const dir_path&,
+ const package_manifest&,
+ const string&,
+ const small_vector<language, 1>&,
+ optional<bool>,
+ bool) override;
+
+ public:
+ // Expect os_release::name_id to be "debian" or os_release::like_ids to
+ // contain "debian".
+ //
+ // @@ TODO: we currently don't handle non-host arch in consumption.
+ //
+ system_package_manager_debian (bpkg::os_release&& osr,
+ const target_triplet& h,
+ string a,
+ optional<bool> progress,
+ optional<size_t> fetch_timeout,
+ bool install,
+ bool fetch,
+ bool yes,
+ string sudo)
+ : system_package_manager (move (osr),
+ h,
+ a.empty () ? arch_from_target (h) : move (a),
+ progress,
+ fetch_timeout,
+ install,
+ fetch,
+ yes,
+ move (sudo)) {}
+
+ // Note: options can only be NULL when testing functions that don't need
+ // them.
+ //
+ system_package_manager_debian (bpkg::os_release&& osr,
+ const target_triplet& h,
+ string a,
+ optional<bool> progress,
+ const pkg_bindist_options* ops)
+ : system_package_manager (move (osr),
+ h,
+ a.empty () ? arch_from_target (h) : move (a),
+ progress),
+ ops_ (ops) {}
+
+ // Implementation details exposed for testing (see definitions for
+ // documentation).
+ //
+ public:
+ using package_status = system_package_status_debian;
+ using package_policy = package_status::package_policy;
+
+ void
+ apt_cache_policy (vector<package_policy>&, size_t = 0);
+
+ string
+ apt_cache_show (const string&, const string&);
+
+ void
+ apt_get_update ();
+
+ void
+ apt_get_install (const strings&);
+
+ pair<cstrings, const process_path&>
+ apt_get_common (const char*, strings& args_storage);
+
+ static package_status
+ parse_name_value (const string&, const string&, bool, bool);
+
+ static string
+ main_from_dev (const string&, const string&, const string&);
+
+ static string
+ arch_from_target (const target_triplet&);
+
+ package_status
+ map_package (const package_name&,
+ const version&,
+ const available_packages&,
+ const optional<string>&) const;
+
+ // If simulate is not NULL, then instead of executing the actual apt-cache
+ // and apt-get commands simulate their execution: (1) for apt-cache by
+ // printing their command lines and reading the results from files
+ // specified in the below apt_cache_* maps and (2) for apt-get by printing
+ // their command lines and failing if requested.
+ //
+ // In the (1) case if the corresponding map entry does not exist or the
+ // path is empty, then act as if the specified package/version is
+ // unknown. If the path is special "-" then read from stdin. For apt-cache
+ // different post-fetch and (for policy) post-install results can be
+ // specified (if the result is not found in one of the later maps, the
+ // previous map is used as a fallback). Note that the keys in the
+ // apt_cache_policy_* maps are the package sets and the corresponding
+ // result file is expected to contain (or not) the results for all of
+ // them. See apt_cache_policy() and apt_cache_show() implementations for
+ // details on the expected results.
+ //
+ struct simulation
+ {
+ std::map<strings, path> apt_cache_policy_;
+ std::map<strings, path> apt_cache_policy_fetched_;
+ std::map<strings, path> apt_cache_policy_installed_;
+
+ std::map<pair<string, string>, path> apt_cache_show_;
+ std::map<pair<string, string>, path> apt_cache_show_fetched_;
+
+ bool apt_get_update_fail_ = false;
+ bool apt_get_install_fail_ = false;
+ };
+
+ const simulation* simulate_ = nullptr;
+
+ private:
+ optional<system_package_status_debian>
+ status (const package_name&, const available_packages&);
+
+ private:
+ bool fetched_ = false; // True if already fetched metadata.
+ bool installed_ = false; // True if already installed.
+
+ std::map<package_name, optional<system_package_status_debian>> status_cache_;
+
+ const pkg_bindist_options* ops_ = nullptr; // Only for production.
+ };
+}
+
+#endif // BPKG_SYSTEM_PACKAGE_MANAGER_DEBIAN_HXX
diff --git a/bpkg/system-package-manager-debian.test.cxx b/bpkg/system-package-manager-debian.test.cxx
new file mode 100644
index 0000000..c85b231
--- /dev/null
+++ b/bpkg/system-package-manager-debian.test.cxx
@@ -0,0 +1,386 @@
+// file : bpkg/system-package-manager-debian.test.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <bpkg/system-package-manager-debian.hxx>
+
+#include <map>
+#include <iostream>
+
+#include <bpkg/types.hxx>
+#include <bpkg/utility.hxx>
+
+#undef NDEBUG
+#include <cassert>
+
+#include <bpkg/system-package-manager.test.hxx>
+
+using namespace std;
+
+namespace bpkg
+{
+ using package_status = system_package_status_debian;
+ using package_policy = package_status::package_policy;
+
+ using butl::manifest_parser;
+ using butl::manifest_parsing;
+
+ // Usage: args[0] <command> ...
+ //
+ // Where <command> is one of:
+ //
+ // apt-cache-policy <pkg>... result comes from stdin
+ //
+ // apt-cache-show <pkg> <ver> result comes from stdin
+ //
+ // parse-name-value <pkg> debian-name value from stdin
+ //
+ // main-from-dev <dev-pkg> <dev-ver> depends comes from stdin
+ //
+ // map-package [<build-metadata>] manifest comes from stdin
+ //
+ // build <query-pkg>... [--install [--no-fetch] <install-pkg>...]
+ //
+ // The stdin of the build command is used to read the simulation description
+ // which consists of lines in the following forms (blanks are ignored):
+ //
+ // manifest: <query-pkg> <file>
+ //
+ // Available package manifest for one of <query-pkg>. If none is
+ // specified, then a stub is automatically added.
+ //
+ // apt-cache-policy[-{fetched,installed}]: <sys-pkg>... <file>
+ //
+ // Values for simulation::apt_cache_policy_*. If <file> is the special `!`
+ // value, then make the entry empty.
+ //
+ // apt-cache-show[-fetched]: <sys-pkg> <sys-ver> <file>
+ //
+ // Values for simulation::apt_cache_show_*. If <file> is the special `!`
+ // value, then make the entry empty.
+ //
+ // apt-get-update-fail: true
+ // apt-get-install-fail: true
+ //
+ // Values for simulation::apt_get_{update,install}_fail_.
+ //
+ int
+ main (int argc, char* argv[])
+ try
+ {
+ assert (argc >= 2); // <command>
+
+ string cmd (argv[1]);
+
+ // @@ TODO: add option to customize? Maybe option before command?
+ //
+ os_release osr {"debian", {}, "10", "", "Debian", "", ""};
+
+ if (cmd == "apt-cache-policy")
+ {
+ assert (argc >= 3); // <pkg>...
+
+ strings key;
+ vector<package_policy> pps;
+ for (int i (2); i != argc; ++i)
+ {
+ key.push_back (argv[i]);
+ pps.push_back (package_policy (argv[i]));
+ }
+
+ system_package_manager_debian::simulation s;
+ s.apt_cache_policy_.emplace (move (key), path ("-"));
+
+ system_package_manager_debian m (move (osr),
+ host_triplet,
+ "" /* arch */,
+ nullopt /* progress */,
+ nullopt /* fetch_timeout */,
+ false /* install */,
+ false /* fetch */,
+ false /* yes */,
+ "sudo");
+ m.simulate_ = &s;
+
+ m.apt_cache_policy (pps);
+
+ for (const package_policy& pp: pps)
+ {
+ cout << pp.name << " '"
+ << pp.installed_version << "' '"
+ << pp.candidate_version << "'\n";
+ }
+ }
+ else if (cmd == "apt-cache-show")
+ {
+ assert (argc == 4); // <pkg> <ver>
+
+ pair<string, string> key (argv[2], argv[3]);
+
+ system_package_manager_debian::simulation s;
+ s.apt_cache_show_.emplace (key, path ("-"));
+
+ system_package_manager_debian m (move (osr),
+ host_triplet,
+ "" /* arch */,
+ nullopt /* progress */,
+ nullopt /* fetch_timeout */,
+ false /* install */,
+ false /* fetch */,
+ false /* yes */,
+ "sudo");
+ m.simulate_ = &s;
+
+ cout << m.apt_cache_show (key.first, key.second) << '\n';
+ }
+ else if (cmd == "parse-name-value")
+ {
+ assert (argc == 3); // <pkg>
+
+ package_name pn (argv[2]);
+ string pt (package_manifest::effective_type (nullopt, pn));
+
+ string v;
+ getline (cin, v);
+
+ package_status s (
+ system_package_manager_debian::parse_name_value (pt, v, false, false));
+
+ if (!s.main.empty ()) cout << "main: " << s.main << '\n';
+ if (!s.dev.empty ()) cout << "dev: " << s.dev << '\n';
+ if (!s.doc.empty ()) cout << "doc: " << s.doc << '\n';
+ if (!s.dbg.empty ()) cout << "dbg: " << s.dbg << '\n';
+ if (!s.common.empty ()) cout << "common: " << s.common << '\n';
+ if (!s.extras.empty ())
+ {
+ cout << "extras:";
+ for (const string& e: s.extras)
+ cout << ' ' << e;
+ cout << '\n';
+ }
+ }
+ else if (cmd == "main-from-dev")
+ {
+ assert (argc == 4); // <dev-pkg> <dev-ver>
+
+ string n (argv[2]);
+ string v (argv[3]);
+ string d;
+ getline (cin, d);
+
+ cout << system_package_manager_debian::main_from_dev (n, v, d) << '\n';
+ }
+ else if (cmd == "map-package")
+ {
+ assert (argc >= 2 && argc <= 3); // [<build-metadata>]
+
+ optional<string> bm;
+ if (argc > 2)
+ bm = argv[2];
+
+ available_packages aps;
+ aps.push_back (make_available_from_manifest ("", "-"));
+
+ const package_name& n (aps.front ().first->id.name);
+ const version& v (aps.front ().first->version);
+
+ system_package_manager_debian m (move (osr),
+ host_triplet,
+ "" /* arch */,
+ nullopt /* progress */,
+ nullptr /* options */);
+
+ package_status s (m.map_package (n, v, aps, bm));
+
+ cout << "version: " << s.system_version << '\n'
+ << "main: " << s.main << '\n';
+ if (!s.dev.empty ()) cout << "dev: " << s.dev << '\n';
+ if (!s.doc.empty ()) cout << "doc: " << s.doc << '\n';
+ if (!s.dbg.empty ()) cout << "dbg: " << s.dbg << '\n';
+ if (!s.common.empty ()) cout << "common: " << s.common << '\n';
+ }
+ else if (cmd == "build")
+ {
+ assert (argc >= 3); // <query-pkg>...
+
+ strings qps;
+ map<string, available_packages> aps;
+
+ // Parse <query-pkg>...
+ //
+ int argi (2);
+ for (; argi != argc; ++argi)
+ {
+ string a (argv[argi]);
+
+ if (a.compare (0, 2, "--") == 0)
+ break;
+
+ aps.emplace (a, available_packages {});
+ qps.push_back (move (a));
+ }
+
+ // Parse --install [--no-fetch]
+ //
+ bool install (false);
+ bool fetch (true);
+
+ for (; argi != argc; ++argi)
+ {
+ string a (argv[argi]);
+
+ if (a == "--install") install = true;
+ else if (a == "--no-fetch") fetch = false;
+ else break;
+ }
+
+ // Parse the description.
+ //
+ system_package_manager_debian::simulation s;
+
+ for (string l; !eof (getline (cin, l)); )
+ {
+ if (l.empty ())
+ continue;
+
+ size_t p (l.find (':')); assert (p != string::npos);
+ string k (l, 0, p);
+
+ if (k == "manifest")
+ {
+ size_t q (l.rfind (' ')); assert (q != string::npos);
+ string n (l, p + 2, q - p - 2); trim (n);
+ string f (l, q + 1); trim (f);
+
+ auto i (aps.find (n));
+ if (i == aps.end ())
+ fail << "unknown package " << n << " in '" << l << "'";
+
+ i->second.push_back (make_available_from_manifest (n, f));
+ }
+ else if (
+ map<strings, path>* policy =
+ k == "apt-cache-policy" ? &s.apt_cache_policy_ :
+ k == "apt-cache-policy-fetched" ? &s.apt_cache_policy_fetched_ :
+ k == "apt-cache-policy-installed" ? &s.apt_cache_policy_installed_ :
+ nullptr)
+ {
+ size_t q (l.rfind (' ')); assert (q != string::npos);
+ string n (l, p + 2, q - p - 2); trim (n);
+ string f (l, q + 1); trim (f);
+
+ strings ns;
+ for (size_t b (0), e (0); next_word (n, b, e); )
+ ns.push_back (string (n, b, e - b));
+
+ if (f == "!")
+ f.clear ();
+
+ policy->emplace (move (ns), path (move (f)));
+ }
+ else if (map<pair<string, string>, path>* show =
+ k == "apt-cache-show" ? &s.apt_cache_show_ :
+ k == "apt-cache-show-fetched" ? &s.apt_cache_show_fetched_ :
+ nullptr)
+ {
+ size_t q (l.rfind (' ')); assert (q != string::npos);
+ string n (l, p + 2, q - p - 2); trim (n);
+ string f (l, q + 1); trim (f);
+
+ q = n.find (' '); assert (q != string::npos);
+ pair<string, string> nv (string (n, 0, q), string (n, q + 1));
+ trim (nv.second);
+
+ if (f == "!")
+ f.clear ();
+
+ show->emplace (move (nv), path (move (f)));
+ }
+ else if (k == "apt-get-update-fail")
+ {
+ s.apt_get_update_fail_ = true;
+ }
+ else if (k == "apt-get-install-fail")
+ {
+ s.apt_get_install_fail_ = true;
+ }
+ else
+ fail << "unknown keyword '" << k << "' in simulation description";
+ }
+
+ // Fallback to stubs and sort in the version descending order.
+ //
+ for (pair<const string, available_packages>& p: aps)
+ {
+ if (p.second.empty ())
+ p.second.push_back (make_available_stub (p.first));
+
+ sort_available (p.second);
+ }
+
+ system_package_manager_debian m (move (osr),
+ host_triplet,
+ "" /* arch */,
+ nullopt /* progress */,
+ nullopt /* fetch_timeout */,
+ install,
+ fetch,
+ false /* yes */,
+ "sudo");
+ m.simulate_ = &s;
+
+ // Query each package.
+ //
+ for (const string& n: qps)
+ {
+ package_name pn (n);
+
+ const system_package_status* s (*m.status (pn, &aps[n]));
+
+ assert (*m.status (pn, nullptr) == s); // Test caching.
+
+ if (s == nullptr)
+ fail << "no installed " << (install ? "or available " : "")
+ << "system package for " << pn;
+
+ cout << pn << ' ' << s->version
+ << " (" << s->system_name << ' ' << s->system_version << ") ";
+
+ switch (s->status)
+ {
+ case package_status::installed: cout << "installed"; break;
+ case package_status::partially_installed: cout << "part installed"; break;
+ case package_status::not_installed: cout << "not installed"; break;
+ }
+
+ cout << '\n';
+ }
+
+ // Install if requested.
+ //
+ if (install)
+ {
+ assert (argi != argc); // <install-pkg>...
+
+ vector<package_name> ips;
+ for (; argi != argc; ++argi)
+ ips.push_back (package_name (argv[argi]));
+
+ m.install (ips);
+ }
+ }
+ else
+ fail << "unknown command '" << cmd << "'";
+
+ return 0;
+ }
+ catch (const failed&)
+ {
+ return 1;
+ }
+}
+
+int
+main (int argc, char* argv[])
+{
+ return bpkg::main (argc, argv);
+}
diff --git a/bpkg/system-package-manager-debian.test.testscript b/bpkg/system-package-manager-debian.test.testscript
new file mode 100644
index 0000000..56c6785
--- /dev/null
+++ b/bpkg/system-package-manager-debian.test.testscript
@@ -0,0 +1,1177 @@
+# file : bpkg/system-package-manager-debian.test.testscript
+# license : MIT; see accompanying LICENSE file
+
+: apt-cache-policy
+:
+{
+ test.arguments += apt-cache-policy
+
+ : basics
+ :
+ $* libssl3 libssl1.1 libssl-dev libsqlite5 libxerces-c-dev <<EOI 2>>EOE >>EOO
+ libssl3:
+ Installed: 3.0.7-1
+ Candidate: 3.0.7-2
+ Version table:
+ 3.0.7-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ *** 3.0.7-1 100
+ 100 /var/lib/dpkg/status
+ libssl1.1:
+ Installed: 1.1.1n-0+deb11u3
+ Candidate: 1.1.1n-0+deb11u3
+ Version table:
+ *** 1.1.1n-0+deb11u3 100
+ 100 /var/lib/dpkg/status
+ libssl-dev:
+ Installed: 3.0.7-1
+ Candidate: 3.0.7-2
+ Version table:
+ 3.0.7-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ *** 3.0.7-1 100
+ 100 /var/lib/dpkg/status
+ libxerces-c-dev:
+ Installed: (none)
+ Candidate: 3.2.4+debian-1
+ Version table:
+ 3.2.4+debian-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ LC_ALL=C apt-cache policy --quiet libssl3 libssl1.1 libssl-dev libsqlite5 libxerces-c-dev <-
+ EOE
+ libssl3 '3.0.7-1' '3.0.7-2'
+ libssl1.1 '1.1.1n-0+deb11u3' '1.1.1n-0+deb11u3'
+ libssl-dev '3.0.7-1' '3.0.7-2'
+ libsqlite5 '' ''
+ libxerces-c-dev '' '3.2.4+debian-1'
+ EOO
+
+ : empty
+ :
+ $* libsqlite5 <:'' 2>>EOE >>EOO
+ LC_ALL=C apt-cache policy --quiet libsqlite5 <-
+ EOE
+ libsqlite5 '' ''
+ EOO
+
+ : none-none
+ :
+ $* pulseaudio <<EOI 2>>EOE >>EOO
+ pulseaudio:
+ Installed: (none)
+ Candidate: (none)
+ Version table:
+ 1:11.1-1ubuntu7.5 -1
+ 500 http://au.archive.ubuntu.com/ubuntu bionic-updates/main amd64 Packages
+ 1:11.1-1ubuntu7 -1
+ 500 http://au.archive.ubuntu.com/ubuntu bionic/main amd64 Packages
+ EOI
+ LC_ALL=C apt-cache policy --quiet pulseaudio <-
+ EOE
+ pulseaudio '' ''
+ EOO
+}
+
+: apt-cache-show
+:
+{
+ test.arguments += apt-cache-show
+
+ # Note: put Depends last to test folded/multiline parsing.
+ #
+ : basics
+ :
+ $* libssl1.1 1.1.1n-0+deb11u3 <<EOI 2>>EOE >>EOO
+ Package: libssl1.1
+ Status: install ok installed
+ Priority: optional
+ Section: libs
+ Installed-Size: 4120
+ Maintainer: Debian OpenSSL Team <pkg-openssl-devel@lists.alioth.debian.org>
+ Architecture: amd64
+ Multi-Arch: same
+ Source: openssl
+ Version: 1.1.1n-0+deb11u3
+ Breaks: isync (<< 1.3.0-2), lighttpd (<< 1.4.49-2), python-boto (<< 2.44.0-1.1), python-httplib2 (<< 0.11.3-1), python-imaplib2 (<< 2.57-5), python3-boto (<< 2.44.0-1.1), python3-imaplib2 (<< 2.57-5)
+ Description: Secure Sockets Layer toolkit - shared libraries
+ This package is part of the OpenSSL project's implementation of the SSL
+ and TLS cryptographic protocols for secure communication over the
+ Internet.
+ .
+ It provides the libssl and libcrypto shared libraries.
+ Description-md5: 88547c6206c7fbc4fcc7d09ce100d210
+ Homepage: https://www.openssl.org/
+ Depends: libc6 (>= 2.25), debconf (>= 0.5) | debconf-2.0
+
+ EOI
+ LC_ALL=C apt-cache show --quiet libssl1.1=1.1.1n-0+deb11u3 <-
+ EOE
+ libc6 (>= 2.25), debconf (>= 0.5) | debconf-2.0
+ EOO
+
+ : no-depends
+ :
+ $* libssl1.1 1.1.1n-0+deb11u3 <<EOI 2>>EOE >''
+ Package: libssl1.1
+ Status: install ok installed
+ Priority: optional
+ Section: libs
+ Installed-Size: 4120
+ Maintainer: Debian OpenSSL Team <pkg-openssl-devel@lists.alioth.debian.org>
+ Architecture: amd64
+ Multi-Arch: same
+ Source: openssl
+ Version: 1.1.1n-0+deb11u3
+ Breaks: isync (<< 1.3.0-2), lighttpd (<< 1.4.49-2), python-boto (<< 2.44.0-1.1), python-httplib2 (<< 0.11.3-1), python-imaplib2 (<< 2.57-5), python3-boto (<< 2.44.0-1.1), python3-imaplib2 (<< 2.57-5)
+ Description: Secure Sockets Layer toolkit - shared libraries
+ This package is part of the OpenSSL project's implementation of the SSL
+ and TLS cryptographic protocols for secure communication over the
+ Internet.
+ .
+ It provides the libssl and libcrypto shared libraries.
+ Description-md5: 88547c6206c7fbc4fcc7d09ce100d210
+ Homepage: https://www.openssl.org/
+
+ EOI
+ LC_ALL=C apt-cache show --quiet libssl1.1=1.1.1n-0+deb11u3 <-
+ EOE
+}
+
+: parse-name-value
+:
+{
+ test.arguments += parse-name-value
+
+ : basics
+ :
+ $* libssl <<EOI >>EOO
+ libssl3 libssl-common libssl-doc libssl-dev libssl-dbg libssl-extras, libc6 libc-dev libc-common libc-doc, libz-dev
+ EOI
+ main: libssl3
+ dev: libssl-dev
+ doc: libssl-doc
+ dbg: libssl-dbg
+ common: libssl-common
+ extras: libssl-extras libc6 libc-dev libz-dev
+ EOO
+
+ : non-lib
+ :
+ $* sqlite3 <<EOI >>EOO
+ sqlite3 sqlite3-common sqlite3-doc
+ EOI
+ main: sqlite3
+ doc: sqlite3-doc
+ common: sqlite3-common
+ EOO
+
+ : lib-dev
+ :
+ $* libssl <<EOI >>EOO
+ libssl-dev
+ EOI
+ dev: libssl-dev
+ EOO
+
+ : non-lib-dev
+ :
+ $* ssl-dev <<EOI >>EOO
+ ssl-dev
+ EOI
+ main: ssl-dev
+ EOO
+
+ : lib-custom-dev
+ :
+ $* libfoo-dev <<EOI >>EOO
+ libfoo-dev libfoo-dev-dev
+ EOI
+ main: libfoo-dev
+ dev: libfoo-dev-dev
+ EOO
+}
+
+: main-from-dev
+:
+{
+ test.arguments += main-from-dev
+
+ : first
+ :
+ $* libssl-dev 3.0.7-1 <<EOI >'libssl3'
+ libssl3 (= 3.0.7-1), debconf (>= 0.5) | debconf-2.0
+ EOI
+
+ : not-first
+ :
+ $* libxerces-c-dev 3.2.4+debian-1 <<EOI >'libxerces-c3.2'
+ libc6-dev | libc-dev, libicu-dev, libxerces-c3.2 (= 3.2.4+debian-1)
+ EOI
+
+ : exact
+ :
+ $* libexpat1-dev 2.5.0-1 <<EOI >'libexpat1'
+ libexpat1 (= 2.5.0-1), libc6-dev | libc-dev
+ EOI
+
+ : not-stem
+ :
+ $* libcurl4-openssl-dev 7.87.0-2 <<EOI >''
+ libcurl4 (= 7.87.0-2)
+ EOI
+}
+
+: map-package
+:
+{
+ test.arguments += map-package
+
+ : default-name
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: byacc
+ version: 20210808
+ summary: yacc parser generator
+ license: other: public domain
+ EOI
+ version: 20210808-0~debian10
+ main: byacc
+ EOO
+
+ : default-name-lib
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: libsqlite3
+ version: 3.40.1
+ summary: database library
+ license: other: public domain
+ EOI
+ version: 3.40.1-0~debian10
+ main: libsqlite3
+ dev: libsqlite3-dev
+ EOO
+
+ : custom-name
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: libsqlite3
+ debian_9-name: libsqlite3-0 libsqlite3-dev
+ version: 3.40.1
+ summary: database library
+ license: other: public domain
+ EOI
+ version: 3.40.1-0~debian10
+ main: libsqlite3-0
+ dev: libsqlite3-dev
+ EOO
+
+ : custom-name-dev-only
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: libsqlite3
+ debian_9-name: libsqlite3-0-dev
+ version: 3.40.1
+ summary: database library
+ license: other: public domain
+ EOI
+ version: 3.40.1-0~debian10
+ main: libsqlite3-0
+ dev: libsqlite3-0-dev
+ EOO
+
+ : custom-name-non-native
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: libsqlite3
+ debian_0-name: libsqlite libsqlite-dev
+ debian_9-name: libsqlite3-0 libsqlite3-dev
+ version: 3.40.1
+ summary: database library
+ license: other: public domain
+ EOI
+ version: 3.40.1-0~debian10
+ main: libsqlite
+ dev: libsqlite-dev
+ EOO
+
+ : version-upstream
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: byacc
+ version: +2-1.2.3-beta.1+3
+ upstream-version: 20210808
+ summary: yacc parser generator
+ license: other: public domain
+ EOI
+ version: 20210808~beta.1-3~debian10
+ main: byacc
+ EOO
+
+ : version-distribution
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: byacc
+ version: +2-1.2.3-beta.1+3
+ debian-version: 20210808~beta.1
+ summary: yacc parser generator
+ license: other: public domain
+ EOI
+ version: 20210808~beta.1-0~debian10
+ main: byacc
+ EOO
+
+ : version-distribution-epoch-revision
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: byacc
+ version: +2-1.2.3-beta.1+3
+ debian-version: 1:1.2.3-2
+ summary: yacc parser generator
+ license: other: public domain
+ EOI
+ version: 1:1.2.3-2~debian10
+ main: byacc
+ EOO
+
+ : version-distribution-empty-release
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: byacc
+ version: +2-1.2.3-beta.1+3
+ debian-version: 20210808~-4
+ summary: yacc parser generator
+ license: other: public domain
+ EOI
+ version: 20210808~beta.1-4~debian10
+ main: byacc
+ EOO
+
+ : version-distribution-empty-revision
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: byacc
+ version: +2-1.2.3-beta.1+3
+ debian-version: 20210808~b.1-
+ summary: yacc parser generator
+ license: other: public domain
+ EOI
+ version: 20210808~b.1-3~debian10
+ main: byacc
+ EOO
+
+ : version-distribution-empty-release-revision
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: byacc
+ version: +2-1.2.3-beta.1+3
+ debian-version: 20210808~-
+ summary: yacc parser generator
+ license: other: public domain
+ EOI
+ version: 20210808~beta.1-3~debian10
+ main: byacc
+ EOO
+
+ : version-no-build-metadata
+ :
+ $* '' <<EOI >>EOO
+ : 1
+ name: byacc
+ version: 1.2.3
+ summary: yacc parser generator
+ license: other: public domain
+ EOI
+ version: 1.2.3
+ main: byacc
+ EOO
+
+ : version-distribution-no-build-metadata
+ :
+ $* '' <<EOI >>EOO
+ : 1
+ name: byacc
+ version: 1.2.3
+ debian-version: 20210808
+ summary: yacc parser generator
+ license: other: public domain
+ EOI
+ version: 20210808
+ main: byacc
+ EOO
+}
+
+: build
+:
+{
+ test.arguments += build
+
+ : libsqlite3
+ :
+ {
+ : installed
+ :
+ cat <<EOI >=libsqlite3-dev.policy;
+ libsqlite3-dev:
+ Installed: 3.40.1-1
+ Candidate: 3.40.1-1
+ Version table:
+ *** 3.40.1-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ 100 /var/lib/dpkg/status
+ EOI
+ cat <<EOI >=libsqlite3-dev.show;
+ Package: libsqlite3-dev
+ Version: 3.40.1-1
+ Depends: libsqlite3-0 (= 3.40.1-1), libc-dev
+ EOI
+ cat <<EOI >=libsqlite3-0.policy;
+ libsqlite3-0:
+ Installed: 3.40.1-1
+ Candidate: 3.40.1-1
+ Version table:
+ *** 3.40.1-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ 100 /var/lib/dpkg/status
+ EOI
+ $* libsqlite3 --install libsqlite3 <<EOI 2>>EOE >>EOO
+ apt-cache-policy: libsqlite3-dev libsqlite3-dev.policy
+ apt-cache-show: libsqlite3-dev 3.40.1-1 libsqlite3-dev.show
+ apt-cache-policy: libsqlite3-0 libsqlite3-0.policy
+ EOI
+ LC_ALL=C apt-cache policy --quiet libsqlite3-dev <libsqlite3-dev.policy
+ LC_ALL=C apt-cache show --quiet libsqlite3-dev=3.40.1-1 <libsqlite3-dev.show
+ LC_ALL=C apt-cache policy --quiet libsqlite3-0 <libsqlite3-0.policy
+ sudo apt-get install --quiet --assume-no libsqlite3-0=3.40.1-1 libsqlite3-dev=3.40.1-1
+ LC_ALL=C apt-cache policy --quiet libsqlite3-0 <libsqlite3-0.policy
+ EOE
+ libsqlite3 3.40.1 (libsqlite3-0 3.40.1-1) installed
+ EOO
+
+
+ : part-installed
+ :
+ cat <<EOI >=libsqlite3-dev.policy;
+ libsqlite3-dev:
+ Installed: (none)
+ Candidate: 3.40.1-1
+ Version table:
+ 3.40.1-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ cat <<EOI >=libsqlite3-dev.show;
+ Package: libsqlite3-dev
+ Version: 3.40.1-1
+ Depends: libsqlite3-0 (= 3.40.1-1), libc-dev
+ EOI
+ cat <<EOI >=libsqlite3-0.policy;
+ libsqlite3-0:
+ Installed: 3.40.1-1
+ Candidate: 3.40.1-1
+ Version table:
+ *** 3.40.1-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ 100 /var/lib/dpkg/status
+ EOI
+ $* libsqlite3 --install libsqlite3 <<EOI 2>>EOE >>EOO
+ apt-cache-policy: libsqlite3-dev libsqlite3-dev.policy
+ apt-cache-show: libsqlite3-dev 3.40.1-1 libsqlite3-dev.show
+ apt-cache-policy: libsqlite3-0 libsqlite3-0.policy
+ EOI
+ LC_ALL=C apt-cache policy --quiet libsqlite3-dev <libsqlite3-dev.policy
+ sudo apt-get update --quiet --assume-no
+ LC_ALL=C apt-cache policy --quiet libsqlite3-dev <libsqlite3-dev.policy
+ LC_ALL=C apt-cache show --quiet libsqlite3-dev=3.40.1-1 <libsqlite3-dev.show
+ LC_ALL=C apt-cache policy --quiet libsqlite3-0 <libsqlite3-0.policy
+ sudo apt-get install --quiet --assume-no libsqlite3-0 libsqlite3-dev
+ LC_ALL=C apt-cache policy --quiet libsqlite3-0 <libsqlite3-0.policy
+ EOE
+ libsqlite3 3.40.1 (libsqlite3-0 3.40.1-1) part installed
+ EOO
+
+
+ : part-installed-upgrade
+ :
+ cat <<EOI >=libsqlite3-dev.policy;
+ libsqlite3-dev:
+ Installed: (none)
+ Candidate: 3.39.4-1
+ Version table:
+ 3.39.4-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ cat <<EOI >=libsqlite3-dev.policy-fetched;
+ libsqlite3-dev:
+ Installed: (none)
+ Candidate: 3.40.1-1
+ Version table:
+ 3.40.1-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ cat <<EOI >=libsqlite3-dev.show-fetched;
+ Package: libsqlite3-dev
+ Version: 3.40.1-1
+ Depends: libsqlite3-0 (= 3.40.1-1), libc-dev
+ EOI
+ cat <<EOI >=libsqlite3-0.policy-fetched;
+ libsqlite3-0:
+ Installed: 3.39.4-1
+ Candidate: 3.40.1-1
+ Version table:
+ 3.40.1-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ *** 3.39.4-1 100
+ 100 /var/lib/dpkg/status
+ EOI
+ cat <<EOI >=libsqlite3-0.policy-installed;
+ libsqlite3-0:
+ Installed: 3.40.1-1
+ Candidate: 3.40.1-1
+ Version table:
+ *** 3.40.1-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ 100 /var/lib/dpkg/status
+ EOI
+ $* libsqlite3 --install libsqlite3 <<EOI 2>>EOE >>EOO
+ apt-cache-policy: libsqlite3-dev libsqlite3-dev.policy
+ apt-cache-policy-fetched: libsqlite3-dev libsqlite3-dev.policy-fetched
+ apt-cache-show: libsqlite3-dev 3.40.1-1 libsqlite3-dev.show-fetched
+ apt-cache-policy-fetched: libsqlite3-0 libsqlite3-0.policy-fetched
+ apt-cache-policy-installed: libsqlite3-0 libsqlite3-0.policy-installed
+ EOI
+ LC_ALL=C apt-cache policy --quiet libsqlite3-dev <libsqlite3-dev.policy
+ sudo apt-get update --quiet --assume-no
+ LC_ALL=C apt-cache policy --quiet libsqlite3-dev <libsqlite3-dev.policy-fetched
+ LC_ALL=C apt-cache show --quiet libsqlite3-dev=3.40.1-1 <libsqlite3-dev.show-fetched
+ LC_ALL=C apt-cache policy --quiet libsqlite3-0 <libsqlite3-0.policy-fetched
+ sudo apt-get install --quiet --assume-no libsqlite3-0 libsqlite3-dev
+ LC_ALL=C apt-cache policy --quiet libsqlite3-0 <libsqlite3-0.policy-installed
+ EOE
+ libsqlite3 3.40.1 (libsqlite3-0 3.40.1-1) part installed
+ EOO
+
+
+ # Note that the semantics is unrealistic (maybe background apt-get update
+ # happenned in between).
+ #
+ : part-installed-upgrade-version-change
+ :
+ cat <<EOI >=libsqlite3-dev.policy;
+ libsqlite3-dev:
+ Installed: (none)
+ Candidate: 3.39.4-1
+ Version table:
+ 3.39.4-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ cat <<EOI >=libsqlite3-dev.show;
+ Package: libsqlite3-dev
+ Version: 3.39.4-1
+ Depends: libsqlite3-0 (= 3.39.4-1), libc-dev
+ EOI
+ cat <<EOI >=libsqlite3-0.policy;
+ libsqlite3-0:
+ Installed: 3.39.4-1
+ Candidate: 3.39.4-1
+ Version table:
+ *** 3.39.4-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ 100 /var/lib/dpkg/status
+ EOI
+ cat <<EOI >=libsqlite3-0.policy-installed;
+ libsqlite3-0:
+ Installed: 3.40.1-1
+ Candidate: 3.40.1-1
+ Version table:
+ *** 3.40.1-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ 100 /var/lib/dpkg/status
+ EOI
+ $* libsqlite3 --install --no-fetch libsqlite3 <<EOI 2>>EOE >>EOO != 0
+ apt-cache-policy: libsqlite3-dev libsqlite3-dev.policy
+ apt-cache-show: libsqlite3-dev 3.39.4-1 libsqlite3-dev.show
+ apt-cache-policy: libsqlite3-0 libsqlite3-0.policy
+ apt-cache-policy-installed: libsqlite3-0 libsqlite3-0.policy-installed
+ EOI
+ LC_ALL=C apt-cache policy --quiet libsqlite3-dev <libsqlite3-dev.policy
+ LC_ALL=C apt-cache show --quiet libsqlite3-dev=3.39.4-1 <libsqlite3-dev.show
+ LC_ALL=C apt-cache policy --quiet libsqlite3-0 <libsqlite3-0.policy
+ sudo apt-get install --quiet --assume-no libsqlite3-0 libsqlite3-dev
+ LC_ALL=C apt-cache policy --quiet libsqlite3-0 <libsqlite3-0.policy-installed
+ error: unexpected debian package version for libsqlite3-0
+ info: expected: 3.39.4-1
+ info: installed: 3.40.1-1
+ info: consider retrying the bpkg command
+ EOE
+ libsqlite3 3.39.4 (libsqlite3-0 3.39.4-1) part installed
+ EOO
+
+
+ : not-installed
+ :
+ cat <<EOI >=libsqlite3-dev.policy;
+ libsqlite3-dev:
+ Installed: (none)
+ Candidate: 3.40.1-1
+ Version table:
+ 3.40.1-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ cat <<EOI >=libsqlite3-dev.show;
+ Package: libsqlite3-dev
+ Version: 3.40.1-1
+ Depends: libsqlite3-0 (= 3.40.1-1), libc-dev
+ EOI
+ cat <<EOI >=libsqlite3-0.policy;
+ libsqlite3-0:
+ Installed: (none)
+ Candidate: 3.40.1-1
+ Version table:
+ 3.40.1-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ cat <<EOI >=libsqlite3-0.policy-installed;
+ libsqlite3-0:
+ Installed: 3.40.1-1
+ Candidate: 3.40.1-1
+ Version table:
+ *** 3.40.1-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ 100 /var/lib/dpkg/status
+ EOI
+ $* libsqlite3 --install libsqlite3 <<EOI 2>>EOE >>EOO
+ apt-cache-policy: libsqlite3-dev libsqlite3-dev.policy
+ apt-cache-show: libsqlite3-dev 3.40.1-1 libsqlite3-dev.show
+ apt-cache-policy: libsqlite3-0 libsqlite3-0.policy
+ apt-cache-policy-installed: libsqlite3-0 libsqlite3-0.policy-installed
+ EOI
+ LC_ALL=C apt-cache policy --quiet libsqlite3-dev <libsqlite3-dev.policy
+ sudo apt-get update --quiet --assume-no
+ LC_ALL=C apt-cache policy --quiet libsqlite3-dev <libsqlite3-dev.policy
+ LC_ALL=C apt-cache show --quiet libsqlite3-dev=3.40.1-1 <libsqlite3-dev.show
+ LC_ALL=C apt-cache policy --quiet libsqlite3-0 <libsqlite3-0.policy
+ sudo apt-get install --quiet --assume-no libsqlite3-0 libsqlite3-dev
+ LC_ALL=C apt-cache policy --quiet libsqlite3-0 <libsqlite3-0.policy-installed
+ EOE
+ libsqlite3 3.40.1 (libsqlite3-0 3.40.1-1) not installed
+ EOO
+
+
+ : no-install
+ :
+ cat <<EOI >=libsqlite3-dev.policy;
+ libsqlite3-dev:
+ Installed: (none)
+ Candidate: 3.40.1-1
+ Version table:
+ 3.40.1-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ $* libsqlite3 <<EOI 2>>EOE != 0
+ apt-cache-policy: libsqlite3-dev libsqlite3-dev.policy
+ EOI
+ LC_ALL=C apt-cache policy --quiet libsqlite3-dev <libsqlite3-dev.policy
+ error: no installed system package for libsqlite3
+ EOE
+
+
+ : not-available
+ :
+ $* libsqlite3 --install libsqlite3 <<EOI 2>>EOE != 0
+ apt-cache-policy: libsqlite3-dev !
+ EOI
+ LC_ALL=C apt-cache policy --quiet libsqlite3-dev </dev/null
+ sudo apt-get update --quiet --assume-no
+ LC_ALL=C apt-cache policy --quiet libsqlite3-dev </dev/null
+ error: no installed or available system package for libsqlite3
+ EOE
+
+
+ : not-available-no-fetch
+ :
+ $* libsqlite3 --install --no-fetch libsqlite3 <<EOI 2>>EOE != 0
+ apt-cache-policy: libsqlite3-dev !
+ EOI
+ LC_ALL=C apt-cache policy --quiet libsqlite3-dev </dev/null
+ error: no installed or available system package for libsqlite3
+ EOE
+ }
+
+ : sqlite3
+ :
+ {
+ : installed
+ :
+ cat <<EOI >=sqlite3.policy;
+ sqlite3:
+ Installed: 3.40.1-1
+ Candidate: 3.40.1-1
+ Version table:
+ *** 3.40.1-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ 100 /var/lib/dpkg/status
+ EOI
+ $* sqlite3 --install sqlite3 <<EOI 2>>EOE >>EOO
+ apt-cache-policy: sqlite3 sqlite3.policy
+ EOI
+ LC_ALL=C apt-cache policy --quiet sqlite3 <sqlite3.policy
+ sudo apt-get install --quiet --assume-no sqlite3=3.40.1-1
+ LC_ALL=C apt-cache policy --quiet sqlite3 <sqlite3.policy
+ EOE
+ sqlite3 3.40.1 (sqlite3 3.40.1-1) installed
+ EOO
+
+ : not-installed
+ :
+ cat <<EOI >=sqlite3.policy;
+ sqlite3:
+ Installed: (none)
+ Candidate: 3.39.4-1
+ Version table:
+ 3.39.4-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ cat <<EOI >=sqlite3.policy-fetched;
+ sqlite3:
+ Installed: (none)
+ Candidate: 3.40.1-1
+ Version table:
+ 3.40.1-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ cat <<EOI >=sqlite3.policy-installed;
+ sqlite3:
+ Installed: 3.40.1-1
+ Candidate: 3.40.1-1
+ Version table:
+ *** 3.40.1-1 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ 100 /var/lib/dpkg/status
+ EOI
+ $* sqlite3 --install sqlite3 <<EOI 2>>EOE >>EOO
+ apt-cache-policy: sqlite3 sqlite3.policy
+ apt-cache-policy-fetched: sqlite3 sqlite3.policy-fetched
+ apt-cache-policy-installed: sqlite3 sqlite3.policy-installed
+ EOI
+ LC_ALL=C apt-cache policy --quiet sqlite3 <sqlite3.policy
+ sudo apt-get update --quiet --assume-no
+ LC_ALL=C apt-cache policy --quiet sqlite3 <sqlite3.policy-fetched
+ sudo apt-get install --quiet --assume-no sqlite3
+ LC_ALL=C apt-cache policy --quiet sqlite3 <sqlite3.policy-installed
+ EOE
+ sqlite3 3.40.1 (sqlite3 3.40.1-1) not installed
+ EOO
+ }
+
+ : libssl
+ :
+ {
+ +cat <<EOI >=libcrypto.manifest
+ : 1
+ name: libcrypto
+ version: 1.1.1+18
+ upstream-version: 1.1.1n
+ debian-name: libssl1.1 libssl-dev
+ debian-to-downstream-version: /1\.1\.1[a-z]/1.1.1/
+ summary: OpenSSL libcrypto
+ license: OpenSSL
+ EOI
+ +cat <<EOI >=libssl.manifest
+ : 1
+ name: libssl
+ version: 1.1.1+18
+ upstream-version: 1.1.1n
+ debian-name: libssl1.1 libssl-dev
+ debian-to-downstream-version: /1\.1\.1[a-z]/1.1.1/
+ summary: OpenSSL libssl
+ license: OpenSSL
+ EOI
+
+ : installed
+ :
+ ln -s ../libcrypto.manifest ./;
+ ln -s ../libssl.manifest ./;
+ cat <<EOI >=libssl1.1+libssl-dev.policy;
+ libssl1.1:
+ Installed: 1.1.1n-0+deb11u3
+ Candidate: 1.1.1n-0+deb11u3
+ Version table:
+ *** 1.1.1n-0+deb11u3 100
+ 100 /var/lib/dpkg/status
+ libssl-dev:
+ Installed: 1.1.1n-0+deb11u3
+ Candidate: 1.1.1n-0+deb11u3
+ Version table:
+ *** 1.1.1n-0+deb11u3 100
+ 100 /var/lib/dpkg/status
+ EOI
+ cat <<EOI >=libssl1.1.policy-installed;
+ libssl1.1:
+ Installed: 1.1.1n-0+deb11u3
+ Candidate: 1.1.1n-0+deb11u3
+ Version table:
+ *** 1.1.1n-0+deb11u3 100
+ 100 /var/lib/dpkg/status
+ EOI
+ $* libcrypto libssl --install libcrypto libssl <<EOI 2>>EOE >>EOO
+ manifest: libcrypto libcrypto.manifest
+ manifest: libssl libssl.manifest
+
+ apt-cache-policy: libssl1.1 libssl-dev libssl1.1+libssl-dev.policy
+ apt-cache-policy-installed: libssl1.1 libssl1.1.policy-installed
+ EOI
+ LC_ALL=C apt-cache policy --quiet libssl1.1 libssl-dev <libssl1.1+libssl-dev.policy
+ LC_ALL=C apt-cache policy --quiet libssl1.1 libssl-dev <libssl1.1+libssl-dev.policy
+ sudo apt-get install --quiet --assume-no libssl1.1=1.1.1n-0+deb11u3 libssl-dev=1.1.1n-0+deb11u3
+ LC_ALL=C apt-cache policy --quiet libssl1.1 <libssl1.1.policy-installed
+ EOE
+ libcrypto 1.1.1 (libssl1.1 1.1.1n-0+deb11u3) installed
+ libssl 1.1.1 (libssl1.1 1.1.1n-0+deb11u3) installed
+ EOO
+
+ : part-installed
+ :
+ ln -s ../libcrypto.manifest ./;
+ ln -s ../libssl.manifest ./;
+ cat <<EOI >=libssl1.1+libssl-dev.policy;
+ libssl1.1:
+ Installed: 1.1.1n-0+deb11u3
+ Candidate: 1.1.1n-0+deb11u3
+ Version table:
+ *** 1.1.1n-0+deb11u3 100
+ 100 /var/lib/dpkg/status
+ libssl-dev:
+ Installed: (none)
+ Candidate: 1.1.1n-0+deb11u3
+ Version table:
+ 1.1.1n-0+deb11u3 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ cat <<EOI >=libssl1.1.policy-installed;
+ libssl1.1:
+ Installed: 1.1.1n-0+deb11u3
+ Candidate: 1.1.1n-0+deb11u3
+ Version table:
+ *** 1.1.1n-0+deb11u3 100
+ 100 /var/lib/dpkg/status
+ EOI
+ $* libcrypto libssl --install libcrypto libssl <<EOI 2>>EOE >>EOO
+ manifest: libcrypto libcrypto.manifest
+ manifest: libssl libssl.manifest
+
+ apt-cache-policy: libssl1.1 libssl-dev libssl1.1+libssl-dev.policy
+ apt-cache-policy-installed: libssl1.1 libssl1.1.policy-installed
+ EOI
+ LC_ALL=C apt-cache policy --quiet libssl1.1 libssl-dev <libssl1.1+libssl-dev.policy
+ sudo apt-get update --quiet --assume-no
+ LC_ALL=C apt-cache policy --quiet libssl1.1 libssl-dev <libssl1.1+libssl-dev.policy
+ LC_ALL=C apt-cache policy --quiet libssl1.1 libssl-dev <libssl1.1+libssl-dev.policy
+ sudo apt-get install --quiet --assume-no libssl1.1 libssl-dev
+ LC_ALL=C apt-cache policy --quiet libssl1.1 <libssl1.1.policy-installed
+ EOE
+ libcrypto 1.1.1 (libssl1.1 1.1.1n-0+deb11u3) part installed
+ libssl 1.1.1 (libssl1.1 1.1.1n-0+deb11u3) part installed
+ EOO
+
+ : not-installed
+ :
+ ln -s ../libcrypto.manifest ./;
+ ln -s ../libssl.manifest ./;
+ cat <<EOI >=libssl1.1+libssl-dev.policy;
+ libssl1.1:
+ Installed: (none)
+ Candidate: 1.1.1n-0+deb11u3
+ Version table:
+ *** 1.1.1n-0+deb11u3 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ libssl-dev:
+ Installed: (none)
+ Candidate: 1.1.1n-0+deb11u3
+ Version table:
+ 1.1.1n-0+deb11u3 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ cat <<EOI >=libssl1.1.policy-installed;
+ libssl1.1:
+ Installed: 1.1.1n-0+deb11u3
+ Candidate: 1.1.1n-0+deb11u3
+ Version table:
+ *** 1.1.1n-0+deb11u3 100
+ 100 /var/lib/dpkg/status
+ EOI
+ $* libcrypto libssl --install libcrypto libssl <<EOI 2>>EOE >>EOO
+ manifest: libcrypto libcrypto.manifest
+ manifest: libssl libssl.manifest
+
+ apt-cache-policy: libssl1.1 libssl-dev libssl1.1+libssl-dev.policy
+ apt-cache-policy-installed: libssl1.1 libssl1.1.policy-installed
+ EOI
+ LC_ALL=C apt-cache policy --quiet libssl1.1 libssl-dev <libssl1.1+libssl-dev.policy
+ sudo apt-get update --quiet --assume-no
+ LC_ALL=C apt-cache policy --quiet libssl1.1 libssl-dev <libssl1.1+libssl-dev.policy
+ LC_ALL=C apt-cache policy --quiet libssl1.1 libssl-dev <libssl1.1+libssl-dev.policy
+ sudo apt-get install --quiet --assume-no libssl1.1 libssl-dev
+ LC_ALL=C apt-cache policy --quiet libssl1.1 <libssl1.1.policy-installed
+ EOE
+ libcrypto 1.1.1 (libssl1.1 1.1.1n-0+deb11u3) not installed
+ libssl 1.1.1 (libssl1.1 1.1.1n-0+deb11u3) not installed
+ EOO
+ }
+
+ : libcurl
+ :
+ {
+ # Note that libcurl3-gnutls libcurl4-gnutls-dev is not a mistake.
+ #
+ # Note also that there is a third flavor, libcurl3-nss libcurl4-nss-dev,
+ # but we omit it to keep the tests manageable.
+ #
+ #
+ +cat <<EOI >=libcurl.manifest
+ : 1
+ name: libcurl
+ version: 7.84.0
+ debian-name: libcurl4 libcurl4-openssl-dev libcurl4-doc
+ debian-name: libcurl3-gnutls libcurl4-gnutls-dev libcurl4-doc
+ summary: C library for transferring data with URLs
+ license: curl
+ EOI
+
+
+ : one-full-installed
+ :
+ ln -s ../libcurl.manifest ./;
+ cat <<EOI >=libcurl4+libcurl4-openssl-dev.policy;
+ libcurl4:
+ Installed: 7.85.0-1
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ *** 7.85.0-1 100
+ 100 /var/lib/dpkg/status
+ libcurl4-openssl-dev:
+ Installed: 7.85.0-1
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ *** 7.85.0-1 100
+ 100 /var/lib/dpkg/status
+ EOI
+ cat <<EOI >=libcurl3-gnutls+libcurl4-gnutls-dev.policy;
+ libcurl3-gnutls:
+ Installed: 7.85.0-1
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ *** 7.85.0-1 100
+ 100 /var/lib/dpkg/status
+ libcurl4-gnutls-dev:
+ Installed: (none)
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ cat <<EOI >=libcurl4.policy-installed;
+ libcurl4:
+ Installed: 7.85.0-1
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ *** 7.85.0-1 100
+ 100 /var/lib/dpkg/status
+ EOI
+ $* libcurl --install libcurl <<EOI 2>>EOE >>EOO
+ manifest: libcurl libcurl.manifest
+
+ apt-cache-policy: libcurl4 libcurl4-openssl-dev libcurl4+libcurl4-openssl-dev.policy
+ apt-cache-policy: libcurl3-gnutls libcurl4-gnutls-dev libcurl3-gnutls+libcurl4-gnutls-dev.policy
+ apt-cache-policy-installed: libcurl4 libcurl4.policy-installed
+ EOI
+ LC_ALL=C apt-cache policy --quiet libcurl4 libcurl4-openssl-dev <libcurl4+libcurl4-openssl-dev.policy
+ LC_ALL=C apt-cache policy --quiet libcurl3-gnutls libcurl4-gnutls-dev <libcurl3-gnutls+libcurl4-gnutls-dev.policy
+ sudo apt-get install --quiet --assume-no libcurl4=7.85.0-1 libcurl4-openssl-dev=7.85.0-1
+ LC_ALL=C apt-cache policy --quiet libcurl4 <libcurl4.policy-installed
+ EOE
+ libcurl 7.85.0 (libcurl4 7.85.0-1) installed
+ EOO
+
+
+ : one-part-installed
+ :
+ ln -s ../libcurl.manifest ./;
+ cat <<EOI >=libcurl4+libcurl4-openssl-dev.policy;
+ libcurl4:
+ Installed: 7.85.0-1
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ *** 7.85.0-1 100
+ 100 /var/lib/dpkg/status
+ libcurl4-openssl-dev:
+ Installed: (none)
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ cat <<EOI >=libcurl3-gnutls+libcurl4-gnutls-dev.policy;
+ libcurl3-gnutls:
+ Installed: (none)
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ libcurl4-gnutls-dev:
+ Installed: (none)
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ cat <<EOI >=libcurl4.policy-installed;
+ libcurl4:
+ Installed: 7.87.0-2
+ Candidate: 7.87.0-2
+ Version table:
+ *** 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ 100 /var/lib/dpkg/status
+ EOI
+ $* libcurl --install libcurl <<EOI 2>>EOE >>EOO
+ manifest: libcurl libcurl.manifest
+
+ apt-cache-policy: libcurl4 libcurl4-openssl-dev libcurl4+libcurl4-openssl-dev.policy
+ apt-cache-policy: libcurl3-gnutls libcurl4-gnutls-dev libcurl3-gnutls+libcurl4-gnutls-dev.policy
+ apt-cache-policy-installed: libcurl4 libcurl4.policy-installed
+ EOI
+ LC_ALL=C apt-cache policy --quiet libcurl4 libcurl4-openssl-dev <libcurl4+libcurl4-openssl-dev.policy
+ LC_ALL=C apt-cache policy --quiet libcurl3-gnutls libcurl4-gnutls-dev <libcurl3-gnutls+libcurl4-gnutls-dev.policy
+ sudo apt-get update --quiet --assume-no
+ LC_ALL=C apt-cache policy --quiet libcurl4 libcurl4-openssl-dev <libcurl4+libcurl4-openssl-dev.policy
+ LC_ALL=C apt-cache policy --quiet libcurl3-gnutls libcurl4-gnutls-dev <libcurl3-gnutls+libcurl4-gnutls-dev.policy
+ sudo apt-get install --quiet --assume-no libcurl4 libcurl4-openssl-dev
+ LC_ALL=C apt-cache policy --quiet libcurl4 <libcurl4.policy-installed
+ EOE
+ libcurl 7.87.0 (libcurl4 7.87.0-2) part installed
+ EOO
+
+
+ : none-installed
+ :
+ ln -s ../libcurl.manifest ./;
+ cat <<EOI >=libcurl4+libcurl4-openssl-dev.policy;
+ libcurl4:
+ Installed: (none)
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ libcurl4-openssl-dev:
+ Installed: (none)
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ cat <<EOI >=libcurl3-gnutls+libcurl4-gnutls-dev.policy;
+ libcurl3-gnutls:
+ Installed: (none)
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ libcurl4-gnutls-dev:
+ Installed: (none)
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ $* libcurl --install libcurl <<EOI 2>>EOE != 0
+ manifest: libcurl libcurl.manifest
+
+ apt-cache-policy: libcurl4 libcurl4-openssl-dev libcurl4+libcurl4-openssl-dev.policy
+ apt-cache-policy: libcurl3-gnutls libcurl4-gnutls-dev libcurl3-gnutls+libcurl4-gnutls-dev.policy
+ EOI
+ LC_ALL=C apt-cache policy --quiet libcurl4 libcurl4-openssl-dev <libcurl4+libcurl4-openssl-dev.policy
+ LC_ALL=C apt-cache policy --quiet libcurl3-gnutls libcurl4-gnutls-dev <libcurl3-gnutls+libcurl4-gnutls-dev.policy
+ sudo apt-get update --quiet --assume-no
+ LC_ALL=C apt-cache policy --quiet libcurl4 libcurl4-openssl-dev <libcurl4+libcurl4-openssl-dev.policy
+ LC_ALL=C apt-cache policy --quiet libcurl3-gnutls libcurl4-gnutls-dev <libcurl3-gnutls+libcurl4-gnutls-dev.policy
+ error: multiple available debian packages for libcurl
+ info: candidate: libcurl4 7.87.0-2
+ info: candidate: libcurl3-gnutls 7.87.0-2
+ info: consider installing the desired package manually and retrying the bpkg command
+ EOE
+
+
+ : both-part-installed
+ :
+ ln -s ../libcurl.manifest ./;
+ cat <<EOI >=libcurl4+libcurl4-openssl-dev.policy;
+ libcurl4:
+ Installed: 7.85.0-1
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ *** 7.85.0-1 100
+ 100 /var/lib/dpkg/status
+ libcurl4-openssl-dev:
+ Installed: (none)
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ cat <<EOI >=libcurl3-gnutls+libcurl4-gnutls-dev.policy;
+ libcurl3-gnutls:
+ Installed: 7.85.0-1
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ *** 7.85.0-1 100
+ 100 /var/lib/dpkg/status
+ libcurl4-gnutls-dev:
+ Installed: (none)
+ Candidate: 7.87.0-2
+ Version table:
+ 7.87.0-2 500
+ 500 http://deb.debian.org/debian bookworm/main amd64 Packages
+ EOI
+ $* libcurl --install libcurl <<EOI 2>>EOE != 0
+ manifest: libcurl libcurl.manifest
+
+ apt-cache-policy: libcurl4 libcurl4-openssl-dev libcurl4+libcurl4-openssl-dev.policy
+ apt-cache-policy: libcurl3-gnutls libcurl4-gnutls-dev libcurl3-gnutls+libcurl4-gnutls-dev.policy
+ EOI
+ LC_ALL=C apt-cache policy --quiet libcurl4 libcurl4-openssl-dev <libcurl4+libcurl4-openssl-dev.policy
+ LC_ALL=C apt-cache policy --quiet libcurl3-gnutls libcurl4-gnutls-dev <libcurl3-gnutls+libcurl4-gnutls-dev.policy
+ sudo apt-get update --quiet --assume-no
+ LC_ALL=C apt-cache policy --quiet libcurl4 libcurl4-openssl-dev <libcurl4+libcurl4-openssl-dev.policy
+ LC_ALL=C apt-cache policy --quiet libcurl3-gnutls libcurl4-gnutls-dev <libcurl3-gnutls+libcurl4-gnutls-dev.policy
+ error: multiple partially installed debian packages for libcurl
+ info: candidate: libcurl4 7.87.0-2, missing components: libcurl4-openssl-dev
+ info: candidate: libcurl3-gnutls 7.87.0-2, missing components: libcurl4-gnutls-dev
+ info: consider fully installing the desired package manually and retrying the bpkg command
+ EOE
+ }
+}
diff --git a/bpkg/system-package-manager-fedora.cxx b/bpkg/system-package-manager-fedora.cxx
new file mode 100644
index 0000000..3b79c50
--- /dev/null
+++ b/bpkg/system-package-manager-fedora.cxx
@@ -0,0 +1,4560 @@
+// file : bpkg/system-package-manager-fedora.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <bpkg/system-package-manager-fedora.hxx>
+
+#include <locale>
+
+#include <bpkg/diagnostics.hxx>
+
+#include <bpkg/pkg-bindist-options.hxx>
+
+using namespace butl;
+
+namespace bpkg
+{
+ using package_status = system_package_status_fedora;
+
+ // Translate host CPU to Fedora package architecture.
+ //
+ string system_package_manager_fedora::
+ arch_from_target (const target_triplet& h)
+ {
+ const string& c (h.cpu);
+ return
+ c == "i386" || c == "i486" || c == "i586" || c == "i686" ? "i686" :
+ c;
+ }
+
+ // Parse the fedora-name (or alike) value. The first argument is the package
+ // type.
+ //
+ // Note that for now we treat all the packages from the non-main groups as
+ // extras omitting the -common package (assuming it's pulled by the main
+ // package) as well as -doc and -debug* unless requested with the
+ // extra_{doc,debug*} arguments. Note that we treat -static as -devel (since
+ // we can't know whether the static library is needed or not).
+ //
+ package_status system_package_manager_fedora::
+ parse_name_value (const string& pt,
+ const string& nv,
+ bool extra_doc,
+ bool extra_debuginfo,
+ bool extra_debugsource)
+ {
+ auto split = [] (const string& s, char d) -> strings
+ {
+ strings r;
+ for (size_t b (0), e (0); next_word (s, b, e, d); )
+ r.push_back (string (s, b, e - b));
+ return r;
+ };
+
+ auto suffix = [] (const string& n, const string& s) -> bool
+ {
+ size_t nn (n.size ());
+ size_t sn (s.size ());
+ return nn > sn && n.compare (nn - sn, sn, s) == 0;
+ };
+
+ auto parse_group = [&split, &suffix] (const string& g, const string* pt)
+ {
+ strings ns (split (g, ' '));
+
+ if (ns.empty ())
+ fail << "empty package group";
+
+ package_status r;
+
+ // Handle the "devel instead of main" special case for libraries.
+ //
+ // Check that the following name does not end with -devel. This will be
+ // the only way to disambiguate the case where the library name happens
+ // to end with -devel (e.g., libfoo-devel libfoo-devel-devel).
+ //
+ {
+ string& m (ns[0]);
+
+ if (pt != nullptr &&
+ *pt == "lib" &&
+ suffix (m, "-devel") &&
+ !(ns.size () > 1 && suffix (ns[1], "-devel")))
+ {
+ r = package_status ("", move (m));
+ }
+ else
+ r = package_status (move (m));
+ }
+
+ // Handle the rest.
+ //
+ for (size_t i (1); i != ns.size (); ++i)
+ {
+ string& n (ns[i]);
+
+ const char* w;
+ if (string* v = (suffix (n, (w = "-devel")) ? &r.devel :
+ suffix (n, (w = "-static")) ? &r.static_ :
+ suffix (n, (w = "-doc")) ? &r.doc :
+ suffix (n, (w = "-debuginfo")) ? &r.debuginfo :
+ suffix (n, (w = "-debugsource")) ? &r.debugsource :
+ suffix (n, (w = "-common")) ? &r.common :
+ nullptr))
+ {
+ if (!v->empty ())
+ fail << "multiple " << w << " package names in '" << g << "'" <<
+ info << "did you forget to separate package groups with comma?";
+
+ *v = move (n);
+ }
+ else
+ r.extras.push_back (move (n));
+ }
+
+ return r;
+ };
+
+ strings gs (split (nv, ','));
+ assert (!gs.empty ()); // *-name value cannot be empty.
+
+ package_status r;
+ for (size_t i (0); i != gs.size (); ++i)
+ {
+ if (i == 0) // Main group.
+ r = parse_group (gs[i], &pt);
+ else
+ {
+ package_status g (parse_group (gs[i], nullptr));
+
+ if (!g.main.empty ()) r.extras.push_back (move (g.main));
+ if (!g.devel.empty ()) r.extras.push_back (move (g.devel));
+ if (!g.static_.empty ()) r.extras.push_back (move (g.static_));
+ if (!g.doc.empty () && extra_doc) r.extras.push_back (move (g.doc));
+
+ if (!g.debuginfo.empty () && extra_debuginfo)
+ r.extras.push_back (move (g.debuginfo));
+
+ if (!g.debugsource.empty () && extra_debugsource)
+ r.extras.push_back (move (g.debugsource));
+
+ if (!g.common.empty () && false) r.extras.push_back (move (g.common));
+ if (!g.extras.empty ()) r.extras.insert (
+ r.extras.end (),
+ make_move_iterator (g.extras.begin ()),
+ make_move_iterator (g.extras.end ()));
+ }
+ }
+
+ return r;
+ }
+
+ // Attempt to determine the main package name from its -devel package based
+ // on the extracted (by dnf_repoquery_requires()) dependencies, passed as a
+ // list of the package name/version pairs. Return empty string if unable to.
+ //
+ string system_package_manager_fedora::
+ main_from_devel (const string& devel_name,
+ const string& devel_ver,
+ const vector<pair<string, string>>& depends)
+ {
+ // For the main package we first look for a dependency with the
+ // <devel-stem>-libs name and the devel_ver version. Failed that, we try
+ // just <devel-stem>.
+ //
+ // Note that the order is important since for a mixed package we need to
+ // end up with the -libs sub-package rather than with the base package as,
+ // for example, in the following case:
+ //
+ // sqlite-devel 3.36.0-3.fc35 ->
+ // sqlite 3.36.0-3.fc35
+ // sqlite-libs 3.36.0-3.fc35
+ //
+ string devel_stem (devel_name, 0, devel_name.rfind ("-devel"));
+
+ auto find = [&devel_ver, &depends] (const string& n)
+ {
+ auto i (find_if (depends.begin (), depends.end (),
+ [&n, &devel_ver] (const pair<string, string>& d)
+ {
+ return d.first == n && d.second == devel_ver;
+ }));
+
+ return i != depends.end () ? i->first : string ();
+ };
+
+ string r (find (devel_stem + "-libs"));
+ return !r.empty () ? r : find (devel_stem);
+ }
+
+ static process_path dnf_path;
+ static process_path sudo_path;
+
+ // Obtain the installed and candidate versions for the specified list of
+ // Fedora packages by executing `dnf list`.
+ //
+ // If the n argument is not 0, then only query the first n packages.
+ //
+ void system_package_manager_fedora::
+ dnf_list (vector<package_info>& pis, size_t n)
+ {
+ if (n == 0)
+ n = pis.size ();
+
+ assert (n != 0 && n <= pis.size ());
+
+ // The --quiet option makes sure we don't get 'Last metadata expiration
+ // check: <timestamp>' printed to stderr. It does not appear to affect
+ // error diagnostics (try specifying a single unknown package).
+ //
+ cstrings args {
+ "dnf", "list",
+ "--all", // Look for both installed and available.
+ "--cacheonly", // Don't automatically update the metadata.
+ "--quiet"};
+
+ for (size_t i (0); i != n; ++i)
+ {
+ package_info& pi (pis[i]);
+
+ string& n (pi.name);
+ assert (!n.empty ());
+
+ pi.installed_version.clear ();
+ pi.candidate_version.clear ();
+
+ pi.installed_arch.clear ();
+ pi.candidate_arch.clear ();
+
+ args.push_back (n.c_str ());
+ }
+
+ // Note that `dnf list` fails if there are no matching packages to print.
+ // Thus, let's hack around this by adding the rpm package to the list, so
+ // that at least one package is always present and the command can never
+ // fail for that reason.
+ //
+ // Also note that we still allow the rpm package to appear in the
+ // specified package list.
+ //
+ bool rpm (false);
+ args.push_back ("rpm");
+
+ args.push_back (nullptr);
+
+ // Run with the C locale to make sure there is no localization.
+ //
+ const char* evars[] = {"LC_ALL=C", nullptr};
+
+ try
+ {
+ if (dnf_path.empty () && !simulate_)
+ dnf_path = process::path_search (args[0], false /* init */);
+
+ process_env pe (dnf_path, evars);
+
+ if (verb >= 3)
+ print_process (pe, args);
+
+ // Redirect stdout to a pipe. For good measure also redirect stdin to
+ // /dev/null to make sure there are no prompts of any kind.
+ //
+ process pr;
+ if (!simulate_)
+ pr = process (dnf_path,
+ args,
+ -2 /* stdin */,
+ -1 /* stdout */,
+ 2 /* stderr */,
+ nullptr /* cwd */,
+ evars);
+ else
+ {
+ strings k;
+ for (size_t i (0); i != n; ++i)
+ k.push_back (pis[i].name);
+
+ const path* f (nullptr);
+ if (installed_)
+ {
+ auto i (simulate_->dnf_list_installed_.find (k));
+ if (i != simulate_->dnf_list_installed_.end ())
+ f = &i->second;
+ }
+ if (f == nullptr && fetched_)
+ {
+ auto i (simulate_->dnf_list_fetched_.find (k));
+ if (i != simulate_->dnf_list_fetched_.end ())
+ f = &i->second;
+ }
+ if (f == nullptr)
+ {
+ auto i (simulate_->dnf_list_.find (k));
+ if (i != simulate_->dnf_list_.end ())
+ f = &i->second;
+ }
+
+ diag_record dr (text);
+ print_process (dr, pe, args);
+ dr << " <" << (f == nullptr || f->empty () ? "/dev/null" : f->string ());
+
+ pr = process (process_exit (0));
+ pr.in_ofd = f == nullptr || f->empty ()
+ ? fdopen_null ()
+ : (f->string () == "-"
+ ? fddup (stdin_fd ())
+ : fdopen (*f, fdopen_mode::in));
+ }
+
+ try
+ {
+ ifdstream is (move (pr.in_ofd), fdstream_mode::skip, ifdstream::badbit);
+
+ // The output of `dnf list <pkg1> <pkg2> ...` is the 2 groups of lines
+ // in the following form:
+ //
+ // Installed Packages
+ // <pkg1>.<arch1> 13.0.0-3.fc35 @<repo1>
+ // <pkg2>.<arch2> 69.1-6.fc35 @<repo2>
+ // Available Packages
+ // <pkg1>.<arch1> 13.0.1-1.fc35 <repo1>
+ // <pkg3>.<arch3> 1.2.11-32.fc35 <repo3>
+ //
+ // Where unknown packages are omitted. The lines order does not
+ // necessarily match the order of the packages on the command line.
+ // It looks like there should be not blank lines but who really knows.
+ //
+ // Note also that if a package appears in the 'Installed Packages'
+ // group, then it only appears in the 'Available Packages' if the
+ // candidate version is better. Only the single (best) available
+ // version is listed, which we call the candidate version.
+ //
+ {
+ auto df = make_diag_frame (
+ [&pe, &args] (diag_record& dr)
+ {
+ dr << info << "while parsing output of ";
+ print_process (dr, pe, args);
+ });
+
+ // Keep track of whether we are inside of the 'Installed Packages'
+ // or 'Available Packages' sections.
+ //
+ optional<bool> installed;
+
+ for (string l; !eof (getline (is, l)); )
+ {
+ if (l == "Installed Packages")
+ {
+ if (installed)
+ fail << "unexpected line '" << l << "'";
+
+ installed = true;
+ continue;
+ }
+
+ if (l == "Available Packages")
+ {
+ if (installed && !*installed)
+ fail << "duplicate line '" << l << "'";
+
+ installed = false;
+ continue;
+ }
+
+ if (!installed)
+ fail << "unexpected line '" << l << "'";
+
+ // Parse the package name.
+ //
+ size_t e (l.find (' '));
+
+ if (l.empty () || e == 0)
+ fail << "expected package name in '" << l << "'";
+
+ if (e == string::npos)
+ fail << "expected package version in '" << l << "'";
+
+ string p (l, 0, e);
+
+ // Parse the package version.
+ //
+ size_t b (l.find_first_not_of (' ', e + 1));
+
+ if (b == string::npos)
+ fail << "expected package version in '" << l << "'";
+
+ // It doesn't not seem that the repository id can be absent. Even
+ // if the package is installed manually it is assumed to come from
+ // some special repository (@commandline, etc). For example:
+ //
+ // # dnf install ./libsigc++30-3.0.7-2.fc35.x86_64.rpm
+ // # rpm -i ./libsigc++30-devel-3.0.7-2.fc35.x86_64.rpm
+ // # dnf list --quiet libsigc++30.x86_64 libsigc++30-devel.x86_64
+ // Installed Packages
+ // libsigc++30.x86_64 3.0.7-2.fc35 @@commandline
+ // libsigc++30-devel.x86_64 3.0.7-2.fc35 @@System
+ //
+ // Thus, we assume that the version is always followed with the
+ // space character.
+ //
+ e = l.find (' ', b + 1);
+
+ if (e == string::npos)
+ fail << "expected package repository in '" << l << "'";
+
+ string v (l, b, e - b);
+
+ // While we don't really care about the rest of the line, let's
+ // verify that it contains a repository id, for good measure.
+ //
+ b = l.find_first_not_of (' ', e + 1);
+
+ if (b == string::npos)
+ fail << "expected package repository in '" << l << "'";
+
+ // Separate the architecture from the package name.
+ //
+ e = p.rfind ('.');
+
+ if (e == string::npos || e == 0 || e == p.size () - 1)
+ fail << "can't extract architecture for package " << p
+ << " in '" << l << "'";
+
+ string a (p, e + 1);
+
+ // Skip the package if its architecture differs from the host
+ // architecture.
+ //
+ if (a != arch && a != "noarch")
+ continue;
+
+ p.resize (e);
+
+ if (p == "rpm")
+ rpm = true;
+
+ // Find the package info to update.
+ //
+ auto i (find_if (pis.begin (), pis.end (),
+ [&p] (const package_info& pi)
+ {return pi.name == p;}));
+
+ if (i == pis.end ())
+ {
+ // Skip the special rpm package which may not be present in the
+ // list.
+ //
+ if (p == "rpm")
+ continue;
+
+ fail << "unexpected package " << p << '.' << a << ' ' << v
+ << " in '" << l << "'";
+ }
+
+ string& ver (*installed
+ ? i->installed_version
+ : i->candidate_version);
+
+ if (!ver.empty ())
+ fail << "multiple " << (*installed ? "installed " : "available ")
+ << "versions of package " << p << '.' << a <<
+ info << "version: " << ver <<
+ info << "version: " << v;
+
+ ver = move (v);
+
+ (*installed ? i->installed_arch : i->candidate_arch) = move (a);
+ }
+ }
+
+ is.close ();
+ }
+ catch (const io_error& e)
+ {
+ if (pr.wait ())
+ fail << "unable to read " << args[0] << " list output: " << e;
+
+ // Fall through.
+ }
+
+ if (!pr.wait ())
+ {
+ diag_record dr (fail);
+ dr << args[0] << " list exited with non-zero code";
+
+ if (verb < 3)
+ {
+ dr << info << "command line: ";
+ print_process (dr, pe, args);
+ }
+ }
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e;
+
+ if (e.child)
+ exit (1);
+
+ throw failed ();
+ }
+
+ if (!rpm)
+ fail << "rpm package doesn't exist";
+
+ // Note that if a Fedora package is installed but the repository doesn't
+ // contain a better version, then this package won't appear in the
+ // 'Available Packages' section of the `dnf list` output and thus the
+ // candidate_version will stay empty. Let's set it to the installed
+ // version in this case to be consistent with the Debian's semantics and
+ // keep the Fedora and Debian system package manager implementations
+ // aligned.
+ //
+ for (size_t i (0); i != n; ++i)
+ {
+ package_info& pi (pis[i]);
+
+ if (pi.candidate_version.empty () && !pi.installed_version.empty ())
+ {
+ pi.candidate_version = pi.installed_version;
+ pi.candidate_arch = pi.installed_arch;
+ }
+ }
+ }
+
+ // Execute `dnf repoquery --requires` for the specified
+ // package/version/architecture and return its dependencies as a list of the
+ // name/version pairs.
+ //
+ // It is expected that the specified package/version/architecture is known
+ // (e.g., returned by the `dnf list` command). Note that if that's not the
+ // case (can happen due to a race), then an empty list is returned. This,
+ // however, is ok for our current usage since in this case we will shortly
+ // fail with the 'unable to guess main package' error anyway.
+ //
+ // Note that the returned dependencies are always of the host architecture
+ // or noarch. For example:
+ //
+ // dhcp-client-12:4.4.3-4.P1.fc35.x86_64 ->
+ // dhcp-common-12:4.4.3-4.P1.fc35.noarch
+ // coreutils-8.32-36.fc35.x86_64
+ // ...
+ //
+ // rust-uuid+std-devel-1.2.1-1.fc35.noarch ->
+ // rust-uuid-devel-1.2.1-1.fc35.noarch
+ // cargo-1.65.0-1.fc35.x86_64
+ //
+ vector<pair<string, string>> system_package_manager_fedora::
+ dnf_repoquery_requires (const string& name,
+ const string& ver,
+ const string& qarch,
+ bool installed)
+ {
+ assert (!name.empty () && !ver.empty () && !arch.empty ());
+
+ // Qualify the package with the architecture suffix.
+ //
+ // Note that for reasons unknown, the below command may still print some
+ // dependencies with different architecture (see the below example). It
+ // feels sensible to just skip them.
+ //
+ string spec (name + '-' + ver + '.' + qarch);
+
+ // The --quiet option makes sure we don't get 'Last metadata expiration
+ // check: <timestamp>' printed to stderr. It does not appear to affect
+ // error diagnostics (try specifying an unknown option).
+ //
+ cstrings args {
+ "dnf", "repoquery", "--requires",
+ "--quiet",
+ "--cacheonly", // Don't automatically update the metadata.
+ "--resolve", // Resolve requirements to packages/versions.
+ "--qf", "%{name} %{arch} %{epoch}:%{version}-%{release}"};
+
+ // Note that installed packages which are not available from configured
+ // repositories (e.g. packages installed from local rpm files or temporary
+ // local repositories, package versions not available anymore from their
+ // original repositories, etc) are not seen by `dnf repoquery` by
+ // default. It also turned out that the --installed option not only limits
+ // the resulting set to the installed packages, but also makes `dnf
+ // repoquery` to see all the installed packages, including the unavailable
+ // ones. Thus, we always add this option to query dependencies of the
+ // installed packages.
+ //
+ if (installed)
+ {
+ args.push_back ("--installed");
+
+ // dnf(8) also recommends to use --disableexcludes together with
+ // --install to make sure that all installed packages will be listed and
+ // no configuration file may influence the result.
+ //
+ args.push_back ("--disableexcludes=all");
+ }
+
+ args.push_back (spec.c_str ());
+ args.push_back (nullptr);
+
+ // Note that for this command there seems to be no need to run with the C
+ // locale since the output is presumably not localizable. But let's do it
+ // for good measure.
+ //
+ const char* evars[] = {"LC_ALL=C", nullptr};
+
+ vector<pair<string, string>> r;
+ try
+ {
+ if (dnf_path.empty () && !simulate_)
+ dnf_path = process::path_search (args[0], false /* init */);
+
+ process_env pe (dnf_path, evars);
+
+ if (verb >= 3)
+ print_process (pe, args);
+
+ // Redirect stdout to a pipe. For good measure also redirect stdin to
+ // /dev/null to make sure there are no prompts of any kind.
+ //
+ process pr;
+ if (!simulate_)
+ pr = process (dnf_path,
+ args,
+ -2 /* stdin */,
+ -1 /* stdout */,
+ 2 /* stderr */,
+ nullptr /* cwd */,
+ evars);
+ else
+ {
+ simulation::package k {name, ver, qarch, installed};
+
+ const path* f (nullptr);
+ if (fetched_)
+ {
+ auto i (simulate_->dnf_repoquery_requires_fetched_.find (k));
+ if (i != simulate_->dnf_repoquery_requires_fetched_.end ())
+ f = &i->second;
+ }
+ if (f == nullptr)
+ {
+ auto i (simulate_->dnf_repoquery_requires_.find (k));
+ if (i != simulate_->dnf_repoquery_requires_.end ())
+ f = &i->second;
+ }
+
+ diag_record dr (text);
+ print_process (dr, pe, args);
+ dr << " <" << (f == nullptr || f->empty () ? "/dev/null" : f->string ());
+
+ pr = process (process_exit (0));
+ pr.in_ofd = f == nullptr || f->empty ()
+ ? fdopen_null ()
+ : (f->string () == "-"
+ ? fddup (stdin_fd ())
+ : fdopen (*f, fdopen_mode::in));
+ }
+
+ try
+ {
+ ifdstream is (move (pr.in_ofd), fdstream_mode::skip, ifdstream::badbit);
+
+ // The output of the command will be the sequence of the package lines
+ // in the `<name> <arc> <version>` form (per the -qf option above). So
+ // for example for the libicu-devel-69.1-6.fc35.x86_64 package it is
+ // as follows:
+ //
+ // bash i686 0:5.1.8-3.fc35
+ // bash x86_64 0:5.1.8-3.fc35
+ // glibc i686 0:2.34-49.fc35
+ // glibc x86_64 0:2.34-49.fc35
+ // libicu x86_64 0:69.1-6.fc35
+ // libicu-devel i686 0:69.1-6.fc35
+ // libicu-devel x86_64 0:69.1-6.fc35
+ // pkgconf-pkg-config i686 0:1.8.0-1.fc35
+ // pkgconf-pkg-config x86_64 0:1.8.0-1.fc35
+ //
+ // Note that there is also a self-dependency.
+ //
+ for (string l; !eof (getline (is, l)); )
+ {
+ // Parse the package name.
+ //
+ size_t e (l.find (' '));
+
+ if (l.empty () || e == 0)
+ fail << "expected package name in '" << l << "'";
+
+ if (e == string::npos)
+ fail << "expected package architecture in '" << l << "'";
+
+ string p (l, 0, e);
+
+ // Parse the package architecture.
+ //
+ size_t b (e + 1);
+ e = l.find (' ', b);
+
+ if (e == string::npos)
+ fail << "expected package version in '" << l << "'";
+
+ string a (l, b, e - b);
+ if (a.empty ())
+ fail << "expected package architecture in '" << l << "'";
+
+ // Parse the package version.
+ //
+ string v (l, e + 1);
+
+ // Strip the '0:' epoch from the package version to align with
+ // versions retrieved by other functions (dnf_list(), etc).
+ //
+ e = v.find (':');
+ if (e == string::npos || e == 0)
+ fail << "no epoch for package version in '" << l << "'";
+
+ if (e == 1 && v[0] == '0')
+ v.erase (0, 2);
+
+ // Skip a potential self-dependency and dependencies of a different
+ // architecture.
+ //
+ if (p == name || (a != arch && a != "noarch"))
+ continue;
+
+ r.emplace_back (move (p), move (v));
+ }
+
+ is.close ();
+ }
+ catch (const io_error& e)
+ {
+ if (pr.wait ())
+ fail << "unable to read " << args[0] << " repoquery --requires "
+ << "output: " << e;
+
+ // Fall through.
+ }
+
+ if (!pr.wait ())
+ {
+ diag_record dr (fail);
+ dr << args[0] << " repoquery --requires exited with non-zero code";
+
+ if (verb < 3)
+ {
+ dr << info << "command line: ";
+ print_process (dr, pe, args);
+ }
+ }
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e;
+
+ if (e.child)
+ exit (1);
+
+ throw failed ();
+ }
+
+ return r;
+ }
+
+ // Prepare the common options for commands which update the system.
+ //
+ pair<cstrings, const process_path&> system_package_manager_fedora::
+ dnf_common (const char* command,
+ optional<size_t> fetch_timeout,
+ strings& args_storage)
+ {
+ // Pre-allocate the required number of entries in the arguments storage.
+ //
+ if (fetch_timeout)
+ args_storage.reserve (1);
+
+ cstrings args;
+
+ if (!sudo_.empty ())
+ args.push_back (sudo_.c_str ());
+
+ args.push_back ("dnf");
+ args.push_back (command);
+
+ // Map our verbosity/progress to dnf --quiet and --verbose options.
+ //
+ // Note that all the diagnostics, including the progress indication and
+ // general information (like what's being installed) but excluding error
+ // messages, is printed to stdout. So we fix this by redirecting stdout to
+ // stderr. By default the progress bar for network transfers is printed,
+ // unless stdout is not a terminal. The --quiet option disables printing
+ // the plan and all the progress indication, but not the confirmation
+ // prompt nor error messages.
+ //
+ if (progress_ && *progress_)
+ {
+ // Print the progress bar by default, unless this is not a terminal
+ // (there is no way to force it).
+ }
+ else if (verb == 0 || (progress_ && !*progress_))
+ {
+ args.push_back ("--quiet");
+ }
+
+ if (yes_)
+ {
+ args.push_back ("--assumeyes");
+ }
+ else if (!stderr_term)
+ {
+ // Suppress any prompts if stderr is not a terminal for good measure.
+ //
+ args.push_back ("--assumeno");
+ }
+
+ // Add the network operations timeout configuration options, if requested.
+ //
+ if (fetch_timeout)
+ {
+ args_storage.push_back (
+ "--setopt=timeout=" + to_string (*fetch_timeout));
+
+ args.push_back (args_storage.back ().c_str ());
+ args.push_back ("--setopt=minrate=0");
+ }
+
+ try
+ {
+ const process_path* pp (nullptr);
+
+ if (!sudo_.empty ())
+ {
+ if (sudo_path.empty () && !simulate_)
+ sudo_path = process::path_search (args[0], false /* init */);
+
+ pp = &sudo_path;
+ }
+ else
+ {
+ if (dnf_path.empty () && !simulate_)
+ dnf_path = process::path_search (args[0], false /* init */);
+
+ pp = &dnf_path;
+ }
+
+ return pair<cstrings, const process_path&> (move (args), *pp);
+ }
+ catch (const process_error& e)
+ {
+ fail << "unable to execute " << args[0] << ": " << e << endf;
+ }
+ }
+
+ // Execute `dnf makecache` to download and cache the repositories metadata.
+ //
+ void system_package_manager_fedora::
+ dnf_makecache ()
+ {
+ strings args_storage;
+ pair<cstrings, const process_path&> args_pp (
+ dnf_common ("makecache", fetch_timeout_, args_storage));
+
+ cstrings& args (args_pp.first);
+ const process_path& pp (args_pp.second);
+
+ args.push_back ("--refresh");
+ args.push_back (nullptr);
+
+ try
+ {
+ if (verb >= 2)
+ print_process (args);
+ else if (verb == 1)
+ text << "updating " << os_release.name_id << " repositories metadata...";
+
+ process pr;
+ if (!simulate_)
+ {
+ // Redirect stdout to stderr.
+ //
+ pr = process (pp, args, 0 /* stdin */, 2 /* stdout */);
+ }
+ else
+ {
+ print_process (args);
+ pr = process (process_exit (simulate_->dnf_makecache_fail_ ? 1 : 0));
+ }
+
+ if (!pr.wait ())
+ {
+ diag_record dr (fail);
+ dr << "dnf makecache exited with non-zero code";
+
+ if (verb < 2)
+ {
+ dr << info << "command line: ";
+ print_process (dr, args);
+ }
+ }
+
+ if (verb == 1)
+ text << "updated " << os_release.name_id << " repositories metadata";
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e;
+
+ if (e.child)
+ exit (1);
+
+ throw failed ();
+ }
+ }
+
+ // Execute `dnf install` to install the specified packages (e.g.,
+ // libfoo.x86_64 or libfoo-1.2.3-1.fc35.x86_64).
+ //
+ // Note that the package name can only contain alpha-numeric characters,
+ // '-', '.', '_', and '+' (see Guidelines for Naming Fedora Packages for
+ // details). If specified, both the version (1.2.3) and release (1.fc35)
+ // parts are mandatory and may only contain alpha-numeric characters, `.`,
+ // `_`, `+`, `~`, and `^` (see the RPM spec file format documentation for
+ // details). Thus, package specs (which are actually wildcards) are
+ // generally ambiguous, so that libfoo-1.2.3-1.fc35.x86_64 may theoretically
+ // be a package name and libfoo-bar a specific package version.
+ //
+ // By default, `dnf install` tries to interpret the spec as the
+ // <name>-[<epoch>:]<version>-<release>.<arch> form prior to trying the
+ // <name>.<arch> form until any matched packages are found (see SPECIFYING
+ // PACKAGES section of dnf(8) for more details on the spec matching
+ // rules). We could potentially use `dnf install-nevra` command for the
+ // package version specs and `dnf install-na` for the package name specs.
+ // Let's, however, keep it simple for now given that clashes for our
+ // use-case are presumably not very likely.
+ //
+ void system_package_manager_fedora::
+ dnf_install (const strings& pkgs)
+ {
+ assert (!pkgs.empty ());
+
+ strings args_storage;
+ pair<cstrings, const process_path&> args_pp (
+ dnf_common ("install", fetch_timeout_, args_storage));
+
+ cstrings& args (args_pp.first);
+ const process_path& pp (args_pp.second);
+
+ // Note that we can't use --cacheonly here to prevent the metadata update,
+ // since the install command then expects the package RPM files to also be
+ // cached and fails if that's not the case. Thus we have to override the
+ // metadata_expire=never configuration option instead. Which makes the
+ // whole thing quite hairy and of dubious value -- there is nothing wrong
+ // with letting it re-fetch the metadata during install (which in fact may
+ // save us from attempting to download no longer existing packages).
+ //
+#if 0
+ args.push_back ("--setopt=metadata_expire=never");
+#endif
+
+ for (const string& p: pkgs)
+ args.push_back (p.c_str ());
+
+ args.push_back (nullptr);
+
+ try
+ {
+ if (verb >= 2)
+ print_process (args);
+ else if (verb == 1)
+ text << "installing " << os_release.name_id << " packages...";
+
+ process pr;
+ if (!simulate_)
+ {
+ // Redirect stdout to stderr.
+ //
+ pr = process (pp, args, 0 /* stdin */, 2 /* stdout */);
+ }
+ else
+ {
+ print_process (args);
+ pr = process (process_exit (simulate_->dnf_install_fail_ ? 100 : 0));
+ }
+
+ if (!pr.wait ())
+ {
+ diag_record dr (fail);
+ dr << "dnf install exited with non-zero code";
+
+ if (verb < 2)
+ {
+ dr << info << "command line: ";
+ print_process (dr, args);
+ }
+
+ dr << info << "consider resolving the issue manually and retrying "
+ << "the bpkg command";
+ }
+
+ if (verb == 1)
+ text << "installed " << os_release.name_id << " packages";
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e;
+
+ if (e.child)
+ exit (1);
+
+ throw failed ();
+ }
+ }
+
+ // Execute `dnf mark install` to mark the installed packages as installed by
+ // the user (see dnf_install() for details on the package specs).
+ //
+ // Note that an installed package may be marked as installed by the user
+ // rather than as a dependency. In particular, such a package will never be
+ // automatically removed as an unused dependency. This mark can be added and
+ // removed by the `dnf mark install` and `dnf mark remove` commands,
+ // respectively. Besides that, this mark is automatically added by `dnf
+ // install` for a package specified on the command line, but only if it is
+ // not yet installed. Note that this mark will not be added automatically
+ // for an already installed package even if it is upgraded explicitly. For
+ // example:
+ //
+ // $ sudo dnf install libsigc++30-devel-3.0.2-2.fc32 --repofrompath test,./repo --setopt=gpgcheck=0 --assumeyes
+ // Installed: libsigc++30-3.0.2-2.fc32.x86_64 libsigc++30-devel-3.0.2-2.fc32.x86_64
+ //
+ // $ sudo dnf install --best libsigc++30 --assumeyes
+ // Upgraded: libsigc++30-3.0.7-2.fc35.x86_64 libsigc++30-devel-3.0.7-2.fc35.x86_64
+ //
+ // $ sudo dnf remove libsigc++30-devel --assumeyes
+ // Removed: libsigc++30-3.0.7-2.fc35.x86_64 libsigc++30-devel-3.0.7-2.fc35.x86_64
+ //
+ void system_package_manager_fedora::
+ dnf_mark_install (const strings& pkgs)
+ {
+ assert (!pkgs.empty ());
+
+ strings args_storage;
+ pair<cstrings, const process_path&> args_pp (
+ dnf_common ("mark", nullopt /* fetch_timeout */, args_storage));
+
+ cstrings& args (args_pp.first);
+ const process_path& pp (args_pp.second);
+
+ args.push_back ("install");
+ args.push_back ("--cacheonly");
+
+ for (const string& p: pkgs)
+ args.push_back (p.c_str ());
+
+ args.push_back (nullptr);
+
+ try
+ {
+ if (verb >= 2)
+ print_process (args);
+
+ process pr;
+ if (!simulate_)
+ {
+ // Redirect stdout to stderr.
+ //
+ pr = process (pp, args, 0 /* stdin */, 2 /* stdout */);
+ }
+ else
+ {
+ print_process (args);
+ pr = process (process_exit (simulate_->dnf_mark_install_fail_ ? 1 : 0));
+ }
+
+ if (!pr.wait ())
+ {
+ diag_record dr (fail);
+ dr << "dnf mark install exited with non-zero code";
+
+ if (verb < 2)
+ {
+ dr << info << "command line: ";
+ print_process (dr, args);
+ }
+
+ dr << info << "consider resolving the issue manually and retrying "
+ << "the bpkg command";
+ }
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e;
+
+ if (e.child)
+ exit (1);
+
+ throw failed ();
+ }
+ }
+
+ optional<const system_package_status*> system_package_manager_fedora::
+ status (const package_name& pn, const available_packages* aps)
+ {
+ // First check the cache.
+ //
+ {
+ auto i (status_cache_.find (pn));
+
+ if (i != status_cache_.end ())
+ return i->second ? &*i->second : nullptr;
+
+ if (aps == nullptr)
+ return nullopt;
+ }
+
+ optional<package_status> r (status (pn, *aps));
+
+ // Cache.
+ //
+ auto i (status_cache_.emplace (pn, move (r)).first);
+ return i->second ? &*i->second : nullptr;
+ }
+
+ optional<package_status> system_package_manager_fedora::
+ status (const package_name& pn, const available_packages& aps)
+ {
+ tracer trace ("system_package_manager_fedora::status");
+
+ // For now we ignore -doc and -debug* package components (but we may want
+ // to have options controlling this later). Note also that we assume
+ // -common is pulled automatically by the base package so we ignore it as
+ // well (see equivalent logic in parse_name_value()).
+ //
+ bool need_doc (false);
+ bool need_debuginfo (false);
+ bool need_debugsource (false);
+
+ vector<package_status> candidates;
+
+ // Translate our package name to the Fedora package names.
+ //
+ {
+ auto df = make_diag_frame (
+ [this, &pn] (diag_record& dr)
+ {
+ dr << info << "while mapping " << pn << " to " << os_release.name_id
+ << " package name";
+ });
+
+ // Without explicit type, the best we can do in trying to detect whether
+ // this is a library is to check for the lib prefix. Libraries without
+ // the lib prefix and non-libraries with the lib prefix (both of which
+ // we do not recomment) will have to provide a manual mapping (or
+ // explicit type).
+ //
+ // Note that using the first (latest) available package as a source of
+ // type information seems like a reasonable choice.
+ //
+ const string& pt (!aps.empty ()
+ ? aps.front ().first->effective_type ()
+ : package_manifest::effective_type (nullopt, pn));
+
+ strings ns;
+ if (!aps.empty ())
+ ns = system_package_names (aps,
+ os_release.name_id,
+ os_release.version_id,
+ os_release.like_ids,
+ true /* native */);
+ if (ns.empty ())
+ {
+ // Attempt to automatically translate our package name. Failed that we
+ // should try to use the project name, if present, as a fallback.
+ //
+ const string& n (pn.string ());
+
+ // Note that theoretically different available packages can have
+ // different project names. But taking it from the latest version
+ // feels good enough.
+ //
+ const shared_ptr<available_package>& ap (!aps.empty ()
+ ? aps.front ().first
+ : nullptr);
+
+ string f (ap != nullptr && ap->project && *ap->project != pn
+ ? ap->project->string ()
+ : empty_string);
+
+ if (pt == "lib")
+ {
+ // If there is no project name let's try to use the package name
+ // with the lib prefix stripped as a fallback. Note that naming
+ // library packages without the lib prefix is quite common in Fedora
+ // (xerces-c, uuid-c++, etc).
+ //
+ if (f.empty ())
+ f = string (n, 3);
+
+ f += "-devel";
+
+ // Keep the base package name empty as an indication that it is to
+ // be discovered.
+ //
+ candidates.push_back (package_status ("", n + "-devel", move (f)));
+ }
+ else
+ candidates.push_back (package_status (n, "", move (f)));
+ }
+ else
+ {
+ // Parse each manual mapping.
+ //
+ for (const string& n: ns)
+ {
+ package_status s (parse_name_value (pt,
+ n,
+ need_doc,
+ need_debuginfo,
+ need_debugsource));
+
+ // Suppress duplicates for good measure based on the base package
+ // name (and falling back to -devel if empty).
+ //
+ auto i (find_if (candidates.begin (), candidates.end (),
+ [&s] (const package_status& x)
+ {
+ // Note that it's possible for one mapping to be
+ // specified as -devel only while the other as
+ // main and -devel.
+ //
+ return s.main.empty () || x.main.empty ()
+ ? s.devel == x.devel
+ : s.main == x.main;
+ }));
+ if (i == candidates.end ())
+ candidates.push_back (move (s));
+ else
+ {
+ // Should we verify the rest matches for good measure? But what
+ // if we need to override, as in:
+ //
+ // fedora_35-name: libfoo libfoo-bar-devel
+ // fedora_34-name: libfoo libfoo-devel
+ //
+ // Note that for this to work we must get fedora_35 values before
+ // fedora_34, which is the semantics guaranteed by
+ // system_package_names().
+ }
+ }
+ }
+ }
+
+ // Guess unknown main package given the -devel package, its version, and
+ // architecture. Failed that, assume the package to be a binless library
+ // and leave the main member of the package_status object empty.
+ //
+ auto guess_main = [this, &trace] (package_status& s,
+ const string& ver,
+ const string& qarch,
+ bool installed)
+ {
+ vector<pair<string, string>> depends (
+ dnf_repoquery_requires (s.devel, ver, qarch, installed));
+
+ s.main = main_from_devel (s.devel, ver, depends);
+
+ if (s.main.empty ())
+ {
+ if (verb >= 4)
+ {
+ diag_record dr (trace);
+ dr << "unable to guess main package for " << s.devel << ' ' << ver;
+
+ if (!depends.empty ())
+ {
+ dr << ", depends on";
+
+ for (auto b (depends.begin ()), i (b); i != depends.end (); ++i)
+ dr << (i == b ? " " : ", ") << i->first << ' ' << i->second;
+ }
+ else
+ dr << ", has no dependencies";
+ }
+ }
+ };
+
+ // Calculate the package status from individual package components.
+ // Return nullopt if there is a component without installed or candidate
+ // version (which means the package cannot be installed).
+ //
+ // The main argument specifies the size of the main group. Only components
+ // from this group are considered for partially_installed determination.
+ //
+ // @@ TODO: we should probably prioritize partially installed with fully
+ // installed main group. Add almost_installed next to partially_installed?
+ //
+ using status_type = package_status::status_type;
+
+ auto status = [] (const vector<package_info>& pis, size_t main)
+ -> optional<status_type>
+ {
+ bool i (false), u (false);
+
+ for (size_t j (0); j != pis.size (); ++j)
+ {
+ const package_info& pi (pis[j]);
+
+ if (pi.installed_version.empty ())
+ {
+ if (pi.candidate_version.empty ())
+ return nullopt;
+
+ u = true;
+ }
+ else if (j < main)
+ i = true;
+ }
+
+ return (!u ? package_status::installed :
+ !i ? package_status::not_installed :
+ package_status::partially_installed);
+ };
+
+ // First look for an already fully installed package.
+ //
+ optional<package_status> r;
+
+ {
+ diag_record dr; // Ambiguity diagnostics.
+
+ for (package_status& ps: candidates)
+ {
+ vector<package_info>& pis (ps.package_infos);
+
+ // Query both main and fallback packages with a single dns_list()
+ // invocation.
+ //
+ if (!ps.main.empty ()) pis.emplace_back (ps.main);
+ if (!ps.devel.empty ()) pis.emplace_back (ps.devel);
+ if (!ps.fallback.empty ()) pis.emplace_back (ps.fallback);
+ if (!ps.static_.empty ()) pis.emplace_back (ps.static_);
+ if (!ps.doc.empty () && need_doc) pis.emplace_back (ps.doc);
+
+ if (!ps.debuginfo.empty () && need_debuginfo)
+ pis.emplace_back (ps.debuginfo);
+
+ if (!ps.debugsource.empty () && need_debugsource)
+ pis.emplace_back (ps.debugsource);
+
+ if (!ps.common.empty () && false) pis.emplace_back (ps.common);
+ ps.package_infos_main = pis.size ();
+ for (const string& n: ps.extras) pis.emplace_back (n);
+
+ dnf_list (pis);
+
+ // Handle the fallback package name, if specified.
+ //
+ // Specifically, if the main/devel package is known to the system
+ // package manager we use that. Otherwise, if the fallback package is
+ // known we use that. And if neither is known, then we skip this
+ // candidate (ps).
+ //
+ if (!ps.fallback.empty ())
+ {
+ assert (pis.size () > 1); // devel+fallback or main+fallback
+
+ package_info& mp (pis[0]); // Main/devel package info.
+ package_info& fp (pis[1]); // Fallback package info.
+
+ // Note that at this stage we can only use the installed main/devel
+ // and fallback packages (since the candidate versions may change
+ // after fetch).
+ //
+ // Also note that this logic prefers installed fallback package to
+ // potentially available non-fallback package.
+ //
+ if (mp.installed_version.empty ())
+ {
+ if (!fp.installed_version.empty ())
+ {
+ // Use the fallback.
+ //
+ (ps.main.empty () ? ps.devel : ps.main) = move (ps.fallback);
+ mp = move (fp);
+ }
+ else
+ continue; // Skip the candidate at this stage.
+ }
+
+ // Whether it was used or not, cleanup the fallback information.
+ //
+ ps.fallback.clear ();
+ pis.erase (pis.begin () + 1);
+ --ps.package_infos_main;
+ }
+
+ // Handle the unknown main package.
+ //
+ if (ps.main.empty ())
+ {
+ const package_info& devel (pis.front ());
+
+ // Note that at this stage we can only use the installed -devel
+ // package (since the candidate version may change after fetch).
+ //
+ if (devel.installed_version.empty ())
+ continue;
+
+ guess_main (ps,
+ devel.installed_version,
+ devel.installed_arch,
+ true /* installed */);
+
+ if (!ps.main.empty ()) // Not a binless library?
+ {
+ pis.emplace (pis.begin (), ps.main);
+ ps.package_infos_main++;
+ dnf_list (pis, 1);
+ }
+ }
+
+ optional<status_type> s (status (pis, ps.package_infos_main));
+
+ if (!s || *s != package_status::installed)
+ continue;
+
+ const package_info& main (pis.front ()); // Main/devel.
+
+ ps.status = *s;
+ ps.system_name = main.name;
+ ps.system_version = main.installed_version;
+
+ if (!r)
+ {
+ r = move (ps);
+ continue;
+ }
+
+ if (dr.empty ())
+ {
+ dr << fail << "multiple installed " << os_release.name_id
+ << " packages for " << pn <<
+ info << "candidate: " << r->system_name << ' ' << r->system_version;
+ }
+
+ dr << info << "candidate: " << ps.system_name << ' '
+ << ps.system_version;
+ }
+
+ if (!dr.empty ())
+ dr << info << "consider specifying the desired version manually";
+ }
+
+ // Next look for available versions if we are allowed to install. Indicate
+ // the non-installable candidates by setting both their main and -devel
+ // package names to empty strings.
+ //
+ if (!r && install_)
+ {
+ // If we weren't instructed to fetch or we already fetched, then we
+ // don't need to re-run dnf_list().
+ //
+ bool requery;
+ if ((requery = fetch_ && !fetched_))
+ {
+ dnf_makecache ();
+ fetched_ = true;
+ }
+
+ {
+ diag_record dr; // Ambiguity diagnostics.
+
+ for (package_status& ps: candidates)
+ {
+ vector<package_info>& pis (ps.package_infos);
+
+ if (requery)
+ dnf_list (pis);
+
+ // Handle the fallback package name, if specified.
+ //
+ if (!ps.fallback.empty ())
+ {
+ assert (pis.size () > 1); // devel+fallback or main+fallback
+
+ package_info& mp (pis[0]); // Main/devel package info.
+ package_info& fp (pis[1]); // Fallback package info.
+
+ // Note that this time we use the candidate versions.
+ //
+ if (mp.candidate_version.empty ())
+ {
+ string& main (!ps.main.empty () ? ps.main : ps.devel);
+
+ if (!fp.candidate_version.empty ())
+ {
+ // Use the fallback.
+ //
+ main = move (ps.fallback);
+ mp = move (fp);
+ }
+ else
+ {
+ // Otherwise, we would have resolved the name on the previous
+ // stage.
+ //
+ assert (mp.installed_version.empty () &&
+ fp.installed_version.empty ());
+
+ // Main/devel package is not installable.
+ //
+ main.clear ();
+ continue;
+ }
+ }
+
+ // Whether it was used or not, cleanup the fallback information.
+ //
+ ps.fallback.clear ();
+ pis.erase (pis.begin () + 1);
+ --ps.package_infos_main;
+ }
+
+ // Handle the unknown main package.
+ //
+ if (ps.main.empty ())
+ {
+ const package_info& devel (pis.front ());
+
+ // Note that this time we use the candidate version.
+ //
+ if (devel.candidate_version.empty ())
+ {
+ // Not installable.
+ //
+ ps.devel.clear ();
+ continue;
+ }
+
+ guess_main (ps,
+ devel.candidate_version,
+ devel.candidate_arch,
+ devel.candidate_version == devel.installed_version);
+
+ if (!ps.main.empty ()) // Not a binless library?
+ {
+ pis.emplace (pis.begin (), ps.main);
+ ps.package_infos_main++;
+ dnf_list (pis, 1);
+ }
+ }
+
+ optional<status_type> s (status (pis, ps.package_infos_main));
+
+ if (!s)
+ {
+ // Not installable.
+ //
+ ps.main.clear ();
+ ps.devel.clear ();
+ continue;
+ }
+
+ assert (*s != package_status::installed); // Sanity check.
+
+ const package_info& main (pis.front ()); // Main/devel.
+
+ // Note that if we are installing something for this main package,
+ // then we always go for the candidate version even though it may
+ // have an installed version that may be good enough (especially if
+ // what we are installing are extras). The reason is that it may as
+ // well not be good enough (especially if we are installing the
+ // -devel package) and there is no straightforward way to change our
+ // mind.
+ //
+ ps.status = *s;
+ ps.system_name = main.name;
+ ps.system_version = main.candidate_version;
+
+ // Prefer partially installed to not installed. This makes detecting
+ // ambiguity a bit trickier so we handle partially installed here
+ // and not installed in a separate loop below.
+ //
+ if (ps.status != package_status::partially_installed)
+ continue;
+
+ if (!r)
+ {
+ r = move (ps);
+ continue;
+ }
+
+ auto print_missing = [&dr] (const package_status& s)
+ {
+ for (const package_info& pi: s.package_infos)
+ if (pi.installed_version.empty ())
+ dr << ' ' << pi.name;
+ };
+
+ if (dr.empty ())
+ {
+ dr << fail << "multiple partially installed "
+ << os_release.name_id << " packages for " << pn;
+
+ dr << info << "candidate: " << r->system_name << ' '
+ << r->system_version << ", missing components:";
+ print_missing (*r);
+ }
+
+ dr << info << "candidate: " << ps.system_name << ' '
+ << ps.system_version << ", missing components:";
+ print_missing (ps);
+ }
+
+ if (!dr.empty ())
+ dr << info << "consider fully installing the desired package "
+ << "manually and retrying the bpkg command";
+ }
+
+ if (!r)
+ {
+ diag_record dr; // Ambiguity diagnostics.
+
+ for (package_status& ps: candidates)
+ {
+ if (ps.main.empty () && ps.devel.empty ()) // Not installable?
+ continue;
+
+ assert (ps.status == package_status::not_installed); // Sanity check.
+
+ if (!r)
+ {
+ r = move (ps);
+ continue;
+ }
+
+ if (dr.empty ())
+ {
+ dr << fail << "multiple available " << os_release.name_id
+ << " packages for " << pn <<
+ info << "candidate: " << r->system_name << ' '
+ << r->system_version;
+ }
+
+ dr << info << "candidate: " << ps.system_name << ' '
+ << ps.system_version;
+ }
+
+ if (!dr.empty ())
+ dr << info << "consider installing the desired package manually and "
+ << "retrying the bpkg command";
+ }
+ }
+
+ if (r)
+ {
+ // Map the Fedora version to the bpkg version. But first strip the
+ // release from Fedora version ([<epoch>:]<version>-<release>).
+ //
+ string sv (r->system_version, 0, r->system_version.rfind ('-'));
+
+ optional<version> v;
+ if (!aps.empty ())
+ v = downstream_package_version (sv,
+ aps,
+ os_release.name_id,
+ os_release.version_id,
+ os_release.like_ids);
+
+ if (!v)
+ {
+ // Fallback to using system version as downstream version. But first
+ // strip the epoch, if any. Also convert the potential pre-release
+ // separator to the bpkg version pre-release separator.
+ //
+ size_t p (sv.find (':'));
+ if (p != string::npos)
+ sv.erase (0, p + 1);
+
+ // Consider the first '~' character as a pre-release separator. Note
+ // that if there are more of them, then we will fail since '~' is an
+ // invalid character for bpkg version.
+ //
+ p = sv.find ('~');
+ if (p != string::npos)
+ sv[p] = '-';
+
+ try
+ {
+ v = version (sv);
+ }
+ catch (const invalid_argument& e)
+ {
+ fail << "unable to map " << os_release.name_id << " package "
+ << r->system_name << " version " << sv << " to bpkg package "
+ << pn << " version" <<
+ info << os_release.name_id << " version is not a valid bpkg "
+ << "version: " << e.what () <<
+ info << "consider specifying explicit mapping in " << pn
+ << " package manifest";
+ }
+ }
+
+ r->version = move (*v);
+ }
+
+ return r;
+ }
+
+ void system_package_manager_fedora::
+ install (const vector<package_name>& pns)
+ {
+ assert (!pns.empty ());
+
+ assert (install_ && !installed_);
+ installed_ = true;
+
+ // Collect and merge all the Fedora packages/versions for the specified
+ // bpkg packages.
+ //
+ struct package
+ {
+ string name;
+ string version; // Empty if unspecified.
+ string arch; // Always specified.
+ };
+ vector<package> pkgs;
+
+ // At first it may seem we don't need to do anything for already fully
+ // installed packages. But it's possible some of them were automatically
+ // installed, meaning that they can be automatically removed if they no
+ // longer have any dependents (see dnf(8) for details). Which in turn
+ // means that things may behave differently depending on whether we've
+ // installed a package ourselves or if it was already installed.
+ //
+ // So what we are going to do is to run `dnf install` only if there are
+ // any non-fully installed packages. In this case we will pass all the
+ // packages, including the fully installed ones. But we must be careful
+ // not to force their upgrade. To achieve this we will specify the
+ // installed version as the desired version. Whether we run `dnf install`
+ // or not we will also always run `dnf mark install` afterwards for all
+ // the packages to mark them as installed by the user.
+ //
+ // Note also that for partially/not installed we don't specify the
+ // version, expecting the candidate version to be installed. We, however,
+ // still specify the candidate architecture in this case, since for
+ // reasons unknown dnf may install a package of a different architecture
+ // otherwise.
+ //
+ bool install (false);
+
+ for (const package_name& pn: pns)
+ {
+ auto it (status_cache_.find (pn));
+ assert (it != status_cache_.end () && it->second);
+
+ const package_status& ps (*it->second);
+ bool fi (ps.status == package_status::installed);
+
+ if (!fi)
+ install = true;
+
+ for (const package_info& pi: ps.package_infos)
+ {
+ string n (pi.name);
+ string v (fi ? pi.installed_version : string ());
+ string a (fi ? pi.installed_arch : pi.candidate_arch);
+
+ auto i (find_if (pkgs.begin (), pkgs.end (),
+ [&n] (const package& p)
+ {
+ return p.name == n;
+ }));
+
+ if (i != pkgs.end ())
+ {
+ if (i->version.empty ())
+ {
+ i->version = move (v);
+ i->arch = move (a);
+ }
+ else
+ // Feels like this cannot happen since we always use the installed
+ // version of the package.
+ //
+ assert (i->version == v && i->arch == a);
+ }
+ else
+ pkgs.push_back (package {move (n), move (v), move (a)});
+ }
+ }
+
+ // Convert to the <name>-[<epoch>:]<version>-<release>.<arch> package spec
+ // for the installed packages and to the <name> spec for partially/not
+ // installed ones (see dnf_install() for details on the package specs).
+ //
+ strings specs;
+ specs.reserve (pkgs.size ());
+ for (const package& p: pkgs)
+ {
+ string s (p.name);
+ if (!p.version.empty ())
+ {
+ s += '-';
+ s += p.version;
+ }
+ s += '.';
+ s += p.arch;
+
+ specs.push_back (move (s));
+ }
+
+ // Install.
+ //
+ if (install)
+ dnf_install (specs);
+
+ // Mark as installed by the user.
+ //
+ dnf_mark_install (specs);
+
+ // Verify that versions we have promised in status() match what actually
+ // got installed.
+ //
+ if (install)
+ {
+ vector<package_info> pis;
+
+ // Here we just check the main package component of each package.
+ //
+ for (const package_name& pn: pns)
+ {
+ const package_status& ps (*status_cache_.find (pn)->second);
+
+ if (find_if (pis.begin (), pis.end (),
+ [&ps] (const package_info& pi)
+ {
+ return pi.name == ps.system_name;
+ }) == pis.end ())
+ {
+ pis.push_back (package_info (ps.system_name));
+ }
+ }
+
+ dnf_list (pis);
+
+ for (const package_name& pn: pns)
+ {
+ const package_status& ps (*status_cache_.find (pn)->second);
+
+ auto i (find_if (pis.begin (), pis.end (),
+ [&ps] (const package_info& pi)
+ {
+ return pi.name == ps.system_name;
+ }));
+ assert (i != pis.end ());
+
+ const package_info& pi (*i);
+
+ if (pi.installed_version != ps.system_version)
+ {
+ fail << "unexpected " << os_release.name_id << " package version "
+ << "for " << ps.system_name <<
+ info << "expected: " << ps.system_version <<
+ info << "installed: " << pi.installed_version <<
+ info << "consider retrying the bpkg command";
+ }
+ }
+ }
+ }
+
+ // Map non-system bpkg package to system package name(s) and version.
+ //
+ // This is used both to map the package being generated and its
+ // dependencies. What should we do with extras returned in package_status?
+ // We can't really generate any of them (which files would we place in
+ // them?) nor can we list them as dependencies (we don't know their system
+ // versions). So it feels like the only sensible choice is to ignore extras.
+ //
+ // In a sense, we have a parallel arrangement going on here: binary packages
+ // that we generate don't have extras (i.e., they include everything
+ // necessary in the "standard" packages from the main group) and when we
+ // punch a system dependency based on a non-system bpkg package, we assume
+ // it was generated by us and thus doesn't have any extras. Or, to put it
+ // another way, if you want the system dependency to refer to a "native"
+ // system package with extras you need to configure it as a system bpkg
+ // package.
+ //
+ // In fact, this extends to package names. For example, unless custom
+ // mapping is specified, we will generate libsqlite3 and libsqlite3-devel
+ // while native names are sqlite-libs and sqlite-devel. While this duality
+ // is not ideal, presumably we will normally only be producing our binary
+ // packages if there are no suitable native packages. And for a few
+ // exceptions (e.g., our package is "better" in some way, such as configured
+ // differently or fixes a critical bug), we will just have to provide
+ // appropriate manual mapping that makes sure the names match (the extras is
+ // still a potential problem though -- we will only have them as
+ // dependencies if we build against a native system package; maybe we can
+ // add them manually with an option).
+ //
+ package_status system_package_manager_fedora::
+ map_package (const package_name& pn,
+ const version& pv,
+ const available_packages& aps) const
+ {
+ // We should only have one available package corresponding to this package
+ // name/version.
+ //
+ assert (aps.size () == 1);
+
+ const shared_ptr<available_package>& ap (aps.front ().first);
+ const lazy_shared_ptr<repository_fragment>& rf (aps.front ().second);
+
+ // Without explicit type, the best we can do in trying to detect whether
+ // this is a library is to check for the lib prefix. Libraries without the
+ // lib prefix and non-libraries with the lib prefix (both of which we do
+ // not recomment) will have to provide a manual mapping (or explicit
+ // type).
+ //
+ const string& pt (ap->effective_type ());
+
+ strings ns (system_package_names (aps,
+ os_release.name_id,
+ os_release.version_id,
+ os_release.like_ids,
+ false /* native */));
+ package_status r;
+ if (ns.empty ())
+ {
+ // Automatically translate our package name similar to the consumption
+ // case above. Except here we don't attempt to deduce main from -devel
+ // or fallback to the project name, naturally.
+ //
+ const string& n (pn.string ());
+
+ if (pt == "lib")
+ r = package_status (n, n + "-devel");
+ else
+ r = package_status (n);
+ }
+ else
+ {
+ // Even though we only pass one available package, we may still end up
+ // with multiple mappings. In this case we take the first, per the
+ // documentation.
+ //
+ r = parse_name_value (pt,
+ ns.front (),
+ false /* need_doc */,
+ false /* need_debuginfo */,
+ false /* need_debugsource */);
+
+ // If this is -devel without main, then derive main by stripping the
+ // -devel suffix. This feels tighter than just using the bpkg package
+ // name.
+ //
+ if (r.main.empty ())
+ {
+ assert (!r.devel.empty ());
+ r.main.assign (r.devel, 0, r.devel.size () - 6);
+ }
+ }
+
+ // Map the version.
+ //
+ // To recap, a Fedora package version has the following form:
+ //
+ // [<epoch>:]<version>-<release>
+ //
+ // Where <release> has the following form:
+ //
+ // <release-number>[.<distribution-tag>]
+ //
+ // For details on the ordering semantics, see the Fedora Versioning
+ // Guidelines. While overall unsurprising, the only notable exceptions are
+ // `~`, which sorts before anything else and is commonly used for upstream
+ // pre-releases, and '^', which sorts after anything else and is
+ // supposedly used for upstream post-release snapshots. For example,
+ // 0.1.0~alpha.1-1.fc35 sorts earlier than 0.1.0-1.fc35.
+ //
+ // Ok, so how do we map our version to that? To recap, the bpkg version
+ // has the following form:
+ //
+ // [+<epoch>-]<upstream>[-<prerel>][+<revision>]
+ //
+ // Let's start with the case where neither distribution nor upstream
+ // version is specified and we need to derive everything from the bpkg
+ // version.
+ //
+ // <epoch>
+ //
+ // On one hand, if we keep the epoch, it won't necessarily match
+ // Fedora's native package epoch. But on the other it will allow our
+ // binary packages from different epochs to co-exist. Seeing that this
+ // can be easily overridden with a custom distribution version, let's
+ // keep it.
+ //
+ // Note that while the Fedora start/default epoch is 0, ours is 1 (we
+ // use the 0 epoch for stub packages). So we will need to shift this
+ // value range.
+ //
+ //
+ // <upstream>[-<prerel>]
+ //
+ // Our upstream version maps naturally to Fedora's <version>. That is,
+ // our upstream version format/semantics is a subset of Fedora's
+ // <version>.
+ //
+ // If this is a pre-release, then we could fail (that is, don't allow
+ // pre-releases) but then we won't be able to test on pre-release
+ // packages, for example, to make sure the name mapping is correct.
+ // Plus sometimes it's useful to publish pre-releases. We could ignore
+ // it, but then such packages will be indistinguishable from each other
+ // and the final release, which is not ideal. On the other hand, Fedora
+ // has the mechanism (`~`) which is essentially meant for this, so let's
+ // use it. We will use <prerel> as is since its format is the same as
+ // <upstream> and thus should map naturally.
+ //
+ //
+ // <revision>
+ //
+ // Similar to epoch, our revision won't necessarily match Fedora's
+ // native package release number. But on the other hand it will allow us
+ // to establish a correspondence between source and binary packages.
+ // Plus, upgrades between binary package releases will be handled
+ // naturally. Also note that the revision is mandatory in Fedora.
+ // Seeing that we allow overriding the releases with a custom
+ // distribution version (see below), let's use it.
+ //
+ // Note that the Fedora start release number is 1 and our revision is
+ // 0. So we will need to shift this value range.
+ //
+ // Another related question is whether we should do anything about the
+ // distribution tag (.fc35, .el8, etc). Given that the use of hardcoded
+ // distribution tags in RPM spec files is strongly discouraged we will
+ // just rely on the standard approach to include the appropriate tag
+ // (while allowing the user to redefine it with an option). Note that
+ // the distribution tag is normally specified for the Release and
+ // Requires directives using the %{?dist} macro expansion and can be
+ // left unspecified for the Requires directive. For example:
+ //
+ // Name: curl
+ // Version: 7.87.0
+ // Release: 1%{?dist}
+ // Requires: libcurl%{?_isa} >= %{version}-%{release}
+ // %global libpsl_version 1.2.3
+ // Requires: libpsl%{?_isa} >= %{libpsl_version}
+ //
+ // The next case to consider is when we have the upstream version
+ // (upstream-version manifest value). After some rumination it feels
+ // correct to use it in place of the <epoch>-<upstream> components in the
+ // above mapping (upstream version itself cannot have epoch). In other
+ // words, we will add the pre-release and revision components from the
+ // bpkg version. If this is not the desired semantics, then it can always
+ // be overrided with the distribution version.
+ //
+ // Finally, we have the distribution version. The <epoch> and <version>
+ // components are straightforward: they should be specified by the
+ // distribution version as required. This leaves pre-release and
+ // release. It feels like in most cases we would want these copied over
+ // from the bpkg version automatically -- it's too tedious and error-
+ // prone to maintain them manually. However, we want the user to have the
+ // full override ability. So instead, if empty release is specified, as in
+ // 1.2.3-, then we automatically add bpkg revision. Similarly, if empty
+ // pre-release is specified, as in 1.2.3~, then we add bpkg pre-release.
+ // To add both automatically, we would specify 1.2.3~- (other combinations
+ // are 1.2.3~b.1- and 1.2.3~-1). If specified, the release must not
+ // contain the distribution tag, since it is deduced automatically using
+ // the %{?dist} macro expansion if required. Also, since the release
+ // component is mandatory in Fedora, if it is omitted together with the
+ // separating dash we will add the release 1 automatically.
+ //
+ // Note also that per the RPM spec file format documentation neither
+ // version nor release components may contain `:` or `-`. Note that the
+ // bpkg upstream version may not contain either.
+ //
+ string& sv (r.system_version);
+
+ if (optional<string> ov = system_package_version (ap,
+ rf,
+ os_release.name_id,
+ os_release.version_id,
+ os_release.like_ids))
+ {
+ string& dv (*ov);
+ size_t n (dv.size ());
+
+ // Find the package release and upstream pre-release positions, if any.
+ //
+ size_t rp (dv.rfind ('-'));
+ size_t pp (dv.rfind ('~', rp));
+
+ // Copy over the [<epoch>:]<version> part.
+ //
+ sv.assign (dv, 0, pp < rp ? pp : rp);
+
+ // Add pre-release copying over the bpkg version value if empty.
+ //
+ if (pp != string::npos)
+ {
+ if (size_t pn = (rp != string::npos ? rp : n) - (pp + 1))
+ {
+ sv.append (dv, pp, pn + 1);
+ }
+ else
+ {
+ if (pv.release)
+ {
+ assert (!pv.release->empty ()); // Cannot be earliest special.
+ sv += '~';
+ sv += *pv.release;
+ }
+ }
+ }
+
+ // Add release copying over the bpkg version revision if empty.
+ //
+ if (rp != string::npos)
+ {
+ if (size_t rn = n - (rp + 1))
+ {
+ sv.append (dv, rp, rn + 1);
+ }
+ else
+ {
+ sv += '-';
+ sv += to_string (pv.revision ? *pv.revision + 1 : 1);
+ }
+ }
+ else
+ sv += "-1"; // Default to 1 since the release is mandatory.
+ }
+ else
+ {
+ if (ap->upstream_version)
+ {
+ const string& uv (*ap->upstream_version);
+
+ // Make sure the upstream version doesn't contain ':' and '-'
+ // characters since they are not allowed in the <version> component
+ // (see the RPM spec file format documentation for details).
+ //
+ // Note that this verification is not exhaustive and here we only make
+ // sure that these characters are only used to separate the version
+ // components.
+ //
+ size_t p (uv.find (":-"));
+ if (p != string::npos)
+ fail << "'" << uv[p] << "' character in upstream-version manifest "
+ << "value " << uv << " of package " << pn << ' '
+ << ap->version <<
+ info << "consider specifying explicit " << os_release.name_id
+ << " version mapping in " << pn << " package manifest";
+
+ sv += uv;
+ }
+ else
+ {
+ // Add epoch unless maps to 0.
+ //
+ assert (pv.epoch != 0); // Cannot be a stub.
+ if (pv.epoch != 1)
+ {
+ sv = to_string (pv.epoch - 1);
+ sv += ':';
+ }
+
+ sv += pv.upstream;
+ }
+
+ // Add pre-release.
+ //
+ if (pv.release)
+ {
+ assert (!pv.release->empty ()); // Cannot be earliest special.
+ sv += '~';
+ sv += *pv.release;
+ }
+
+ // Add revision.
+ //
+ sv += '-';
+ sv += to_string (pv.revision ? *pv.revision + 1 : 1);
+ }
+
+ return r;
+ }
+
+ // Evaluate the specified expressions expanding the contained macros by
+ // executing `rpm --eval <expr1> --eval <expr2>...` and return the list of
+ // the resulting lines read from the process stdout. Note that an expression
+ // may potentially end up with multiple lines which the caller is expected
+ // to deal with (ensure fixed number of lines, eval only one expression,
+ // etc).
+ //
+ strings system_package_manager_fedora::
+ rpm_eval (const cstrings& opts, const cstrings& expressions)
+ {
+ strings r;
+
+ if (expressions.empty ())
+ return r;
+
+ cstrings args;
+ args.reserve (2 + opts.size () + expressions.size () * 2);
+
+ args.push_back ("rpm");
+
+ for (const char* o: opts)
+ args.push_back (o);
+
+ for (const char* e: expressions)
+ {
+ args.push_back ("--eval");
+ args.push_back (e);
+ }
+
+ args.push_back (nullptr);
+
+ try
+ {
+ process_path pp (process::path_search (args[0]));
+ process_env pe (pp);
+
+ if (verb >= 3)
+ print_process (pe, args);
+
+ process pr (pp, args, -2 /* stdin */, -1 /* stdout */, 2);
+
+ try
+ {
+ ifdstream is (move (pr.in_ofd), fdstream_mode::skip, ifdstream::badbit);
+
+ // The number of lines is normally equal to or greater than the number
+ // of expressions.
+ //
+ r.reserve (expressions.size ());
+
+ for (string l; !eof (getline (is, l)); )
+ r.push_back (move (l));
+
+ is.close ();
+ }
+ catch (const io_error& e)
+ {
+ if (pr.wait ())
+ fail << "unable to read " << args[0] << " --eval output: " << e;
+
+ // Fall through.
+ }
+
+ if (!pr.wait ())
+ {
+ diag_record dr (fail);
+ dr << args[0] << " exited with non-zero code";
+
+ if (verb < 3)
+ {
+ dr << info << "command line: ";
+ print_process (dr, pe, args);
+ }
+ }
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e;
+
+ if (e.child)
+ exit (1);
+
+ throw failed ();
+ }
+
+ return r;
+ }
+
+ // Some background on creating Fedora packages (for a bit more detailed
+ // overview see the RPM Packaging Guide).
+ //
+ // An RPM package consists of the cpio archive, which contains the package
+ // files plus the RPM header file with metadata about the package. The RPM
+ // package manager uses this metadata to determine dependencies, where to
+ // install files, and other information. There are two types of RPM
+ // packages: source RPM and binary RPM. A source RPM contains source code,
+ // optionally patches to apply, and the spec file, which describes how to
+ // build the source code into a binary RPM. A binary RPM contains the
+ // binaries built from the sources package. While it's possible to create
+ // the package completely manually without using any of the Fedora tools, we
+ // are not going to go this route (see reasons mentioned in the Debian
+ // implementation for the list of issues with this approach).
+ //
+ // Based on this our plan is to produce an RPM spec file and then invoke
+ // rpmbuild to produce the binary package from that. While this approach is
+ // normally used to build things from source, it feels like we should be
+ // able to pretend that we are. Specifially, we can implement the %install
+ // section of the spec file to invoke the build system and install all the
+ // packages directly from their bpkg locations.
+ //
+ // Note that the -debuginfo sub-packages are generated by default and all we
+ // need to do from our side is to compile with debug information (-g),
+ // failed which we get a warning from rpmbuild. We will also disable
+ // generating the -debugsource sub-packages since that would require to set
+ // up the source files infrastructure in the ~/rpmbuild/BUILD/ directory,
+ // which feels too hairy for now.
+ //
+ // Note: this setup requires rpmdevtools (rpmdev-setuptree) and its
+ // dependency rpm-build and rpm packages.
+ //
+ auto system_package_manager_fedora::
+ generate (const packages& pkgs,
+ const packages& deps,
+ const strings& vars,
+ const dir_path& cfg_dir,
+ const package_manifest& pm,
+ const string& pt,
+ const small_vector<language, 1>& langs,
+ optional<bool> recursive_full,
+ bool /* first */) -> binary_files
+ {
+ tracer trace ("system_package_manager_fedora::generate");
+
+ assert (!langs.empty ()); // Should be effective.
+
+ const shared_ptr<selected_package>& sp (pkgs.front ().selected);
+ const package_name& pn (sp->name);
+ const version& pv (sp->version);
+
+ // Use version without iteration in paths, etc.
+ //
+ string pvs (pv.string (false /* ignore_revision */,
+ true /* ignore_iteration */));
+
+ const available_packages& aps (pkgs.front ().available);
+
+ bool lib (pt == "lib");
+ bool priv (ops_->private_ ()); // Private installation.
+
+ // For now we only know how to handle libraries with C-common interface
+ // languages. But we allow other implementation languages.
+ //
+ if (lib)
+ {
+ for (const language& l: langs)
+ if (!l.impl && l.name != "c" && l.name != "c++" && l.name != "cc")
+ fail << l.name << " libraries are not yet supported";
+ }
+
+ // Return true if this package uses the specified language, only as
+ // interface language if intf_only is true.
+ //
+ auto lang = [&langs] (const char* n, bool intf_only = false) -> bool
+ {
+ return find_if (langs.begin (), langs.end (),
+ [n, intf_only] (const language& l)
+ {
+ return (!intf_only || !l.impl) && l.name == n;
+ }) != langs.end ();
+ };
+
+ // As a first step, figure out the system names and version of the package
+ // we are generating and all the dependencies, diagnosing anything fishy.
+ // If the main package is not present for a dependency, then set the main
+ // package name to an empty string.
+ //
+ // Note that there should be no duplicate dependencies and we can sidestep
+ // the status cache.
+ //
+ package_status st (map_package (pn, pv, aps));
+
+ vector<package_status> sdeps;
+ sdeps.reserve (deps.size ());
+ for (const package& p: deps)
+ {
+ const shared_ptr<selected_package>& sp (p.selected);
+ const available_packages& aps (p.available);
+
+ package_status s;
+ if (sp->substate == package_substate::system)
+ {
+ // Note that for a system dependency the main package name is already
+ // empty if it is not present in the distribution.
+ //
+ optional<package_status> os (status (sp->name, aps));
+
+ if (!os || os->status != package_status::installed)
+ fail << os_release.name_id << " package for " << sp->name
+ << " system package is no longer installed";
+
+ // For good measure verify the mapped back version still matches
+ // configured. Note that besides the normal case (queried by the
+ // system package manager), it could have also been specified by the
+ // user as an actual version or a wildcard. Ignoring this check for a
+ // wildcard feels consistent with the overall semantics.
+ //
+ if (sp->version != wildcard_version && sp->version != os->version)
+ {
+ fail << "current " << os_release.name_id << " package version for "
+ << sp->name << " system package does not match configured" <<
+ info << "configured version: " << sp->version <<
+ info << "current version: " << os->version << " ("
+ << os->system_version << ')';
+ }
+
+ s = move (*os);
+
+ // Note that the system version retrieved with status() likely
+ // contains the distribution tag in its release component. We,
+ // however, don't want it to ever be mentioned in the spec file and so
+ // just strip it right away. This will also make it consistent with
+ // the non-system dependencies.
+ //
+ string& v (s.system_version);
+ size_t p (v.find_last_of ("-."));
+ assert (p != string::npos); // The release is mandatory.
+
+ if (v[p] == '.')
+ v.resize (p);
+ }
+ else
+ {
+ s = map_package (sp->name, sp->version, aps);
+
+ // Set the main package name to an empty string if we wouldn't be
+ // generating the main package for this dependency (binless library
+ // without the -common sub-package).
+ //
+ assert (aps.size () == 1);
+
+ const optional<string>& t (aps.front ().first->type);
+
+ if (s.common.empty () &&
+ package_manifest::effective_type (t, sp->name) == "lib")
+ {
+ strings sos (package_manifest::effective_type_sub_options (t));
+
+ if (find (sos.begin (), sos.end (), "binless") != sos.end ())
+ s.main.clear ();
+ }
+ }
+
+ sdeps.push_back (move (s));
+ }
+
+ // We only allow the standard -debug* sub-package names.
+ //
+ if (!st.debuginfo.empty () && st.debuginfo != st.main + "-debuginfo")
+ fail << "generation of -debuginfo packages with custom names not "
+ << "supported" <<
+ info << "use " << st.main << "-debuginfo name instead";
+
+ if (!st.debugsource.empty () && st.debuginfo != st.main + "-debugsource")
+ fail << "generation of -debugsource packages with custom names not "
+ << "supported" <<
+ info << "use " << st.main << "-debugsource name instead";
+
+ // Prepare the common extra options that need to be passed to both
+ // rpmbuild and rpm.
+ //
+ strings common_opts {"--target", arch};
+
+ // Add the dist macro (un)definition if --fedora-dist-tag is specified.
+ //
+ if (ops_->fedora_dist_tag_specified ())
+ {
+ string dist (ops_->fedora_dist_tag ());
+
+ if (!dist.empty ())
+ {
+ bool f (dist.front () == '+');
+ bool b (dist.back () == '+');
+
+ if (f && b) // Note: covers just `+`.
+ fail << "invalid distribution tag '" << dist << "'";
+
+ // If the distribution tag is specified with a leading/trailing '+',
+ // then we query the default tag value and modify it using the
+ // specified suffix/prefix.
+ //
+ // Note that we rely on the fact that the dist tag doesn't depend on
+ // the --target option which we also pass to rpmbuild.
+ //
+ if (f || b)
+ {
+ string affix (move (dist));
+ strings expansions (rpm_eval (cstrings (), cstrings {"%{?dist}"}));
+
+ if (expansions.size () != 1)
+ fail << "one line expected as an expansion of macro %{?dist}";
+
+ dist = move (expansions[0]);
+
+ // Normally, the default distribution tag starts with the dot, in
+ // which case we insert the prefix after it. Note, however, that the
+ // tag can potentially be re/un-defined (for example in
+ // ~/.rpmmacros), so we need to also handle the potential absence of
+ // the leading dot inserting the prefix right at the beginning in
+ // this case.
+ //
+ if (f)
+ dist.append (affix, 1, affix.size () - 1);
+ else
+ dist.insert (dist[0] == '.' ? 1 : 0, affix, 0, affix.size () - 1);
+ }
+ else
+ {
+ // Insert the leading dot into the distribution tag if missing.
+ //
+ if (dist.front () != '.')
+ dist.insert (dist.begin (), '.');
+ }
+
+ common_opts.push_back ("--define=dist " + dist);
+ }
+ else
+ common_opts.push_back ("--define=dist %{nil}");
+ }
+
+ // Evaluate the specified expressions expanding the contained macros. Make
+ // sure these macros are expanded to the same values as if used in the
+ // being generated spec file.
+ //
+ // Note that %{_docdir} and %{_licensedir} macros are set internally by
+ // rpmbuild (may depend on DocDir spec file directive, etc which we will
+ // not use) and thus cannot be queried with `rpm --eval` out of the
+ // box. To allow using these macros in the expressions, we provide their
+ // definitions to their default values on the command line.
+ //
+ auto eval = [&common_opts, this] (const cstrings& expressions)
+ {
+ cstrings opts;
+ opts.reserve (common_opts.size () +
+ 2 +
+ ops_->fedora_query_option ().size ());
+
+ // Pass the rpmbuild/rpm common options.
+ //
+ for (const string& o: common_opts)
+ opts.push_back (o.c_str ());
+
+ // Pass the %{_docdir} and %{_licensedir} macro definitions.
+ //
+ opts.push_back ("--define=_docdir %{_defaultdocdir}");
+ opts.push_back ("--define=_licensedir %{_defaultlicensedir}");
+
+ // Pass any additional options specified by the user.
+ //
+ for (const string& o: ops_->fedora_query_option ())
+ opts.push_back (o.c_str ());
+
+ return rpm_eval (opts, expressions);
+ };
+
+ // We override every config.install.* variable in order not to pick
+ // anything configured. Note that we add some more in the spec file below.
+ //
+ // We make use of the <project> substitution since in the recursive mode
+ // we may be installing multiple projects. Note that the <private>
+ // directory component is automatically removed if this functionality is
+ // not enabled. One side-effect of using <project> is that we will be
+ // using the bpkg package name instead of the Fedora package name. But
+ // perhaps that's correct: while in Fedora the source package name (which
+ // is the same as the main binary package name) does not necessarily
+ // correspond to the "logical" package name, we still want to use the
+ // logical name (consider libsqlite3 which is mapped to sqlite-libs and
+ // sqlite-devel; we don't want <project> to be sqlite-libs). To keep
+ // things consistent we use the bpkg package name for <private> as well.
+ //
+ // Let's only use those directory macros which we can query with `rpm
+ // --eval` (see eval() lambda for details). Note that this means our
+ // installed_entries paths (see below) may not correspond exactly to where
+ // things will actually be installed during rpmbuild. But that shouldn't
+ // be an issue since we make sure to never use these paths directly in the
+ // spec file (always using macros instead).
+ //
+ // NOTE: make sure to update the expressions evaluation and the %files
+ // sections below if changing anything here.
+ //
+ strings config {
+ "config.install.root=%{_prefix}/",
+ "config.install.data_root=%{_exec_prefix}/",
+ "config.install.exec_root=%{_exec_prefix}/",
+
+ "config.install.bin=%{_bindir}/",
+ "config.install.sbin=%{_sbindir}/",
+
+ // On Fedora shared libraries should be executable.
+ //
+ "config.install.lib=%{_libdir}/<private>/",
+ "config.install.lib.mode=755",
+ "config.install.libexec=%{_libexecdir}/<private>/<project>/",
+ "config.install.pkgconfig=lib/pkgconfig/",
+
+ "config.install.etc=%{_sysconfdir}/",
+ "config.install.include=%{_includedir}/<private>/",
+ "config.install.include_arch=include/",
+ "config.install.share=%{_datadir}/",
+ "config.install.data=share/<private>/<project>/",
+ "config.install.buildfile=share/build2/export/<project>/",
+
+ "config.install.doc=%{_docdir}/<private>/<project>/",
+ "config.install.legal=%{_licensedir}/<private>/<project>/",
+ "config.install.man=%{_mandir}/",
+ "config.install.man1=man/man1/",
+ "config.install.man2=man/man2/",
+ "config.install.man3=man/man3/",
+ "config.install.man4=man/man4/",
+ "config.install.man5=man/man5/",
+ "config.install.man6=man/man6/",
+ "config.install.man7=man/man7/",
+ "config.install.man8=man/man8/"};
+
+ config.push_back ("config.install.private=" +
+ (priv ? pn.string () : "[null]"));
+
+ // Add user-specified configuration variables last to allow them to
+ // override anything.
+ //
+ for (const string& v: vars)
+ config.push_back (v);
+
+ // Note that we need to expand macros in the configuration variables
+ // before passing them to the below installed_entries() call.
+ //
+ // Also note that we expand the variables passed on the command line as
+ // well. While this can be useful, it can also be surprising. However, it
+ // is always possible to escape the '%' character which introduces the
+ // macro expansion, which in most cases won't be necessary since an
+ // undefined macro expansion is preserved literally.
+ //
+ // While at it, also obtain some other information that we will need down
+ // the road.
+ //
+ strings expansions;
+
+ // Installed entry directories for sorting out the installed files into
+ // the %files sections of the sub-packages.
+ //
+ // We put exported buildfiles into the main package, which makes sense
+ // after some meditation: they normally contain rules and are bundled
+ // either with a tool (say, thrift), a module (say, libbuild2-thrift), or
+ // an add-on package (say, thrift-build2).
+ //
+ dir_path bindir;
+ dir_path sbindir;
+ dir_path libexecdir;
+ dir_path confdir;
+ dir_path incdir;
+ dir_path bfdir;
+ dir_path libdir;
+ dir_path pkgdir; // Not queried, set as libdir/pkgconfig/.
+ dir_path sharedir;
+ dir_path docdir;
+ dir_path mandir;
+ dir_path licensedir;
+ dir_path build2dir;
+
+ // Note that the ~/rpmbuild/{.,BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
+ // directory paths used by rpmbuild are actually defined as the
+ // %{_topdir}, %{_builddir}, %{_buildrootdir}, %{_rpmdir}, %{_sourcedir},
+ // %{_specdir}, and %{_srcrpmdir} RPM macros. These macros can potentially
+ // be redefined in RPM configuration files, in particular, in
+ // ~/.rpmmacros.
+ //
+ dir_path topdir; // ~/rpmbuild/
+ dir_path specdir; // ~/rpmbuild/SPECS/
+
+ // RPM file absolute path template.
+ //
+ // Note that %{_rpmfilename} normally expands as the following template:
+ //
+ // %{ARCH}/%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm
+ //
+ string rpmfile;
+ {
+ cstrings expressions;
+ expressions.reserve (config.size () + 13);
+
+ for (const string& c: config)
+ expressions.push_back (c.c_str ());
+
+ expressions.push_back ("%{?_bindir}");
+ expressions.push_back ("%{?_sbindir}");
+ expressions.push_back ("%{?_libexecdir}");
+ expressions.push_back ("%{?_sysconfdir}");
+ expressions.push_back ("%{?_includedir}");
+ expressions.push_back ("%{?_libdir}");
+ expressions.push_back ("%{?_datadir}");
+ expressions.push_back ("%{?_docdir}");
+ expressions.push_back ("%{?_mandir}");
+ expressions.push_back ("%{?_licensedir}");
+
+ expressions.push_back ("%{?_topdir}");
+ expressions.push_back ("%{?_specdir}");
+
+ expressions.push_back ("%{_rpmdir}/%{_rpmfilename}");
+
+ // Note that we rely on the fact that these macros are defined while
+ // refer to them in the spec file, etc. Thus, let's verify that and fail
+ // early if that's not the case for whatever reason.
+ //
+ expressions.push_back ("%{?_rpmdir}");
+ expressions.push_back ("%{?_rpmfilename}");
+ expressions.push_back ("%{?_usrsrc}");
+ expressions.push_back ("%{?buildroot}");
+
+ // Note that if the architecture passed with the --target option is
+ // invalid, then rpmbuild will fail with some ugly diagnostics since
+ // %{_arch} macro stays unexpanded in some commands executed by
+ // rpmbuild. Thus, let's verify that the architecture is recognized by
+ // rpmbuild and fail early if that's not the case.
+ //
+ expressions.push_back ("%{?_arch}");
+
+ expansions = eval (expressions);
+
+ // Shouldn't happen unless some paths contain newlines, which we don't
+ // care about.
+ //
+ if (expansions.size () != expressions.size ())
+ fail << "number of RPM directory path expansions differs from number "
+ << "of path expressions";
+
+ // Pop the string/directory expansions.
+ //
+ auto pop_string = [&expansions, &expressions] ()
+ {
+ assert (!expansions.empty ());
+
+ string r (move (expansions.back ()));
+
+ if (r.empty ())
+ fail << "macro '" << expressions.back () << "' expands into empty "
+ << "string";
+
+ expansions.pop_back ();
+ expressions.pop_back ();
+ return r;
+ };
+
+ auto pop_path = [&expansions, &expressions] ()
+ {
+ assert (!expansions.empty ());
+
+ try
+ {
+ path r (move (expansions.back ()));
+
+ if (r.empty ())
+ fail << "macro '" << expressions.back () << "' expands into empty "
+ << "path";
+
+ expansions.pop_back ();
+ expressions.pop_back ();
+ return r;
+ }
+ catch (const invalid_path& e)
+ {
+ fail << "macro '" << expressions.back () << "' expands into invalid "
+ << "path '" << e.path << "'" << endf;
+ }
+ };
+
+ auto pop_dir = [&pop_path] ()
+ {
+ return path_cast<dir_path> (pop_path ());
+ };
+
+ // The source of a potentially invalid architecture is likely to be the
+ // --architecture option specified by the user. But can probably also be
+ // some mis-configuration.
+ //
+ if (expansions.back ().empty ()) // %{?_arch}
+ fail << "unknown target architecture '" << arch << "'";
+
+ // We only need the following macro expansions for the verification.
+ //
+ pop_string (); // %{?_arch}
+ pop_dir (); // %{?buildroot}
+ pop_dir (); // %{?_usrsrc}
+ pop_string (); // %{?_rpmfilename}
+ pop_dir (); // %{?_rpmdir}
+
+ rpmfile = pop_string ();
+ specdir = pop_dir ();
+ topdir = pop_dir ();
+
+ // Let's tighten things up and only look for the installed files in
+ // <private>/ (if specified) to make sure there is nothing stray.
+ //
+ dir_path pd (priv ? pn.string () : "");
+
+ licensedir = pop_dir () / pd;
+ mandir = pop_dir ();
+ docdir = pop_dir () / pd;
+ sharedir = pop_dir ();
+ build2dir = sharedir / dir_path ("build2");
+ bfdir = build2dir / dir_path ("export");
+ sharedir /= pd;
+ libdir = pop_dir () / pd;
+ pkgdir = libdir / dir_path ("pkgconfig");
+ incdir = pop_dir () / pd;
+ confdir = pop_dir ();
+ libexecdir = pop_dir () / pd;
+ sbindir = pop_dir ();
+ bindir = pop_dir ();
+
+ // Only configuration variables expansions must remain.
+ //
+ assert (expansions.size () == config.size ());
+ }
+
+ // Note that the conventional place for all the inputs and outputs of the
+ // rpmbuild operations is the directory tree rooted at ~/rpmbuild/. We
+ // won't fight with rpmbuild and will use this tree as the user would
+ // do while creating the binary package manually.
+ //
+ // Specifially, we will create the RPM spec file in ~/rpmbuild/SPECS/,
+ // install the package(s) under the ~/rpmbuild/BUILDROOT/<package-dir>/
+ // chroot, and expect the generated RPM files under ~/rpmbuild/RPMS/.
+ //
+ // That, in particular, means that we have no use for the --output-root
+ // directory. We will also make sure that we don't overwrite an existing
+ // RPM spec file unless --wipe-output is specified.
+ //
+ if (ops_->output_root_specified () && ops_->output_root () != topdir)
+ fail << "--output-root|-o must be " << topdir << " if specified";
+
+ // Note that in Fedora the Name spec file directive names the source
+ // package as well as the main binary package and the spec file should
+ // match this name.
+ //
+ // @@ TODO (maybe/later): it's unclear whether it's possible to rename
+ // the main binary package. Maybe makes sense to investigate if/when
+ // we decide to generate source packages.
+ //
+ path spec (specdir / (st.main + ".spec"));
+
+ if (exists (spec) && !ops_->wipe_output ())
+ fail << "RPM spec file " << spec << " already exists" <<
+ info << "use --wipe-output to remove but be careful";
+
+ // Note that we can use weak install scope for the auto recursive mode
+ // since we know dependencies cannot be spread over multiple linked
+ // configurations.
+ //
+ string scope (!recursive_full || *recursive_full ? "project" : "weak");
+
+ // Get the map of files that will end up in the binary packages.
+ //
+ installed_entry_map ies (
+ installed_entries (*ops_, pkgs, expansions, scope));
+
+ if (ies.empty ())
+ fail << "specified package(s) do not install any files";
+
+ if (verb >= 4)
+ {
+ for (const auto& p: ies)
+ {
+ diag_record dr (trace);
+ dr << "installed entry: " << p.first;
+
+ if (p.second.target != nullptr)
+ dr << " -> " << p.second.target->first; // Symlink.
+ else
+ dr << ' ' << p.second.mode;
+ }
+ }
+
+ // As an optimization, don't generate the main and -debug* packages for a
+ // binless library unless it also specifies the -common sub-package.
+ //
+ // If this is a binless library, then verify that it doesn't install any
+ // executable, library, or configuration files. Also verify that it has
+ // the -devel sub-package but doesn't specify the -static sub-package.
+ //
+ bool binless (false);
+
+ if (lib)
+ {
+ assert (aps.size () == 1);
+
+ const shared_ptr<available_package>& ap (aps.front ().first);
+ strings sos (package_manifest::effective_type_sub_options (ap->type));
+
+ if (find (sos.begin (), sos.end (), "binless") != sos.end ())
+ {
+ // Verify installed files.
+ //
+ auto bad_install = [&pn, &pv] (const string& w)
+ {
+ fail << "binless library " << pn << ' ' << pv << " installs " << w;
+ };
+
+ auto verify_not_installed = [&ies, &bad_install] (const dir_path& d)
+ {
+ auto p (ies.find_sub (d));
+ if (p.first != p.second)
+ bad_install (p.first->first.string ());
+ };
+
+ verify_not_installed (bindir);
+ verify_not_installed (sbindir);
+ verify_not_installed (libexecdir);
+
+ // It would probably be better not to fail here but generate the main
+ // package instead (as we do if the -common sub-package is also being
+ // generated). Then, however, it would not be easy to detect if a
+ // dependency has the main package or not (see sdeps initialization
+ // for details).
+ //
+ verify_not_installed (confdir);
+
+ for (auto p (ies.find_sub (libdir)); p.first != p.second; ++p.first)
+ {
+ const path& f (p.first->first);
+
+ if (!f.sub (pkgdir))
+ bad_install (f.string ());
+ }
+
+ // Verify sub-packages.
+ //
+ if (st.devel.empty ())
+ fail << "binless library " << pn << ' ' << pv << " doesn't have "
+ << os_release.name_id << " -devel package";
+
+ if (!st.static_.empty ())
+ fail << "binless library " << pn << ' ' << pv << " has "
+ << os_release.name_id << ' ' << st.static_ << " package";
+
+ binless = true;
+ }
+ }
+
+ bool gen_main (!binless || !st.common.empty ());
+
+ // If we don't generate the main package (and thus the -common
+ // sub-package), then fail if there are any data files installed. It would
+ // probably be better not to fail but generate the main package instead in
+ // this case. Then, however, it would not be easy to detect if a
+ // dependency has the main package or not.
+ //
+ if (!gen_main)
+ {
+ for (auto p (ies.find_sub (sharedir)); p.first != p.second; ++p.first)
+ {
+ const path& f (p.first->first);
+
+ if (!f.sub (docdir) && !f.sub (mandir) && !f.sub (licensedir))
+ {
+ fail << "binless library " << pn << ' ' << pv << " installs " << f <<
+ info << "consider specifying -common package in explicit "
+ << os_release.name_id << " name mapping in package manifest";
+ }
+ }
+
+ for (auto p (ies.find_sub (bfdir)); p.first != p.second; ++p.first)
+ {
+ const path& f (p.first->first);
+
+ fail << "binless library " << pn << ' ' << pv << " installs " << f <<
+ info << "consider specifying -common package in explicit "
+ << os_release.name_id << " name mapping in package manifest";
+ }
+ }
+
+ if (verb >= 3)
+ {
+ auto print_status = [] (diag_record& dr,
+ const package_status& s,
+ const string& main)
+ {
+ dr << (main.empty () ? "" : " ") << main
+ << (s.devel.empty () ? "" : " ") << s.devel
+ << (s.static_.empty () ? "" : " ") << s.static_
+ << (s.doc.empty () ? "" : " ") << s.doc
+ << (s.debuginfo.empty () ? "" : " ") << s.debuginfo
+ << (s.debugsource.empty () ? "" : " ") << s.debugsource
+ << (s.common.empty () ? "" : " ") << s.common
+ << ' ' << s.system_version;
+ };
+
+ {
+ diag_record dr (trace);
+ dr << "package:";
+ print_status (dr, st, gen_main ? st.main : empty_string);
+ }
+
+ for (const package_status& s: sdeps)
+ {
+ diag_record dr (trace);
+ dr << "dependency:";
+ print_status (dr, s, s.main);
+ }
+ }
+
+ // Prepare the data for the RPM spec file.
+ //
+ // Url directive.
+ //
+ string url (pm.package_url ? pm.package_url->string () :
+ pm.url ? pm.url->string () :
+ string ());
+
+ // Packager directive.
+ //
+ string packager;
+ if (ops_->fedora_packager_specified ())
+ {
+ packager = ops_->fedora_packager ();
+ }
+ else
+ {
+ const email* e (pm.package_email ? &*pm.package_email :
+ pm.email ? &*pm.email :
+ nullptr);
+
+ if (e == nullptr)
+ fail << "unable to determine packager from manifest" <<
+ info << "specify explicitly with --fedora-packager";
+
+ // In certain places (e.g., %changelog), Fedora expect this to be in the
+ // `John Doe <john@example.org>` form while we often specify just the
+ // email address (e.g., to the mailing list). Try to detect such a case
+ // and complete it to the desired format.
+ //
+ if (e->find (' ') == string::npos && e->find ('@') != string::npos)
+ {
+ // Try to use comment as name, if any.
+ //
+ if (!e->comment.empty ())
+ {
+ packager = e->comment;
+
+ // Strip the potential trailing dot.
+ //
+ if (packager.back () == '.')
+ packager.pop_back ();
+ }
+ else
+ packager = pn.string () + " package maintainer";
+
+ packager += " <" + *e + '>';
+ }
+ else
+ packager = *e;
+ }
+
+ // Version, Release, and Epoch directives.
+ //
+ struct system_version
+ {
+ string epoch;
+ string version;
+ string release;
+ };
+
+ auto parse_system_version = [] (const string& v)
+ {
+ system_version r;
+
+ size_t e (v.find (':'));
+ if (e != string::npos)
+ r.epoch = string (v, 0, e);
+
+ size_t b (e != string::npos ? e + 1 : 0);
+ e = v.find ('-', b);
+ assert (e != string::npos); // Release is required.
+
+ r.version = string (v, b, e - b);
+
+ b = e + 1;
+ r.release = string (v, b);
+ return r;
+ };
+
+ system_version sys_version (parse_system_version (st.system_version));
+
+ // License directive.
+ //
+ // The directive value is a SPDX license expression. Note that the OR/AND
+ // operators must be specified in upper case and the AND operator has a
+ // higher precedence than OR.
+ //
+ string license;
+ for (const licenses& ls: pm.license_alternatives)
+ {
+ if (!license.empty ())
+ license += " OR ";
+
+ for (auto b (ls.begin ()), i (b); i != ls.end (); ++i)
+ {
+ if (i != b)
+ license += " AND ";
+
+ license += *i;
+ }
+ }
+
+ // Create the ~/rpmbuild directory tree if it doesn't exist yet.
+ //
+ if (!exists (topdir))
+ {
+ cstrings args {"rpmdev-setuptree", nullptr};
+
+ try
+ {
+ process_path pp (process::path_search (args[0]));
+ process_env pe (pp);
+
+ if (verb >= 3)
+ print_process (pe, args);
+
+ process pr (pp, args);
+
+ if (!pr.wait ())
+ {
+ diag_record dr (fail);
+ dr << args[0] << " exited with non-zero code";
+
+ if (verb < 3)
+ {
+ dr << info << "command line: ";
+ print_process (dr, pe, args);
+ }
+ }
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e;
+
+ if (e.child)
+ exit (1);
+
+ throw failed ();
+ }
+
+ // For good measure verify that ~/rpmbuild directory now exists.
+ //
+ if (!exists (topdir))
+ fail << "unable to create RPM build directory " << topdir;
+ }
+
+ // We cannot easily detect architecture-independent packages (think
+ // libbutl.bash) and providing an option feels like the best we can do.
+ // Note that the noarch value means architecture-independent and any other
+ // value means architecture-dependent.
+ //
+ const string& build_arch (ops_->fedora_build_arch_specified ()
+ ? ops_->fedora_build_arch ()
+ : empty_string);
+
+ // The RPM spec file.
+ //
+ // Note that we try to do a reasonably thorough job (e.g., using macros
+ // rather than hardcoding values, trying to comply with Fedora guidelines
+ // and recommendations, etc) with the view that this can be used as a
+ // starting point for manual packaging.
+ //
+ // NOTE: if changing anything here make sure that all the macros expanded
+ // in the spec file unconditionally are defined (see above how we do
+ // that for the _usrsrc macro as an example).
+ //
+ try
+ {
+ ofdstream os (spec);
+
+ // Note that Fedora Packaging Guidelines recommend to declare the
+ // package dependencies in the architecture-specific fashion using the
+ // %{?_isa} macro in the corresponding Requires directive (e.g.,
+ // `Requires: foo%{?_isa}` which would expand to something like
+ // `Requires: foo(x86-64)`). We, however, cannot easily detect if the
+ // distribution packages which correspond to the bpkg package
+ // dependencies are architecture-specific or not. Thus, we will generate
+ // the architecture-independent Requires directives for them which
+ // postpones the architecture resolution until the package installation
+ // time by dnf. We could potentially still try to guess if the
+ // dependency package is architecture-specific or not based on its
+ // languages, but let's keep it simple for now seeing that it's not a
+ // deal breaker.
+ //
+ // Also note that we will generate the architecture-specific
+ // dependencies on our own sub-packages, unless the --fedora-build-arch
+ // option has been specified, and for the C/C++ language related
+ // dependencies (glibc, etc). In other words, we will not try to craft
+ // the architecture specifier ourselves when we cannot use %{?_isa}.
+ //
+ string isa (build_arch.empty () ? "%{?_isa}" : "");
+
+ // Add the Requires directive(s), optionally separating them from the
+ // previous directives with an empty line.
+ //
+ auto add_requires = [&os] (bool& first, const string& v)
+ {
+ if (first)
+ {
+ os << '\n';
+ first = false;
+ }
+
+ os << "Requires: " << v << '\n';
+ };
+
+ auto add_requires_list = [&add_requires] (bool& first, const strings& vs)
+ {
+ for (const string& v: vs)
+ add_requires (first, v);
+ };
+
+ // Add the Requires directives for language dependencies of a
+ // sub-package. Deduce the language dependency packages (such as glibc,
+ // libstdc++, etc), unless they are specified explicitly via the
+ // --fedora-*-langreq options. If single option with an empty value is
+ // specified, then no language dependencies are added. The valid
+ // sub-package suffixes are '' (main package), '-devel', and '-static'.
+ //
+ auto add_lang_requires = [&lang, &add_requires, &add_requires_list]
+ (bool& first,
+ const string& suffix,
+ const strings& options,
+ bool intf_only = false)
+ {
+ if (!options.empty ())
+ {
+ if (options.size () != 1 || !options[0].empty ())
+ add_requires_list (first, options);
+ }
+ else
+ {
+ // Add dependency on libstdc++<suffix> and glibc<suffix> packages.
+ //
+ // It doesn't seems that the -static sub-package needs to define any
+ // default C/C++ language dependencies. That is a choice of the
+ // dependent packages which may want to link the standard libraries
+ // either statically or dynamically, so let's leave if for them to
+ // arrange.
+ //
+ if (suffix != "-static")
+ {
+ // If this is an undetermined C-common library, we assume it may
+ // be C++ (better to over- than under-specify).
+ //
+ bool cc (lang ("cc", intf_only));
+ if (cc || lang ("c++", intf_only))
+ add_requires (first, string ("libstdc++") + suffix + "%{?_isa}");
+
+ if (cc || lang ("c", intf_only))
+ add_requires (first, string ("glibc") + suffix + "%{?_isa}");
+ }
+ }
+ };
+
+ // We need to add the mandatory Summary and %description directives both
+ // for the main package and for the sub-packages. In the Summary
+ // directives we will use the `summary` package manifest value. In the
+ // %description directives we will just describe the sub-package content
+ // since using the `description` package manifest value is not going to
+ // be easy: it can be arbitrarily long and may not even be plain text
+ // (it's commonly the contents of the README.md file).
+ //
+ // We will disable automatic dependency discovery for all sub-packages
+ // using the `AutoReqProv: no` directive since we have an accurate set
+ // and some of them may not be system packages.
+ //
+
+ // The common information and the main package.
+ //
+ {
+ os << "Name: " << st.main << '\n'
+ << "Version: " << sys_version.version << '\n'
+ << "Release: " << sys_version.release << "%{?dist}" << '\n';
+
+ if (!sys_version.epoch.empty ())
+ os << "Epoch: " << sys_version.epoch << '\n';
+
+ os << "License: " << license << '\n'
+ << "Summary: " << pm.summary << '\n'
+ << "Url: " << url << '\n';
+
+ if (!packager.empty ())
+ os << "Packager: " << packager << '\n';
+
+#if 0
+ os << "#Source: https://pkg.cppget.org/1/???/"
+ << pm.effective_project () << '/' << sp->name << '-'
+ << sp->version << ".tar.gz" << '\n';
+#endif
+
+ // Idiomatic epoch-version-release value.
+ //
+ os << '\n'
+ << "%global evr %{?epoch:%{epoch}:}%{version}-%{release}" << '\n';
+
+ if (gen_main)
+ {
+ os << '\n'
+ << "# " << st.main << '\n'
+ << "#" << '\n';
+
+ if (!build_arch.empty ())
+ os << "BuildArch: " << build_arch << '\n';
+
+ os << "AutoReqProv: no" << '\n';
+
+ // Requires directives.
+ //
+ {
+ bool first (true);
+ if (!st.common.empty ())
+ add_requires (first, st.common + " = %{evr}");
+
+ for (const package_status& s: sdeps)
+ {
+ if (!s.main.empty ())
+ add_requires (first, s.main + " >= " + s.system_version);
+ }
+
+ add_lang_requires (first,
+ "" /* suffix */,
+ ops_->fedora_main_langreq ());
+
+ if (ops_->fedora_main_extrareq_specified ())
+ add_requires_list (first, ops_->fedora_main_extrareq ());
+ }
+ }
+
+ // Note that we need to add the %description directive regardless if
+ // the main package is being generated or not.
+ //
+ if (!binless)
+ {
+ os << '\n'
+ << "%description" << '\n'
+ << "This package contains the runtime files." << '\n';
+ }
+ else
+ {
+ os << '\n'
+ << "%description" << '\n'
+ << "This package contains the development files." << '\n';
+ }
+ }
+
+ // The -devel sub-package.
+ //
+ if (!st.devel.empty ())
+ {
+ os << '\n'
+ << "# " << st.devel << '\n'
+ << "#" << '\n'
+ << "%package -n " << st.devel << '\n'
+ << "Summary: " << pm.summary << '\n';
+
+ // Feels like the architecture should be the same as for the main
+ // package.
+ //
+ if (!build_arch.empty ())
+ os << "BuildArch: " << build_arch << '\n';
+
+ os << '\n'
+ << "AutoReqProv: no" << '\n';
+
+ // Requires directives.
+ //
+ {
+ bool first (true);
+
+ // Dependency on the main package.
+ //
+ if (gen_main)
+ add_requires (first, "%{name}" + isa + " = %{evr}");
+
+ for (const package_status& s: sdeps)
+ {
+ // Doesn't look like we can distinguish between interface and
+ // implementation dependencies here. So better to over- than
+ // under-specify.
+ //
+ // Note that if the -devel sub-package doesn't exist for a
+ // dependency, then its potential content may be part of the main
+ // package. If that's the case we, strictly speaking, should add
+ // the dependency on the main package. Let's, however, skip that
+ // since we already have this dependency implicitly via our own
+ // main package, which the -devel sub-package depends on.
+ //
+ if (!s.devel.empty ())
+ add_requires (first, s.devel + " >= " + s.system_version);
+ }
+
+ add_lang_requires (first,
+ "-devel",
+ ops_->fedora_devel_langreq (),
+ true /* intf_only */);
+
+ if (ops_->fedora_devel_extrareq_specified ())
+ add_requires_list (first, ops_->fedora_devel_extrareq ());
+ }
+
+ // If the -static sub-package is not being generated but there are
+ // some static libraries installed, then they will be added to the
+ // -devel sub-package. If that's the case, we add the
+ // `Provides: %{name}-static` directive for the -devel sub-package, as
+ // recommended.
+ //
+ // Should we do the same for the main package, where the static
+ // libraries go if the -devel sub-package is not being generated
+ // either? While it feels sensible, we've never seen such a practice
+ // or recommendation. So let's not do it for now.
+ //
+ if (st.static_.empty ())
+ {
+ for (auto p (ies.find_sub (libdir)); p.first != p.second; ++p.first)
+ {
+ const path& f (p.first->first);
+ path l (f.leaf (libdir));
+ const string& n (l.string ());
+
+ if (l.simple () &&
+ n.size () > 3 && n.compare (0, 3, "lib") == 0 &&
+ l.extension () == "a")
+ {
+ os << '\n'
+ << "Provides: %{name}-static" << isa << " = %{evr}" << '\n';
+
+ break;
+ }
+ }
+ }
+
+ os << '\n'
+ << "%description -n " << st.devel << '\n'
+ << "This package contains the development files." << '\n';
+ }
+
+ // The -static sub-package.
+ //
+ if (!st.static_.empty ())
+ {
+ os << '\n'
+ << "# " << st.static_ << '\n'
+ << "#" << '\n'
+ << "%package -n " << st.static_ << '\n'
+ << "Summary: " << pm.summary << '\n';
+
+ // Feels like the architecture should be the same as for the -devel
+ // sub-package.
+ //
+ if (!build_arch.empty ())
+ os << "BuildArch: " << build_arch << '\n';
+
+ os << '\n'
+ << "AutoReqProv: no" << '\n';
+
+ // Requires directives.
+ //
+ {
+ bool first (true);
+
+ // The static libraries without headers doesn't seem to be of any
+ // use. Thus, add dependency on the -devel or main sub-package, if
+ // not being generated.
+ //
+ // Note that if there is no -devel package, then this cannot be a
+ // binless library and thus the main package is being generated.
+ //
+ add_requires (
+ first,
+ (!st.devel.empty () ? st.devel : "%{name}") + isa + " = %{evr}");
+
+ // Add dependency on sub-packages that may contain static libraries.
+ // Note that in the -devel case we can potentially over-specify the
+ // dependency which is better than to under-specify.
+ //
+ for (const package_status& s: sdeps)
+ {
+ // Note that if the -static sub-package doesn't exist for a
+ // dependency, then its potential content may be part of the
+ // -devel sub-package, if exists, or the main package otherwise.
+ // If that's the case we, strictly speaking, should add the
+ // dependency on the -devel sub-package, if exists, or the main
+ // package otherwise. Let's, however, also consider the implicit
+ // dependencies via our own -devel and main (sub-)packages, which
+ // we depend on, and simplify things similar to what we do for the
+ // -devel sub-package above.
+ //
+ // Also note that we only refer to the dependency's -devel
+ // sub-package if we don't have our own -devel sub-package
+ // (unlikely, but possible), which would provide us with such an
+ // implicit dependency.
+ //
+ const string& p (!s.static_.empty () ? s.static_ :
+ st.devel.empty () ? s.devel :
+ empty_string);
+
+ if (!p.empty ())
+ add_requires (first, p + " >= " + st.system_version);
+ }
+
+ add_lang_requires (first, "-static", ops_->fedora_stat_langreq ());
+
+ if (ops_->fedora_stat_extrareq_specified ())
+ add_requires_list (first, ops_->fedora_stat_extrareq ());
+ }
+
+ os << '\n'
+ << "%description -n " << st.static_ << '\n'
+ << "This package contains the static libraries." << '\n';
+ }
+
+ // The -doc sub-package.
+ //
+ if (!st.doc.empty ())
+ {
+ os << '\n'
+ << "# " << st.doc << '\n'
+ << "#" << '\n'
+ << "%package -n " << st.doc << '\n'
+ << "Summary: " << pm.summary << '\n'
+ << "BuildArch: noarch" << '\n'
+ << '\n'
+ << "AutoReqProv: no" << '\n'
+ << '\n'
+ << "%description -n " << st.doc << '\n'
+ << "This package contains the documentation." << '\n';
+ }
+
+ // The -common sub-package.
+ //
+ if (!st.common.empty ())
+ {
+ // Generally, this sub-package is not necessarily architecture-
+ // independent (for example, it could contain something shared between
+ // multiple binary packages produced from the same source package
+ // rather than something shared between all the architectures of a
+ // binary package). But seeing that we always generate one binary
+ // package, for us it only makes sense as architecture-independent.
+ //
+ // It's also not clear what dependencies we can deduce for this
+ // sub-package. Assuming that it depends on all the dependency -common
+ // sub-packages is probably unreasonable.
+ //
+ os << '\n'
+ << "# " << st.common << '\n'
+ << "#" << '\n'
+ << "%package -n " << st.common << '\n'
+ << "Summary: " << pm.summary << '\n'
+ << "BuildArch: noarch" << '\n'
+ << '\n'
+ << "AutoReqProv: no" << '\n'
+ << '\n'
+ << "%description -n " << st.common << '\n'
+ << "This package contains the architecture-independent files." << '\n';
+ }
+
+ // Build setup.
+ //
+ {
+ bool lang_c (lang ("c"));
+ bool lang_cxx (lang ("c++"));
+ bool lang_cc (lang ("cc"));
+
+ os << '\n'
+ << "# Build setup." << '\n'
+ << "#" << '\n';
+
+ // The -debuginfo and -debugsource sub-packages.
+ //
+ // Note that the -debuginfo and -debugsource sub-packages are defined
+ // in the spec file by expanding the %{debug_package} macro (search
+ // the macro definition in `rpm --showrc` stdout for details). This
+ // expansion happens as part of the %install section processing but
+ // only if the %{buildsubdir} macro is defined. This macro refers to
+ // the package source subdirectory in the ~/rpmbuild/BUILD directory
+ // and is normally set by the %setup macro expansion in the %prep
+ // section which, in particular, extracts source files from an
+ // archive, defines the %{buildsubdir} macro, and make this directory
+ // current. Since we don't have an archive to extract, we will use the
+ // %setup macro disabling sources extraction (-T) and creating an
+ // empty source directory instead (-c). This directory is also used by
+ // rpmbuild for saving debuginfo-related intermediate files
+ // (debugfiles.list, etc). See "Fedora Debuginfo packages" and "Using
+ // RPM build flags" documentation for better understanding what's
+ // going on under the hood. There is also the "[Rpm-ecosystem] Trying
+ // to understand %buildsubdir and debuginfo generation" mailing list
+ // thread which provides some additional clarifications.
+ //
+ // Also note that we disable generating the -debugsource sub-packages
+ // (see the generate() description above for the reasoning).
+ //
+ // For a binless library no -debug* packages are supposed to be
+ // generated. Thus, we just drop their definitions by redefining the
+ // %{debug_package} macro as an empty string.
+ //
+ if (!binless)
+ {
+ os << "%undefine _debugsource_packages" << '\n';
+
+ // Append the -ffile-prefix-map option which is normally used to
+ // strip source file path prefix in debug information (besides other
+ // places). By default it is not used since rpmbuild replaces the
+ // recognized prefixes by using the debugedit program (see below for
+ // details) and we cannot rely on that since in our case the prefix
+ // (bpkg configuration directory) is not recognized. We need to
+ // replace the bpkg configuration directory prefix in the source
+ // file paths with the destination directory where the -debugsource
+ // sub-package files would be installed (if we were to generate it).
+ // For example:
+ //
+ // /usr/src/debug/foo-1.0.0-1.fc35.x86_64
+ //
+ // There is just one complication:
+ //
+ // While the generation of the -debugsource sub-packages is
+ // currently disabled, the executed by rpmbuild find-debuginfo
+ // script still performs some preparations for them. It runs the
+ // debugedit program, which, in particular, reads the source file
+ // paths from the debug information in package binaries and saves
+ // those which start with the ~/rpmbuild/BUILD/foo-1.0.0 or
+ // /usr/src/debug/foo-1.0.0-1.fc35.x86_64 directory prefix into the
+ // ~/rpmbuild/BUILD/foo-1.0.0/debugsources.list file, stripping the
+ // prefixes. It also saves all the relative source file paths as is
+ // (presumably assuming they are sub-entries of the
+ // ~/rpmbuild/BUILD/foo-1.0.0 directory where the package archive
+ // would normally be extracted). Afterwards, the content of the
+ // debugsources.list file is piped as an input to the cpio program
+ // executed in the ~/rpmbuild/BUILD/foo-1.0.0 directory as its
+ // current working directory, which tries to copy these source files
+ // to the
+ // ~/rpmbuild/BUILDROOT/foo-1.0.0-1.fc35.x86_64/usr/src/debug/foo-1.0.0-1.fc35.x86_64
+ // directory. Given that these source files are actually located in
+ // the bpkg configuration directory rather than in the
+ // ~/rpmbuild/BUILD/foo-1.0.0 directory the cpio program fails to
+ // stat them and complains. To work around that we need to change
+ // the replacement directory path in the -ffile-prefix-map option
+ // value with some other absolute (not necessarily existing) path
+ // which is not a subdirectory of the directory prefixes recognized
+ // by the debugedit program. This way debugedit won't recognize any
+ // of the package source files, will create an empty
+ // debugsources.list file, and thus the cpio program won't try to
+ // copy anything. Not to confuse the user (who can potentially see
+ // such paths in gdb while examining a core file produced by the
+ // package binary), we will keep this replacement directory path
+ // close to the desired one, but will also make it clear that the
+ // path is bogus:
+ //
+ // /usr/src/debug/bogus/foo-1.0.0-1.fc35.x86_64
+ //
+ // Note that this path mapping won't work for external packages with
+ // source out of configuration (e.g., managed by bdep).
+ //
+ // @@ Supposedly this code won't be necessary when we add support
+ // for -debugsource sub-packages somehow. Feels like one way
+ // would be to make ~/rpmbuild/BUILD/foo-1.0.0 a symlink to the
+ // bpkg configuration (or to the primary package inside, if not
+ // --recursive).
+ //
+ if (ops_->fedora_buildflags () != "ignore")
+ {
+ const char* debugsource_dir (
+ "%{_usrsrc}/debug/bogus/%{name}-%{evr}.%{_arch}");
+
+ if (lang_c || lang_cc)
+ os << "%global build_cflags %{?build_cflags} -ffile-prefix-map="
+ << cfg_dir.string () << '=' << debugsource_dir << '\n';
+
+ if (lang_cxx || lang_cc)
+ os << "%global build_cxxflags %{?build_cxxflags} -ffile-prefix-map="
+ << cfg_dir.string () << '=' << debugsource_dir << '\n';
+ }
+ }
+ else
+ os << "%global debug_package %{nil}" << '\n';
+
+ // Common arguments for build2 commands.
+ //
+ // Let's use absolute path to the build system driver in case we are
+ // invoked with altered environment or some such.
+ //
+ // Note: should be consistent with the invocation in installed_entries()
+ // above.
+ //
+ cstrings verb_args; string verb_arg;
+ map_verb_b (*ops_, verb_b::normal, verb_args, verb_arg);
+
+ os << '\n'
+ << "%global build2 " << search_b (*ops_).effect_string ();
+ for (const char* o: verb_args) os << ' ' << o;
+ for (const string& o: ops_->build_option ()) os << ' ' << o;
+
+ // Map the %{_smp_build_ncpus} macro value to the build2 --jobs or
+ // --serial-stop options.
+ //
+ os << '\n'
+ << '\n'
+ << "%if %{defined _smp_build_ncpus}" << '\n'
+ << " %if %{_smp_build_ncpus} == 1" << '\n'
+ << " %global build2 %{build2} --serial-stop" << '\n'
+ << " %else" << '\n'
+ << " %global build2 %{build2} --jobs=%{_smp_build_ncpus}" << '\n'
+ << " %endif" << '\n'
+ << "%endif" << '\n';
+
+ // Configuration variables.
+ //
+ // Note: we need to quote values that contain `<>`, `[]`, since they
+ // will be passed through shell. For simplicity, let's just quote
+ // everything.
+ //
+ os << '\n'
+ << "%global config_vars";
+
+ auto add_macro_line = [&os] (const auto& v)
+ {
+ os << " \\\\\\\n " << v;
+ };
+
+ add_macro_line ("config.install.chroot='%{buildroot}/'");
+ add_macro_line ("config.install.sudo='[null]'");
+
+ // If this is a C-based language, add rpath for private installation.
+ //
+ if (priv && (lang_c || lang_cxx || lang_cc))
+ add_macro_line ("config.bin.rpath='%{_libdir}/" + pn.string () + "/'");
+
+ // Add build flags.
+ //
+ if (ops_->fedora_buildflags () != "ignore")
+ {
+ const string& m (ops_->fedora_buildflags ());
+
+ string o (m == "assign" ? "=" :
+ m == "append" ? "+=" :
+ m == "prepend" ? "=+" : "");
+
+ if (o.empty ())
+ fail << "unknown --fedora-buildflags option value '" << m << "'";
+
+ // Note that config.cc.* doesn't play well with the append/prepend
+ // modes because the orders are:
+ //
+ // x.poptions cc.poptions
+ // cc.coptions x.coptions
+ // cc.loptions x.loptions
+ //
+ // Oh, well, hopefully it will be close enough for most cases.
+ //
+ // Note also that there are compiler mode options that are not
+ // overridden. Also the preprocessor options are normally contained
+ // in the %{build_cflags} and %{build_cxxflags} macro definitions
+ // and have no separate macros associated at this level (see "Using
+ // RPM build flags" documentation for details). For example:
+ //
+ // $ rpm --eval "%{build_cflags}"
+ // -O2 -flto=auto -ffat-lto-objects -fexceptions -g
+ // -grecord-gcc-switches -pipe -Wall -Werror=format-security
+ // -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS
+ // -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1
+ // -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1
+ // -m64 -mtune=generic -fasynchronous-unwind-tables
+ // -fstack-clash-protection -fcf-protection
+ //
+ // Note the -Wp options above. Thus, we reset config.{c,cxx}.poptions
+ // to [null] in the assign mode and, for simplicity, leave them as
+ // configured otherwise. We could potentially fix that either by
+ // extracting the -Wp,... options from %{build_cflags} and
+ // %{build_cxxflags} macro values or using more lower level macros
+ // instead (%{_preprocessor_defines}, %{_hardened_cflags}, etc),
+ // which all feels quite hairy and brittle.
+ //
+ if (o == "=" && (lang_c || lang_cxx || lang_cc))
+ {
+ add_macro_line ("config.cc.poptions='[null]'");
+ add_macro_line ("config.cc.coptions='[null]'");
+ add_macro_line ("config.cc.loptions='[null]'");
+ }
+
+ if (lang_c || lang_cc)
+ {
+ if (o == "=")
+ add_macro_line ("config.c.poptions='[null]'");
+
+ add_macro_line ("config.c.coptions" + o + "'%{?build_cflags}'");
+ add_macro_line ("config.c.loptions" + o + "'%{?build_ldflags}'");
+ }
+
+ if (lang_cxx || lang_cc)
+ {
+ if (o == "=")
+ add_macro_line ("config.cxx.poptions='[null]'");
+
+ add_macro_line ("config.cxx.coptions" + o + "'%{?build_cxxflags}'");
+ add_macro_line ("config.cxx.loptions" + o + "'%{?build_ldflags}'");
+ }
+ }
+
+ // Keep last to allow user-specified configuration variables to
+ // override anything.
+ //
+ for (const string& c: config)
+ {
+ // Quote the value unless already quoted (see above). Presense of
+ // potentially-quoted user variables complicates things a bit (can
+ // be partially quoted, double-quoted, etc).
+ //
+ size_t p (c.find_first_of ("=+ \t")); // End of name.
+ if (p != string::npos)
+ {
+ p = c.find_first_not_of ("=+ \t", p); // Beginning of value.
+ if (p != string::npos)
+ {
+ if (c.find_first_of ("'\"", p) == string::npos) // Not quoted.
+ {
+ add_macro_line (string (c, 0, p) + '\'' + string (c, p) + '\'');
+ continue;
+ }
+ }
+ }
+
+ add_macro_line (c);
+ }
+
+ os << '\n'; // Close the macro definition.
+
+ // List of packages we need to install.
+ //
+ os << '\n'
+ << "%global packages";
+
+ for (const package& p: pkgs)
+ add_macro_line (p.out_root.representation ());
+
+ os << '\n'; // Close the macro definition.
+ }
+
+ // Build sections.
+ //
+ {
+ os << '\n'
+ << "# Build sections." << '\n'
+ << "#" << '\n'
+ << "%prep" << '\n'
+ << "%setup -T -c" << '\n'
+ << '\n'
+ << "%build" << '\n'
+ << "%{build2} %{config_vars} update-for-install: %{packages}" << '\n'
+ << '\n'
+ << "%install" << '\n'
+ << "%{build2} %{config_vars} '!config.install.scope=" << scope
+ << "' install: %{packages}" << '\n';
+ }
+
+ // Files sections.
+ //
+ // Generate the %files section for each sub-package in order to sort out
+ // which files belong where.
+ //
+ // For the details on the %files section directives see "Directives For
+ // the %files list" documentation. But the summary is:
+ //
+ // - Supports only simple wildcards (?, *, [...]; no recursive/**).
+ // - Includes directories recursively, unless the path is prefixed
+ // with the %dir directive, in which case only includes this
+ // directory entry, which will be created on install and removed on
+ // uninstall, if empty.
+ // - An entry that doesn't match anything is an error (say,
+ // /usr/sbin/*).
+ //
+ // Keep in mind that wherever there is <project> in the config.install.*
+ // variable, we can end up with multiple different directories (bundled
+ // packages).
+ //
+ {
+ string main;
+ string devel;
+ string static_;
+ string doc;
+ string common;
+
+ // Note that declaring package ownership for standard directories is
+ // considered in Fedora a bad idea and is reported as an error by some
+ // RPM package checking tools (rpmlint, etc). Thus, we generate, for
+ // example, libexecdir/* entry rather than libexecdir/. However, if
+ // the private directory is specified we generate libexecdir/<private>/
+ // to own the directory.
+ //
+ // NOTE: use consistently with the above install directory expressions
+ // (%{?_includedir}, etc) evaluation.
+ //
+ string pd (priv ? pn.string () + '/' : "");
+
+ // The main package contains everything that doesn't go to another
+ // packages.
+ //
+ if (gen_main)
+ {
+ if (ies.contains_sub (bindir)) main += "%{_bindir}/*\n";
+ if (ies.contains_sub (sbindir)) main += "%{_sbindir}/*\n";
+
+ if (ies.contains_sub (libexecdir))
+ main += "%{_libexecdir}/" + (priv ? pd : "*") + '\n';
+
+ // This could potentially go to -common but it could also be target-
+ // specific, who knows. So let's keep it in main for now.
+ //
+ // Let's also specify that the confdir/ sub-entries are
+ // non-replacable configuration files. This, in particular, means
+ // that if edited they will not be replaced/removed on the package
+ // upgrade or uninstallation (see RPM Packaging Guide for more
+ // details on the %config(noreplace) directive). Also note that the
+ // binary package configuration files can later be queried by the
+ // user via the `rpm --query --configfiles` command.
+ //
+ if (ies.contains_sub (confdir))
+ main += "%config(noreplace) %{_sysconfdir}/*\n";
+ }
+
+ if (ies.contains_sub (incdir))
+ (!st.devel.empty () ? devel : main) +=
+ "%{_includedir}/" + (priv ? pd : "*") + '\n';
+
+ if (st.devel.empty () && st.static_.empty ())
+ {
+ assert (gen_main); // Shouldn't be here otherwise.
+
+ if (ies.contains_sub (libdir))
+ main += "%{_libdir}/" + (priv ? pd : "*") + '\n';
+ }
+ else
+ {
+ // Ok, time for things to get hairy: we need to split the contents
+ // of lib/ into the main, -devel, and/or -static sub-packages. The
+ // -devel sub-package, if present, should contain three things:
+ //
+ // 1. Static libraries (.a), if no -static sub-package is present.
+ // 2. Non-versioned shared library symlinks (.so).
+ // 3. Contents of the pkgconfig/ subdirectory, except for *.static.pc
+ // files if -static sub-package is present.
+ //
+ // The -static sub-package, if present, should contain two things:
+ //
+ // 1. Static libraries (.a).
+ // 2. *.static.pc files in pkgconfig/ subdirectory.
+ //
+ // Everything else should go into the main package.
+ //
+ // The shared libraries are tricky. Here we can have three plausible
+ // arrangements:
+ //
+ // A. Portably-versioned library:
+ //
+ // libfoo-1.2.so
+ // libfoo.so -> libfoo-1.2.so
+ //
+ // B. Natively-versioned library:
+ //
+ // libfoo.so.1.2.3
+ // libfoo.so.1.2 -> libfoo.so.1.2.3
+ // libfoo.so.1 -> libfoo.so.1.2
+ // libfoo.so -> libfoo.so.1
+ //
+ // C. Non-versioned library:
+ //
+ // libfoo.so
+ //
+ // Note that in the (C) case the library should go into the main
+ // package. Based on this, the criteria appears to be
+ // straightforward: the extension is .so and it's a symlink. For
+ // good measure we also check that there is the `lib` prefix
+ // (plugins, etc).
+ //
+ // Also note that if <private>/ is specified, then to establish
+ // ownership of the libdir/<private>/ directory we also need to add
+ // it non-recursively to one of the potentially 3 sub-packages,
+ // which all can contain some of its sub-entries. Not doing this
+ // will result in an empty libdir/<private>/ subdirectory after the
+ // binary package uninstallation. Naturally, the owner should be the
+ // right-most sub-package on the following diagram which contains
+ // any of the libdir/<private>/ sub-entries:
+ //
+ // -static -> -devel -> main
+ //
+ // The same reasoning applies to libdir/<private>/pkgconfig/.
+ //
+ string* owners[] = {&static_, &devel, &main};
+
+ // Indexes (in owners) of sub-packages which should own
+ // libdir/<private>/ and libdir/<private>/pkgconfig/. If nullopt,
+ // then no additional directory ownership entry needs to be added
+ // (installation is not private, recursive directory entry is
+ // already added, etc).
+ //
+ optional<size_t> private_owner;
+ optional<size_t> pkgconfig_owner;
+
+ for (auto p (ies.find_sub (libdir)); p.first != p.second; )
+ {
+ const path& f (p.first->first);
+ const installed_entry& ie ((p.first++)->second);
+
+ path l (f.leaf (libdir));
+ const string& n (l.string ());
+ string* fs (&main); // Go to the main package as a last resort.
+
+ auto update_ownership = [&owners, &fs] (optional<size_t>& pi)
+ {
+ size_t i (0);
+ for (; owners[i] != fs; ++i) ;
+
+ if (!pi || *pi < i)
+ pi = i;
+ };
+
+ if (l.simple ())
+ {
+ if (n.size () > 3 && n.compare (0, 3, "lib") == 0)
+ {
+ string e (l.extension ());
+
+ if (e == "a")
+ {
+ fs = !st.static_.empty () ? &static_ : &devel;
+ }
+ else if (e == "so" && ie.target != nullptr &&
+ !st.devel.empty ())
+ {
+ fs = &devel;
+ }
+ }
+
+ *fs += "%{_libdir}/" + pd + n + '\n';
+ }
+ else
+ {
+ // Let's keep things tidy and, when possible, use a
+ // sub-directory rather than listing all its sub-entries
+ // verbatim.
+ //
+ dir_path sd (*l.begin ());
+ dir_path d (libdir / sd);
+
+ if (d == pkgdir)
+ {
+ // If the -static sub-package is not being generated, then the
+ // whole directory goes into the -devel sub-package.
+ // Otherwise, *.static.pc files go into the -static
+ // sub-package and the rest into the -devel sub-package,
+ // unless it is not being generated in which case it goes into
+ // the main package.
+ //
+ if (!st.static_.empty ())
+ {
+ if (n.size () > 10 &&
+ n.compare (n.size () - 10, 10, ".static.pc") == 0)
+ fs = &static_;
+ else if (!st.devel.empty ())
+ fs = &devel;
+
+ *fs += "%{_libdir}/" + pd + n;
+
+ // Update the index of a sub-package which should own
+ // libdir/<private>/pkgconfig/.
+ //
+ if (priv)
+ update_ownership (pkgconfig_owner);
+ }
+ else
+ {
+ fs = &devel;
+ *fs += "%{_libdir}/" + pd + sd.string () + (priv ? "/" : "/*");
+ }
+ }
+ else
+ *fs += "%{_libdir}/" + pd + sd.string () + '/';
+
+ // In the case of the directory (has the trailing slash) or
+ // wildcard (has the trailing asterisk) skip all the other
+ // entries in this subdirectory (in the prefix map they will all
+ // be in a contiguous range).
+ //
+ char c (fs->back ());
+
+ if (c == '/' || c == '*')
+ {
+ while (p.first != p.second && p.first->first.sub (d))
+ ++p.first;
+ }
+
+ *fs += '\n';
+ }
+
+ // We can only add files to the main package if we generate it.
+ //
+ assert (fs != &main || gen_main);
+
+ // Update the index of a sub-package which should own
+ // libdir/<private>/.
+ //
+ if (priv)
+ update_ownership (private_owner);
+ }
+
+ // Add the directory ownership entries.
+ //
+ if (private_owner)
+ *owners[*private_owner] += "%dir %{_libdir}/" + pd + '\n';
+
+ if (pkgconfig_owner)
+ *owners[*pkgconfig_owner] +=
+ "%dir %{_libdir}/" + pd + "pkgconfig/" + '\n';
+ }
+
+ // We cannot just do usr/share/* since it will clash with doc/, man/,
+ // and licenses/ below. So we have to list all the top-level entries
+ // in usr/share/ that are not doc/, man/, licenses/, or build2/.
+ //
+ if (gen_main)
+ {
+ // Note that if <private>/ is specified, then we also need to
+ // establish ownership of the sharedir/<private>/ directory (similar
+ // to what we do for libdir/<private>/ above).
+ //
+ string* private_owner (nullptr);
+
+ string& fs (!st.common.empty () ? common : main);
+
+ for (auto p (ies.find_sub (sharedir)); p.first != p.second; )
+ {
+ const path& f ((p.first++)->first);
+
+ if (f.sub (docdir) ||
+ f.sub (mandir) ||
+ f.sub (licensedir) ||
+ f.sub (build2dir))
+ continue;
+
+ path l (f.leaf (sharedir));
+
+ if (l.simple ())
+ {
+ fs += "%{_datadir}/" + pd + l.string () + '\n';
+ }
+ else
+ {
+ // Let's keep things tidy and use a sub-directory rather than
+ // listing all its sub-entries verbatim.
+ //
+ dir_path sd (*l.begin ());
+
+ fs += "%{_datadir}/" + pd + sd.string () + '/' + '\n';
+
+ // Skip all the other entries in this subdirectory (in the prefix
+ // map they will all be in a contiguous range).
+ //
+ dir_path d (sharedir / sd);
+ while (p.first != p.second && p.first->first.sub (d))
+ ++p.first;
+ }
+
+ // Indicate that we need to establish ownership of
+ // sharedir/<private>/.
+ //
+ if (priv)
+ private_owner = &fs;
+ }
+
+ // Add the directory ownership entry.
+ //
+ if (private_owner != nullptr)
+ *private_owner += "%dir %{_datadir}/" + pd + '\n';
+ }
+
+ // Note that we only consider the bfdir/<project>/* sub-entries,
+ // adding the bfdir/<project>/ subdirectories to the %files
+ // section. This way no additional directory ownership entry needs to
+ // be added. Any immediate sub-entries of bfdir/, if present, will be
+ // ignored, which will end up with the 'unpackaged files' rpmbuild
+ // error.
+ //
+ // Also note that the bfdir/ directory is not owned by any package.
+ //
+ if (gen_main)
+ {
+ for (auto p (ies.find_sub (bfdir)); p.first != p.second; )
+ {
+ const path& f ((p.first++)->first);
+
+ path l (f.leaf (bfdir));
+
+ if (!l.simple ())
+ {
+ // Let's keep things tidy and use a sub-directory rather than
+ // listing all its sub-entries verbatim.
+ //
+ dir_path sd (*l.begin ());
+
+ main += "%{_datadir}/build2/export/" + sd.string () + '/' + '\n';
+
+ // Skip all the other entries in this subdirectory (in the
+ // prefix map they will all be in a contiguous range).
+ //
+ dir_path d (bfdir / sd);
+ while (p.first != p.second && p.first->first.sub (d))
+ ++p.first;
+ }
+ }
+ }
+
+ // Should we put the documentation into -common if there is no -doc?
+ // While there doesn't seem to be anything explicit in the policy,
+ // there are packages that do it this way (e.g., mariadb-common). And
+ // the same logic seems to apply to -devel (e.g., zlib-devel).
+ //
+ {
+ string& fs (!st.doc.empty () ? doc :
+ !st.common.empty () ? common :
+ !st.devel.empty () ? devel :
+ main);
+
+ // We can only add doc files to the main or -common packages if we
+ // generate the main package.
+ //
+ assert ((&fs != &main && &fs != &common) || gen_main);
+
+ // Let's specify that the docdir/ sub-entries are documentation
+ // files. Note that the binary package documentation files can later
+ // be queried by the user via the `rpm --query --docfiles` command.
+ //
+ if (ies.contains_sub (docdir))
+ fs += "%doc %{_docdir}/" + (priv ? pd : "*") + '\n';
+
+ // Since the man file may not appear directly in the man/
+ // subdirectory we use the man/*/* wildcard rather than man/* not to
+ // declare ownership for standard directories.
+ //
+ // As a side note, rpmbuild compresses the man files in the
+ // installation directory, which needs to be taken into account if
+ // writing more specific wildcards (e.g., %{_mandir}/man1/foo.1*).
+ //
+ if (ies.contains_sub (mandir))
+ fs += "%{_mandir}/*/*\n";
+ }
+
+ // Let's specify that the licensedir/ sub-entries are license files.
+ // Note that the binary package license files can later be queried by
+ // the user via the `rpm --query --licensefiles` command.
+ //
+ if (ies.contains_sub (licensedir))
+ (gen_main ? main : devel) +=
+ "%license %{_licensedir}/" + (priv ? pd : "*") + '\n';
+
+ // Finally, write the %files sections.
+ //
+ if (!main.empty ())
+ {
+ assert (gen_main); // Shouldn't be here otherwise.
+
+ os << '\n'
+ << "# " << st.main << " files." << '\n'
+ << "#" << '\n'
+ << "%files" << '\n'
+ << main;
+ }
+
+ if (!devel.empty ())
+ {
+ os << '\n'
+ << "# " << st.devel << " files." << '\n'
+ << "#" << '\n'
+ << "%files -n " << st.devel << '\n'
+ << devel;
+ }
+
+ if (!static_.empty ())
+ {
+ os << '\n'
+ << "# " << st.static_ << " files." << '\n'
+ << "#" << '\n'
+ << "%files -n " << st.static_ << '\n'
+ << static_;
+ }
+
+ if (!doc.empty ())
+ {
+ os << '\n'
+ << "# " << st.doc << " files." << '\n'
+ << "#" << '\n'
+ << "%files -n " << st.doc << '\n'
+ << doc;
+ }
+
+ if (!common.empty ())
+ {
+ os << '\n'
+ << "# " << st.common << " files." << '\n'
+ << "#" << '\n'
+ << "%files -n " << st.common << '\n'
+ << common;
+ }
+ }
+
+ // Changelog section.
+ //
+ // The section entry has the following format:
+ //
+ // * <day-of-week> <month> <day> <year> <name> <surname> <email> - <version>-<release>
+ // - <change1-description>
+ // - <change2-description>
+ // ...
+ //
+ // For example:
+ //
+ // * Wed Feb 22 2023 John Doe <john@example.com> - 2.3.4-1
+ // - New bpkg package release 2.3.4.
+ //
+ // We will use the Packager value for the `<name> <surname> <email>`
+ // fields. Strictly speaking it may not exactly match the fields set but
+ // it doesn't seem to break anything if that's the case. For good
+ // measure, me will also use the English locale for the date.
+ //
+ // Note that the <release> field doesn't contain the distribution tag.
+ //
+ {
+ os << '\n'
+ << "%changelog" << '\n'
+ << "* ";
+
+ // Given that we don't include the timezone there is no much sense to
+ // print the current time as local.
+ //
+ std::locale l (os.imbue (std::locale ("C")));
+ to_stream (os,
+ system_clock::now (),
+ "%a %b %d %Y",
+ false /* special */,
+ false /* local */);
+ os.imbue (l);
+
+ os << ' ' << packager << " - ";
+
+ if (!sys_version.epoch.empty ())
+ os << sys_version.epoch << ':';
+
+ os << sys_version.version << '-' << sys_version.release << '\n'
+ << "- New bpkg package release " << pvs << '.' << '\n';
+ }
+
+ os.close ();
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to write to " << spec << ": " << e;
+ }
+
+ // Run rpmbuild.
+ //
+ // Note that rpmbuild causes recompilation periodically by setting the
+ // SOURCE_DATE_EPOCH environment variable (which we track for changes
+ // since it affects GCC). Its value depends on the timestamp of the latest
+ // change log entry and thus has a day resolution. Note that since we
+ // don't have this SOURCE_DATE_EPOCH during dry-run caused by
+ // installed_entries(), there would be a recompilation even if the value
+ // weren't changing.
+ //
+ cstrings args {"rpmbuild", "-bb"}; // Only build binary packages.
+
+ // Map our verbosity to rpmbuild --quiet and -vv options (-v is the
+ // default). Note that there doesn't seem to be any way to control its
+ // progress.
+ //
+ // Also note that even in the quiet mode rpmbuild may still print some
+ // progress lines.
+ //
+ if (verb == 0)
+ args.push_back ("--quiet");
+ else if (verb >= 4) // Note that -vv feels too verbose for level 3.
+ args.push_back ("-vv");
+
+ // If requested, keep the installation directory, etc.
+ //
+ if (ops_->keep_output ())
+ args.push_back ("--noclean");
+
+ // Pass our --jobs value, if any.
+ //
+ string jobs_arg;
+ if (size_t n = ops_->jobs_specified () ? ops_->jobs () : 0)
+ {
+ jobs_arg = "--define=_smp_build_ncpus " + to_string (n);
+ args.push_back (jobs_arg.c_str ());
+ }
+
+ // Pass the rpmbuild/rpm common options.
+ //
+ for (const string& o: common_opts)
+ args.push_back (o.c_str ());
+
+ // Pass any additional options specified by the user.
+ //
+ for (const string& o: ops_->fedora_build_option ())
+ args.push_back (o.c_str ());
+
+ args.push_back (spec.string ().c_str ());
+ args.push_back (nullptr);
+
+ if (ops_->fedora_prepare_only ())
+ {
+ if (verb >= 1)
+ {
+ diag_record dr (text);
+
+ dr << "prepared " << spec <<
+ text << "command line: ";
+
+ print_process (dr, args);
+ }
+
+ return binary_files {};
+ }
+
+ try
+ {
+ process_path pp (process::path_search (args[0]));
+ process_env pe (pp);
+
+ // There is going to be quite a bit of diagnostics so print the command
+ // line unless quiet.
+ //
+ if (verb >= 1)
+ print_process (pe, args);
+
+ // Redirect stdout to stderr since some of rpmbuild diagnostics goes
+ // there. For good measure also redirect stdin to /dev/null to make sure
+ // there are no prompts of any kind.
+ //
+ process pr (pp, args, -2 /* stdin */, 2 /* stdout */, 2 /* stderr */);
+
+ if (!pr.wait ())
+ {
+ // Let's repeat the command line even if it was printed at the
+ // beginning to save the user a rummage through the logs.
+ //
+ diag_record dr (fail);
+ dr << args[0] << " exited with non-zero code" <<
+ info << "command line: "; print_process (dr, pe, args);
+ }
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e;
+
+ if (e.child)
+ exit (1);
+
+ throw failed ();
+ }
+
+ // While it's tempting to always keep the spec file let's remove it,
+ // unless requested not to, since it contains absolute paths to
+ // configuration.
+ //
+ if (!ops_->keep_output ())
+ rm (spec);
+
+ // Collect and return the binary sub-package paths.
+ //
+ // Here we will use `rpm --eval` to resolve the RPM sub-package paths.
+ //
+ binary_files r;
+ r.system_version = st.system_version;
+ {
+ string expressions;
+
+ auto add_macro = [&expressions] (const string& name, const string& value)
+ {
+ expressions += "%global " + name + ' ' + value + '\n';
+ };
+
+ add_macro ("VERSION", sys_version.version);
+ add_macro ("RELEASE", sys_version.release + "%{?dist}");
+
+ const string& package_arch (!build_arch.empty () ? build_arch : arch);
+
+ vector<binary_file> files;
+
+ auto add_package = [&files, &expressions, &rpmfile, &add_macro]
+ (const string& name,
+ const string& arch,
+ const char* type) -> size_t
+ {
+ add_macro ("NAME", name);
+ add_macro ("ARCH", arch);
+ expressions += rpmfile + '\n';
+
+ // Note: path is unknown yet.
+ //
+ files.push_back (binary_file {type, path (), name});
+ return files.size () - 1;
+ };
+
+ if (gen_main)
+ add_package (st.main, package_arch, "main.rpm");
+
+ if (!st.devel.empty ())
+ add_package (st.devel, package_arch, "devel.rpm");
+
+ if (!st.static_.empty ())
+ add_package (st.static_, package_arch, "static.rpm");
+
+ if (!st.doc.empty ())
+ add_package (st.doc, "noarch", "doc.rpm");
+
+ if (!st.common.empty ())
+ add_package (st.common, "noarch", "common.rpm");
+
+ optional<size_t> di (
+ !binless
+ ? add_package (st.main + "-debuginfo", arch, "debuginfo.rpm")
+ : optional<size_t> ());
+
+ // Strip the trailing newline since rpm adds one.
+ //
+ expressions.pop_back ();
+
+ strings expansions (eval (cstrings ({expressions.c_str ()})));
+
+ if (expansions.size () != files.size ())
+ fail << "number of RPM file path expansions differs from number "
+ << "of path expressions";
+
+ for (size_t i (0); i != files.size(); ++i)
+ {
+ try
+ {
+ path p (move (expansions[i]));
+
+ if (p.empty ())
+ throw invalid_path ("");
+
+ // Note that the -debuginfo sub-package may potentially not be
+ // generated (no installed binaries to extract the debug info from,
+ // etc).
+ //
+ if (exists (p))
+ {
+ binary_file& f (files[i]);
+
+ r.push_back (
+ binary_file {move (f.type), move (p), move (f.system_name)});
+ }
+ else if (!di || i != *di) // Not a -debuginfo sub-package?
+ fail << "expected output file " << p << " does not exist";
+ }
+ catch (const invalid_path& e)
+ {
+ fail << "invalid path '" << e.path << "' in RPM file path expansions";
+ }
+ }
+ }
+
+ return r;
+ }
+}
diff --git a/bpkg/system-package-manager-fedora.hxx b/bpkg/system-package-manager-fedora.hxx
new file mode 100644
index 0000000..3e68b98
--- /dev/null
+++ b/bpkg/system-package-manager-fedora.hxx
@@ -0,0 +1,372 @@
+// file : bpkg/system-package-manager-fedora.hxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BPKG_SYSTEM_PACKAGE_MANAGER_FEDORA_HXX
+#define BPKG_SYSTEM_PACKAGE_MANAGER_FEDORA_HXX
+
+#include <map>
+
+#include <bpkg/types.hxx>
+#include <bpkg/utility.hxx>
+
+#include <bpkg/system-package-manager.hxx>
+
+namespace bpkg
+{
+ // The system package manager implementation for Fedora and alike (Red Hat
+ // Enterprise Linux, CentOS, etc) using the DNF frontend.
+ //
+ // NOTE: THE BELOW DESCRIPTION IS ALSO REPRODUCED IN THE BPKG MANUAL.
+ //
+ // For background, a library in Fedora is normally split up into several
+ // packages: the shared library package (e.g., libfoo), the development
+ // files package (e.g., libfoo-devel), the static library package (e.g.,
+ // libfoo-static; may also be placed into the -devel package), the
+ // documentation files package (e.g., libfoo-doc), the debug symbols and
+ // source files packages (e.g., libfoo-debuginfo and libfoo-debugsource),
+ // and the common or architecture-independent files (e.g., libfoo-common).
+ // All the packages except -devel are optional and there is quite a bit of
+ // variability here. In particular, the lib prefix in libfoo is not a
+ // requirement (unlike in Debian) and is normally present only if upstream
+ // name has it (see some examples below).
+ //
+ // For mixed packages which include both applications and libraries, the
+ // shared library package normally has the -libs suffix (e.g., foo-libs).
+ // Such packages may have separate -debuginfo packages for applications and
+ // libraries (e.g. openssl-debuginfo and openssl-libs-debuginfo).
+ //
+ // A package name may also include an upstream version based suffix if
+ // multiple versions of the package can be installed simultaneously (e.g.,
+ // libfoo1.1 libfoo1.1-devel, libfoo2 libfoo2-devel).
+ //
+ // Terminology-wise, the term "base package" (sometime also "main package")
+ // normally refers to either the application or shared library package (as
+ // decided by the package maintainer in the spec file) with the suffixed
+ // packages (-devel, -doc, etc) called "subpackages".
+ //
+ // Here are a few examples:
+ //
+ // libpq libpq-devel
+ //
+ // zlib zlib-devel zlib-static
+ //
+ // catch-devel
+ //
+ // eigen3-devel eigen3-doc
+ //
+ // xerces-c xerces-c-devel xerces-c-doc
+ //
+ // libsigc++20 libsigc++20-devel libsigc++20-doc
+ // libsigc++30 libsigc++30-devel libsigc++30-doc
+ //
+ // icu libicu libicu-devel libicu-doc
+ //
+ // openssl openssl-libs openssl-devel openssl-static
+ // openssl1.1 openssl1.1-devel
+ //
+ // curl libcurl libcurl-devel
+ //
+ // sqlite sqlite-libs sqlite-devel sqlite-doc
+ //
+ // community-mysql community-mysql-libs community-mysql-devel
+ // community-mysql-common community-mysql-server
+ //
+ // ncurses ncurses-libs ncurses-c++-libs ncurses-devel ncurses-static
+ //
+ // keyutils keyutils-libs keyutils-libs-devel
+ //
+ // Note that while we support arbitrary -debug* sub-package names for
+ // consumption, we only generate <main-package>-debug*.
+ //
+ // Based on that, it seems our best bet when trying to automatically map our
+ // library package name to Fedora package names is to go for the -devel
+ // package first and figure out the shared library package from that based
+ // on the fact that the -devel package should have the == dependency on the
+ // shared library package with the same version and its name should normally
+ // start with the -devel package's stem and be potentially followed with the
+ // -libs suffix. Failed to find the -devel package, we may re-try but now
+ // using the project name instead of the package name (see, for example,
+ // openssl, sqlite).
+ //
+ // For application packages there is normally no -devel packages but
+ // -debug*, -doc, and -common are plausible.
+ //
+ // The format of the fedora-name (or alike) manifest value is a comma-
+ // separated list of one or more package groups:
+ //
+ // <package-group> [, <package-group>...]
+ //
+ // Where each <package-group> is the space-separated list of one or more
+ // package names:
+ //
+ // <package-name> [ <package-name>...]
+ //
+ // All the packages in the group should belong to the same "logical
+ // package", such as -devel, -doc, -common packages. They normally have the
+ // same version.
+ //
+ // The first group is called the main group and the first package in the
+ // group is called the main package. Note that all the groups are consumed
+ // (installed) but only the main group is produced (packaged).
+ //
+ // (Note that above we use the term "logical package" instead of "base
+ // package" since the main package may not be the base package, for example
+ // being the -libs subpackage.)
+ //
+ // We allow/recommend specifying the -devel package instead of the main
+ // package for libraries (the bpkg package name starts with lib), seeing
+ // that we are capable of detecting the main package automatically. If the
+ // library name happens to end with -devel (which poses an ambiguity), then
+ // the -devel package should be specified explicitly as the second package
+ // to disambiguate this situation (if a non-library name happened to start
+ // with lib and end with -devel, well, you are out of luck, I guess).
+ //
+ // Note also that for now we treat all the packages from the non-main groups
+ // as extras but in the future we may decide to sort them out like the main
+ // group (see parse_name_value() for details).
+ //
+ // The Fedora package version has the [<epoch>:]<version>-<release> form
+ // where the parts correspond to the Epoch (optional upstream versioning
+ // scheme), Version (upstream version), and Release (Fedora's package
+ // revision) RPM tags (see the Fedora Package Versioning Guidelines and RPM
+ // tags documentation for details). If no explicit mapping to the bpkg
+ // version is specified with the fedora-to-downstream-version (or alike)
+ // manifest values or none match, then we fallback to using the <version>
+ // part as the bpkg version. If explicit mapping is specified, then we match
+ // it against the [<epoch>:]<version> parts ignoring <release>.
+ //
+ struct system_package_status_fedora: system_package_status
+ {
+ string main;
+ string devel;
+ string static_;
+ string doc;
+ string debuginfo;
+ string debugsource;
+ string common;
+ strings extras;
+
+ string fallback; // Fallback for main/devel package based on project name.
+
+ // The `dnf list` output.
+ //
+ struct package_info
+ {
+ string name;
+ string installed_version; // Empty if none.
+ string candidate_version; // Empty if none and no installed_version.
+
+ // The architecture of the installed/candidate package version. Can only
+ // be the host architecture or noarch (so it could have been bool but
+ // it's more convenient to have the actual name).
+ //
+ // Note that in Fedora the same package version can be available for
+ // multiple architectures or be architecture-independent. For example:
+ //
+ // dbus-libs-1:1.12.22-1.fc35.i686
+ // dbus-libs-1:1.12.22-1.fc35.x86_64
+ // dbus-common-1:1.12.22-1.fc35.noarch
+ // code-insiders-1.75.0-1675123170.el7.armv7hl
+ // code-insiders-1.75.0-1675123170.el7.aarch64
+ // code-insiders-1.75.0-1675123170.el7.x86_64
+ //
+ // Thus, for a package query we normally need to qualify the package
+ // with the architecture suffix or filter the query result, normally
+ // skipping packages for architectures other than the host architecture.
+ //
+ string installed_arch;
+ string candidate_arch;
+
+ explicit
+ package_info (string n): name (move (n)) {}
+ };
+
+ vector<package_info> package_infos;
+ size_t package_infos_main = 0; // Size of the main group.
+
+ explicit
+ system_package_status_fedora (string m, string d = {}, string f = {})
+ : main (move (m)), devel (move (d)), fallback (move (f))
+ {
+ assert (!main.empty () || !devel.empty ());
+ }
+
+ system_package_status_fedora () = default;
+ };
+
+ class system_package_manager_fedora: public system_package_manager
+ {
+ public:
+ virtual optional<const system_package_status*>
+ status (const package_name&, const available_packages*) override;
+
+ virtual void
+ install (const vector<package_name>&) override;
+
+ virtual binary_files
+ generate (const packages&,
+ const packages&,
+ const strings&,
+ const dir_path&,
+ const package_manifest&,
+ const string&,
+ const small_vector<language, 1>&,
+ optional<bool>,
+ bool) override;
+
+ public:
+ // Expect os_release::name_id to be "fedora" or os_release::like_ids to
+ // contain "fedora".
+ //
+ system_package_manager_fedora (bpkg::os_release&& osr,
+ const target_triplet& h,
+ string a,
+ optional<bool> progress,
+ optional<size_t> fetch_timeout,
+ bool install,
+ bool fetch,
+ bool yes,
+ string sudo)
+ : system_package_manager (move (osr),
+ h,
+ a.empty () ? arch_from_target (h) : move (a),
+ progress,
+ fetch_timeout,
+ install,
+ fetch,
+ yes,
+ move (sudo)) {}
+
+ // Note: options can only be NULL when testing functions that don't need
+ // them.
+ //
+ system_package_manager_fedora (bpkg::os_release&& osr,
+ const target_triplet& h,
+ string a,
+ optional<bool> progress,
+ const pkg_bindist_options* ops)
+ : system_package_manager (move (osr),
+ h,
+ a.empty () ? arch_from_target (h) : move (a),
+ progress),
+ ops_ (ops) {}
+
+ // Implementation details exposed for testing (see definitions for
+ // documentation).
+ //
+ public:
+ using package_status = system_package_status_fedora;
+ using package_info = package_status::package_info;
+
+ void
+ dnf_list (vector<package_info>&, size_t = 0);
+
+ vector<pair<string, string>>
+ dnf_repoquery_requires (const string&, const string&, const string&, bool);
+
+ void
+ dnf_makecache ();
+
+ void
+ dnf_install (const strings&);
+
+ void
+ dnf_mark_install (const strings&);
+
+ pair<cstrings, const process_path&>
+ dnf_common (const char*,
+ optional<size_t> fetch_timeout,
+ strings& args_storage);
+
+ static package_status
+ parse_name_value (const string&, const string&, bool, bool, bool);
+
+ static string
+ main_from_devel (const string&,
+ const string&,
+ const vector<pair<string, string>>&);
+
+ static string
+ arch_from_target (const target_triplet&);
+
+ package_status
+ map_package (const package_name&,
+ const version&,
+ const available_packages&) const;
+
+ static strings
+ rpm_eval (const cstrings& opts, const cstrings& expressions);
+
+ // If simulate is not NULL, then instead of executing the actual dnf
+ // commands simulate their execution: (1) for `dnf list` and `dnf
+ // repoquery --requires` by printing their command lines and reading the
+ // results from files specified in the below dnf_* maps and (2) for `dnf
+ // makecache`, `dnf install`, and `dnf mark install` by printing their
+ // command lines and failing if requested.
+ //
+ // In the (1) case if the corresponding map entry does not exist or the
+ // path is empty, then act as if the specified package/version is
+ // unknown. If the path is special "-" then read from stdin. For `dnf
+ // list` and `dnf repoquery --requires` different post-fetch and (for the
+ // former) post-install results can be specified (if the result is not
+ // found in one of the later maps, the previous map is used as a
+ // fallback). Note that the keys in the dnf_list_* maps are the package
+ // sets and the corresponding result file is expected to contain (or not)
+ // the results for all of them. See dnf_list() and
+ // dnf_repoquery_requires() implementations for details on the expected
+ // results.
+ //
+ struct simulation
+ {
+ std::map<strings, path> dnf_list_;
+ std::map<strings, path> dnf_list_fetched_;
+ std::map<strings, path> dnf_list_installed_;
+
+ struct package
+ {
+ string name;
+ string version;
+ string arch;
+ bool installed;
+
+ bool
+ operator< (const package& p) const
+ {
+ if (int r = name.compare (p.name))
+ return r < 0;
+
+ if (int r = version.compare (p.version))
+ return r < 0;
+
+ if (int r = arch.compare (p.arch))
+ return r < 0;
+
+ return installed < p.installed;
+ }
+ };
+
+ std::map<package, path> dnf_repoquery_requires_;
+ std::map<package, path> dnf_repoquery_requires_fetched_;
+
+ bool dnf_makecache_fail_ = false;
+ bool dnf_install_fail_ = false;
+ bool dnf_mark_install_fail_ = false;
+ };
+
+ const simulation* simulate_ = nullptr;
+
+ private:
+ optional<system_package_status_fedora>
+ status (const package_name&, const available_packages&);
+
+ private:
+ bool fetched_ = false; // True if already fetched metadata.
+ bool installed_ = false; // True if already installed.
+
+ std::map<package_name, optional<system_package_status_fedora>> status_cache_;
+
+ const pkg_bindist_options* ops_ = nullptr; // Only for production.
+ };
+}
+
+#endif // BPKG_SYSTEM_PACKAGE_MANAGER_FEDORA_HXX
diff --git a/bpkg/system-package-manager-fedora.test.cxx b/bpkg/system-package-manager-fedora.test.cxx
new file mode 100644
index 0000000..4e59da1
--- /dev/null
+++ b/bpkg/system-package-manager-fedora.test.cxx
@@ -0,0 +1,431 @@
+// file : bpkg/system-package-manager-fedora.test.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <bpkg/system-package-manager-fedora.hxx>
+
+#include <map>
+#include <iostream>
+
+#include <bpkg/types.hxx>
+#include <bpkg/utility.hxx>
+
+#undef NDEBUG
+#include <cassert>
+
+#include <bpkg/system-package-manager.test.hxx>
+
+using namespace std;
+
+namespace bpkg
+{
+ using package_status = system_package_status_fedora;
+ using package_info_ = package_status::package_info;
+ using package = system_package_manager_fedora::simulation::package;
+
+ using butl::manifest_parser;
+ using butl::manifest_parsing;
+
+ // Usage: args[0] <command> ...
+ //
+ // Where <command> is one of:
+ //
+ // dnf-list <pkg>... result comes from stdin
+ //
+ // dnf-repoquery-requires <pkg> <ver> <arc> result comes from stdin
+ //
+ // parse-name-value <pkg> fedora-name value from stdin
+ //
+ // main-from-devel <dev-pkg> <dev-ver> depends comes from stdin in
+ // the `<dep-pkg> <dep-ver>`
+ // per line form
+ //
+ // map-package manifest comes from stdin
+ //
+ // build <query-pkg>... [--install [--no-fetch] <install-pkg>...]
+ //
+ // The stdin of the build command is used to read the simulation description
+ // which consists of lines in the following forms (blanks are ignored):
+ //
+ // manifest: <query-pkg> <file>
+ //
+ // Available package manifest for one of <query-pkg>. If none is
+ // specified, then a stub is automatically added.
+ //
+ // dnf-list[-{fetched,installed}]: <sys-pkg>... <file>
+ //
+ // Values for simulation::dnf_list_*. If <file> is the special `!` value,
+ // then make the entry empty.
+ //
+ // dnf-repoquery-requires[-fetched]: <sys-pkg> <sys-ver> <sys-arch> <file>
+ //
+ // Values for simulation::dnf_repoquery_requires_*. If <file> is the
+ // special `!` value, then make the entry empty.
+ //
+ // dnf_makecache-fail: true
+ // dnf-install-fail: true
+ // dnf-mark-install-fail: true
+ //
+ // Values for simulation::dnf_{makecache,install,mark_install}_fail_.
+ //
+ // While creating the system package manager always pretend to be the x86_64
+ // Fedora host (x86_64-redhat-linux-gnu), regardless of the actual host
+ // platform.
+ //
+ int
+ main (int argc, char* argv[])
+ try
+ {
+ assert (argc >= 2); // <command>
+
+ target_triplet host_triplet ("x86_64-redhat-linux-gnu");
+
+ string cmd (argv[1]);
+
+ // @@ TODO: add option to customize? Maybe option before command?
+ //
+ os_release osr {"fedora", {}, "35", "", "Fedora Linux", "", ""};
+
+ auto to_bool = [] (const string& s)
+ {
+ assert (s == "true" || s == "false");
+ return s == "true";
+ };
+
+ if (cmd == "dnf-list")
+ {
+ assert (argc >= 3); // <pkg>...
+
+ strings key;
+ vector<package_info_> pis;
+ for (int i (2); i != argc; ++i)
+ {
+ key.push_back (argv[i]);
+ pis.push_back (package_info_ (argv[i]));
+ }
+
+ system_package_manager_fedora::simulation s;
+ s.dnf_list_.emplace (move (key), path ("-"));
+
+ system_package_manager_fedora m (move (osr),
+ host_triplet,
+ "" /* arch */,
+ nullopt /* progress */,
+ nullopt /* fetch_timeout */,
+ false /* install */,
+ false /* fetch */,
+ false /* yes */,
+ "sudo");
+ m.simulate_ = &s;
+
+ m.dnf_list (pis);
+
+ for (const package_info_& pi: pis)
+ {
+ cout << pi.name << " '"
+ << pi.installed_version << "' '"
+ << pi.installed_arch << "' '"
+ << pi.candidate_version << "' '"
+ << pi.candidate_arch << "'\n";
+ }
+ }
+ else if (cmd == "dnf-repoquery-requires")
+ {
+ assert (argc == 6); // <pkg> <ver> <arch> <installed>
+
+ package key {argv[2], argv[3], argv[4], to_bool (argv[5])};
+
+ system_package_manager_fedora::simulation s;
+ s.dnf_repoquery_requires_.emplace (key, path ("-"));
+
+ system_package_manager_fedora m (move (osr),
+ host_triplet,
+ "" /* arch */,
+ nullopt /* progress */,
+ nullopt /* fetch_timeout */,
+ false /* install */,
+ false /* fetch */,
+ false /* yes */,
+ "sudo");
+ m.simulate_ = &s;
+
+ for (const pair<string, string>& d:
+ m.dnf_repoquery_requires (key.name,
+ key.version,
+ key.arch,
+ key.installed))
+ {
+ cout << d.first << ' ' << d.second << '\n';
+ }
+ }
+ else if (cmd == "parse-name-value")
+ {
+ assert (argc == 3); // <pkg>
+
+ package_name pn (argv[2]);
+ string pt (package_manifest::effective_type (nullopt, pn));
+
+ string v;
+ getline (cin, v);
+
+ package_status s (
+ system_package_manager_fedora::parse_name_value (
+ pt, v, false, false, false));
+
+ if (!s.main.empty ()) cout << "main: " << s.main << '\n';
+ if (!s.devel.empty ()) cout << "devel: " << s.devel << '\n';
+ if (!s.static_.empty ()) cout << "static: " << s.static_ << '\n';
+ if (!s.doc.empty ()) cout << "doc: " << s.doc << '\n';
+ if (!s.debuginfo.empty ()) cout << "debuginfo: " << s.debuginfo << '\n';
+ if (!s.debugsource.empty ()) cout << "debugsource: " << s.debugsource << '\n';
+ if (!s.common.empty ()) cout << "common: " << s.common << '\n';
+ if (!s.extras.empty ())
+ {
+ cout << "extras:";
+ for (const string& e: s.extras)
+ cout << ' ' << e;
+ cout << '\n';
+ }
+ }
+ else if (cmd == "main-from-devel")
+ {
+ assert (argc == 4); // <dev-pkg> <dev-ver>
+
+ string n (argv[2]);
+ string v (argv[3]);
+ vector<pair<string, string>> ds;
+
+ for (string l; !eof (getline (cin, l)); )
+ {
+ size_t p (l.find (' '));
+ assert (p != string::npos);
+
+ ds.emplace_back (string (l, 0, p), string (l, p + 1));
+ }
+
+ cout << system_package_manager_fedora::main_from_devel (n, v, ds) << '\n';
+ }
+ else if (cmd == "map-package")
+ {
+ assert (argc == 2);
+
+ available_packages aps;
+ aps.push_back (make_available_from_manifest ("", "-"));
+
+ const package_name& n (aps.front ().first->id.name);
+ const version& v (aps.front ().first->version);
+
+ system_package_manager_fedora m (move (osr),
+ host_triplet,
+ "" /* arch */,
+ nullopt /* progress */,
+ nullptr /* options */);
+
+ package_status s (m.map_package (n, v, aps));
+
+ cout << "version: " << s.system_version << '\n'
+ << "main: " << s.main << '\n';
+ if (!s.devel.empty ()) cout << "devel: " << s.devel << '\n';
+ if (!s.static_.empty ()) cout << "static: " << s.static_ << '\n';
+ if (!s.doc.empty ()) cout << "doc: " << s.doc << '\n';
+ if (!s.debuginfo.empty ()) cout << "debuginfo: " << s.debuginfo << '\n';
+ if (!s.debugsource.empty ()) cout << "debugsource: " << s.debugsource << '\n';
+ if (!s.common.empty ()) cout << "common: " << s.common << '\n';
+ }
+ else if (cmd == "build")
+ {
+ assert (argc >= 3); // <query-pkg>...
+
+ strings qps;
+ map<string, available_packages> aps;
+
+ // Parse <query-pkg>...
+ //
+ int argi (2);
+ for (; argi != argc; ++argi)
+ {
+ string a (argv[argi]);
+
+ if (a.compare (0, 2, "--") == 0)
+ break;
+
+ aps.emplace (a, available_packages {});
+ qps.push_back (move (a));
+ }
+
+ // Parse --install [--no-fetch]
+ //
+ bool install (false);
+ bool fetch (true);
+
+ for (; argi != argc; ++argi)
+ {
+ string a (argv[argi]);
+
+ if (a == "--install") install = true;
+ else if (a == "--no-fetch") fetch = false;
+ else break;
+ }
+
+ // Parse the description.
+ //
+ system_package_manager_fedora::simulation s;
+
+ for (string l; !eof (getline (cin, l)); )
+ {
+ if (l.empty ())
+ continue;
+
+ size_t p (l.find (':')); assert (p != string::npos);
+ string k (l, 0, p);
+
+ if (k == "manifest")
+ {
+ size_t q (l.rfind (' ')); assert (q != string::npos);
+ string n (l, p + 2, q - p - 2); trim (n);
+ string f (l, q + 1); trim (f);
+
+ auto i (aps.find (n));
+ if (i == aps.end ())
+ fail << "unknown package " << n << " in '" << l << "'";
+
+ i->second.push_back (make_available_from_manifest (n, f));
+ }
+ else if (
+ map<strings, path>* infos =
+ k == "dnf-list" ? &s.dnf_list_ :
+ k == "dnf-list-fetched" ? &s.dnf_list_fetched_ :
+ k == "dnf-list-installed" ? &s.dnf_list_installed_ :
+ nullptr)
+ {
+ size_t q (l.rfind (' ')); assert (q != string::npos);
+ string n (l, p + 2, q - p - 2); trim (n);
+ string f (l, q + 1); trim (f);
+
+ strings ns;
+ for (size_t b (0), e (0); next_word (n, b, e); )
+ ns.push_back (string (n, b, e - b));
+
+ if (f == "!")
+ f.clear ();
+
+ infos->emplace (move (ns), path (move (f)));
+ }
+ else if (map<package, path>* req =
+ k == "dnf-repoquery-requires" ? &s.dnf_repoquery_requires_ :
+ k == "dnf-repoquery-requires-fetched" ? &s.dnf_repoquery_requires_fetched_ :
+ nullptr)
+ {
+ size_t q (l.rfind (' ')); assert (q != string::npos);
+ string n (l, p + 2, q - p - 2); trim (n);
+ string f (l, q + 1); trim (f);
+
+ q = n.rfind (' '); assert (q != string::npos);
+ bool i (to_bool (string (n, q + 1)));
+ n.resize (q);
+
+ q = n.rfind (' '); assert (q != string::npos);
+ string a (n, q + 1);
+ n.resize (q);
+
+ q = n.find (' '); assert (q != string::npos);
+
+ package pkg {string (n, 0, q), string (n, q + 1), move (a), i};
+
+ if (f == "!")
+ f.clear ();
+
+ req->emplace (move (pkg), path (move (f)));
+ }
+ else if (k == "dnf-makecache-fail")
+ {
+ s.dnf_makecache_fail_ = true;
+ }
+ else if (k == "dnf-install-fail")
+ {
+ s.dnf_install_fail_ = true;
+ }
+ else if (k == "dnf-mark-install-fail")
+ {
+ s.dnf_mark_install_fail_ = true;
+ }
+ else
+ fail << "unknown keyword '" << k << "' in simulation description";
+ }
+
+ // Fallback to stubs and sort in the version descending order.
+ //
+ for (pair<const string, available_packages>& p: aps)
+ {
+ if (p.second.empty ())
+ p.second.push_back (make_available_stub (p.first));
+
+ sort_available (p.second);
+ }
+
+ system_package_manager_fedora m (move (osr),
+ host_triplet,
+ "" /* arch */,
+ nullopt /* progress */,
+ nullopt /* fetch_timeout */,
+ install,
+ fetch,
+ false /* yes */,
+ "sudo");
+ m.simulate_ = &s;
+
+ // Query each package.
+ //
+ for (const string& n: qps)
+ {
+ package_name pn (n);
+
+ const system_package_status* s (*m.status (pn, &aps[n]));
+
+ assert (*m.status (pn, nullptr) == s); // Test caching.
+
+ if (s == nullptr)
+ fail << "no installed " << (install ? "or available " : "")
+ << "system package for " << pn;
+
+ cout << pn << ' ' << s->version
+ << " (" << s->system_name << ' ' << s->system_version << ") ";
+
+ switch (s->status)
+ {
+ case package_status::installed: cout << "installed"; break;
+ case package_status::partially_installed: cout << "part installed"; break;
+ case package_status::not_installed: cout << "not installed"; break;
+ }
+
+ cout << '\n';
+ }
+
+ // Install if requested.
+ //
+ if (install)
+ {
+ assert (argi != argc); // <install-pkg>...
+
+ vector<package_name> ips;
+ for (; argi != argc; ++argi)
+ ips.push_back (package_name (argv[argi]));
+
+ m.install (ips);
+ }
+ }
+ else
+ fail << "unknown command '" << cmd << "'";
+
+ return 0;
+ }
+ catch (const failed&)
+ {
+ return 1;
+ }
+}
+
+int
+main (int argc, char* argv[])
+{
+ return bpkg::main (argc, argv);
+}
diff --git a/bpkg/system-package-manager-fedora.test.testscript b/bpkg/system-package-manager-fedora.test.testscript
new file mode 100644
index 0000000..b1d5b8c
--- /dev/null
+++ b/bpkg/system-package-manager-fedora.test.testscript
@@ -0,0 +1,1410 @@
+# file : bpkg/system-package-manager-fedora.test.testscript
+# license : MIT; see accompanying LICENSE file
+
+: dnf-list
+:
+{
+ test.arguments += dnf-list
+
+ : basics
+ :
+ $* openssl-libs openssl-devel openssl1.1 openssl1.1-devel libsigc++40 libcurl lrmi rust-uuid+std-devel <<EOI 2>>EOE >>EOO
+ Installed Packages
+ libcurl.i686 7.79.1-5.fc35 @updates
+ libcurl.x86_64 7.79.1-5.fc35 @updates
+ openssl-devel.x86_64 1:1.1.1q-1.fc35 @updates
+ openssl-libs.i686 1:1.1.1q-1.fc35 @updates
+ openssl-libs.x86_64 1:1.1.1q-1.fc35 @updates
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ libcurl.i686 7.79.1-7.fc35 updates
+ libcurl.x86_64 7.79.1-7.fc35 updates
+ lrmi.i686 0.10-28.fc35 fedora
+ openssl-devel.i686 1:1.1.1q-1.fc35 updates
+ openssl1.1.i686 1:1.1.1i-3.fc35 fedora
+ openssl1.1.x86_64 1:1.1.1i-3.fc35 fedora
+ openssl1.1-devel.i686 1:1.1.1i-3.fc35 fedora
+ openssl1.1-devel.x86_64 1:1.1.1i-3.fc35 fedora
+ rpm.x86_64 4.17.1-3.fc35 updates
+ rust-uuid+std-devel.noarch 1.2.1-1.fc35 updates
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet openssl-libs openssl-devel openssl1.1 openssl1.1-devel libsigc++40 libcurl lrmi rust-uuid+std-devel rpm <-
+ EOE
+ openssl-libs '1:1.1.1q-1.fc35' 'x86_64' '1:1.1.1q-1.fc35' 'x86_64'
+ openssl-devel '1:1.1.1q-1.fc35' 'x86_64' '1:1.1.1q-1.fc35' 'x86_64'
+ openssl1.1 '' '' '1:1.1.1i-3.fc35' 'x86_64'
+ openssl1.1-devel '' '' '1:1.1.1i-3.fc35' 'x86_64'
+ libsigc++40 '' '' '' ''
+ libcurl '7.79.1-5.fc35' 'x86_64' '7.79.1-7.fc35' 'x86_64'
+ lrmi '' '' '' ''
+ rust-uuid+std-devel '' '' '1.2.1-1.fc35' 'noarch'
+ EOO
+
+ : unknown
+ :
+ $* libsigc++40 <<EOI 2>>EOE >>EOO
+ Installed Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ Available Packages
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libsigc++40 rpm <-
+ EOE
+ libsigc++40 '' '' '' ''
+ EOO
+
+ : non-host-arc
+ :
+ $* lrmi <<EOI 2>>EOE >>EOO
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ lrmi.i686 0.10-28.fc35 fedora
+ rpm.x86_64 4.17.1-3.fc35 updates
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet lrmi rpm <-
+ EOE
+ lrmi '' '' '' ''
+ EOO
+
+ : dnf
+ :
+ $* rpm <<EOI 2>>EOE >>EOO
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet rpm rpm <-
+ EOE
+ rpm '4.17.1-2.fc35' 'x86_64' '4.17.1-3.fc35' 'x86_64'
+ EOO
+
+ : dnf-not-exist
+ :
+ $* openssl-libs <<EOI 2>>EOE != 0
+ Installed Packages
+ openssl-libs.i686 1:1.1.1q-1.fc35 @updates
+ openssl-libs.x86_64 1:1.1.1q-1.fc35 @updates
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet openssl-libs rpm <-
+ error: rpm package doesn't exist
+ EOE
+}
+
+: dnf-repoquery-requires
+:
+{
+ test.arguments += dnf-repoquery-requires
+
+ : basics
+ :
+ $* openssl-devel '1:1.1.1q-1.fc35' x86_64 true <<EOI 2>>EOE >>EOO
+ opae-devel x86_64 0:2.0.0-2.3.fc35
+ openssl-devel i686 1:1.1.1q-1.fc35
+ openssl-devel x86_64 1:1.1.1q-1.fc35
+ openssl-libs x86_64 1:1.1.1q-1.fc35
+ openssl1.1 x86_64 1:1.1.1i-3.fc35
+ openssl1.1-devel i686 1:1.1.1i-3.fc35
+ openssl1.1-devel x86_64 1:1.1.1i-3.fc35
+ pkgconf-pkg-config i686 0:1.8.0-1.fc35
+ pkgconf-pkg-config x86_64 0:1.8.0-1.fc35
+ EOI
+ LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" --installed --disableexcludes=all openssl-devel-1:1.1.1q-1.fc35.x86_64 <-
+ EOE
+ opae-devel 2.0.0-2.3.fc35
+ openssl-libs 1:1.1.1q-1.fc35
+ openssl1.1 1:1.1.1i-3.fc35
+ openssl1.1-devel 1:1.1.1i-3.fc35
+ pkgconf-pkg-config 1.8.0-1.fc35
+ EOO
+
+ : no-arch
+ :
+ $* rust-uuid+std-devel 1.2.1-1.fc35 noarch false <<EOI 2>>EOE >>EOO
+ cargo x86_64 0:1.65.0-1.fc35
+ rust-uuid-devel noarch 0:1.2.1-1.fc35
+ EOI
+ LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" rust-uuid+std-devel-1.2.1-1.fc35.noarch <-
+ EOE
+ cargo 1.65.0-1.fc35
+ rust-uuid-devel 1.2.1-1.fc35
+ EOO
+
+ : no-arch-dependency
+ :
+ $* dhcp-client '12:4.4.3-4.P1.fc35' x86_64 true <<EOI 2>>EOE >>EOO
+ bash i686 0:5.1.8-3.fc35
+ bash x86_64 0:5.1.8-3.fc35
+ coreutils x86_64 0:8.32-36.fc35
+ coreutils-single x86_64 0:8.32-36.fc35
+ dhcp-common noarch 12:4.4.3-4.P1.fc35
+ gawk i686 0:5.1.0-4.fc35
+ gawk x86_64 0:5.1.0-4.fc35
+ glibc i686 0:2.34-49.fc35
+ glibc x86_64 0:2.34-49.fc35
+ grep x86_64 0:3.6-4.fc35
+ ipcalc x86_64 0:1.0.1-2.fc35
+ iproute x86_64 0:5.13.0-2.fc35
+ iputils x86_64 0:20210722-1.fc35
+ libcap-ng x86_64 0:0.8.2-8.fc35
+ sed x86_64 0:4.8-8.fc35
+ systemd i686 0:249.13-6.fc35
+ systemd x86_64 0:249.13-6.fc35
+ EOI
+ LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" --installed --disableexcludes=all dhcp-client-12:4.4.3-4.P1.fc35.x86_64 <-
+ EOE
+ bash 5.1.8-3.fc35
+ coreutils 8.32-36.fc35
+ coreutils-single 8.32-36.fc35
+ dhcp-common 12:4.4.3-4.P1.fc35
+ gawk 5.1.0-4.fc35
+ glibc 2.34-49.fc35
+ grep 3.6-4.fc35
+ ipcalc 1.0.1-2.fc35
+ iproute 5.13.0-2.fc35
+ iputils 20210722-1.fc35
+ libcap-ng 0.8.2-8.fc35
+ sed 4.8-8.fc35
+ systemd 249.13-6.fc35
+ EOO
+
+ : no-depends
+ :
+ $* glibc 2.34-38.fc35 x86_64 true <:'' 2>>EOE >:''
+ LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" --installed --disableexcludes=all glibc-2.34-38.fc35.x86_64 <-
+ EOE
+
+ : unknown
+ :
+ $* glibg 2.34-38.fc35 x86_64 false <:'' 2>>EOE >:''
+ LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" glibg-2.34-38.fc35.x86_64 <-
+ EOE
+}
+
+: parse-name-value
+:
+{
+ test.arguments += parse-name-value
+
+ : basics
+ :
+ $* libmysqlclient <<EOI >>EOO
+ community-mysql-libs community-mysql-devel community-mysql-common community-mysql-libs-debuginfo community-mysql-debugsource community-mysql-extras, libstdc++ libstdc++-devel libstdc++-docs libstdc++-static, libz-dev
+ EOI
+ main: community-mysql-libs
+ devel: community-mysql-devel
+ debuginfo: community-mysql-libs-debuginfo
+ debugsource: community-mysql-debugsource
+ common: community-mysql-common
+ extras: community-mysql-extras libstdc++ libstdc++-devel libstdc++-static libstdc++-docs libz-dev
+ EOO
+
+ : non-lib
+ :
+ $* sqlite3 <<EOI >>EOO
+ sqlite sqlite-doc sqlite-analyzer sqlite-tools
+ EOI
+ main: sqlite
+ doc: sqlite-doc
+ extras: sqlite-analyzer sqlite-tools
+ EOO
+
+ : lib-devel
+ :
+ $* libsqlite3 <<EOI >>EOO
+ sqlite-devel
+ EOI
+ devel: sqlite-devel
+ EOO
+
+ : non-lib-devel
+ :
+ $* ssl-devel <<EOI >>EOO
+ ssl-devel
+ EOI
+ main: ssl-devel
+ EOO
+
+ : lib-custom-devel
+ :
+ $* libfoo-devel <<EOI >>EOO
+ libfoo-devel libfoo-devel-devel
+ EOI
+ main: libfoo-devel
+ devel: libfoo-devel-devel
+ EOO
+}
+
+: main-from-devel
+:
+{
+ test.arguments += main-from-devel
+
+ : libs
+ :
+ $* sqlite-devel 3.36.0-3.fc35 <<EOI >'sqlite-libs'
+ pkgconf-pkg-config 1.8.0-1.fc35
+ sqlite 3.36.0-3.fc35
+ sqlite-libs 3.36.0-3.fc35
+ EOI
+
+ : no-libs
+ :
+ $* xerces-c-devel 3.2.3-4.fc35 <<EOI >'xerces-c'
+ pkgconf-pkg-config 1.8.0-1.fc35
+ xerces-c 3.2.3-4.fc35
+ EOI
+
+ : no-dependencies
+ :
+ $* boost-http-server-devel 0-1.20220116gitcd5245f.fc35 <:'' >''
+}
+
+: map-package
+:
+{
+ test.arguments += map-package
+
+ : default-name
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: byacc
+ version: 20210808
+ summary: yacc parser generator
+ license: other: public domain
+ EOI
+ version: 20210808-1
+ main: byacc
+ EOO
+
+ : default-name-lib
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: libsqlite3
+ version: 3.40.1
+ summary: database library
+ license: other: public domain
+ EOI
+ version: 3.40.1-1
+ main: libsqlite3
+ devel: libsqlite3-devel
+ EOO
+
+ : custom-name
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: libsqlite3
+ fedora_35-name: libsqlite3 libsqlite3-devel
+ version: 3.40.1
+ summary: database library
+ license: other: public domain
+ EOI
+ version: 3.40.1-1
+ main: libsqlite3
+ devel: libsqlite3-devel
+ EOO
+
+ : custom-name-dev-only
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: libsqlite3
+ fedora_35-name: libsqlite3-devel
+ version: 3.40.1
+ summary: database library
+ license: other: public domain
+ EOI
+ version: 3.40.1-1
+ main: libsqlite3
+ devel: libsqlite3-devel
+ EOO
+
+ : custom-name-non-native
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: libsqlite3
+ fedora_0-name: libsqlite libsqlite-devel
+ fedor_35-name: libsqlite3 libsqlite3-devel
+ version: 3.40.1
+ summary: database library
+ license: other: public domain
+ EOI
+ version: 3.40.1-1
+ main: libsqlite
+ devel: libsqlite-devel
+ EOO
+
+ : version-upstream
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: byacc
+ version: +2-1.2.3-beta.1+3
+ upstream-version: 20210808
+ summary: yacc parser generator
+ license: other: public domain
+ EOI
+ version: 20210808~beta.1-4
+ main: byacc
+ EOO
+
+ : version-distribution
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: byacc
+ version: +2-1.2.3-beta.1+3
+ fedora-version: 20210808~beta.1
+ summary: yacc parser generator
+ license: other: public domain
+ EOI
+ version: 20210808~beta.1-1
+ main: byacc
+ EOO
+
+ : version-distribution-epoch-revision
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: byacc
+ version: +2-1.2.3-beta.1+3
+ fedora-version: 1:1.2.3-2
+ summary: yacc parser generator
+ license: other: public domain
+ EOI
+ version: 1:1.2.3-2
+ main: byacc
+ EOO
+
+ : version-distribution-empty-prerelease
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: byacc
+ version: +2-1.2.3-beta.1+3
+ fedora-version: 20210808~-4
+ summary: yacc parser generator
+ license: other: public domain
+ EOI
+ version: 20210808~beta.1-4
+ main: byacc
+ EOO
+
+ : version-distribution-empty-revision
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: byacc
+ version: +2-1.2.3-beta.1+3
+ fedora-version: 20210808~b.1-
+ summary: yacc parser generator
+ license: other: public domain
+ EOI
+ version: 20210808~b.1-4
+ main: byacc
+ EOO
+
+ : version-distribution-empty-release-revision
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: byacc
+ version: +2-1.2.3-beta.1+3
+ fedora-version: 20210808~-
+ summary: yacc parser generator
+ license: other: public domain
+ EOI
+ version: 20210808~beta.1-4
+ main: byacc
+ EOO
+}
+
+: build
+:
+{
+ test.arguments += build
+
+ : libpq
+ :
+ {
+ : installed
+ :
+ cat <<EOI >=libpq-devel+pq-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ libpq-devel.x86_64 13.4-1.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libpq-devel.i686 13.4-1.fc35 fedora
+ EOI
+ cat <<EOI >=libpq-devel.requires;
+ glibc i686 0:2.34-49.fc35
+ glibc x86_64 0:2.34-49.fc35
+ libpq x86_64 0:13.4-1.fc35
+ pkgconf-pkg-config i686 0:1.8.0-1.fc35
+ pkgconf-pkg-config x86_64 0:1.8.0-1.fc35
+ EOI
+ cat <<EOI >=libpq.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ libpq.x86_64 13.4-1.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libpq.i686 13.4-1.fc35 fedora
+ EOI
+ $* libpq --install libpq <<EOI 2>>EOE >>EOO
+ dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info
+ dnf-repoquery-requires: libpq-devel 13.4-1.fc35 x86_64 true libpq-devel.requires
+ dnf-list: libpq libpq.info
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm <libpq-devel+pq-devel.info
+ LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" --installed --disableexcludes=all libpq-devel-13.4-1.fc35.x86_64 <libpq-devel.requires
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq rpm <libpq.info
+ sudo dnf mark --quiet --assumeno install --cacheonly libpq-13.4-1.fc35.x86_64 libpq-devel-13.4-1.fc35.x86_64
+ EOE
+ libpq 13.4 (libpq 13.4-1.fc35) installed
+ EOO
+
+
+ : part-installed
+ :
+ cat <<EOI >=libpq-devel+pq-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libpq-devel.i686 13.4-1.fc35 fedora
+ libpq-devel.x86_64 13.4-1.fc35 fedora
+ EOI
+ cat <<EOI >=libpq-devel.requires;
+ glibc i686 0:2.34-49.fc35
+ glibc x86_64 0:2.34-49.fc35
+ libpq x86_64 0:13.4-1.fc35
+ pkgconf-pkg-config i686 0:1.8.0-1.fc35
+ pkgconf-pkg-config x86_64 0:1.8.0-1.fc35
+ EOI
+ cat <<EOI >=libpq.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ libpq.x86_64 13.4-1.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libpq.i686 13.4-1.fc35 fedora
+ EOI
+ $* libpq --install libpq <<EOI 2>>EOE >>EOO
+ dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info
+ dnf-repoquery-requires: libpq-devel 13.4-1.fc35 x86_64 false libpq-devel.requires
+ dnf-list: libpq libpq.info
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm <libpq-devel+pq-devel.info
+ sudo dnf makecache --quiet --assumeno --refresh
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm <libpq-devel+pq-devel.info
+ LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" libpq-devel-13.4-1.fc35.x86_64 <libpq-devel.requires
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq rpm <libpq.info
+ sudo dnf install --quiet --assumeno libpq.x86_64 libpq-devel.x86_64
+ sudo dnf mark --quiet --assumeno install --cacheonly libpq.x86_64 libpq-devel.x86_64
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq rpm <libpq.info
+ EOE
+ libpq 13.4 (libpq 13.4-1.fc35) part installed
+ EOO
+
+
+ : part-installed-upgrade
+ :
+ cat <<EOI >=libpq-devel+pq-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libpq-devel.i686 13.3-3.fc35 fedora
+ libpq-devel.x86_64 13.3-3.fc35 fedora
+ EOI
+ cat <<EOI >=libpq-devel+pq-devel.info-fetched;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libpq-devel.i686 13.4-1.fc35 fedora
+ libpq-devel.x86_64 13.4-1.fc35 fedora
+ EOI
+ cat <<EOI >=libpq-devel.requires-fetched;
+ glibc i686 0:2.34-49.fc35
+ glibc x86_64 0:2.34-49.fc35
+ libpq x86_64 0:13.4-1.fc35
+ pkgconf-pkg-config i686 0:1.8.0-1.fc35
+ pkgconf-pkg-config x86_64 0:1.8.0-1.fc35
+ EOI
+ cat <<EOI >=libpq.info-fetched;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ libpq.x86_64 13.3-3.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libpq.i686 13.4-1.fc35 fedora
+ libpq.x86_64 13.4-1.fc35 @fedora
+ EOI
+ cat <<EOI >=libpq.info-installed;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ libpq.x86_64 13.4-1.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libpq.i686 13.4-1.fc35 fedora
+ EOI
+ $* libpq --install libpq <<EOI 2>>EOE >>EOO
+ dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info
+ dnf-list-fetched: libpq-devel pq-devel libpq-devel+pq-devel.info-fetched
+ dnf-repoquery-requires: libpq-devel 13.4-1.fc35 x86_64 false libpq-devel.requires-fetched
+ dnf-list-fetched: libpq libpq.info-fetched
+ dnf-list-installed: libpq libpq.info-installed
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm <libpq-devel+pq-devel.info
+ sudo dnf makecache --quiet --assumeno --refresh
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm <libpq-devel+pq-devel.info-fetched
+ LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" libpq-devel-13.4-1.fc35.x86_64 <libpq-devel.requires-fetched
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq rpm <libpq.info-fetched
+ sudo dnf install --quiet --assumeno libpq.x86_64 libpq-devel.x86_64
+ sudo dnf mark --quiet --assumeno install --cacheonly libpq.x86_64 libpq-devel.x86_64
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq rpm <libpq.info-installed
+ EOE
+ libpq 13.4 (libpq 13.4-1.fc35) part installed
+ EOO
+
+
+ # Note that the semantics is unrealistic (maybe background metadata update
+ # happened right before installing libpq). Also note that in contrast to
+ # the part-installed-upgrade test we operate in the --sys-no-fetch mode.
+ #
+ : part-installed-upgrade-version-change
+ :
+ cat <<EOI >=libpq-devel+pq-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libpq-devel.i686 13.3-3.fc35 fedora
+ libpq-devel.x86_64 13.3-3.fc35 fedora
+ EOI
+ cat <<EOI >=libpq-devel.requires;
+ glibc i686 0:2.34-49.fc35
+ glibc x86_64 0:2.34-49.fc35
+ libpq x86_64 0:13.3-3.fc35
+ pkgconf-pkg-config i686 0:1.8.0-1.fc35
+ pkgconf-pkg-config x86_64 0:1.8.0-1.fc35
+ EOI
+ cat <<EOI >=libpq.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ libpq.x86_64 13.3-3.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libpq.i686 13.3-3.fc35 fedora
+ EOI
+ cat <<EOI >=libpq.info-installed;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ libpq.x86_64 13.4-1.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libpq.i686 13.4-1.fc35 fedora
+ EOI
+ $* libpq --install --no-fetch libpq <<EOI 2>>EOE >>EOO != 0
+ dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info
+ dnf-repoquery-requires: libpq-devel 13.3-3.fc35 x86_64 false libpq-devel.requires
+ dnf-list: libpq libpq.info
+ dnf-list-installed: libpq libpq.info-installed
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm <libpq-devel+pq-devel.info
+ LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" libpq-devel-13.3-3.fc35.x86_64 <libpq-devel.requires
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq rpm <libpq.info
+ sudo dnf install --quiet --assumeno libpq.x86_64 libpq-devel.x86_64
+ sudo dnf mark --quiet --assumeno install --cacheonly libpq.x86_64 libpq-devel.x86_64
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq rpm <libpq.info-installed
+ error: unexpected fedora package version for libpq
+ info: expected: 13.3-3.fc35
+ info: installed: 13.4-1.fc35
+ info: consider retrying the bpkg command
+ EOE
+ libpq 13.3 (libpq 13.3-3.fc35) part installed
+ EOO
+
+
+ : not-installed
+ :
+ cat <<EOI >=libpq-devel+pq-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libpq-devel.i686 13.4-1.fc35 fedora
+ libpq-devel.x86_64 13.4-1.fc35 @fedora
+ EOI
+ cat <<EOI >=libpq-devel.requires;
+ glibc i686 0:2.34-49.fc35
+ glibc x86_64 0:2.34-49.fc35
+ libpq x86_64 0:13.4-1.fc35
+ pkgconf-pkg-config i686 0:1.8.0-1.fc35
+ pkgconf-pkg-config x86_64 0:1.8.0-1.fc35
+ EOI
+ cat <<EOI >=libpq.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libpq.i686 13.4-1.fc35 fedora
+ libpq.x86_64 13.4-1.fc35 @fedora
+ EOI
+ cat <<EOI >=libpq.info-installed;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ libpq.x86_64 13.4-1.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libpq.i686 13.4-1.fc35 fedora
+ EOI
+ $* libpq --install libpq <<EOI 2>>EOE >>EOO
+ dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info
+ dnf-repoquery-requires: libpq-devel 13.4-1.fc35 x86_64 false libpq-devel.requires
+ dnf-list: libpq libpq.info
+ dnf-list-installed: libpq libpq.info-installed
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm <libpq-devel+pq-devel.info
+ sudo dnf makecache --quiet --assumeno --refresh
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm <libpq-devel+pq-devel.info
+ LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" libpq-devel-13.4-1.fc35.x86_64 <libpq-devel.requires
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq rpm <libpq.info
+ sudo dnf install --quiet --assumeno libpq.x86_64 libpq-devel.x86_64
+ sudo dnf mark --quiet --assumeno install --cacheonly libpq.x86_64 libpq-devel.x86_64
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq rpm <libpq.info-installed
+ EOE
+ libpq 13.4 (libpq 13.4-1.fc35) not installed
+ EOO
+
+
+ : no-install
+ :
+ cat <<EOI >=libpq-devel+pq-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libpq-devel.i686 13.4-1.fc35 fedora
+ libpq-devel.x86_64 13.4-1.fc35 @fedora
+ EOI
+ $* libpq <<EOI 2>>EOE != 0
+ dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm <libpq-devel+pq-devel.info
+ error: no installed system package for libpq
+ EOE
+
+
+ : not-available
+ :
+ cat <<EOI >=libpq-devel+pq-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ EOI
+ $* libpq --install libpq <<EOI 2>>EOE != 0
+ dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm <libpq-devel+pq-devel.info
+ sudo dnf makecache --quiet --assumeno --refresh
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm <libpq-devel+pq-devel.info
+ error: no installed or available system package for libpq
+ EOE
+
+
+ : not-available-no-fetch
+ :
+ cat <<EOI >=libpq-devel+pq-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ EOI
+ $* libpq --install --no-fetch libpq <<EOI 2>>EOE != 0
+ dnf-list: libpq-devel pq-devel libpq-devel+pq-devel.info
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libpq-devel pq-devel rpm <libpq-devel+pq-devel.info
+ error: no installed or available system package for libpq
+ EOE
+ }
+
+ : libsqlite3
+ :
+ {
+ +cat <<EOI >=libsqlite3.manifest
+ : 1
+ name: libsqlite3
+ version: 3.39.4+1
+ project: sqlite
+ summary: SQL database engine as an in-process C library
+ license: blessing ; SQLite Blessing.
+ EOI
+
+
+ : dev-resolve-fail
+ :
+ cat <<EOI >=libsqlite3-devel+sqlite3-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ EOI
+ $* libsqlite3 --install libsqlite3 <<EOI 2>>EOE != 0
+ dnf-list: libsqlite3-devel sqlite3-devel libsqlite3-devel+sqlite3-devel.info
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libsqlite3-devel sqlite3-devel rpm <libsqlite3-devel+sqlite3-devel.info
+ sudo dnf makecache --quiet --assumeno --refresh
+ LC_ALL=C dnf list --all --cacheonly --quiet libsqlite3-devel sqlite3-devel rpm <libsqlite3-devel+sqlite3-devel.info
+ error: no installed or available system package for libsqlite3
+ EOE
+
+
+ : installed
+ :
+ : In particular test the project name-based resolution of the -devel
+ : package.
+ :
+ ln -s ../libsqlite3.manifest ./;
+ cat <<EOI >=libsqlite3-devel+sqlite-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ sqlite-devel.x86_64 3.36.0-3.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ sqlite-devel.i686 3.36.0-3.fc35 fedora
+ EOI
+ cat <<EOI >=sqlite-devel.requires;
+ pkgconf-pkg-config i686 0:1.8.0-1.fc35
+ pkgconf-pkg-config x86_64 0:1.8.0-1.fc35
+ sqlite x86_64 0:3.36.0-3.fc35
+ sqlite-libs x86_64 0:3.36.0-3.fc35
+ EOI
+ cat <<EOI >=sqlite-libs.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ sqlite-libs.i686 3.36.0-3.fc35 @fedora
+ sqlite-libs.x86_64 3.36.0-3.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ EOI
+ $* libsqlite3 --install libsqlite3 <<EOI 2>>EOE >>EOO
+ manifest: libsqlite3 libsqlite3.manifest
+
+ dnf-list: libsqlite3-devel sqlite-devel libsqlite3-devel+sqlite-devel.info
+ dnf-repoquery-requires: sqlite-devel 3.36.0-3.fc35 x86_64 true sqlite-devel.requires
+ dnf-list: sqlite-libs sqlite-libs.info
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libsqlite3-devel sqlite-devel rpm <libsqlite3-devel+sqlite-devel.info
+ LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" --installed --disableexcludes=all sqlite-devel-3.36.0-3.fc35.x86_64 <sqlite-devel.requires
+ LC_ALL=C dnf list --all --cacheonly --quiet sqlite-libs rpm <sqlite-libs.info
+ sudo dnf mark --quiet --assumeno install --cacheonly sqlite-libs-3.36.0-3.fc35.x86_64 sqlite-devel-3.36.0-3.fc35.x86_64
+ EOE
+ libsqlite3 3.36.0 (sqlite-libs 3.36.0-3.fc35) installed
+ EOO
+
+
+ : not-installed
+ :
+ : Note that without fetch the -devel package could not be resolved since
+ : `dnf list libsqlite3-devel sqlite-devel` provides no information
+ : regarding any of these packages.
+ :
+ ln -s ../libsqlite3.manifest ./;
+ cat <<EOI >=libsqlite3-devel+sqlite-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ EOI
+ cat <<EOI >=sqlite-devel.requires-fetched;
+ pkgconf-pkg-config i686 0:1.8.0-1.fc35
+ pkgconf-pkg-config x86_64 0:1.8.0-1.fc35
+ sqlite x86_64 0:3.36.0-3.fc35
+ sqlite-libs x86_64 0:3.36.0-3.fc35
+ EOI
+ cat <<EOI >=libsqlite3-devel+sqlite-devel.info-fetched;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ sqlite-devel.i686 3.36.0-3.fc35 fedora
+ sqlite-devel.x86_64 3.36.0-3.fc35 @fedora
+ EOI
+ cat <<EOI >=sqlite-libs.info-fetched;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ sqlite-libs.i686 3.36.0-3.fc35 @fedora
+ sqlite-libs.x86_64 3.36.0-3.fc35 @fedora
+ EOI
+ cat <<EOI >=sqlite-libs.info-installed;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ sqlite-libs.x86_64 3.36.0-3.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ sqlite-libs.i686 3.36.0-3.fc35 @fedora
+ EOI
+ $* libsqlite3 --install libsqlite3 <<EOI 2>>EOE >>EOO
+ manifest: libsqlite3 libsqlite3.manifest
+
+ dnf-list: libsqlite3-devel sqlite-devel libsqlite3-devel+sqlite-devel.info
+ dnf-repoquery-requires-fetched: sqlite-devel 3.36.0-3.fc35 x86_64 false sqlite-devel.requires-fetched
+ dnf-list-fetched: libsqlite3-devel sqlite-devel libsqlite3-devel+sqlite-devel.info-fetched
+ dnf-list-fetched: sqlite-libs sqlite-libs.info-fetched
+ dnf-list-installed: sqlite-libs sqlite-libs.info-installed
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libsqlite3-devel sqlite-devel rpm <libsqlite3-devel+sqlite-devel.info
+ sudo dnf makecache --quiet --assumeno --refresh
+ LC_ALL=C dnf list --all --cacheonly --quiet libsqlite3-devel sqlite-devel rpm <libsqlite3-devel+sqlite-devel.info-fetched
+ LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" sqlite-devel-3.36.0-3.fc35.x86_64 <sqlite-devel.requires-fetched
+ LC_ALL=C dnf list --all --cacheonly --quiet sqlite-libs rpm <sqlite-libs.info-fetched
+ sudo dnf install --quiet --assumeno sqlite-libs.x86_64 sqlite-devel.x86_64
+ sudo dnf mark --quiet --assumeno install --cacheonly sqlite-libs.x86_64 sqlite-devel.x86_64
+ LC_ALL=C dnf list --all --cacheonly --quiet sqlite-libs rpm <sqlite-libs.info-installed
+ EOE
+ libsqlite3 3.36.0 (sqlite-libs 3.36.0-3.fc35) not installed
+ EOO
+ }
+
+ : sqlite3
+ :
+ {
+ +cat <<EOI >=sqlite3.manifest
+ : 1
+ name: sqlite3
+ version: 3.39.4+1
+ project: sqlite
+ summary: SQLite database engine shell program
+ license: blessing ; SQLite Blessing.
+ EOI
+
+
+ : main-resolve-fail
+ :
+ cat <<EOI >=sqlite3.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ EOI
+ $* sqlite3 --install sqlite3 <<EOI 2>>EOE != 0
+ dnf-list: sqlite3 sqlite3.info
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet sqlite3 rpm <sqlite3.info
+ sudo dnf makecache --quiet --assumeno --refresh
+ LC_ALL=C dnf list --all --cacheonly --quiet sqlite3 rpm <sqlite3.info
+ error: no installed or available system package for sqlite3
+ EOE
+
+
+ : installed
+ :
+ : In particular test the project name-based resolution of the main
+ : package.
+ :
+ ln -s ../sqlite3.manifest ./;
+ cat <<EOI >=sqlite3+sqlite.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ sqlite.x86_64 3.36.0-3.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ sqlite.i686 3.36.0-3.fc35 fedora
+ EOI
+ $* sqlite3 --install sqlite3 <<EOI 2>>EOE >>EOO
+ manifest: sqlite3 sqlite3.manifest
+
+ dnf-list: sqlite3 sqlite sqlite3+sqlite.info
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet sqlite3 sqlite rpm <sqlite3+sqlite.info
+ sudo dnf mark --quiet --assumeno install --cacheonly sqlite-3.36.0-3.fc35.x86_64
+ EOE
+ sqlite3 3.36.0 (sqlite 3.36.0-3.fc35) installed
+ EOO
+
+
+ : not-installed
+ :
+ ln -s ../sqlite3.manifest ./;
+ cat <<EOI >=sqlite3+sqlite.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ sqlite.i686 3.35.0-1.fc35 fedora
+ sqlite.x86_64 3.35.0-1.fc35 @fedora
+ EOI
+ cat <<EOI >=sqlite3+sqlite.info-fetched;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ sqlite.i686 3.36.0-3.fc35 fedora
+ sqlite.x86_64 3.36.0-3.fc35 @fedora
+ EOI
+ cat <<EOI >=sqlite.info-installed;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ sqlite.x86_64 3.36.0-3.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ sqlite.i686 3.36.0-3.fc35 fedora
+ EOI
+ $* sqlite3 --install sqlite3 <<EOI 2>>EOE >>EOO
+ manifest: sqlite3 sqlite3.manifest
+
+ dnf-list: sqlite3 sqlite sqlite3+sqlite.info
+ dnf-list-fetched: sqlite3 sqlite sqlite3+sqlite.info-fetched
+ dnf-list-installed: sqlite sqlite.info-installed
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet sqlite3 sqlite rpm <sqlite3+sqlite.info
+ sudo dnf makecache --quiet --assumeno --refresh
+ LC_ALL=C dnf list --all --cacheonly --quiet sqlite3 sqlite rpm <sqlite3+sqlite.info-fetched
+ sudo dnf install --quiet --assumeno sqlite.x86_64
+ sudo dnf mark --quiet --assumeno install --cacheonly sqlite.x86_64
+ LC_ALL=C dnf list --all --cacheonly --quiet sqlite rpm <sqlite.info-installed
+ EOE
+ sqlite3 3.36.0 (sqlite 3.36.0-3.fc35) not installed
+ EOO
+ }
+
+ : libncurses
+ :
+ {
+ +cat <<EOI >=libncurses.manifest
+ : 1
+ name: libncurses
+ version: 6.4
+ upstream-version: 6.4.0
+ project: ncurses
+ fedora-to-downstream-version: /([0-9]+)\.([0-9]+)/\1.\2.0/
+ summary: ncurses C library
+ license: MIT
+ EOI
+ +cat <<EOI >=libncurses-c++.manifest
+ : 1
+ name: libncurses-c++
+ version: 6.4
+ upstream-version: 6.4.0
+ project: ncurses
+ fedora-name: ncurses-c++-libs ncurses-devel
+ fedora-to-downstream-version: /([0-9]+)\.([0-9]+)/\1.\2.0/
+ summary: ncurses C++ library
+ license: MIT
+ EOI
+
+
+ : installed
+ :
+ ln -s ../libncurses.manifest ./;
+ ln -s ../libncurses-c++.manifest ./;
+ cat <<EOI >=libncurses-devel+ncurses-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ ncurses-devel.x86_64 6.2-8.20210508.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ ncurses-devel.i686 6.2-8.20210508.fc35 fedora
+ EOI
+ cat <<EOI >=ncurses-devel.requires;
+ bash i686 0:5.1.8-3.fc35
+ bash x86_64 0:5.1.8-3.fc35
+ ncurses-c++-libs x86_64 0:6.2-8.20210508.fc35
+ ncurses-devel i686 0:6.2-8.20210508.fc35
+ ncurses-devel x86_64 0:6.2-8.20210508.fc35
+ ncurses-libs x86_64 0:6.2-8.20210508.fc35
+ pkgconf-pkg-config i686 0:1.8.0-1.fc35
+ pkgconf-pkg-config x86_64 0:1.8.0-1.fc35
+ EOI
+ cat <<EOI >=ncurses-libs.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ ncurses-libs.i686 6.2-8.20210508.fc35 @fedora
+ ncurses-libs.x86_64 6.2-8.20210508.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ EOI
+ cat <<EOI >=ncurses-c++-libs+ncurses-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ ncurses-c++-libs.x86_64 6.2-8.20210508.fc35 @fedora
+ ncurses-devel.x86_64 6.2-8.20210508.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ ncurses-c++-libs.i686 6.2-8.20210508.fc35 fedora
+ ncurses-devel.i686 6.2-8.20210508.fc35 fedora
+ EOI
+ $* libncurses libncurses-c++ --install libncurses libncurses-c++ <<EOI 2>>EOE >>EOO
+ manifest: libncurses libncurses.manifest
+ manifest: libncurses-c++ libncurses-c++.manifest
+
+ dnf-list: libncurses-devel ncurses-devel libncurses-devel+ncurses-devel.info
+ dnf-repoquery-requires: ncurses-devel 6.2-8.20210508.fc35 x86_64 true ncurses-devel.requires
+ dnf-list: ncurses-libs ncurses-libs.info
+ dnf-list: ncurses-c++-libs ncurses-devel ncurses-c++-libs+ncurses-devel.info
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libncurses-devel ncurses-devel rpm <libncurses-devel+ncurses-devel.info
+ LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" --installed --disableexcludes=all ncurses-devel-6.2-8.20210508.fc35.x86_64 <ncurses-devel.requires
+ LC_ALL=C dnf list --all --cacheonly --quiet ncurses-libs rpm <ncurses-libs.info
+ LC_ALL=C dnf list --all --cacheonly --quiet ncurses-c++-libs ncurses-devel rpm <ncurses-c++-libs+ncurses-devel.info
+ sudo dnf mark --quiet --assumeno install --cacheonly ncurses-libs-6.2-8.20210508.fc35.x86_64 ncurses-devel-6.2-8.20210508.fc35.x86_64 ncurses-c++-libs-6.2-8.20210508.fc35.x86_64
+ EOE
+ libncurses 6.2.0 (ncurses-libs 6.2-8.20210508.fc35) installed
+ libncurses-c++ 6.2.0 (ncurses-c++-libs 6.2-8.20210508.fc35) installed
+ EOO
+
+
+ : part-installed
+ :
+ ln -s ../libncurses.manifest ./;
+ ln -s ../libncurses-c++.manifest ./;
+ cat <<EOI >=libncurses-devel+ncurses-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ ncurses-devel.i686 6.2-8.20210508.fc35 fedora
+ ncurses-devel.x86_64 6.2-8.20210508.fc35 @fedora
+ EOI
+ cat <<EOI >=ncurses-devel.requires-fetched;
+ bash i686 0:5.1.8-3.fc35
+ bash x86_64 0:5.1.8-3.fc35
+ ncurses-c++-libs x86_64 0:6.2-8.20210508.fc35
+ ncurses-devel i686 0:6.2-8.20210508.fc35
+ ncurses-devel x86_64 0:6.2-8.20210508.fc35
+ ncurses-libs x86_64 0:6.2-8.20210508.fc35
+ pkgconf-pkg-config i686 0:1.8.0-1.fc35
+ pkgconf-pkg-config x86_64 0:1.8.0-1.fc35
+ EOI
+ cat <<EOI >=ncurses-libs.info-fetched;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ ncurses-libs.i686 6.2-8.20210508.fc35 @fedora
+ ncurses-libs.x86_64 6.2-8.20210508.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ EOI
+ cat <<EOI >=ncurses-c++-libs+ncurses-devel.info-fetched;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ ncurses-c++-libs.x86_64 6.2-8.20210508.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ ncurses-c++-libs.i686 6.2-8.20210508.fc35 fedora
+ ncurses-devel.i686 6.2-8.20210508.fc35 fedora
+ ncurses-devel.x86_64 6.2-8.20210508.fc35 fedora
+ EOI
+ cat <<EOI >=ncurses-libs+ncurses-c++-libs.info-installed;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ ncurses-c++-libs.x86_64 6.2-8.20210508.fc35 @fedora
+ ncurses-libs.i686 6.2-8.20210508.fc35 @fedora
+ ncurses-libs.x86_64 6.2-8.20210508.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ ncurses-c++-libs.i686 6.2-8.20210508.fc35 fedora
+ EOI
+ $* libncurses libncurses-c++ --install libncurses libncurses-c++ <<EOI 2>>EOE >>EOO
+ manifest: libncurses libncurses.manifest
+ manifest: libncurses-c++ libncurses-c++.manifest
+
+ dnf-list: libncurses-devel ncurses-devel libncurses-devel+ncurses-devel.info
+ dnf-repoquery-requires-fetched: ncurses-devel 6.2-8.20210508.fc35 x86_64 false ncurses-devel.requires-fetched
+ dnf-list-fetched: ncurses-libs ncurses-libs.info-fetched
+ dnf-list-fetched: ncurses-c++-libs ncurses-devel ncurses-c++-libs+ncurses-devel.info-fetched
+ dnf-list-installed: ncurses-libs ncurses-c++-libs ncurses-libs+ncurses-c++-libs.info-installed
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libncurses-devel ncurses-devel rpm <libncurses-devel+ncurses-devel.info
+ sudo dnf makecache --quiet --assumeno --refresh
+ LC_ALL=C dnf list --all --cacheonly --quiet libncurses-devel ncurses-devel rpm <libncurses-devel+ncurses-devel.info
+ LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" ncurses-devel-6.2-8.20210508.fc35.x86_64 <ncurses-devel.requires-fetched
+ LC_ALL=C dnf list --all --cacheonly --quiet ncurses-libs rpm <ncurses-libs.info-fetched
+ LC_ALL=C dnf list --all --cacheonly --quiet ncurses-c++-libs ncurses-devel rpm <ncurses-c++-libs+ncurses-devel.info-fetched
+ sudo dnf install --quiet --assumeno ncurses-libs.x86_64 ncurses-devel.x86_64 ncurses-c++-libs.x86_64
+ sudo dnf mark --quiet --assumeno install --cacheonly ncurses-libs.x86_64 ncurses-devel.x86_64 ncurses-c++-libs.x86_64
+ LC_ALL=C dnf list --all --cacheonly --quiet ncurses-libs ncurses-c++-libs rpm <ncurses-libs+ncurses-c++-libs.info-installed
+ EOE
+ libncurses 6.2.0 (ncurses-libs 6.2-8.20210508.fc35) part installed
+ libncurses-c++ 6.2.0 (ncurses-c++-libs 6.2-8.20210508.fc35) part installed
+ EOO
+
+
+ : not-installed
+ :
+ ln -s ../libncurses.manifest ./;
+ ln -s ../libncurses-c++.manifest ./;
+ cat <<EOI >=libncurses-devel+ncurses-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ ncurses-devel.i686 6.2-8.20210508.fc35 fedora
+ ncurses-devel.x86_64 6.2-8.20210508.fc35 @fedora
+ EOI
+ cat <<EOI >=libncurses-devel+ncurses-devel.info-fetched;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ ncurses-devel.i686 6.2-8.20210508.fc35 fedora
+ ncurses-devel.x86_64 6.2-8.20210508.fc35 fedora
+ EOI
+ cat <<EOI >=ncurses-devel.requires-fetched;
+ bash i686 0:5.1.8-3.fc35
+ bash x86_64 0:5.1.8-3.fc35
+ ncurses-c++-libs x86_64 0:6.2-8.20210508.fc35
+ ncurses-devel i686 0:6.2-8.20210508.fc35
+ ncurses-devel x86_64 0:6.2-8.20210508.fc35
+ ncurses-libs x86_64 0:6.2-8.20210508.fc35
+ pkgconf-pkg-config i686 0:1.8.0-1.fc35
+ pkgconf-pkg-config x86_64 0:1.8.0-1.fc35
+ EOI
+ cat <<EOI >=ncurses-libs.info-fetched;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ ncurses-libs.i686 6.2-8.20210508.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ ncurses-libs.x86_64 6.2-8.20210508.fc35 @fedora
+ EOI
+ cat <<EOI >=ncurses-c++-libs+ncurses-devel.info-fetched;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ ncurses-c++-libs.i686 6.2-8.20210508.fc35 fedora
+ ncurses-c++-libs.x86_64 6.2-8.20210508.fc35 @fedora
+ ncurses-devel.i686 6.2-8.20210508.fc35 fedora
+ ncurses-devel.x86_64 6.2-8.20210508.fc35 fedora
+ EOI
+ cat <<EOI >=ncurses-libs+ncurses-c++-libs.info-installed;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ ncurses-c++-libs.x86_64 6.2-8.20210508.fc35 @fedora
+ ncurses-libs.i686 6.2-8.20210508.fc35 @fedora
+ ncurses-libs.x86_64 6.2-8.20210508.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ ncurses-c++-libs.i686 6.2-8.20210508.fc35 fedora
+ EOI
+ $* libncurses libncurses-c++ --install libncurses libncurses-c++ <<EOI 2>>EOE >>EOO
+ manifest: libncurses libncurses.manifest
+ manifest: libncurses-c++ libncurses-c++.manifest
+
+ dnf-list: libncurses-devel ncurses-devel libncurses-devel+ncurses-devel.info
+ dnf-list-fetched: libncurses-devel ncurses-devel libncurses-devel+ncurses-devel.info-fetched
+ dnf-repoquery-requires-fetched: ncurses-devel 6.2-8.20210508.fc35 x86_64 false ncurses-devel.requires-fetched
+ dnf-list-fetched: ncurses-libs ncurses-libs.info-fetched
+ dnf-list-fetched: ncurses-c++-libs ncurses-devel ncurses-c++-libs+ncurses-devel.info-fetched
+ dnf-list-installed: ncurses-libs ncurses-c++-libs ncurses-libs+ncurses-c++-libs.info-installed
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libncurses-devel ncurses-devel rpm <libncurses-devel+ncurses-devel.info
+ sudo dnf makecache --quiet --assumeno --refresh
+ LC_ALL=C dnf list --all --cacheonly --quiet libncurses-devel ncurses-devel rpm <libncurses-devel+ncurses-devel.info-fetched
+ LC_ALL=C dnf repoquery --requires --quiet --cacheonly --resolve --qf "%{name} %{arch} %{epoch}:%{version}-%{release}" ncurses-devel-6.2-8.20210508.fc35.x86_64 <ncurses-devel.requires-fetched
+ LC_ALL=C dnf list --all --cacheonly --quiet ncurses-libs rpm <ncurses-libs.info-fetched
+ LC_ALL=C dnf list --all --cacheonly --quiet ncurses-c++-libs ncurses-devel rpm <ncurses-c++-libs+ncurses-devel.info-fetched
+ sudo dnf install --quiet --assumeno ncurses-libs.x86_64 ncurses-devel.x86_64 ncurses-c++-libs.x86_64
+ sudo dnf mark --quiet --assumeno install --cacheonly ncurses-libs.x86_64 ncurses-devel.x86_64 ncurses-c++-libs.x86_64
+ LC_ALL=C dnf list --all --cacheonly --quiet ncurses-libs ncurses-c++-libs rpm <ncurses-libs+ncurses-c++-libs.info-installed
+ EOE
+ libncurses 6.2.0 (ncurses-libs 6.2-8.20210508.fc35) not installed
+ libncurses-c++ 6.2.0 (ncurses-c++-libs 6.2-8.20210508.fc35) not installed
+ EOO
+ }
+
+ : libsigc++
+ :
+ {
+ +cat <<EOI >=libsigc++.manifest
+ : 1
+ name: libsigc++
+ version: 3.4.0
+ fedora-name: libsigc++30 libsigc++30-devel libsigc++30-doc
+ fedora-name: libsigc++20 libsigc++20-devel libsigc++20-doc
+ summary: Typesafe callback system for standard C++
+ license: LGPL-3.0-only
+ EOI
+
+
+ : one-full-installed
+ :
+ ln -s ../libsigc++.manifest ./;
+ cat <<EOI >=libsigc++30+libsigc++30-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ libsigc++30.x86_64 3.0.7-2.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libsigc++30.i686 3.0.7-2.fc35 fedora
+ libsigc++30-devel.i686 3.0.7-2.fc35 fedora
+ libsigc++30-devel.x86_64 3.0.7-2.fc35 fedora
+ EOI
+ cat <<EOI >=libsigc++20+libsigc++20-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ libsigc++20.x86_64 2.10.7-3.fc35 @fedora
+ libsigc++20-devel.x86_64 2.10.7-3.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libsigc++20.i686 2.10.7-3.fc35 fedora
+ libsigc++20-devel.i686 2.10.7-3.fc35 fedora
+ EOI
+ $* libsigc++ --install libsigc++ <<EOI 2>>EOE >>EOO
+ manifest: libsigc++ libsigc++.manifest
+
+ dnf-list: libsigc++30 libsigc++30-devel libsigc++30+libsigc++30-devel.info
+ dnf-list: libsigc++20 libsigc++20-devel libsigc++20+libsigc++20-devel.info
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libsigc++30 libsigc++30-devel rpm <libsigc++30+libsigc++30-devel.info
+ LC_ALL=C dnf list --all --cacheonly --quiet libsigc++20 libsigc++20-devel rpm <libsigc++20+libsigc++20-devel.info
+ sudo dnf mark --quiet --assumeno install --cacheonly libsigc++20-2.10.7-3.fc35.x86_64 libsigc++20-devel-2.10.7-3.fc35.x86_64
+ EOE
+ libsigc++ 2.10.7 (libsigc++20 2.10.7-3.fc35) installed
+ EOO
+
+
+ : one-part-installed
+ :
+ ln -s ../libsigc++.manifest ./;
+ cat <<EOI >=libsigc++30+libsigc++30-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libsigc++30.i686 3.0.7-2.fc35 fedora
+ libsigc++30.x86_64 3.0.7-2.fc35 fedora
+ libsigc++30-devel.i686 3.0.7-2.fc35 fedora
+ libsigc++30-devel.x86_64 3.0.7-2.fc35 fedora
+ EOI
+ cat <<EOI >=libsigc++20+libsigc++20-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ libsigc++20.x86_64 2.10.7-3.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libsigc++20.i686 2.10.7-3.fc35 fedora
+ libsigc++20-devel.i686 2.10.7-3.fc35 fedora
+ libsigc++20-devel.x86_64 2.10.7-3.fc35 fedora
+ EOI
+ cat <<EOI >=libsigc++20.info-installed;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ libsigc++20.x86_64 2.10.7-3.fc35 @fedora
+ Available Packages
+ rpm.x86_64 4.17.1-3.fc35 updates
+ libsigc++20.i686 2.10.7-3.fc35 fedora
+ EOI
+ $* libsigc++ --install libsigc++ <<EOI 2>>EOE >>EOO
+ manifest: libsigc++ libsigc++.manifest
+
+ dnf-list: libsigc++30 libsigc++30-devel libsigc++30+libsigc++30-devel.info
+ dnf-list: libsigc++20 libsigc++20-devel libsigc++20+libsigc++20-devel.info
+ dnf-list-installed: libsigc++20 libsigc++20.info-installed
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libsigc++30 libsigc++30-devel rpm <libsigc++30+libsigc++30-devel.info
+ LC_ALL=C dnf list --all --cacheonly --quiet libsigc++20 libsigc++20-devel rpm <libsigc++20+libsigc++20-devel.info
+ sudo dnf makecache --quiet --assumeno --refresh
+ LC_ALL=C dnf list --all --cacheonly --quiet libsigc++30 libsigc++30-devel rpm <libsigc++30+libsigc++30-devel.info
+ LC_ALL=C dnf list --all --cacheonly --quiet libsigc++20 libsigc++20-devel rpm <libsigc++20+libsigc++20-devel.info
+ sudo dnf install --quiet --assumeno libsigc++20.x86_64 libsigc++20-devel.x86_64
+ sudo dnf mark --quiet --assumeno install --cacheonly libsigc++20.x86_64 libsigc++20-devel.x86_64
+ LC_ALL=C dnf list --all --cacheonly --quiet libsigc++20 rpm <libsigc++20.info-installed
+ EOE
+ libsigc++ 2.10.7 (libsigc++20 2.10.7-3.fc35) part installed
+ EOO
+
+
+ : none-installed
+ :
+ ln -s ../libsigc++.manifest ./;
+ cat <<EOI >=libsigc++30+libsigc++30-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ libsigc++30.i686 3.0.7-2.fc35 fedora
+ libsigc++30.x86_64 3.0.7-2.fc35 fedora
+ libsigc++30-devel.i686 3.0.7-2.fc35 fedora
+ libsigc++30-devel.x86_64 3.0.7-2.fc35 fedora
+ rpm.x86_64 4.17.1-3.fc35 updates
+ EOI
+ cat <<EOI >=libsigc++20+libsigc++20-devel.info;
+ Installed Packages
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ libsigc++20.i686 2.10.7-3.fc35 fedora
+ libsigc++20.x86_64 2.10.7-3.fc35 @fedora
+ libsigc++20-devel.i686 2.10.7-3.fc35 fedora
+ libsigc++20-devel.x86_64 2.10.7-3.fc35 fedora
+ rpm.x86_64 4.17.1-3.fc35 updates
+ EOI
+ $* libsigc++ --install libsigc++ <<EOI 2>>EOE != 0
+ manifest: libsigc++ libsigc++.manifest
+
+ dnf-list: libsigc++30 libsigc++30-devel libsigc++30+libsigc++30-devel.info
+ dnf-list: libsigc++20 libsigc++20-devel libsigc++20+libsigc++20-devel.info
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libsigc++30 libsigc++30-devel rpm <libsigc++30+libsigc++30-devel.info
+ LC_ALL=C dnf list --all --cacheonly --quiet libsigc++20 libsigc++20-devel rpm <libsigc++20+libsigc++20-devel.info
+ sudo dnf makecache --quiet --assumeno --refresh
+ LC_ALL=C dnf list --all --cacheonly --quiet libsigc++30 libsigc++30-devel rpm <libsigc++30+libsigc++30-devel.info
+ LC_ALL=C dnf list --all --cacheonly --quiet libsigc++20 libsigc++20-devel rpm <libsigc++20+libsigc++20-devel.info
+ error: multiple available fedora packages for libsigc++
+ info: candidate: libsigc++30 3.0.7-2.fc35
+ info: candidate: libsigc++20 2.10.7-3.fc35
+ info: consider installing the desired package manually and retrying the bpkg command
+ EOE
+
+
+ : both-part-installed
+ :
+ ln -s ../libsigc++.manifest ./;
+ cat <<EOI >=libsigc++30+libsigc++30-devel.info;
+ Installed Packages
+ libsigc++30.x86_64 3.0.7-2.fc35 fedora
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ libsigc++30.i686 3.0.7-2.fc35 fedora
+ libsigc++30-devel.i686 3.0.7-2.fc35 fedora
+ libsigc++30-devel.x86_64 3.0.7-2.fc35 fedora
+ rpm.x86_64 4.17.1-3.fc35 updates
+ EOI
+ cat <<EOI >=libsigc++20+libsigc++20-devel.info;
+ Installed Packages
+ libsigc++20.x86_64 2.10.7-3.fc35 @fedora
+ rpm.x86_64 4.17.1-2.fc35 @updates
+ Available Packages
+ libsigc++20.i686 2.10.7-3.fc35 fedora
+ libsigc++20-devel.i686 2.10.7-3.fc35 fedora
+ libsigc++20-devel.x86_64 2.10.7-3.fc35 fedora
+ rpm.x86_64 4.17.1-3.fc35 updates
+ EOI
+ $* libsigc++ --install libsigc++ <<EOI 2>>EOE != 0
+ manifest: libsigc++ libsigc++.manifest
+
+ dnf-list: libsigc++30 libsigc++30-devel libsigc++30+libsigc++30-devel.info
+ dnf-list: libsigc++20 libsigc++20-devel libsigc++20+libsigc++20-devel.info
+ EOI
+ LC_ALL=C dnf list --all --cacheonly --quiet libsigc++30 libsigc++30-devel rpm <libsigc++30+libsigc++30-devel.info
+ LC_ALL=C dnf list --all --cacheonly --quiet libsigc++20 libsigc++20-devel rpm <libsigc++20+libsigc++20-devel.info
+ sudo dnf makecache --quiet --assumeno --refresh
+ LC_ALL=C dnf list --all --cacheonly --quiet libsigc++30 libsigc++30-devel rpm <libsigc++30+libsigc++30-devel.info
+ LC_ALL=C dnf list --all --cacheonly --quiet libsigc++20 libsigc++20-devel rpm <libsigc++20+libsigc++20-devel.info
+ error: multiple partially installed fedora packages for libsigc++
+ info: candidate: libsigc++30 3.0.7-2.fc35, missing components: libsigc++30-devel
+ info: candidate: libsigc++20 2.10.7-3.fc35, missing components: libsigc++20-devel
+ info: consider fully installing the desired package manually and retrying the bpkg command
+ EOE
+ }
+}
diff --git a/bpkg/system-package-manager.cxx b/bpkg/system-package-manager.cxx
new file mode 100644
index 0000000..373e8ff
--- /dev/null
+++ b/bpkg/system-package-manager.cxx
@@ -0,0 +1,904 @@
+// file : bpkg/system-package-manager.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <bpkg/system-package-manager.hxx>
+
+#include <sstream>
+
+#include <libbutl/regex.hxx>
+#include <libbutl/semantic-version.hxx>
+#include <libbutl/json/parser.hxx>
+
+#include <bpkg/package.hxx>
+#include <bpkg/package-odb.hxx>
+#include <bpkg/database.hxx>
+#include <bpkg/diagnostics.hxx>
+
+#include <bpkg/pkg-bindist-options.hxx>
+
+#include <bpkg/system-package-manager-debian.hxx>
+#include <bpkg/system-package-manager-fedora.hxx>
+#include <bpkg/system-package-manager-archive.hxx>
+
+using namespace std;
+using namespace butl;
+
+namespace bpkg
+{
+ system_package_manager::
+ ~system_package_manager ()
+ {
+ // vtable
+ }
+
+ static optional<os_release>
+ host_release (const target_triplet& host)
+ try
+ {
+ return butl::host_os_release (host);
+ }
+ catch (const runtime_error& e)
+ {
+ fail << "unable to determine host operating system release: " << e << endf;
+ }
+
+ // Return true if the specified operating system is or like the specified
+ // id.
+ //
+ static inline bool
+ is_or_like (const os_release& os, const char* id)
+ {
+ return (os.name_id == id ||
+ find_if (os.like_ids.begin (), os.like_ids.end (),
+ [id] (const string& n)
+ {
+ return n == id;
+ }) != os.like_ids.end ());
+ }
+
+ unique_ptr<system_package_manager>
+ make_consumption_system_package_manager (const common_options& co,
+ const target_triplet& host,
+ const string& name,
+ const string& arch,
+ bool install,
+ bool fetch,
+ bool yes,
+ const string& sudo)
+ {
+ // Note: similar to make_consumption_system_package_manager() below.
+
+ optional<bool> progress (co.progress () ? true :
+ co.no_progress () ? false :
+ optional<bool> ());
+
+ optional<size_t> fetch_timeout (co.fetch_timeout_specified ()
+ ? co.fetch_timeout ()
+ : optional<size_t> ());
+
+ unique_ptr<system_package_manager> r;
+
+ if (optional<os_release> oos = host_release (host))
+ {
+ os_release& os (*oos);
+
+ if (host.class_ == "linux")
+ {
+ if (is_or_like (os, "debian") ||
+ is_or_like (os, "ubuntu"))
+ {
+ if (!name.empty () && name != "debian")
+ fail << "unsupported package manager '" << name << "' for "
+ << os.name_id << " host";
+
+ // If we recognized this as Debian-like in an ad hoc manner, then
+ // add debian to like_ids.
+ //
+ if (os.name_id != "debian" && !is_or_like (os, "debian"))
+ os.like_ids.push_back ("debian");
+
+ r.reset (new system_package_manager_debian (
+ move (os), host, arch,
+ progress, fetch_timeout, install, fetch, yes, sudo));
+ }
+ else if (is_or_like (os, "fedora") ||
+ is_or_like (os, "rhel") ||
+ is_or_like (os, "centos") ||
+ is_or_like (os, "rocky") ||
+ is_or_like (os, "almalinux"))
+ {
+ if (!name.empty () && name != "fedora")
+ fail << "unsupported package manager '" << name << "' for "
+ << os.name_id << " host";
+
+ // If we recognized this as Fedora-like in an ad hoc manner, then
+ // add fedora to like_ids.
+ //
+ if (os.name_id != "fedora" && !is_or_like (os, "fedora"))
+ os.like_ids.push_back ("fedora");
+
+ r.reset (new system_package_manager_fedora (
+ move (os), host, arch,
+ progress, fetch_timeout, install, fetch, yes, sudo));
+ }
+ // NOTE: remember to update the --sys-distribution pkg-build option
+ // documentation if adding support for another package manager.
+ }
+ }
+
+ if (r == nullptr)
+ {
+ if (!name.empty ())
+ fail << "unsupported package manager '" << name << "' for host "
+ << host;
+ }
+
+ return r;
+ }
+
+ pair<unique_ptr<system_package_manager>, string>
+ make_production_system_package_manager (const pkg_bindist_options& o,
+ const target_triplet& host,
+ const string& name,
+ const string& arch)
+ {
+ // Note: similar to make_production_system_package_manager() above.
+
+ optional<bool> progress (o.progress () ? true :
+ o.no_progress () ? false :
+ optional<bool> ());
+
+ optional<os_release> oos;
+ if (o.os_release_id_specified ())
+ {
+ oos = os_release ();
+ oos->name_id = o.os_release_id ();
+ }
+ else
+ oos = host_release (host);
+
+ if (o.os_release_name_specified ())
+ oos->name = o.os_release_name ();
+
+ if (o.os_release_version_id_specified ())
+ oos->version_id = o.os_release_version_id ();
+
+ pair<unique_ptr<system_package_manager>, string> r;
+ if (oos)
+ {
+ os_release& os (*oos);
+
+ // Note that we don't make archive the default on any platform in case
+ // we later want to support its native package format.
+ //
+ if (name == "archive")
+ {
+ r.first.reset (new system_package_manager_archive (
+ move (os), host, arch, progress, &o));
+ r.second = "archive";
+ }
+ else if (host.class_ == "linux")
+ {
+ if (is_or_like (os, "debian") ||
+ is_or_like (os, "ubuntu"))
+ {
+ if (!name.empty () && name != "debian")
+ fail << "unsupported package manager '" << name << "' for "
+ << os.name_id << " host";
+
+ if (os.name_id != "debian" && !is_or_like (os, "debian"))
+ os.like_ids.push_back ("debian");
+
+ r.first.reset (new system_package_manager_debian (
+ move (os), host, arch, progress, &o));
+ r.second = "debian";
+ }
+ else if (is_or_like (os, "fedora") ||
+ is_or_like (os, "rhel") ||
+ is_or_like (os, "centos") ||
+ is_or_like (os, "rocky") ||
+ is_or_like (os, "almalinux"))
+ {
+ if (!name.empty () && name != "fedora")
+ fail << "unsupported package manager '" << name << "' for "
+ << os.name_id << " host";
+
+ if (os.name_id != "fedora" && !is_or_like (os, "fedora"))
+ os.like_ids.push_back ("fedora");
+
+ r.first.reset (new system_package_manager_fedora (
+ move (os), host, arch, progress, &o));
+ r.second = "fedora";
+ }
+ // NOTE: remember to update the --distribution pkg-bindist option
+ // documentation if adding support for another package manager.
+ }
+ }
+
+ if (r.first == nullptr)
+ {
+ if (!name.empty ())
+ fail << "unsupported package manager '" << name << "' for host "
+ << host;
+ }
+
+ return r;
+ }
+
+ // Return the version id parsed as a semantic version if it is not empty and
+ // the "0" semantic version otherwise. Issue diagnostics and fail on parsing
+ // errors.
+ //
+ // Note: the name_id argument is only used for diagnostics.
+ //
+ static inline semantic_version
+ parse_version_id (const string& version_id, const string& name_id)
+ {
+ if (version_id.empty ())
+ return semantic_version (0, 0, 0);
+
+ try
+ {
+ return semantic_version (version_id, semantic_version::allow_omit_minor);
+ }
+ catch (const invalid_argument& e)
+ {
+ fail << "invalid version '" << version_id << "' for " << name_id
+ << " host: " << e << endf;
+ }
+ }
+
+ // Parse the <distribution> component of the specified <distribution>-*
+ // value into the distribution name and version (return as "0" if not
+ // present). Leave in the d argument the string representation of the
+ // version (used to detect the special non-native <name>_0). Issue
+ // diagnostics and fail on parsing errors.
+ //
+ // Note: the value_name, ap, and af arguments are only used for diagnostics.
+ //
+ static pair<string, semantic_version>
+ parse_distribution (string& d, // <name>[_<version>]
+ const string& value_name,
+ const shared_ptr<available_package>& ap,
+ const lazy_shared_ptr<repository_fragment>& af)
+ {
+ size_t p (d.rfind ('_')); // Version-separating underscore.
+
+ // If the '_' separator is present, then make sure that the right-hand
+ // part looks like a version (not empty and only contains digits and
+ // dots).
+ //
+ if (p != string::npos)
+ {
+ if (p != d.size () - 1)
+ {
+ for (size_t i (p + 1); i != d.size (); ++i)
+ {
+ if (!digit (d[i]) && d[i] != '.')
+ {
+ p = string::npos;
+ break;
+ }
+ }
+ }
+ else
+ p = string::npos;
+ }
+
+ // Parse the distribution version if present and leave it "0" otherwise.
+ //
+ string dn;
+ semantic_version dv (0, 0, 0);
+ if (p != string::npos)
+ {
+ dn.assign (d, 0, p);
+ d.erase (0, p + 1);
+
+ try
+ {
+ dv = semantic_version (d, semantic_version::allow_omit_minor);
+ }
+ catch (const invalid_argument& e)
+ {
+ // Note: the repository fragment may have no database associated when
+ // used in tests.
+ //
+ shared_ptr<repository_fragment> f (af.get_eager ());
+ database* db (!(f != nullptr && !af.loaded ()) // Not transient?
+ ? &af.database ()
+ : nullptr);
+
+ diag_record dr (fail);
+ dr << "invalid distribution version '" << d << "' in value "
+ << value_name << " for package " << ap->id.name << ' '
+ << ap->version;
+
+ if (db != nullptr)
+ dr << *db;
+
+ dr << " in repository " << (f != nullptr ? f : af.load ())->location
+ << ": " << e;
+ }
+ }
+ else
+ {
+ dn = move (d);
+ d.clear ();
+ }
+
+ return make_pair (move (dn), move (dv));
+ }
+
+ strings system_package_manager::
+ system_package_names (const available_packages& aps,
+ const string& name_id,
+ const string& version_id,
+ const vector<string>& like_ids,
+ bool native)
+ {
+ assert (!aps.empty ());
+
+ semantic_version vid (parse_version_id (version_id, name_id));
+
+ // Return those <name>[_<version>]-name distribution values of the
+ // specified available packages whose <name> component matches the
+ // specified distribution name and the <version> component (assumed as "0"
+ // if not present) is less or equal the specified distribution version.
+ // Suppress duplicate values.
+ //
+ auto name_values = [&aps, native] (const string& n,
+ const semantic_version& v)
+ {
+ strings r;
+
+ // For each available package sort the system package names in the
+ // distribution version descending order and then append them to the
+ // resulting list, keeping this order and suppressing duplicates.
+ //
+ using name_version = pair<string, semantic_version>;
+ vector<name_version> nvs; // Reuse the buffer.
+
+ for (const auto& a: aps)
+ {
+ nvs.clear ();
+
+ const shared_ptr<available_package>& ap (a.first);
+
+ for (const distribution_name_value& dv: ap->distribution_values)
+ {
+ if (optional<string> d = dv.distribution ("-name"))
+ {
+ pair<string, semantic_version> dnv (
+ parse_distribution (*d, dv.name, ap, a.second));
+
+ // Skip <name>_0 if we are only interested in the native mappings.
+ // If we are interested in the non-native mapping, then we treat
+ // <name>_0 as the matching version.
+ //
+ bool nn (*d == "0");
+ if (nn && native)
+ continue;
+
+ semantic_version& dvr (dnv.second);
+
+ if (dnv.first == n && (nn || dvr <= v))
+ {
+ // Add the name/version pair to the sorted vector.
+ //
+ // If this is the non-native mapping, then return just that.
+ //
+ if (nn)
+ {
+ r.clear (); // Drop anything we have accumulated so far.
+ r.push_back (move (dv.value));
+ return r;
+ }
+
+ name_version nv (make_pair (dv.value, move (dvr)));
+
+ nvs.insert (upper_bound (nvs.begin (), nvs.end (), nv,
+ [] (const name_version& x,
+ const name_version& y)
+ {return x.second > y.second;}),
+ move (nv));
+ }
+ }
+ }
+
+ // Append the sorted names to the resulting list.
+ //
+ for (name_version& nv: nvs)
+ {
+ if (find_if (r.begin (), r.end (),
+ [&nv] (const string& n) {return nv.first == n;}) ==
+ r.end ())
+ {
+ r.push_back (move (nv.first));
+ }
+ }
+ }
+
+ return r;
+ };
+
+ // Collect distribution values for those <distribution>-name names which
+ // match the name id and refer to the version which is less or equal than
+ // the version id.
+ //
+ strings r (name_values (name_id, vid));
+
+ // If the resulting list is empty and the like ids are specified, then
+ // re-collect but now using the like id and "0" version id instead.
+ //
+ if (r.empty ())
+ {
+ for (const string& like_id: like_ids)
+ {
+ r = name_values (like_id, semantic_version (0, 0, 0));
+ if (!r.empty ())
+ break;
+ }
+ }
+
+ return r;
+ }
+
+ optional<string> system_package_manager::
+ system_package_version (const shared_ptr<available_package>& ap,
+ const lazy_shared_ptr<repository_fragment>& af,
+ const string& name_id,
+ const string& version_id,
+ const vector<string>& like_ids)
+ {
+ semantic_version vid (parse_version_id (version_id, name_id));
+
+ // Iterate over the <name>[_<version>]-version distribution values of the
+ // passed available package. Only consider those values whose <name>
+ // component matches the specified distribution name and the <version>
+ // component (assumed as "0" if not present) is less or equal the
+ // specified distribution version. Return the system package version if
+ // the distribution version is equal to the specified one. Otherwise (the
+ // version is less), continue iterating while preferring system version
+ // candidates for greater distribution versions. Note that here we are
+ // trying to pick the system version with distribution version closest to
+ // (but never greater than) the specified distribution version, similar to
+ // what we do in downstream_package_version() (see its
+ // downstream_version() lambda for details).
+ //
+ auto system_version = [&ap, &af] (const string& n,
+ const semantic_version& v)
+ -> optional<string>
+ {
+ optional<string> r;
+ semantic_version rv;
+
+ for (const distribution_name_value& dv: ap->distribution_values)
+ {
+ if (optional<string> d = dv.distribution ("-version"))
+ {
+ pair<string, semantic_version> dnv (
+ parse_distribution (*d, dv.name, ap, af));
+
+ semantic_version& dvr (dnv.second);
+
+ if (dnv.first == n && dvr <= v)
+ {
+ // If the distribution version is equal to the specified one, then
+ // we are done. Otherwise, save the system version if it is
+ // preferable and continue iterating.
+ //
+ if (dvr == v)
+ return move (dv.value);
+
+ if (!r || rv < dvr)
+ {
+ r = move (dv.value);
+ rv = move (dvr);
+ }
+ }
+ }
+ }
+
+ return r;
+ };
+
+ // Try to deduce the system package version using the
+ // <distribution>-version values that match the name id and refer to the
+ // version which is less or equal than the version id.
+ //
+ optional<string> r (system_version (name_id, vid));
+
+ // If the system package version is not deduced and the like ids are
+ // specified, then re-try but now using the like id and "0" version id
+ // instead.
+ //
+ if (!r)
+ {
+ for (const string& like_id: like_ids)
+ {
+ r = system_version (like_id, semantic_version (0, 0, 0));
+ if (r)
+ break;
+ }
+ }
+
+ return r;
+
+ }
+
+ optional<version> system_package_manager::
+ downstream_package_version (const string& system_version,
+ const available_packages& aps,
+ const string& name_id,
+ const string& version_id,
+ const vector<string>& like_ids)
+ {
+ assert (!aps.empty ());
+
+ semantic_version vid (parse_version_id (version_id, name_id));
+
+ // Iterate over the passed available packages (in version descending
+ // order) and over the <name>[_<version>]-to-downstream-version
+ // distribution values they contain. Only consider those values whose
+ // <name> component matches the specified distribution name and the
+ // <version> component (assumed as "0" if not present) is less or equal
+ // the specified distribution version. For such values match the regex
+ // pattern against the passed system version and if it matches consider
+ // the replacement as the resulting downstream version candidate. Return
+ // this downstream version if the distribution version is equal to the
+ // specified one. Otherwise (the version is less), continue iterating
+ // while preferring downstream version candidates for greater distribution
+ // versions. Note that here we are trying to use a version mapping for the
+ // distribution version closest to (but never greater than) the specified
+ // distribution version. So, for example, if both following values contain
+ // a matching mapping, then for debian 11 we prefer the downstream version
+ // produced by the debian_10-to-downstream-version value:
+ //
+ // debian_9-to-downstream-version
+ // debian_10-to-downstream-version
+ //
+ auto downstream_version = [&aps, &system_version]
+ (const string& n,
+ const semantic_version& v) -> optional<version>
+ {
+ optional<version> r;
+ semantic_version rv;
+
+ for (const auto& a: aps)
+ {
+ const shared_ptr<available_package>& ap (a.first);
+
+ for (const distribution_name_value& nv: ap->distribution_values)
+ {
+ if (optional<string> d = nv.distribution ("-to-downstream-version"))
+ {
+ pair<string, semantic_version> dnv (
+ parse_distribution (*d, nv.name, ap, a.second));
+
+ semantic_version& dvr (dnv.second);
+
+ if (dnv.first == n && dvr <= v)
+ {
+ auto bad_value = [&nv, &ap, &a] (const string& d)
+ {
+ // Note: the repository fragment may have no database
+ // associated when used in tests.
+ //
+ const lazy_shared_ptr<repository_fragment>& af (a.second);
+ shared_ptr<repository_fragment> f (af.get_eager ());
+ database* db (!(f != nullptr && !af.loaded ()) // Not transient?
+ ? &af.database ()
+ : nullptr);
+
+ diag_record dr (fail);
+ dr << "invalid distribution value '" << nv.name << ": "
+ << nv.value << "' for package " << ap->id.name << ' '
+ << ap->version;
+
+ if (db != nullptr)
+ dr << *db;
+
+ dr << " in repository "
+ << (f != nullptr ? f : af.load ())->location << ": " << d;
+ };
+
+ // Parse the distribution value into the regex pattern and the
+ // replacement.
+ //
+ // Note that in the future we may add support for some regex
+ // flags.
+ //
+ pair<string, string> rep;
+ try
+ {
+ size_t end;
+ const string& val (nv.value);
+ rep = regex_replace_parse (val.c_str (), val.size (), end);
+ }
+ catch (const invalid_argument& e)
+ {
+ bad_value (e.what ());
+ }
+
+ // Match the regex pattern against the system version and skip
+ // the value if it doesn't match or proceed to parsing the
+ // downstream version resulting from the regex replacement
+ // otherwise.
+ //
+ string dv;
+ try
+ {
+ regex re (rep.first, regex::ECMAScript);
+
+ pair<string, bool> rr (
+ regex_replace_match (system_version, re, rep.second));
+
+ // Skip the regex if it doesn't match.
+ //
+ if (!rr.second)
+ continue;
+
+ dv = move (rr.first);
+ }
+ catch (const regex_error& e)
+ {
+ // Print regex_error description if meaningful (no space).
+ //
+ ostringstream os;
+ os << "invalid regex pattern '" << rep.first << "'" << e;
+ bad_value (os.str ());
+ }
+
+ // Parse the downstream version.
+ //
+ try
+ {
+ version ver (dv);
+
+ // If the distribution version is equal to the specified one,
+ // then we are done. Otherwise, save the downstream version if
+ // it is preferable and continue iterating.
+ //
+ // Note that bailing out immediately in the former case is
+ // essential. Otherwise, we can potentially fail later on, for
+ // example, some ill-formed regex which is already fixed in
+ // some newer package.
+ //
+ if (dvr == v)
+ return ver;
+
+ if (!r || rv < dvr)
+ {
+ r = move (ver);
+ rv = move (dvr);
+ }
+ }
+ catch (const invalid_argument& e)
+ {
+ bad_value ("resulting downstream version '" + dv +
+ "' is invalid: " + e.what ());
+ }
+ }
+ }
+ }
+ }
+
+ return r;
+ };
+
+ // Try to deduce the downstream version using the
+ // <distribution>-to-downstream-version values that match the name id and
+ // refer to the version which is less or equal than the version id.
+ //
+ optional<version> r (downstream_version (name_id, vid));
+
+ // If the downstream version is not deduced and the like ids are
+ // specified, then re-try but now using the like id and "0" version id
+ // instead.
+ //
+ if (!r)
+ {
+ for (const string& like_id: like_ids)
+ {
+ r = downstream_version (like_id, semantic_version (0, 0, 0));
+ if (r)
+ break;
+ }
+ }
+
+ return r;
+ }
+
+ auto system_package_manager::
+ installed_entries (const common_options& co,
+ const packages& pkgs,
+ const strings& vars,
+ const string& scope) -> installed_entry_map
+ {
+ process_path pp (search_b (co));
+
+ // Note that we don't use start_b() here since we want to be consistent
+ // with how things will be run when building the package.
+ //
+ cstrings args {
+ pp.recall_string (),
+ "--quiet", // Note: implies --no-progress.
+ "--dry-run"};
+
+ // Pass our --jobs value, if any.
+ //
+ string jobs;
+ if (size_t n = co.jobs_specified () ? co.jobs () : 0)
+ {
+ jobs = to_string (n);
+ args.push_back ("--jobs");
+ args.push_back (jobs.c_str ());
+ }
+
+ // Pass any --build-option.
+ //
+ for (const string& o: co.build_option ()) args.push_back (o.c_str ());
+
+ // Configuration variables.
+ //
+ for (const string& v: vars) args.push_back (v.c_str ());
+
+ string scope_arg;
+ args.push_back ((scope_arg = "!config.install.scope=" + scope).c_str ());
+
+ args.push_back ("!config.install.manifest=-");
+
+ // Package directories to install.
+ //
+ strings dirs;
+ for (const package& p: pkgs) dirs.push_back (p.out_root.representation ());
+ args.push_back ("install:");
+ for (const string& d: dirs) args.push_back (d.c_str ());
+
+ args.push_back (nullptr);
+
+ installed_entry_map r;
+ try
+ {
+ if (verb >= 2)
+ print_process (args);
+ else if (verb == 1)
+ text << "determining filesystem entries that would be installed...";
+
+ // Redirect stdout to a pipe.
+ //
+ process pr (pp,
+ args,
+ 0 /* stdin */,
+ -1 /* stdout */,
+ 2 /* stderr */);
+ try
+ {
+ ifdstream is (move (pr.in_ofd), fdstream_mode::skip);
+
+ json::parser p (is,
+ args[0] /* input_name */,
+ true /* multi_value */,
+ "\n" /* value_separators */);
+
+ using event = json::event;
+
+ // Note: recursive lambda.
+ //
+ auto parse_entry = [&r, &p] (const auto& parse_entry) -> void
+ {
+ // enter: after begin_object
+ // leave: after end_object
+
+ string t (p.next_expect_member_string ("type"));
+
+ if (t == "target")
+ {
+ p.next_expect_member_string ("name");
+
+ p.next_expect_member_array ("entries");
+ while (p.next_expect (event::begin_object, event::end_array))
+ parse_entry (parse_entry);
+ }
+ else if (t == "file" || t == "symlink")
+ {
+ path ep (p.next_expect_member_string ("path"));
+ assert (ep.absolute () && ep.normalized (false /* separators */));
+
+ if (t == "file")
+ {
+ string em (p.next_expect_member_string ("mode"));
+
+ auto p (
+ r.emplace (
+ move (ep), installed_entry {move (em), nullptr}));
+
+ if (!p.second)
+ fail << p.first->first << " is installed multiple times";
+ }
+ else
+ {
+ path et (p.next_expect_member_string ("target"));
+ if (et.relative ())
+ {
+ et = ep.directory () / et;
+ et.normalize ();
+ }
+
+ auto i (r.find (et));
+ if (i == r.end ())
+ fail << "symlink " << ep << " target " << et << " does not "
+ << "refer to previously installed entry";
+
+ auto p (r.emplace (move (ep), installed_entry {"", &*i}));
+
+ if (!p.second)
+ fail << p.first->first << " is installed multiple times";
+ }
+ }
+ else
+ {
+ // Fall through to skip all members of an unknown entry type.
+ //
+ // Note that this also covers the directory entires which we
+ // don't care about.
+ }
+
+ // Skip unknown members.
+ //
+ while (p.next_expect (event::name, event::end_object))
+ p.next_expect_value_skip ();
+ };
+
+ while (p.peek ()) // More values.
+ {
+ p.next_expect (event::begin_object); // entry
+ parse_entry (parse_entry);
+
+ if (p.next ()) // Consume value-terminating nullopt.
+ fail << "unexpected data after entry object";
+ }
+
+ is.close ();
+ }
+ catch (const json::invalid_json_input& e)
+ {
+ if (pr.wait ())
+ fail (location ("<stdin>", e.line, e.column))
+ << "invalid install manifest json input: " << e;
+
+ // Fall through.
+ }
+ catch (const io_error& e)
+ {
+ if (pr.wait ())
+ fail << "unable to read " << args[0] << " output: " << e;
+
+ // Fall through.
+ }
+
+ if (!pr.wait ())
+ {
+ diag_record dr (fail);
+ dr << args[0] << " exited with non-zero code";
+
+ if (verb < 2)
+ {
+ dr << info << "command line: ";
+ print_process (dr, args);
+ }
+ }
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e;
+
+ if (e.child)
+ exit (1);
+
+ throw failed ();
+ }
+
+ return r;
+ }
+}
diff --git a/bpkg/system-package-manager.hxx b/bpkg/system-package-manager.hxx
new file mode 100644
index 0000000..7f5af7d
--- /dev/null
+++ b/bpkg/system-package-manager.hxx
@@ -0,0 +1,463 @@
+// file : bpkg/system-package-manager.hxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BPKG_SYSTEM_PACKAGE_MANAGER_HXX
+#define BPKG_SYSTEM_PACKAGE_MANAGER_HXX
+
+#include <bpkg/types.hxx>
+#include <bpkg/utility.hxx>
+
+#include <libbutl/path-map.hxx>
+#include <libbutl/host-os-release.hxx>
+
+#include <bpkg/package.hxx>
+#include <bpkg/common-options.hxx>
+
+namespace bpkg
+{
+ using os_release = butl::os_release;
+
+ // The system/distribution package manager interface. Used by both pkg-build
+ // (to query and install system packages) and by pkg-bindist (to generate
+ // them).
+ //
+ // Note that currently the result of a query is a single available version.
+ // While some package managers may support having multiple available
+ // versions and may even allow installing multiple versions in parallel,
+ // supporting this on our side will complicate things quite a bit. While we
+ // can probably plug multiple available versions into our constraint
+ // satisfaction machinery, the rabbit hole goes deeper than that since, for
+ // example, different bpkg packages can be mapped to the same system
+ // package, as is the case for libcrypto/libssl which are both mapped to
+ // libssl on Debian. This means we will need to somehow coordinate (and
+ // likely backtrack) version selection between unrelated bpkg packages
+ // because only one underlying system version can be selected. (One
+ // simplified way to handle this would be to detect that different versions
+ // we selected and fail asking the user to resolve this manually.)
+ //
+ // Additionally, parallel installation is unlikely to be suppored for the
+ // packages we are interested in due to the underlying limitations.
+ // Specifically, the packages that we are primarily interested in are
+ // libraries with headers and executables (tools). While most package
+ // managers (e.g., Debian, Fedora) are able to install multiple libraries in
+ // parallel, they normally can only install a single set of headers, static
+ // libraries, pkg-config files, etc., (e.g., -dev/-devel package) at a time
+ // due to them being installed into the same location (e.g., /usr/include).
+ // The same holds for executables, which are installed into the same
+ // location (e.g., /usr/bin).
+ //
+ // It is possible that a certain library has made arrangements for
+ // multiple of its versions to co-exist. For example, hypothetically, our
+ // libssl package could be mapped to both libssl1.1 libssl1.1-dev and
+ // libssl3 libssl3-dev which could be installed at the same time (note
+ // that it is not the case in reality; there is only libssl-dev). However,
+ // in this case, we should probably also have two packages with separate
+ // names (e.g., libssl and libssl3) that can also co-exist. An example of
+ // this would be libQt5Core and libQt6Core. (Note that strictly speaking
+ // there could be different degrees of co-existence: for the system
+ // package manager it is sufficient for different versions not to clobber
+ // each other's files while for us we may also need the ability to use
+ // different versions in the base build).
+ //
+ // Note also that the above reasoning is quite C/C++-centric and it's
+ // possible that multiple versions of libraries (or equivalent) for other
+ // languages (e.g., Rust) can always co-exist. Plus, even in the case of
+ // C/C++ libraries, there is still the plausible case of picking one of
+ // the multiple available version.
+ //
+ // On the other hand, the ultimate goal of system package managers, at least
+ // traditional ones like Debian and Fedora, is to end up with a single,
+ // usually the latest available, version of the package that is used by
+ // everyone. In fact, if one looks at a stable distributions of Debian and
+ // Fedora, they normally provide only a single version of each package. This
+ // decision will also likely simplify the implementation. For example, on
+ // Debian, it's straightforward to get the installed and candidate versions
+ // (e.g., from apt-cache policy). But getting all the possible versions that
+ // can be installed without having to specify the release explicitly is a
+ // lot less straightforward (see the apt-cache command documentation in The
+ // Debian Administrator's Handbook for background).
+ //
+ // So for now we keep it simple and pick a single available version but can
+ // probably revise this decision later.
+ //
+ struct system_package_status
+ {
+ // Downstream (as in, bpkg package) version.
+ //
+ bpkg::version version;
+
+ // System (as in, distribution) package name and version for diagnostics.
+ //
+ // Note that this status may represent multiple system packages (for
+ // example, libfoo and libfoo-dev) and here we have only the
+ // main/representative package name (for example, libfoo).
+ //
+ string system_name;
+ string system_version;
+
+ // The system package can be either "available already installed",
+ // "available partially installed" (for example, libfoo but not
+ // libfoo-dev is installed) or "available not yet installed".
+ //
+ enum status_type {installed, partially_installed, not_installed};
+
+ status_type status = not_installed;
+ };
+
+ // As mentioned above the system package manager API has two parts:
+ // consumption (status() and install()) and production (generate()) and a
+ // particular implementation may only implement one, the other, or both. If
+ // a particular part is not implemented, then the correponding make_*()
+ // function below should never return an instance of such a system package
+ // manager.
+ //
+ class system_package_manager
+ {
+ public:
+ // Query the system package status.
+ //
+ // This function has two modes: cache-only (available_packages is NULL)
+ // and full (available_packages is not NULL). In the cache-only mode this
+ // function returns the status of this package if it has already been
+ // queried and nullopt otherwise. This allows the caller to only collect
+ // all the available packages (for the name/version mapping information)
+ // if really necessary.
+ //
+ // The returned status can be NULL, which indicates that no such package
+ // is available from the system package manager. Note that NULL is also
+ // returned if no fully installed package is available from the system and
+ // package installation is not enabled (see the constructor below).
+ //
+ // Note also that the implementation is expected to issue appropriate
+ // progress and diagnostics if fetching package metadata (again see the
+ // constructor below).
+ //
+ virtual optional<const system_package_status*>
+ status (const package_name&, const available_packages*) = 0;
+
+ // Install the specified subset of the previously-queried packages.
+ // Should only be called if installation is enabled (see the constructor
+ // below).
+ //
+ // Note that this function should be called only once after the final set
+ // of the required system packages has been determined. And the specified
+ // subset should contain all the selected packages, including the already
+ // fully installed. This allows the implementation to merge and de-
+ // duplicate the system package set to be installed (since some bpkg
+ // packages may be mapped to the same system package), perform post-
+ // installation verifications (such as making sure the versions of already
+ // installed packages have not changed due to upgrades), change properties
+ // of already installed packages (e.g., mark them as manually installed in
+ // Debian), etc.
+ //
+ // Note also that the implementation is expected to issue appropriate
+ // progress and diagnostics.
+ //
+ virtual void
+ install (const vector<package_name>&) = 0;
+
+ // Generate a binary distribution package. See the pkg-bindist(1) man page
+ // for background and the pkg_bindist() function implementation for
+ // details. The recursive_full argument corresponds to the --recursive
+ // auto (present false) and full (present true) modes.
+ //
+ // The available packages are loaded for all the packages in pkgs and
+ // deps. For non-system packages (so for all in pkgs) there is always a
+ // single available package that corresponds to the selected package. The
+ // out_root is only set for packages in pkgs. Note also that all the
+ // packages in pkgs and deps are guaranteed to belong to the same build
+ // configuration (as opposed to being spread over multiple linked
+ // configurations). Its absolute path is bassed in cfg_dir.
+ //
+ // The passed package manifest corresponds to the first package in pkgs
+ // (normally used as a source of additional package metadata such as
+ // summary, emails, urls, etc).
+ //
+ // The passed package type corresponds to the first package in pkgs while
+ // the languages -- to all the packages in pkgs plus, in the recursive
+ // mode, to all the non-system dependencies. In other words, the languages
+ // list contains every language that is used by anything that ends up in
+ // the package.
+ //
+ // Return the list of paths to binary packages and any other associated
+ // files (build metadata, etc) that could be useful for their consumption.
+ // Each returned file has a distribution-specific type that classifies it.
+ // If the result is empty, assume the prepare-only mode (or similar) with
+ // appropriate result diagnostics having been already issued.
+ //
+ // Note that this function may be called multiple times in the
+ // --recursive=separate mode. In this case the first argument indicates
+ // whether this is the first call (can be used, for example, to adjust the
+ // --wipe-output semantics).
+ //
+ struct package
+ {
+ shared_ptr<selected_package> selected;
+ available_packages available;
+ dir_path out_root; // Absolute and normalized.
+ };
+
+ using packages = vector<package>;
+
+ struct binary_file
+ {
+ string type;
+ bpkg::path path;
+ string system_name; // Empty if not applicable.
+ };
+
+ struct binary_files: public vector<binary_file>
+ {
+ string system_version; // Empty if not applicable.
+ };
+
+ virtual binary_files
+ generate (const packages& pkgs,
+ const packages& deps,
+ const strings& vars,
+ const dir_path& cfg_dir,
+ const package_manifest&,
+ const string& type,
+ const small_vector<language, 1>&,
+ optional<bool> recursive_full,
+ bool first) = 0;
+
+ public:
+ bpkg::os_release os_release;
+ target_triplet host;
+ string arch; // Architecture in system package manager spelling.
+
+ // Consumption constructor.
+ //
+ // If install is true, then enable package installation.
+ //
+ // If fetch is false, then do not re-fetch the system package repository
+ // metadata (that is, available packages/versions) before querying for the
+ // available version of the not yet installed or partially installed
+ // packages.
+ //
+ // If fetch timeout (in seconds) is specified, then use it for all the
+ // underlying network operations.
+ //
+ system_package_manager (bpkg::os_release&& osr,
+ const target_triplet& h,
+ string a,
+ optional<bool> progress,
+ optional<size_t> fetch_timeout,
+ bool install,
+ bool fetch,
+ bool yes,
+ string sudo)
+ : os_release (move (osr)),
+ host (h),
+ arch (move (a)),
+ progress_ (progress),
+ fetch_timeout_ (fetch_timeout),
+ install_ (install),
+ fetch_ (fetch),
+ yes_ (yes),
+ sudo_ (sudo != "false" ? move (sudo) : string ()) {}
+
+ // Production constructor.
+ //
+ system_package_manager (bpkg::os_release&& osr,
+ const target_triplet& h,
+ string a,
+ optional<bool> progress)
+ : os_release (move (osr)),
+ host (h),
+ arch (move (a)),
+ progress_ (progress),
+ install_ (false),
+ fetch_ (false),
+ yes_ (false) {}
+
+ virtual
+ ~system_package_manager ();
+
+ // Implementation details.
+ //
+ public:
+ // Given the available packages (as returned by find_available_all())
+ // return the list of system package names as mapped by the
+ // <distribution>-name values.
+ //
+ // The name_id, version_id, and like_ids are the values from os_release
+ // (refer there for background). If version_id is empty, then it's treated
+ // as "0".
+ //
+ // First consider <distribution>-name values corresponding to name_id.
+ // Assume <distribution> has the <name>[_<version>] form, where <version>
+ // is a semver-like version (e.g, 10, 10.15, or 10.15.1) and return all
+ // the values that are equal or less than the specified version_id
+ // (include the value with the absent <version>). In a sense, absent
+ // <version> is treated as a 0 semver-like version.
+ //
+ // If no value is found then repeat the above process for every like_ids
+ // entry (from left to right) instead of name_id with version_id equal 0.
+ //
+ // If still no value is found, then return empty list (in which case the
+ // caller may choose to fallback to the downstream package name or do
+ // something more elaborate, like translate version_id to one of the
+ // like_id's version and try that).
+ //
+ // Note that multiple -name values per same distribution can be returned
+ // as, for example, for the following distribution values:
+ //
+ // debian_10-name: libcurl4 libcurl4-doc libcurl4-openssl-dev
+ // debian_10-name: libcurl3-gnutls libcurl4-gnutls-dev (yes, 3 and 4)
+ //
+ // The <distribution> value in the <name>_0 form is the special "non-
+ // native" name mapping. If the native argument is false, then such a
+ // mapping is preferred over any other mapping. If it is true, then such a
+ // mapping is ignored. The purpose of this special value is to allow
+ // specifying different package names for production compared to
+ // consumption. Note, however, that such a deviation may make it
+ // impossible to use native and non-native binary packages
+ // interchangeably, for example, to satisfy dependencies.
+ //
+ // Note also that the values are returned in the "override order", that is
+ // from the newest package version to oldest and then from the highest
+ // distribution version to lowest.
+ //
+ static strings
+ system_package_names (const available_packages&,
+ const string& name_id,
+ const string& version_id,
+ const vector<string>& like_ids,
+ bool native);
+
+ // Given the available package and the repository fragment it belongs to,
+ // return the system package version as mapped by one of the
+ // <distribution>-version values.
+ //
+ // The rest of the arguments as well as the overalls semantics is the same
+ // as in system_package_names() above. That is, first consider
+ // <distribution>-version values corresponding to name_id. If none match,
+ // then repeat the above process for every like_ids entry with version_id
+ // equal 0. If still no match, then return nullopt (in which case the
+ // caller may choose to fallback to the upstream/bpkg package version or
+ // do something more elaborate).
+ //
+ // Note that lazy_shared_ptr<repository_fragment> is used only for
+ // diagnostics and conveys the database the available package object
+ // belongs to.
+ //
+ static optional<string>
+ system_package_version (const shared_ptr<available_package>&,
+ const lazy_shared_ptr<repository_fragment>&,
+ const string& name_id,
+ const string& version_id,
+ const vector<string>& like_ids);
+
+ // Given the system package version and available packages (as returned by
+ // find_available_all()) return the downstream package version as mapped
+ // by one of the <distribution>-to-downstream-version values.
+ //
+ // The rest of the arguments as well as the overalls semantics is the same
+ // as in system_package_names() above. That is, first consider
+ // <distribution>-to-downstream-version values corresponding to
+ // name_id. If none match, then repeat the above process for every
+ // like_ids entry with version_id equal 0. If still no match, then return
+ // nullopt (in which case the caller may choose to fallback to the system
+ // package version or do something more elaborate).
+ //
+ static optional<version>
+ downstream_package_version (const string& system_version,
+ const available_packages&,
+ const string& name_id,
+ const string& version_id,
+ const vector<string>& like_ids);
+
+ // Return the map of filesystem entries (files and symlinks) that would be
+ // installed for the specified packages with the specified configuration
+ // variables.
+ //
+ // In essence, this function runs:
+ //
+ // b --dry-run --quiet <vars> !config.install.scope=<scope>
+ // !config.install.manifest=- install: <pkgs>
+ //
+ // And converts the printed installation manifest into the path map.
+ //
+ // Note that this function prints an appropriate progress indicator since
+ // even in the dry-run mode it may take some time (see the --dry-run
+ // option documentation for details).
+ //
+ struct installed_entry
+ {
+ string mode; // Empty if symlink.
+ const pair<const path, installed_entry>* target; // Target if symlink.
+ };
+
+ class installed_entry_map: public butl::path_map<installed_entry>
+ {
+ public:
+ // Return true if there are filesystem entries in the specified
+ // directory or its subdirectories.
+ //
+ bool
+ contains_sub (const dir_path& d)
+ {
+ auto p (find_sub (d));
+ return p.first != p.second;
+ }
+ };
+
+ installed_entry_map
+ installed_entries (const common_options&,
+ const packages& pkgs,
+ const strings& vars,
+ const string& scope);
+
+ protected:
+ optional<bool> progress_; // --[no]-progress (see also stderr_term)
+ optional<size_t> fetch_timeout_; // --fetch-timeout
+
+ // The --sys-* option values.
+ //
+ bool install_;
+ bool fetch_;
+ bool yes_;
+ string sudo_;
+ };
+
+ // Create a package manager instance corresponding to the specified host
+ // target triplet as well as optional distribution package manager name and
+ // architecture. If name is empty, return NULL if there is no support for
+ // this platform. If architecture is empty, then derive it automatically
+ // from the host target triplet. Currently recognized names:
+ //
+ // debian -- Debian and alike (Ubuntu, etc) using the APT frontend.
+ // fedora -- Fedora and alike (RHEL, Centos, etc) using the DNF frontend.
+ // archive -- Installation archive, any platform, production only.
+ //
+ // Note: the name can be used to select an alternative package manager
+ // implementation on platforms that support multiple.
+ //
+ unique_ptr<system_package_manager>
+ make_consumption_system_package_manager (const common_options&,
+ const target_triplet&,
+ const string& name,
+ const string& arch,
+ bool install,
+ bool fetch,
+ bool yes,
+ const string& sudo);
+
+ // Create for production. The second half of the result is the effective
+ // distribution name.
+ //
+ // Note that the reference to options is expected to outlive the returned
+ // instance.
+ //
+ class pkg_bindist_options;
+
+ pair<unique_ptr<system_package_manager>, string>
+ make_production_system_package_manager (const pkg_bindist_options&,
+ const target_triplet&,
+ const string& name,
+ const string& arch);
+}
+
+#endif // BPKG_SYSTEM_PACKAGE_MANAGER_HXX
diff --git a/bpkg/system-package-manager.test.cxx b/bpkg/system-package-manager.test.cxx
new file mode 100644
index 0000000..f0d7c8f
--- /dev/null
+++ b/bpkg/system-package-manager.test.cxx
@@ -0,0 +1,160 @@
+// file : bpkg/system-package-manager.test.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <bpkg/system-package-manager.hxx>
+
+#include <iostream>
+
+#include <bpkg/types.hxx>
+#include <bpkg/utility.hxx>
+
+#undef NDEBUG
+#include <cassert>
+
+#include <bpkg/system-package-manager.test.hxx>
+
+using namespace std;
+
+namespace bpkg
+{
+ // Usage: args[0] <command> ...
+ //
+ // Where <command> is one of:
+ //
+ // system-package-names <name-id> <ver-id> [<like-id>...] -- [--non-native] <pkg> <file>...
+ //
+ // Where <pkg> is a package name, <file> is a package manifest file.
+ //
+ // system-package-version <name-id> <ver-id> [<like-id>...] -- <pkg> <file>
+ //
+ // Where <pkg> is a package name, <file> is a package manifest file.
+ //
+ // downstream-package-version <name-id> <ver-id> [<like-id>...] -- <ver> <pkg> <file>...
+ //
+ // Where <ver> is a system version to translate, <pkg> is a package
+ // name, and <file> is a package manifest file.
+ //
+ int
+ main (int argc, char* argv[])
+ try
+ {
+ assert (argc >= 2); // <command>
+
+ int argi (1);
+ string cmd (argv[argi++]);
+
+ os_release osr;
+ if (cmd == "system-package-names" ||
+ cmd == "system-package-version" ||
+ cmd == "downstream-package-version")
+ {
+ assert (argc >= 4); // <name-id> <ver-id>
+
+ osr.name_id = argv[argi++];
+ osr.version_id = argv[argi++];
+
+ for (; argi != argc; ++argi)
+ {
+ string a (argv[argi]);
+
+ if (a == "--")
+ break;
+
+ osr.like_ids.push_back (move (a));
+ }
+ }
+
+ if (cmd == "system-package-names")
+ {
+ assert (argi != argc); // --
+ string a (argv[argi++]);
+ assert (a == "--");
+
+ assert (argi != argc);
+ bool native (true);
+ if ((a = argv[argi]) == "--non-native")
+ {
+ native = false;
+ argi++;
+ }
+
+ assert (argi != argc); // <pkg>
+ string pn (argv[argi++]);
+
+ assert (argi != argc); // <file>
+ available_packages aps;
+ for (; argi != argc; ++argi)
+ aps.push_back (make_available_from_manifest (pn, argv[argi]));
+ sort_available (aps);
+
+ strings ns (
+ system_package_manager::system_package_names (
+ aps, osr.name_id, osr.version_id, osr.like_ids, native));
+
+ for (const string& n: ns)
+ cout << n << '\n';
+ }
+ else if (cmd == "system-package-version")
+ {
+ assert (argi != argc); // --
+ string a (argv[argi++]);
+ assert (a == "--");
+
+ assert (argi != argc); // <pkg>
+ string pn (argv[argi++]);
+
+ assert (argi != argc); // <file>
+ pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>> apf (
+ make_available_from_manifest (pn, argv[argi++]));
+
+ assert (argi == argc); // No trailing junk.
+
+ if (optional<string> v =
+ system_package_manager::system_package_version (
+ apf.first, apf.second, osr.name_id, osr.version_id, osr.like_ids))
+ {
+ cout << *v << '\n';
+ }
+ }
+ else if (cmd == "downstream-package-version")
+ {
+ assert (argi != argc); // --
+ string a (argv[argi++]);
+ assert (a == "--");
+
+ assert (argi != argc); // <ver>
+ string sv (argv[argi++]);
+
+ assert (argi != argc); // <pkg>
+ string pn (argv[argi++]);
+
+ assert (argi != argc); // <file>
+ available_packages aps;
+ for (; argi != argc; ++argi)
+ aps.push_back (make_available_from_manifest (pn, argv[argi]));
+ sort_available (aps);
+
+ optional<version> v (
+ system_package_manager::downstream_package_version (
+ sv, aps, osr.name_id, osr.version_id, osr.like_ids));
+
+ if (v)
+ cout << *v << '\n';
+ }
+ else
+ fail << "unknown command '" << cmd << "'";
+
+ return 0;
+ }
+ catch (const failed&)
+ {
+ return 1;
+ }
+}
+
+int
+main (int argc, char* argv[])
+{
+ return bpkg::main (argc, argv);
+}
diff --git a/bpkg/system-package-manager.test.hxx b/bpkg/system-package-manager.test.hxx
new file mode 100644
index 0000000..688eb72
--- /dev/null
+++ b/bpkg/system-package-manager.test.hxx
@@ -0,0 +1,112 @@
+// file : bpkg/system-package-manager.test.hxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BPKG_SYSTEM_PACKAGE_MANAGER_TEST_HXX
+#define BPKG_SYSTEM_PACKAGE_MANAGER_TEST_HXX
+
+#include <bpkg/system-package-manager.hxx>
+
+#include <algorithm> // sort()
+
+#include <bpkg/types.hxx>
+#include <bpkg/utility.hxx>
+
+#include <libbutl/manifest-parser.hxx>
+
+#include <libbpkg/manifest.hxx>
+
+#include <bpkg/package.hxx>
+
+namespace bpkg
+{
+ // Parse the manifest as if it comes from a git repository with a single
+ // package and make an available package out of it. If the file name is
+ // `-` then read fro stdin. If the package name is empty, then take the
+ // name from the manifest. Otherwise, assert they match.
+ //
+ inline
+ pair<shared_ptr<available_package>, lazy_shared_ptr<repository_fragment>>
+ make_available_from_manifest (const string& pn, const string& f)
+ {
+ using butl::manifest_parser;
+ using butl::manifest_parsing;
+
+ path fp (f);
+ path_name fn (fp);
+
+ try
+ {
+ ifdstream ifds;
+ istream& ifs (butl::open_file_or_stdin (fn, ifds));
+
+ manifest_parser mp (ifs, fn.name ? *fn.name : fn.path->string ());
+
+ package_manifest m (mp,
+ false /* ignore_unknown */,
+ true /* complete_values */);
+
+ const string& n (m.name.string ());
+ assert (pn.empty () || n == pn);
+
+ m.alt_naming = false;
+ m.bootstrap_build = "project = " + n + '\n';
+
+ shared_ptr<available_package> ap (
+ make_shared<available_package> (move (m)));
+
+ lazy_shared_ptr<repository_fragment> af (
+ make_shared<repository_fragment> (
+ repository_location ("https://example.com/" + n,
+ repository_type::git)));
+
+ ap->locations.push_back (package_location {af, current_dir});
+
+ return make_pair (move (ap), move (af));
+ }
+ catch (const manifest_parsing& e)
+ {
+ fail (e.name, e.line, e.column) << e.description << endf;
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to read from " << fn << ": " << e << endf;
+ }
+ }
+
+ // Make an available stub package as if it comes from git repository with
+ // a single package.
+ //
+ inline
+ pair<shared_ptr<available_package>, lazy_shared_ptr<repository_fragment>>
+ make_available_stub (const string& n)
+ {
+ shared_ptr<available_package> ap (
+ make_shared<available_package> (package_name (n)));
+
+ lazy_shared_ptr<repository_fragment> af (
+ make_shared<repository_fragment> (
+ repository_location ("https://example.com/" + n,
+ repository_type::git)));
+
+ ap->locations.push_back (package_location {af, current_dir});
+
+ return make_pair (move (ap), move (af));
+ }
+
+ // Sort available packages in the version descending order.
+ //
+ inline void
+ sort_available (available_packages& aps)
+ {
+ using element_type =
+ pair<shared_ptr<available_package>, lazy_shared_ptr<repository_fragment>>;
+
+ std::sort (aps.begin (), aps.end (),
+ [] (const element_type& x, const element_type& y)
+ {
+ return x.first->version > y.first->version;
+ });
+ }
+}
+
+#endif // BPKG_SYSTEM_PACKAGE_MANAGER_TEST_HXX
diff --git a/bpkg/system-package-manager.test.testscript b/bpkg/system-package-manager.test.testscript
new file mode 100644
index 0000000..74c6ad2
--- /dev/null
+++ b/bpkg/system-package-manager.test.testscript
@@ -0,0 +1,158 @@
+# file : bpkg/system-package-manager.test.testscript
+# license : MIT; see accompanying LICENSE file
+
+: system-package-names
+:
+{
+ test.arguments += system-package-names
+
+ : basics
+ :
+ cat <<EOI >=libcurl7.64.manifest;
+ : 1
+ name: libcurl
+ version: 7.64.0
+ debian-name: libcurl2 libcurl2-dev
+ summary: curl
+ license: curl
+ EOI
+ cat <<EOI >=libcurl7.84.manifest;
+ : 1
+ name: libcurl
+ version: 7.84.0
+ debian_9-name: libcurl2 libcurl2-dev libcurl2-doc
+ debian_10-name: libcurl4 libcurl4-openssl-dev
+ debian_10-name: libcurl3-gnutls libcurl4-gnutls-dev
+ summary: curl
+ license: curl
+ EOI
+
+ $* debian 10 -- libcurl libcurl7.64.manifest libcurl7.84.manifest >>EOO;
+ libcurl4 libcurl4-openssl-dev
+ libcurl3-gnutls libcurl4-gnutls-dev
+ libcurl2 libcurl2-dev libcurl2-doc
+ libcurl2 libcurl2-dev
+ EOO
+ $* debian 9 -- libcurl libcurl7.64.manifest libcurl7.84.manifest >>EOO;
+ libcurl2 libcurl2-dev libcurl2-doc
+ libcurl2 libcurl2-dev
+ EOO
+ $* debian '' -- libcurl libcurl7.64.manifest libcurl7.84.manifest >>EOO;
+ libcurl2 libcurl2-dev
+ EOO
+ $* ubuntu 16.04 debian -- libcurl libcurl7.64.manifest libcurl7.84.manifest >>EOO
+ libcurl2 libcurl2-dev
+ EOO
+
+ : native
+ :
+ cat <<EOI >=libcurl.manifest;
+ : 1
+ name: libcurl
+ version: 7.84.0
+ debian-name: libcurl4 libcurl4-openssl-dev
+ debian_0-name: libcurl libcurl-dev
+ summary: curl
+ license: curl
+ EOI
+ $* debian 10 -- libcurl libcurl.manifest >>EOO;
+ libcurl4 libcurl4-openssl-dev
+ EOO
+ $* debian 10 -- --non-native libcurl libcurl.manifest >>EOO
+ libcurl libcurl-dev
+ EOO
+}
+
+: system-package-version
+:
+{
+ test.arguments += system-package-version
+
+ : basics
+ :
+ cat <<EOI >=libssl1.1.1+19.manifest;
+ : 1
+ name: libssl
+ version: 1.1.1+19
+ fedora-name: openssl-libs
+ fedora-version: 1:1.1.1q-1
+ fedora_35-version: 1:1.1.1q-1.fc35
+ fedora_36-version: 1:1.1.1q-1.fc36
+ summary: openssl
+ license: openssl
+ EOI
+
+ $* fedora 34 -- libssl libssl1.1.1+19.manifest >>EOO;
+ 1:1.1.1q-1
+ EOO
+ $* fedora 35 -- libssl libssl1.1.1+19.manifest >>EOO;
+ 1:1.1.1q-1.fc35
+ EOO
+ $* fedora 36 -- libssl libssl1.1.1+19.manifest >>EOO;
+ 1:1.1.1q-1.fc36
+ EOO
+ $* fedora 37 -- libssl libssl1.1.1+19.manifest >>EOO;
+ 1:1.1.1q-1.fc36
+ EOO
+ $* fedora '' -- libssl libssl1.1.1+19.manifest >>EOO;
+ 1:1.1.1q-1
+ EOO
+ $* rhel 7.8 fedora -- libssl libssl1.1.1+19.manifest >>EOO
+ 1:1.1.1q-1
+ EOO
+}
+
+: downstream-package-version
+:
+{
+ test.arguments += downstream-package-version
+
+ : basics
+ :
+ cat <<EOI >=libssl1.manifest;
+ : 1
+ name: libssl
+ version: 1.1.1
+ upstream-version: 1.1.1n
+ debian-to-downstream-version: /1\.1\.1[a-z]/1.1.1/
+ summary: openssl
+ license: openssl
+ EOI
+ cat <<EOI >=libssl3.manifest;
+ : 1
+ name: libssl
+ version: 3.0.0
+ debian-to-downstream-version: /([3-9])\.([0-9]+)\.([0-9]+)/\1.\2.\3/
+ summary: openssl
+ license: openssl
+ EOI
+ $* debian 10 -- 1.1.1l libssl libssl1.manifest libssl3.manifest >'1.1.1';
+ $* debian 10 -- 3.0.7 libssl libssl1.manifest libssl3.manifest >'3.0.7';
+ $* debian '' -- 1.1.1l libssl libssl1.manifest libssl3.manifest >'1.1.1';
+ $* debian '' -- 3.0.7 libssl libssl1.manifest libssl3.manifest >'3.0.7';
+ $* ubuntu 16.04 debian -- 1.1.1l libssl libssl1.manifest libssl3.manifest >'1.1.1';
+ $* ubuntu 16.05 debian -- 3.0.7 libssl libssl1.manifest libssl3.manifest >'3.0.7'
+
+ : order
+ :
+ cat <<EOI >=libssl1.manifest;
+ : 1
+ name: libssl
+ version: 1.1.1
+ debian-to-downstream-version: /.*/0/
+ summary: openssl
+ license: openssl
+ EOI
+ cat <<EOI >=libssl3.manifest;
+ : 1
+ name: libssl
+ version: 3.0.0
+ debian_9-to-downstream-version: /.*/9/
+ debian_10-to-downstream-version: /.*/10/
+ summary: openssl
+ license: openssl
+ EOI
+ $* debian 10 -- 1 libssl libssl1.manifest libssl3.manifest >'10';
+ $* debian 9 -- 1 libssl libssl1.manifest libssl3.manifest >'9';
+ $* debian 8 -- 1 libssl libssl1.manifest libssl3.manifest >'0'
+}
diff --git a/bpkg/system-repository.cxx b/bpkg/system-repository.cxx
index d7a47b7..c308ddb 100644
--- a/bpkg/system-repository.cxx
+++ b/bpkg/system-repository.cxx
@@ -6,9 +6,12 @@
namespace bpkg
{
const version& system_repository::
- insert (const package_name& name, const version& v, bool authoritative)
+ insert (const package_name& name,
+ const version& v,
+ bool authoritative,
+ const system_package_status* s)
{
- auto p (map_.emplace (name, system_package {v, authoritative}));
+ auto p (map_.emplace (name, system_package {v, authoritative, s}));
if (!p.second)
{
@@ -22,6 +25,7 @@ namespace bpkg
{
sp.authoritative = authoritative;
sp.version = v;
+ sp.system_status = s;
}
}
diff --git a/bpkg/system-repository.hxx b/bpkg/system-repository.hxx
index f33d622..d524ee4 100644
--- a/bpkg/system-repository.hxx
+++ b/bpkg/system-repository.hxx
@@ -14,9 +14,11 @@
namespace bpkg
{
+ struct system_package_status; // <bpkg/system-package-manager.hxx>
+
// A map of discovered system package versions. The information can be
// authoritative (i.e., it was provided by the user or auto-discovered
- // on this run) or non-authoritative (i.e., comes from selected_packages
+ // on this run) or non-authoritative (i.e., comes from selected packages
// that are present in the database; in a sence it was authoritative but
// on some previous run.
//
@@ -30,16 +32,25 @@ namespace bpkg
version_type version;
bool authoritative;
+
+ // If the information is authoritative then this member indicates whether
+ // the version came from the system package manager (not NULL) or
+ // user/fallback (NULL).
+ //
+ const system_package_status* system_status;
};
class system_repository
{
public:
const version&
- insert (const package_name& name, const version&, bool authoritative);
+ insert (const package_name& name,
+ const version&,
+ bool authoritative,
+ const system_package_status* = nullptr);
const system_package*
- find (const package_name& name)
+ find (const package_name& name) const
{
auto i (map_.find (name));
return i != map_.end () ? &i->second : nullptr;
diff --git a/bpkg/types-parsers.cxx b/bpkg/types-parsers.cxx
index e27f050..f23751d 100644
--- a/bpkg/types-parsers.cxx
+++ b/bpkg/types-parsers.cxx
@@ -3,6 +3,8 @@
#include <bpkg/types-parsers.hxx>
+#include <libbpkg/manifest.hxx>
+
namespace bpkg
{
namespace cli
@@ -141,6 +143,83 @@ namespace bpkg
throw invalid_value (o, v);
}
+ void parser<git_protocol_capabilities>::
+ parse (git_protocol_capabilities& x, bool& xs, scanner& s)
+ {
+ xs = true;
+ const char* o (s.next ());
+
+ if (!s.more ())
+ throw missing_value (o);
+
+ const string v (s.next ());
+ if (v == "dumb")
+ x = git_protocol_capabilities::dumb;
+ else if (v == "smart")
+ x = git_protocol_capabilities::smart;
+ else if (v == "unadv")
+ x = git_protocol_capabilities::unadv;
+ else
+ throw invalid_value (o, v);
+ }
+
+ void parser<git_capabilities_map>::
+ parse (git_capabilities_map& x, bool& xs, scanner& s)
+ {
+ xs = true;
+ const char* o (s.next ());
+
+ if (!s.more ())
+ throw missing_value (o);
+
+ string v (s.next ());
+ size_t p (v.rfind ('='));
+
+ if (p == string::npos)
+ throw invalid_value (o, v);
+
+ string k (v, 0, p);
+
+ // Verify that the key is a valid remote git repository URL prefix.
+ //
+ try
+ {
+ repository_url u (k);
+
+ if (u.scheme == repository_protocol::file)
+ throw invalid_value (o, k, "local repository location");
+ }
+ catch (const invalid_argument& e)
+ {
+ throw invalid_value (o, k, e.what ());
+ }
+
+ // Parse the protocol capabilities value.
+ //
+ int ac (2);
+ char* av[] = {const_cast<char*> (o),
+ const_cast<char*> (v.c_str () + p + 1)};
+
+ argv_scanner vs (0, ac, av);
+
+ bool dummy;
+ parser<git_protocol_capabilities>::parse (x[k], dummy, vs);
+ }
+
+ void parser<git_capabilities_map>::
+ merge (git_capabilities_map& b, const git_capabilities_map& a)
+ {
+ for (const auto& o: a)
+ {
+ auto i (b.find (o.first));
+
+ if (i != b.end ())
+ i->second = o.second;
+ else
+ b.emplace (o.first, o.second);
+ }
+ }
+
void parser<stdout_format>::
parse (stdout_format& x, bool& xs, scanner& s)
{
diff --git a/bpkg/types-parsers.hxx b/bpkg/types-parsers.hxx
index dba459a..7bbb414 100644
--- a/bpkg/types-parsers.hxx
+++ b/bpkg/types-parsers.hxx
@@ -84,6 +84,29 @@ namespace bpkg
};
template <>
+ struct parser<git_protocol_capabilities>
+ {
+ static void
+ parse (git_protocol_capabilities&, bool&, scanner&);
+
+ static void
+ merge (git_protocol_capabilities& b, const git_protocol_capabilities& a)
+ {
+ b = a;
+ }
+ };
+
+ template <>
+ struct parser<git_capabilities_map>
+ {
+ static void
+ parse (git_capabilities_map&, bool&, scanner&);
+
+ static void
+ merge (git_capabilities_map&, const git_capabilities_map&);
+ };
+
+ template <>
struct parser<stdout_format>
{
static void
diff --git a/bpkg/types.hxx b/bpkg/types.hxx
index 2b6a1f8..80e5a7d 100644
--- a/bpkg/types.hxx
+++ b/bpkg/types.hxx
@@ -33,6 +33,7 @@
#include <libbutl/optional.hxx>
#include <libbutl/fdstream.hxx>
#include <libbutl/small-vector.hxx>
+#include <libbutl/target-triplet.hxx>
#include <libbutl/default-options.hxx>
namespace bpkg
@@ -87,6 +88,8 @@ namespace bpkg
// <libbutl/path.hxx>
//
using butl::path;
+ using butl::path_name;
+ using butl::path_name_view;
using butl::dir_path;
using butl::basic_path;
using butl::invalid_path;
@@ -127,6 +130,10 @@ namespace bpkg
using butl::ofdstream;
using butl::fdstream_mode;
+ // <libbutl/target-triplet.hxx>
+ //
+ using butl::target_triplet;
+
// <libbutl/default-options.hxx>
//
using butl::default_options_files;
@@ -228,6 +235,14 @@ namespace std
::butl::path::traits_type::canonicalize (r);
return os << r;
}
+
+ inline ostream&
+ operator<< (ostream& os, const ::butl::path_name_view& v)
+ {
+ assert (!v.empty ());
+
+ return v.name != nullptr && *v.name ? (os << **v.name) : (os << *v.path);
+ }
}
#endif // BPKG_TYPES_HXX
diff --git a/bpkg/utility.cxx b/bpkg/utility.cxx
index 68d79ad..d084b76 100644
--- a/bpkg/utility.cxx
+++ b/bpkg/utility.cxx
@@ -46,6 +46,8 @@ namespace bpkg
const dir_path current_dir (".");
+ const target_triplet host_triplet (BPKG_HOST_TRIPLET);
+
map<dir_path, dir_path> tmp_dirs;
bool keep_tmp;
@@ -161,7 +163,8 @@ namespace bpkg
}
}
- bool stderr_term;
+ optional<const char*> stderr_term = nullopt;
+ bool stderr_term_color = false;
bool
yn_prompt (const string& p, char d)
@@ -310,6 +313,30 @@ namespace bpkg
return true;
}
+ bool
+ mv (const path& from, const path& to, bool ie)
+ {
+ if (verb >= 3)
+ text << "mv " << from << ' ' << to;
+
+ try
+ {
+ mvfile (from, to,
+ cpflags::overwrite_content | cpflags::overwrite_permissions);
+ }
+ catch (const system_error& e)
+ {
+ error << "unable to move file " << from << " to " << to << ": " << e;
+
+ if (ie)
+ return false;
+
+ throw failed ();
+ }
+
+ return true;
+ }
+
dir_path
change_wd (const dir_path& d)
{
@@ -365,4 +392,43 @@ namespace bpkg
? co.build ().string ().c_str ()
: BPKG_EXE_PREFIX "b" BPKG_EXE_SUFFIX;
}
+
+ process_path
+ search_b (const common_options& co)
+ {
+ const char* b (name_b (co));
+
+ try
+ {
+ // Use our executable directory as a fallback search since normally the
+ // entire toolchain is installed into one directory. This way, for
+ // example, if we installed into /opt/build2 and run bpkg with absolute
+ // path (and without PATH), then bpkg will be able to find "its" b.
+ //
+ return process::path_search (b, true /* init */, exec_dir);
+ }
+ catch (const process_error& e)
+ {
+ fail << "unable to execute " << b << ": " << e << endf;
+ }
+ }
+
+ void
+ dump_stderr (auto_fd&& fd)
+ {
+ ifdstream is (move (fd), fdstream_mode::skip, ifdstream::badbit);
+
+ // We could probably write something like this, instead:
+ //
+ // *diag_stream << is.rdbuf () << flush;
+ //
+ // However, it would never throw and we could potentially miss the reading
+ // failure, unless we decide to additionally mess with the diagnostics
+ // stream exception mask.
+ //
+ for (string l; !eof (getline (is, l)); )
+ *diag_stream << l << endl;
+
+ is.close ();
+ }
}
diff --git a/bpkg/utility.hxx b/bpkg/utility.hxx
index 342d608..7a51948 100644
--- a/bpkg/utility.hxx
+++ b/bpkg/utility.hxx
@@ -10,7 +10,7 @@
#include <cstring> // strcmp(), strchr()
#include <utility> // move(), forward(), declval(), make_pair()
#include <cassert> // assert()
-#include <iterator> // make_move_iterator()
+#include <iterator> // make_move_iterator(), back_inserter()
#include <algorithm> // *
#include <libbutl/ft/lang.hxx>
@@ -33,6 +33,7 @@ namespace bpkg
using std::make_pair;
using std::make_shared;
using std::make_move_iterator;
+ using std::back_inserter;
using std::to_string;
using std::strcmp;
@@ -51,6 +52,7 @@ namespace bpkg
using butl::trim;
using butl::trim_left;
using butl::trim_right;
+ using butl::next_word;
using butl::make_guard;
using butl::make_exception_guard;
@@ -59,9 +61,12 @@ namespace bpkg
using butl::setenv;
using butl::unsetenv;
+ using butl::eof;
+
// <libbutl/process.hxx>
//
using butl::process_start_callback;
+ using butl::process_print_callback;
// <libbutl/filesystem.hxx>
//
@@ -99,6 +104,10 @@ namespace bpkg
extern const dir_path current_dir; // ./
+ // Host target triplet for which we were built.
+ //
+ extern const target_triplet host_triplet;
+
// Temporary directory facility.
//
// An entry normally maps <cfg-dir> to <cfg-dir>/.bpkg/tmp/ but can also map
@@ -152,9 +161,17 @@ namespace bpkg
dir_path
current_directory ();
- // Progress.
+ // Diagnostics.
//
- extern bool stderr_term; // True if stderr is a terminal.
+ // If stderr is not a terminal, then the value is absent (so can be used as
+ // bool). Otherwise, it is the value of the TERM environment variable (which
+ // can be NULL).
+ //
+ extern optional<const char*> stderr_term;
+
+ // True if the color can be used on the stderr terminal.
+ //
+ extern bool stderr_term_color;
// Y/N prompt. See butl::yn_prompt() for details (this is a thin wrapper).
//
@@ -197,6 +214,9 @@ namespace bpkg
bool
mv (const dir_path& from, const dir_path& to, bool ignore_errors = false);
+ bool
+ mv (const path& from, const path& to, bool ignore_errors = false);
+
// Set (with diagnostics at verbosity level 3 or higher) the new and return
// the previous working directory.
//
@@ -228,9 +248,20 @@ namespace bpkg
normal // Run normally (at verbosity 1).
};
+ template <typename V>
+ void
+ map_verb_b (const common_options&, verb_b, V& args, string& verb_arg);
+
const char*
name_b (const common_options&);
+ process_path
+ search_b (const common_options&);
+
+ template <typename... A>
+ void
+ print_b (const common_options&, verb_b, A&&... args);
+
template <typename O, typename E, typename... A>
process
start_b (const common_options&, O&& out, E&& err, verb_b, A&&... args);
@@ -238,6 +269,12 @@ namespace bpkg
template <typename... A>
void
run_b (const common_options&, verb_b, A&&... args);
+
+ // Read out the data from the specified file descriptor and dump it to
+ // stderr. Throw io_error on the underlying OS errors.
+ //
+ void
+ dump_stderr (auto_fd&&);
}
#include <bpkg/utility.txx>
diff --git a/bpkg/utility.txx b/bpkg/utility.txx
index 47619c6..33bb711 100644
--- a/bpkg/utility.txx
+++ b/bpkg/utility.txx
@@ -7,6 +7,88 @@ namespace bpkg
{
// *_b()
//
+ template <typename V>
+ void
+ map_verb_b (const common_options& co, verb_b v, V& ops, string& verb_arg)
+ {
+ // Map verbosity level. If we are running quiet or at level 1,
+ // then run build2 quiet. Otherwise, run it at the same level
+ // as us.
+ //
+ bool progress (co.progress ());
+ bool no_progress (co.no_progress ());
+
+ if (verb == 0)
+ {
+ ops.push_back ("-q");
+ no_progress = false; // Already suppressed with -q.
+ }
+ else if (verb == 1)
+ {
+ // NOTE: search for verb_b usage if changing anything here.
+ //
+ if (v != verb_b::normal)
+ {
+ ops.push_back ("-q");
+
+ if (!no_progress)
+ {
+ if (v == verb_b::progress && stderr_term)
+ {
+ ops.push_back ("--progress");
+ progress = false; // The option is already added.
+ }
+ }
+ else
+ no_progress = false; // Already suppressed with -q.
+ }
+ }
+ else if (verb == 2)
+ ops.push_back ("-v");
+ else
+ {
+ verb_arg = to_string (verb);
+ ops.push_back ("--verbose");
+ ops.push_back (verb_arg.c_str ());
+ }
+
+ if (progress)
+ ops.push_back ("--progress");
+
+ if (no_progress)
+ ops.push_back ("--no-progress");
+ }
+
+ template <typename... A>
+ void
+ print_b (const common_options& co, verb_b v, A&&... args)
+ {
+ process_path pp (search_b (co));
+
+ small_vector<const char*, 1> ops;
+
+ // As in start_b() below.
+ //
+ string verb_arg;
+ map_verb_b (co, v, ops, verb_arg);
+
+ if (co.diag_color ())
+ ops.push_back ("--diag-color");
+
+ if (co.no_diag_color ())
+ ops.push_back ("--no-diag-color");
+
+ process_print_callback (
+ [] (const char* const args[], size_t n)
+ {
+ print_process (args, n);
+ },
+ pp,
+ ops,
+ co.build_option (),
+ forward<A> (args)...);
+ }
+
template <typename O, typename E, typename... A>
process
start_b (const common_options& co,
@@ -15,64 +97,27 @@ namespace bpkg
verb_b v,
A&&... args)
{
- const char* b (name_b (co));
+ process_path pp (search_b (co));
try
{
- // Use our executable directory as a fallback search since normally the
- // entire toolchain is installed into one directory. This way, for
- // example, if we installed into /opt/build2 and run bpkg with absolute
- // path (and without PATH), then bpkg will be able to find "its" b.
- //
- process_path pp (process::path_search (b, exec_dir));
-
small_vector<const char*, 1> ops;
- // Map verbosity level. If we are running quiet or at level 1,
- // then run build2 quiet. Otherwise, run it at the same level
- // as us.
+ // NOTE: see print_b() above if changing anything here.
//
- string vl;
- bool progress (co.progress ());
- bool no_progress (co.no_progress ());
+ // NOTE: see custom versions in system_package_manager* if adding
+ // anything new here (search for search_b()).
- if (verb == 0)
- {
- ops.push_back ("-q");
- no_progress = false; // Already suppressed with -q.
- }
- else if (verb == 1)
- {
- if (v != verb_b::normal)
- {
- ops.push_back ("-q");
-
- if (!no_progress)
- {
- if (v == verb_b::progress && stderr_term)
- {
- ops.push_back ("--progress");
- progress = false; // The option is already added.
- }
- }
- else
- no_progress = false; // Already suppressed with -q.
- }
- }
- else if (verb == 2)
- ops.push_back ("-v");
- else
- {
- vl = to_string (verb);
- ops.push_back ("--verbose");
- ops.push_back (vl.c_str ());
- }
+ string verb_arg;
+ map_verb_b (co, v, ops, verb_arg);
- if (progress)
- ops.push_back ("--progress");
+ // Forward our --[no]diag-color options.
+ //
+ if (co.diag_color ())
+ ops.push_back ("--diag-color");
- if (no_progress)
- ops.push_back ("--no-progress");
+ if (co.no_diag_color ())
+ ops.push_back ("--no-diag-color");
return process_start_callback (
[] (const char* const args[], size_t n)
@@ -90,7 +135,7 @@ namespace bpkg
}
catch (const process_error& e)
{
- fail << "unable to execute " << b << ": " << e << endf;
+ fail << "unable to execute " << pp.recall_string () << ": " << e << endf;
}
}
diff --git a/build/root.build b/build/root.build
index c172018..4a3a866 100644
--- a/build/root.build
+++ b/build/root.build
@@ -16,9 +16,16 @@ if ($cxx.target.system == 'win32-msvc')
if ($cxx.class == 'msvc')
cxx.coptions += /wd4251 /wd4275 /wd4800
elif ($cxx.id == 'gcc')
+{
cxx.coptions += -Wno-maybe-uninitialized -Wno-free-nonheap-object \
-Wno-stringop-overread # libbutl
+ if ($cxx.version.major >= 13)
+ cxx.coptions += -Wno-dangling-reference
+}
+elif ($cxx.id.type == 'clang' && $cxx.version.major >= 15)
+ cxx.coptions += -Wno-unqualified-std-cast-call
+
cxx.poptions =+ "-I$out_root" "-I$src_root"
# Load the cli module but only if it's available. This way a distribution
diff --git a/doc/cli.sh b/doc/cli.sh
index fc81528..326d63c 100755
--- a/doc/cli.sh
+++ b/doc/cli.sh
@@ -1,6 +1,6 @@
#! /usr/bin/env bash
-version=0.16.0-a.0.z
+version=0.17.0-a.0.z
trap 'exit 1' ERR
set -o errtrace # Trap in functions.
@@ -63,26 +63,36 @@ function compile ()
--man-epilogue-file man-epilogue.1 \
--link-regex '%b(#.+)?%$1%' \
--link-regex '%bpkg(#.+)?%$1%' \
+--link-regex '%#.+%%' \
../bpkg/$n.cli
}
-o="--output-prefix bpkg- --class-doc bpkg::common_options=short"
+# Need global --suppress-undocumented because of few undocumented options
+# in common.cli.
+#
+o="--suppress-undocumented --output-prefix bpkg- --class-doc bpkg::common_options=short"
# A few special cases.
#
compile "common" $o --output-suffix "-options" --class-doc bpkg::common_options=long
-compile "bpkg" $o --output-prefix "" --suppress-undocumented --class-doc bpkg::commands=short --class-doc bpkg::topics=short
+compile "bpkg" $o --output-prefix "" --class-doc bpkg::commands=short --class-doc bpkg::topics=short
+
+compile "pkg-build" $o --class-doc bpkg::pkg_build_pkg_options=exclude-base
-compile "pkg-build" $o --class-doc bpkg::pkg_build_pkg_options=exclude-base
+compile "pkg-bindist" $o \
+ --class-doc bpkg::pkg_bindist_common_options=exclude-base \
+ --class-doc bpkg::pkg_bindist_debian_options=exclude-base \
+ --class-doc bpkg::pkg_bindist_fedora_options=exclude-base \
+ --class-doc bpkg::pkg_bindist_archive_options=exclude-base
# NOTE: remember to update a similar list in buildfile and bpkg.cli as well as
# the help topics sections in bpkg/buildfile and help.cxx.
#
pages="cfg-create cfg-info cfg-link cfg-unlink help pkg-clean pkg-configure \
-pkg-disfigure pkg-drop pkg-fetch pkg-checkout pkg-install pkg-purge \
-pkg-status pkg-test pkg-uninstall pkg-unpack pkg-update pkg-verify rep-add \
-rep-remove rep-list rep-create rep-fetch rep-info repository-signing \
-repository-types argument-grouping default-options-files"
+pkg-disfigure pkg-drop pkg-fetch pkg-checkout pkg-install pkg-purge pkg-status \
+pkg-test pkg-uninstall pkg-unpack pkg-update pkg-verify rep-add rep-remove \
+rep-list rep-create rep-fetch rep-info repository-signing repository-types \
+argument-grouping default-options-files"
for p in $pages; do
compile $p $o
@@ -113,6 +123,7 @@ cli -I .. \
--html-epilogue-file doc-epilogue.xhtml \
--link-regex '%b([-.].+)%../../build2/doc/b$1%' \
--link-regex '%b(#.+)?%../../build2/doc/build2-build-system-manual.xhtml$1%' \
+--link-regex '%bbot(#.+)?%../../bbot/doc/build2-build-bot-manual.xhtml$1%' \
--output-prefix build2-package-manager- \
manual.cli
diff --git a/doc/manual.cli b/doc/manual.cli
index d6eeecd..e7e61c0 100644
--- a/doc/manual.cli
+++ b/doc/manual.cli
@@ -1040,6 +1040,9 @@ a full package manifest they can be interleaved with non-header values.
\
name: <name>
version: <version>
+[upstream-version]: <string>
+[type]: <type>
+[language]: <lang>
[project]: <name>
[priority]: <priority> [; <comment>]
summary: <text>
@@ -1052,8 +1055,12 @@ license: <licenses> [; <comment>]
[description]: <text>
[description-file]: <path> [; <comment>]
[description-type]: <text-type>
+[package-description]: <text>
+[package-description-file]: <path> [; <comment>]
+[package-description-type]: <text-type>
[changes]: <text>
[changes-file]: <path> [; <comment>]
+[changes-type]: <text-type>
[url]: <url> [; <comment>]
[doc-url]: <url> [; <comment>]
@@ -1076,12 +1083,20 @@ license: <licenses> [; <comment>]
[builds]: <class-expr> [; <comment>]
[build-include]: <config>[/<target>] [; <comment>]
[build-exclude]: <config>[/<target>] [; <comment>]
+[build-auxiliary]: <config> [; <comment>]
+[build-auxiliary-<name>]: <config> [; <comment>]
[*-build-config]: <args> [; <comment>]
[*-builds]: <class-expr> [; <comment>]
[*-build-include]: <config>[/<target>] [; <comment>]
[*-build-exclude]: <config>[/<target>] [; <comment>]
+[*-build-auxiliary]: <config> [; <comment>]
+[*-build-auxiliary-<name>]: <config> [; <comment>]
+
+[*-build-email]: <email> [; <comment>]
+[*-build-warning-email]: <email> [; <comment>]
+[*-build-error-email]: <email> [; <comment>]
[build-file]: <path>
@@ -1092,6 +1107,10 @@ license: <licenses> [; <comment>]
[bootstrap-build2]: <text>
[root-build2]: <text>
[*-build2]: <text>
+
+[*-name]: <name> [<name>...]
+[*-version]: <string>
+[*-to-downstream-version]: <regex>
\
\h2#manifest-package-name|\c{name}|
@@ -1124,6 +1143,53 @@ and use the \c{upstream-version} value to preserve the original version for
information.
+\h2#manifest-package-type-language|\c{type}, \c{language}|
+
+\
+[type]: <type>
+[language]: <lang>
+
+<type> = <name>[,<sub-options>]
+<lang> = <name>[=impl]
+\
+
+The package type and programming language(s).
+
+The currently recognized package types are \c{exe}, \c{lib}, and \c{other}. If
+the type is not specified, then if the package name starts with \c{lib}, then
+it is assumed to be \c{lib} and \c{exe} otherwise (see \l{#package-name
+Package Name} for details). Other package types may be added in the future and
+code that does not recognize a certain package type should treat it as
+\c{other}. The type name can be followed by a comma-separated list of
+sub-options. Currently, the only recognized sub-option is \c{binless} which
+applies to the \c{lib} type indicating a header-only (or equivalent) library.
+For example:
+
+\
+type: lib,binless
+\
+
+The package language must be in the lower case, for example, \c{c}, \c{c++},
+\c{rust}, \c{bash}. If the language is not specified, then if the package name
+has an extension (as in, for example, \c{libbutl.bash}; see \l{#package-name
+Package Name} for details) the extension is assumed to name the package
+language. Otherwise, \c{cc} (unspecified \c{c}-common language) is assumed. If
+a package uses multiple languages, then multiple \c{language} values must be
+specified. The languages which are only used in a library's implementation (as
+opposed to also in its interface) should be marked as such. For example, for a
+C library with C++ implementation:
+
+\
+type: lib
+language: c
+language: c++=impl
+\
+
+\N|If the use of a language, such as C++, also always implies the use of
+another language, such as C, then such an implied language need not be
+explicitly specified.|
+
+
\h2#manifest-package-project|\c{project}|
\
@@ -1331,23 +1397,30 @@ as well as words from its summary are already considered to be keywords and
need not be repeated in this value.
-\h2#manifest-package-description|\c{description}|
+\h2#manifest-package-description|\c{description}, \c{package-description}|
\
[description]: <text>
[description-file]: <path> [; <comment>]
[description-type]: <text-type>
+[package-description]: <text>
+[package-description-file]: <path> [; <comment>]
+[package-description-type]: <text-type>
\
-The detailed description of the package. It can be provided either inline as a
-text fragment or by referring to a file within a package (e.g., \c{README}),
-but not both.
+The detailed description of the project (\c{description}) and package
+(\c{package-description}). If the package description is not specified, it is
+assumed to be the same as the project description. It only makes sense to
+specify the \c{package-description} value if the project and package are
+maintained separately. A description can be provided either inline as a text
+fragment or by referring to a file within a package (for example, \c{README}),
+but not both. For \c{package-description-file} the recommended file name is
+\c{PACKAGE-README} or \c{README-PACKAGE}.
In the web interface (\c{brep}) the description is displayed according to its
type. Currently, pre-formatted plain text, \l{https://github.github.com/gfm
GitHub-Flavored Markdown}, and \l{https://spec.commonmark.org/current
-CommonMark} are supported with the following \c{description-type} values,
-respectively:
+CommonMark} are supported with the following \c{*-type} values, respectively:
\
text/plain
@@ -1358,13 +1431,13 @@ text/markdown;variant=CommonMark
If just \c{text/markdown} is specified, then the GitHub-Flavored Markdown
(which is a superset of CommonMark) is assumed.
-If the description type is not explicitly specified and the description is
-specified as \c{description-file}, then an attempt to derive the type from the
-file extension is made. Specifically, the \cb{.md} and \cb{.markdown}
-extensions are mapped to \c{text/markdown}, the \cb{.txt} and no extension are
-mapped to \c{text/plain}, and all other extensions are treated as an unknown
-type, similar to unknown \c{description-type} values. And if the description
-is not specified as a file, \c{text/plain} is assumed.
+If a description type is not explicitly specified and the description is
+specified as \c{*-file}, then an attempt to derive the type from the file
+extension is made. Specifically, the \cb{.md} and \cb{.markdown} extensions
+are mapped to \c{text/markdown}, the \cb{.txt} and no extension are mapped to
+\c{text/plain}, and all other extensions are treated as an unknown type,
+similar to unknown \c{*-type} values. And if a description is not specified as
+a file, \c{text/plain} is assumed.
\h2#manifest-package-changes|\c{changes}|
@@ -1372,6 +1445,7 @@ is not specified as a file, \c{text/plain} is assumed.
\
[changes]: <text>
[changes-file]: <path> [; <comment>]
+[changes-type]: <text-type>
\
The description of changes in the release.
@@ -1405,8 +1479,11 @@ changes:
changes-file: NEWS
\
-In the web interface (\c{brep}) the changes are displayed as pre-formatted
-plain text, similar to the package description.
+In the web interface (\c{brep}) the changes are displayed according to their
+type, similar to the package description (see the
+\l{#manifest-package-description \c{description}} value for details). If
+the changes type is not explicitly specified, then the types deduced for
+individual \c{changes} values must all be the same.
\h2#manifest-package-url|\c{url}|
@@ -2063,15 +2140,19 @@ The \c{bootstrap} value should be used to mark build system modules that
require bootstrapping. The \c{host} value should be used to mark packages,
such source code generators, that are normally specified as build-time
dependencies by other packages and therefore should be built in a host
-configuration. See the \c{bbot} documentation for details.
+configuration. See the \l{bbot \c{bbot} documentation} for details.
-\h2#manifest-package-tests-examples-benchmarks|\c{tests, examples, benchmarks}|
+\h2#manifest-package-tests-examples-benchmarks|\c{tests}, \c{examples}, \c{benchmarks}|
\
-[tests]: [*] <name> [<version-constraint>]
-[examples]: [*] <name> [<version-constraint>]
-[benchmarks]: [*] <name> [<version-constraint>]
+[tests]: [*] <package> ['?' <enable-cond>] [<reflect-var>]
+[examples]: [*] <package> ['?' <enable-cond>] [<reflect-var>]
+[benchmarks]: [*] <package> ['?' <enable-cond>] [<reflect-var>]
+
+<package> = <name> [<version-constraint>]
+<enable-cond> = '(' <buildfile-eval-expr> ')'
+<reflect-var> = <config-var> '=' <value>
\
Separate tests, examples, and benchmarks packages. If the value starts with
@@ -2081,8 +2162,8 @@ specified package. Otherwise it is \i{run-time}. See the
dependencies.
These packages are built and tested by automated build bots together with the
-primary package (see the \c{bbot} documentation for details). This, in
-particular, implies that these packages must be available from the primary
+primary package (see the \l{bbot \c{bbot} documentation} for details). This,
+in particular, implies that these packages must be available from the primary
package's repository or its complement repositories, recursively. The
recommended naming convention for these packages is the primary package name
followed by \c{-tests}, \c{-examples}, or \c{-benchmarks}, respectively. For
@@ -2090,7 +2171,7 @@ example:
\
name: hello
-tests : hello-tests
+tests: hello-tests
examples: hello-examples
\
@@ -2103,18 +2184,57 @@ it can also be specified in terms of the primary package's version (see the
tests: hello-tests ~$
\
-Note that normally the tests, etc., packages themselves do not have an
-explicit dependency on the primary package (in a sense, the primary package
-has a special dependency on them). They are also not built by automated build
-bots separately from their primary package but may have their own build
-constraints, for example, to be excluded from building on some platforms where
-the primary package is still built, for example:
+Note that normally the tests, etc., packages themselves (we'll call them all
+test packages for short) do not have an explicit dependency on the primary
+package (in a sense, the primary package has a special test dependency on
+them). They are also not built by automated build bots separately from their
+primary package but may have their own build constraints, for example, to be
+excluded from building on some platforms where the primary package is still
+built, for example:
\
name: hello-tests
builds: -windows
\
+Also note that a test package may potentially be used as a test dependency for
+multiple primary packages. In this case a primary package normally needs to
+reflect to the test package the fact that it is the one being tested. This can
+be achieved by setting the test package's configuration variable (see the
+\l{#manifest-package-depends \c{depends}} value for details on
+reflection). For example:
+
+\
+name: hello-foo
+tests: hello-tests config.hello_tests.test=hello-foo
+
+name: hello-bar
+tests: hello-tests config.hello_tests.test=hello-bar
+\
+
+If it is plausible that the test package may also be built explicitly, for
+example, to achieve a more complicated setup (test multiple main packages
+simultaneously, etc), then the test dependencies need to be made conditional
+in the primary packages so that the explicit configuration is preferred over
+the reflections (see the \l{#manifest-package-depends \c{depends}} value for
+details on conditional dependencies). For example:
+
+\
+name: hello-foo
+tests: hello-tests \
+? (!$defined(config.hello_tests.test)) config.hello_tests.test=hello-foo
+
+name: hello-bar
+tests: hello-tests \
+? (!$defined(config.hello_tests.test)) config.hello_tests.test=hello-bar
+\
+
+Note that in contrast to the \l{#manifest-package-depends \c{depends}} value,
+both the reflection and condition refer to the variables defined not by the
+package which specifies the test dependency (primary package), but the package
+such a dependency refers to (test package).
+
+
\h2#manifest-package-builds|\c{builds}|
\
@@ -2165,20 +2285,20 @@ name or a parenthesized expression. Some examples (based on the
\l{https://ci.cppget.org/?build-configs cppget.org} deployment):
\
-builds: none ; None.
-builds: all ; All (suitable for libraries).
-builds: host ; All host (suitable for tools).
-builds: default ; All default.
-builds: host : &default ; Host default.
-builds: default legacy ; All default and legacy.
-builds: host: &( +default +legacy ) ; Host default and legacy.
-builds: -windows ; Default except Windows.
-builds: all : -windows ; All except Windows.
-builds: all : -mobile ; All except mobile.
-builds: all : &gcc ; All with GCC only.
-builds: all : &gcc-8+ ; All with GCC 8 and up only.
-builds: gcc : -optimized ; GCC without optimization.
-builds: gcc : &( +linux +macos ) ; GCC on Linux and Mac OS.
+builds: none ; None.
+builds: all ; All (suitable for libraries).
+builds: all : &host ; All host (suitable for tools).
+builds: default ; All default.
+builds: default : &host ; Default host.
+builds: default legacy ; All default and legacy.
+builds: default legacy : &host ; Default and legacy host.
+builds: -windows ; Default except Windows.
+builds: all : -windows ; All except Windows.
+builds: all : -mobile ; All except mobile.
+builds: all : &gcc ; All with GCC only.
+builds: all : &gcc-8+ ; All with GCC 8 and up only.
+builds: all : &gcc -optimized ; All GCC without optimization.
+builds: all : &gcc &( +linux +macos ) ; All GCC on Linux and Mac OS.
\
Notice that the colon and parentheses must be separated with spaces from both
@@ -2220,11 +2340,11 @@ The common package build inclusions and exclusions. The \c{build-include} and
\c{build-exclude} values further reduce the configuration set produced by
evaluating the \l{#manifest-package-builds \c{builds}} values. The \i{config}
and \i{target} values are filesystem wildcard patterns which are matched
-against the build target configuration names and target names (see the
-\c{bbot} documentation for details). In particular, the \c{*} wildcard matches
-zero or more characters within the name component while the \c{**} sequence
-matches across the components. Plus, wildcard-only pattern components match
-absent name components. For example:
+against the build target configuration names and target names (see the \l{bbot
+\c{bbot} documentation} for details). In particular, the \c{*} wildcard
+matches zero or more characters within the name component while the \c{**}
+sequence matches across the components. Plus, wildcard-only pattern components
+match absent name components. For example:
\
build-exclude: windows** # matches windows_10-msvc_15
@@ -2256,19 +2376,129 @@ Note that the comment of the matching exclusion is used by the web interface
(\c{brep}) to display the reason for the build target configuration exclusion.
+\h2#manifest-package-build-auxiliary|\c{build-auxiliary}|
+
+\
+[build-auxiliary]: <config> [; <comment>]
+[build-auxiliary-<name>]: <config> [; <comment>]
+\
+
+The common package build auxiliary configurations. The \c{build-auxiliary}
+values can be used to specify auxiliary configurations that provide additional
+components which are required for building or testing a package and that are
+impossible or impractical to provide as part of the build configuration
+itself. For example, a package may need access to a suitably configured
+database, such as PostgreSQL, in order to run its tests. Currently no more
+than \c{9} auxiliary configurations can be specified.
+
+The \i{config} value is a filesystem wildcard patterns which is matched
+against the auxiliary configuration names (which are in turn derived from
+auxiliary machine names; see the \l{bbot \c{bbot} documentation} for
+details). In particular, the \c{*} wildcard matches zero or more characters
+within the name component while the \c{**} sequence matches across the
+components. Plus, wildcard-only pattern components match absent name
+components. For example:
+
+\
+build-auxiliary: linux_debian_12-postgresql_16
+build-auxiliary: linux_*-postgresql_*
+build-auxiliary: *-postgresql**
+\
+
+\N|If multiple auxiliary configurations match the specified pattern, then
+one is picked at random for every build.|
+
+If multiple auxiliary configurations are required, then they must be given
+distinct names with the \i{name} component. For example:
+
+\
+build-auxiliary-pgsql: *-postgresql_*
+build-auxiliary-mysql: *-mysql_*
+\
+
+Another example:
+
+\
+build-auxiliary-primary: *-postgresql_*
+build-auxiliary-secondary: *-postgresql_*
+\
+
+Auxiliary machines communicate information about their setup to the build
+machine using environment variables (see
+\l{bbot#arch-task-auxiliary-environment \c{auxiliary-environment}} for
+details). For example, an auxiliary machine that provides a test PostgreSQL
+database may need to communicate the host IP address and port on which it can
+be accessed as well as the user to login as and the database name to use. For
+example:
+
+\
+DATABASE_HOST=192.168.0.1
+DATABASE_PORT=5432
+DATABASE_USER=test
+DATABASE_NAME=test
+\
+
+If the auxiliary configuration is specified as \c{build-auxiliary-<name>},
+then capitalized and sanitized \i{name}_ is used as a prefix in the
+environment variables corresponding to the machine. For example, for the
+auxiliary configurations specified as:
+
+\
+build-auxiliary-pg-sql: *-postgresql_*
+build-auxiliary-my-sql: *-mysql_*
+\
+
+The environment variables could be:
+
+\
+PG_SQL_DATABASE_HOST=192.168.0.1
+PG_SQL_DATABASE_PORT=5432
+...
+
+MY_SQL_DATABASE_HOST=192.168.0.2
+MY_SQL_DATABASE_PORT=3306
+...
+\
+
+The auxiliary environment variables are in effect for the entire build. The
+recommended place to propagate them to the package configuration is the
+\c{*-build-config} value. For example:
+
+\
+build-auxiliary: *-postgresql_*
+default-build-config:
+\\
+config.hello.pgsql_host=$getenv(DATABASE_HOST)
+config.hello.pgsql_port=$getenv(DATABASE_PORT)
+...
+\\
+\
+
+
\h2#manifest-package-build-config|\c{*-build-config}|
\
[*-build-config]: <args> [; <comment>]
-<args> = [<config-var>]* [<dependency-spec>]*
+<args> = [[[+|-]<prefix>:](<option>|<config-var>)]* \\
+ [(+|-)<prefix>:]* \\
+ [<dependency-spec>]* \\
+ [<package-specific-vars>]*
+
<dependency-spec> = [{ <config-var> [<config-var>]* }+] <dependency>
-<dependency> = ?[sys:]<name>[<version-spec>]
+<dependency> = (?[sys:]|sys:)<name>[<version-spec>]
<version-spec> = /<version> | <version-constraint>
+<package-specific-vars> = { <config-var> [<config-var>]* }+ <name>
[*-builds]: <class-expr> [; <comment>]
[*-build-include]: <config>[/<target>] [; <comment>]
[*-build-exclude]: <config>[/<target>] [; <comment>]
+[*-build-auxiliary]: <config> [; <comment>]
+[*-build-auxiliary-<name>]: <config> [; <comment>]
+
+[*-build-email]: <email> [; <comment>]
+[*-build-warning-email]: <email> [; <comment>]
+[*-build-error-email]: <email> [; <comment>]
\
The package build configurations where the substring matched by \c{*} in
@@ -2277,8 +2507,19 @@ package is built in these configurations by automated build bots in addition
to the default configuration (which is called \c{default}).
The \c{*-build-config} values contain whitespace separated lists of
-potentially double/single-quoted package configuration arguments to the
-\l{bpkg-pkg-build(1)} command. For example:
+potentially double/single-quoted package configuration arguments. The global
+(as opposed to package-specific) options and variables can be prefixed with
+the build bot worker script step ids or a leading portion thereof to restrict
+it to a specific step, operation, phase, or tool (see \l{bbot#arch-worker
+\cb{bbot} worker step ids}). The prefix can optionally begin with the \c{+} or
+\c{-} character (in this case the argument can be omitted) to enable or
+disable the respective step (see the list of \l{bbot#arch-controller worker
+steps} which can be enabled or disabled). Unprefixed global options,
+variables, and dependencies are passed to the \l{bpkg-pkg-build(1)} command at
+the \c{bpkg.configure.build} step. The package-specific configuration
+variables for this and/or the separate test packages are passed to
+\l{bpkg-pkg-build(1)} at the \c{bpkg.configure.build} and
+\c{bpkg.test-separate-installed.configure.build} steps. For example:
\
network-build-config: config.libfoo.network=true; Enable networking API.
@@ -2294,14 +2535,39 @@ Enable caching.
libbar-network-build-config:
\\
{ config.libbar.network=true }+ ?libbar
-; Enable networking API in libbar.
+;
+Enable networking API in libbar.
\\
older-libz-build-config: \"?libz ^1.0.0\"; Test with older libz version.
-sys-build-config: ?sys:libbar ?sys:libz; Test with system dependencies.
+sys-build-config:
+\\
+?sys:libbar ?sys:libz
+;
+Test with system dependencies.
+\\
+
+bindist-build-config:
+\\
++bpkg.bindist.debian:--recursive=full
+-bbot.sys-install:
++bbot.bindist.upload:
+;
+Generate and upload binary distribution package but don't test its installation.
+\\
+
+load-tests-build-config:
+\\
+{ config.libfoo_tests.load=true }+ libfoo-tests
+;
+Enable load testing.
+\\
\
+Note that options with values can only be specified using the single argument
+notation, for example, \c{--verbose=4}.
+
The package build configuration can also override the common build target
configurations set (specified with \l{#manifest-package-builds \c{builds}} and
\l{#manifest-package-include-exclude \c{build-{include, exclude\}}}) by
@@ -2317,6 +2583,32 @@ Note that the common build target configurations set is overridden
hierarchically meaning that the \c{*-build-{include, exclude\}} overrides
don't discard the common \c{builds} values.
+The package build configuration can also override the common build
+notification email addresses (specified with \l{#manifest-package-build-email
+\c{build-email}}, \l{#manifest-package-warning-email \c{build-warning-email}},
+and \l{#manifest-package-error-email \c{build-error-email}}) by specifying the
+matching \c{*-build-email} and/or \c{*-build-{warning, error\}-email} values.
+For example:
+
+\
+bindist-build-config:
+\\
++bpkg.bindist.debian:--recursive=full
++bbot.bindist.upload:
+;
+Generate and upload binary distribution package.
+\\
+bindist-build-error-email: builds@example.org
+\
+
+Note that to disable all the build notification emails for a specific package
+build configuration, specify the empty \c{*-build-email} value. For example:
+
+\
+sys-build-config: ?sys:libz; Test with system dependencies.
+sys-build-email:
+\
+
The default configuration should normally build the package with no
configuration arguments and for the common target build configurations
set. While not recommended, this can be overridden by using the special
@@ -2385,6 +2677,95 @@ automatically added, for example, when the \l{#manifest-package-list-pkg
package list manifest} is created.
+\h2#manifest-package-distribution|\c{*-{name, version, to-downstream-version\}}|
+
+\
+[<distribution>-name]: <name> [<name>...]
+[<distribution>-version]: <string>
+[<distribution>-to-downstream-version]: <regex>
+
+<distribution> = <name>[_<version>]
+<regex> = /<pattern>/<replacement>/
+\
+
+The binary distribution package name and version mapping. The \c{-name} value
+specifies the distribution package(s) this \c{bpkg} package maps to. If
+unspecified, then appropriate name(s) are automatically derived from the
+\c{bpkg} package name (\l{#manifest-package-name \c{name}}). Similarly, the
+\c{-version} value specifies the distribution package version. If unspecified,
+then the \c{upstream-version} value is used if specified and the \c{bpkg}
+version (\l{#manifest-package-version \c{version}}) otherwise. While the
+\c{-to-downstream-version} values specify the reverse mapping, that is, from
+the distribution version to the \c{bpkg} version. If unspecified or none
+match, then the appropriate part of the distribution version is used. For
+example:
+
+\
+name: libssl
+version 1.1.1+18
+debian-name: libssl1.1 libssl-dev
+debian-version: 1.1.1n
+debian-to-downstream-version: /1\.1\.1[a-z]/1.1.1/
+debian-to-downstream-version: /([3-9])\.([0-9]+)\.([0-9]+)/\1.\2.\3/
+\
+
+If \c{upstream-version} is specified but the the distribution package version
+should be the same as the \c{bpkg} package version, then the special \c{$}
+\c{-version} value can be used. For example:
+
+\
+debian-version: $
+\
+
+The \c{<distribution>} name prefix consists of the distribution name followed
+by the optional distribution version. If the version is omitted, then the
+value applies to all versions. Some examples of distribution names and
+versions:
+
+\
+debian
+debian_10
+ubuntu_16.04
+fedora_32
+rhel_8.5
+freebsd_12.1
+windows_10
+macos_10
+macos_10.15
+macos_12
+\
+
+Note also that some distributions are like others (for example, \c{ubuntu} is
+like \c{debian}) and the corresponding \"base\" distribution values are
+considered if no \"derived\" values are specified.
+
+The \c{-name} value is used both during package consumption as a system
+package and production with the \l{bpkg-pkg-bindist(1)} command. During
+production, if multiple mappings match, then the value with the highest
+matching distribution version from the package \c{manifest} with the latest
+version is used. If it's necessary to use different names for the generated
+binary packages (called \"non-native packages\" in contrast to \"native
+packages\" that come from the distribution), the special \c{0} distribution
+version can be used to specify such a mapping. For example:
+
+\
+name: libsqlite3
+debian_9-name: libsqlite3-0 libsqlite3-dev
+debian_0-name: libsqlite3 libsqlite3-dev
+\
+
+Note that this special non-native mapping is ignored during consumption and a
+deviation in the package names that it introduces may make it impossible to
+use native and non-native binary packages interchangeably, for example, to
+satisfy dependencies.
+
+
+The exact format of the \c{-name} and \c{-version} values and the distribution
+version part that is matched against the \c{-to-downstream-version} pattern
+are distribution-specific. For details, see \l{#bindist-mapping-debian Debian
+Package Mapping} and \l{#bindist-mapping-fedora Fedora Package Mapping}.
+
+
\h#manifest-package-list-pkg|Package List Manifest for \cb{pkg} Repositories|
The package list manifest (the \c{packages.manifest} file found in the
@@ -2838,6 +3219,469 @@ signature: <sig>
The signature of the \c{packages.manifest} file. It should be calculated by
encrypting the above \c{sha256sum} value with the repository certificate's
private key and then \c{base64}-encoding the result.
+
+
+\h1#bindist-mapping|Binary Distribution Package Mapping|
+
+
+\h#bindist-mapping-debian|Debian Package Mapping|
+
+This section describes the distribution package mapping for Debian and
+alike (Ubuntu, etc).
+
+\h2#bindist-mapping-debian-consume|Debian Package Mapping for Consumption|
+
+A library in Debian is normally split up into several packages: the shared
+library package (e.g., \c{libfoo1} where \c{1} is the ABI version), the
+development files package (e.g., \c{libfoo-dev}), the documentation files
+package (e.g., \c{libfoo-doc}), the debug symbols package (e.g.,
+\c{libfoo1-dbg}), and the architecture-independent files (e.g.,
+\c{libfoo1-common}). All the packages except \c{-dev} are optional and there
+is quite a bit of variability. Here are a few examples:
+
+\
+libsqlite3-0 libsqlite3-dev
+
+libssl1.1 libssl-dev libssl-doc
+libssl3 libssl-dev libssl-doc
+
+libcurl4 libcurl4-openssl-dev libcurl4-doc
+libcurl3-gnutls libcurl4-gnutls-dev libcurl4-doc
+\
+
+Note that while most library package names in Debian start with \c{lib} (per
+the policy), there are exceptions (e.g., \c{zlib1g} \c{zlib1g-dev}). The
+header-only library package names may or may not start with \c{lib} and end
+with \c{-dev} (e.g., \c{libeigen3-dev}, \c{rapidjson-dev}, \c{catch2}). Also
+note that manual \c{-dbg} packages are obsolete in favor of automatic
+\c{-dbgsym} packages from Debian 9.
+
+For executable packages there is normally no \c{-dev} packages but \c{-dbg},
+\c{-doc}, and \c{-common} are plausible.
+
+Based on that, our approach when trying to automatically map a \c{bpkg}
+library package name to Debian package names is to go for the \c{-dev} package
+first and figure out the shared library package from that based on the fact
+that the \c{-dev} package should have the \c{==} dependency on the shared
+library package with the same version and its name should normally start with
+the \c{-dev} package's stem.
+
+The format of the \c{debian-name} (or alike) manifest value is a
+comma-separated list of one or more package groups:
+
+\
+<package-group> [, <package-group>...]
+\
+
+Where each \c{<package-group>} is the space-separated list of one or more
+package names:
+
+\
+<package-name> [ <package-name>...]
+\
+
+All the packages in the group should be \"package components\" (for the lack
+of a better term) of the same \"logical package\", such as \c{-dev}, \c{-doc},
+\c{-common} packages. They normally have the same version.
+
+The first group is called the main group and the first package in the
+group is called the main package. Note that all the groups are consumed
+(installed) but only the main group is produced (packaged).
+
+We allow/recommend specifying the \c{-dev} package instead of the main package
+for libraries (see \l{#manifest-package-type-language \c{type}} for details),
+seeing that we are capable of detecting the main package automatically (see
+above). If the library name happens to end with \c{-dev} (which poses an
+ambiguity), then the \c{-dev} package should be specified explicitly as the
+second package to disambiguate this situation.
+
+The Debian package version has the \c{[<epoch>:]<upstream>[-<revision>]} form
+(see \cb{deb-version(5)} for details). If no explicit mapping to the \c{bpkg}
+version is specified with the \c{debian-to-downstream-version} (or alike)
+manifest values or none match, then we fallback to using the \c{<upstream>}
+part as the \c{bpkg} version. If explicit mapping is specified, then we match
+it against the \c{[<epoch>:]<upstream>} parts ignoring \c{<revision>}.
+
+
+\h2#bindist-mapping-debian-produce|Debian Package Mapping for Production|
+
+The same \c{debian-name} (or alike) manifest values as used for consumption
+are also used to derive the package names for production except here we have
+the option to specify alternative non-native package names using the special
+\c{debian_0-name} (or alike) value. If only the \c{-dev} package is specified,
+then the main package name is derived from that by removing the \c{-dev}
+suffix. Note that regardless of whether the main package name is specified or
+not, the \l{bpkg-pkg-bindist(1)} command may omit generating the main package
+for a binless library.
+
+The generated binary package version can be specified with the
+\c{debian-version} (or alike) manifest value. If it's not specified, then the
+\c{upstream-version} is used if specified. Otherwise, the \c{bpkg} version
+is translated to the Debian version as described next.
+
+To recap, a Debian package version has the following form:
+
+\
+[<epoch>:]<upstream>[-<revision>]
+\
+
+For details on the ordering semantics, see the \c{Version} \c{control} file
+field documentation in the Debian Policy Manual. While overall unsurprising,
+one notable exception is \c{~}, which sorts before anything else and is
+commonly used for upstream pre-releases. For example, \c{1.0~beta1~svn1245}
+sorts earlier than \c{1.0~beta1}, which sorts earlier than \c{1.0}.
+
+There are also various special version conventions (such as all the revision
+components in \c{1.4-5+deb10u1~bpo9u1}) but they all appear to express
+relationships between native packages and/or their upstream and thus do not
+apply to our case.
+
+To recap, the \c{bpkg} version has the following form (see
+\l{#package-version Package Version} for details):
+
+\
+[+<epoch>-]<upstream>[-<prerel>][+<revision>]
+\
+
+Let's start with the case where neither distribution (\c{debian-version}) nor
+upstream version (\c{upstream-version}) is specified and we need to derive
+everything from the \c{bpkg} version (what follows is as much description as
+rationale).
+
+\dl|
+
+\li|\c{<epoch>}
+
+ On one hand, if we keep our (as in, \c{bpkg}) epoch, it won't necessarily
+ match Debian's native package epoch. But on the other it will allow our
+ binary packages from different epochs to co-exist. Seeing that this can be
+ easily overridden with a custom distribution version (see below), we keep
+ it.
+
+ Note that while the Debian start/default epoch is 0, ours is 1 (we use the 0
+ epoch for stub packages). So we shift this value range.|
+
+\li|\c{<upstream>[-<prerel>]}
+
+ Our upstream version maps naturally to Debian's. That is, our upstream
+ version format/semantics is a subset of Debian's.
+
+ If this is a pre-release, then we could fail (that is, don't allow
+ pre-releases) but then we won't be able to test on pre-release packages, for
+ example, to make sure the name mapping is correct. Plus sometimes it's
+ useful to publish pre-releases. We could ignore it, but then such packages
+ will be indistinguishable from each other and the final release, which is
+ not ideal. On the other hand, Debian has the mechanism (\c{~}) which is
+ essentially meant for this, so we use it. We will use \c{<prerel>} as is
+ since its format is the same as upstream and thus should map naturally.|
+
+\li|\c{<revision>}
+
+ Similar to epoch, our revision won't necessarily match Debian's native
+ package revision. But on the other hand it will allow us to establish a
+ correspondence between source and binary packages. Plus, upgrades between
+ binary package revisions will be handled naturally. Seeing that we allow
+ overriding the revision with a custom distribution version (see below),
+ we keep it.
+
+ Note also that both Debian and our revision start/default is 0. However, it
+ is Debian's convention to start revision from 1. But it doesn't seem worth
+ it for us to do any shifting here and so we will use our revision as is.
+
+ Another related question is whether we should also include some metadata
+ that identifies the distribution and its version that this package is
+ for. The strongest precedent here is probably Ubuntu's PPA. While there
+ doesn't appear to be a consistent approach, one can often see versions like
+ these:
+
+ \
+ 2.1.0-1~ppa0~ubuntu14.04.1,
+ 1.4-5-1.2.1~ubuntu20.04.1~ppa1
+ 22.12.2-0ubuntu1~ubuntu23.04~ppa1
+ \
+
+ Seeing that this is a non-sortable component (what in semver would be called
+ \"build metadata\"), using \c{~} is probably not the worst choice.
+
+ So we follow this lead and add the \c{~<ID><VERSION_ID>} \c{os-release(5)}
+ component to revision. Note that this also means we will have to make the 0
+ revision explicit. For example:
+
+ \
+ 1.2.3-1~debian10
+ 1.2.3-0~ubuntu20.04
+ \
+
+||
+
+The next case to consider is when we have the upstream version
+(\c{upstream-version} manifest value). After some rumination it feels correct
+to use it in place of the \c{<epoch>-<upstream>} components in the above
+mapping (upstream version itself cannot have epoch). In other words, we will
+add the pre-release and revision components from the \c{bpkg} version. If this
+is not the desired semantics, then it can always be overridden with the
+distribution version (see below).
+
+Finally, we have the distribution version. The Debian \c{<epoch>} and
+\c{<upstream>} components are straightforward: they should be specified by the
+distribution version as required. This leaves pre-release and revision. It
+feels like in most cases we would want these copied over from the \c{bpkg}
+version automatically \- it's too tedious and error-prone to maintain them
+manually. However, we want the user to have the full override ability. So
+instead, if empty revision is specified, as in \c{1.2.3-}, then we
+automatically add the \c{bpkg} revision. Similarly, if empty pre-release is
+specified, as in \c{1.2.3~}, then we add the \c{bpkg} pre-release. To add both
+automatically, we would specify \c{1.2.3~-} (other combinations are
+\c{1.2.3~b.1-} and \c{1.2.3~-1}).
+
+Note also that per the Debian version specification, if upstream contains
+\c{:} and/or \c{-}, then epoch and/or revision must be specified explicitly,
+respectively. Note that the \c{bpkg} upstream version may not contain either.
+
+
+\h#bindist-mapping-fedora|Fedora Package Mapping|
+
+This section describes the distribution package mapping for Fedora and alike
+(Red Hat Enterprise Linux, Centos, etc).
+
+\h2#bindist-mapping-fedora-consume|Fedora Package Mapping for Consumption|
+
+A library in Fedora is normally split up into several packages: the shared
+library package (e.g., \c{libfoo}), the development files package (e.g.,
+\c{libfoo-devel}), the static library package (e.g., \c{libfoo-static}; may
+also be placed into the \c{-devel} package), the documentation files package
+(e.g., \c{libfoo-doc}), the debug symbols and source files packages (e.g.,
+\c{libfoo-debuginfo} and \c{libfoo-debugsource}), and the common or
+architecture-independent files (e.g., \c{libfoo-common}). All the packages
+except \c{-devel} are optional and there is quite a bit of variability. In
+particular, the \c{lib} prefix in \c{libfoo} is not a requirement (unlike in
+Debian) and is normally present only if upstream name has it (see some
+examples below).
+
+For application packages there is normally no \c{-devel} packages but
+\c{-debug*}, \c{-doc}, and \c{-common} are plausible.
+
+For mixed packages which include both applications and libraries, the shared
+library package normally has the \c{-libs} suffix (e.g., \c{foo-libs}).
+
+A package name may also include an upstream version based suffix if
+multiple versions of the package can be installed simultaneously (e.g.,
+\c{libfoo1.1} \c{libfoo1.1-devel}, \c{libfoo2} \c{libfoo2-devel}).
+
+Terminology-wise, the term \"base package\" (sometime also \"main package\")
+normally refers to either the application or shared library package (as
+decided by the package maintainer in the spec file) with the suffixed packages
+(\c{-devel}, \c{-doc}, etc) called \"subpackages\".
+
+Here are a few examples:
+
+\
+libpq libpq-devel
+
+zlib zlib-devel zlib-static
+
+catch-devel
+
+eigen3-devel eigen3-doc
+
+xerces-c xerces-c-devel xerces-c-doc
+
+libsigc++20 libsigc++20-devel libsigc++20-doc
+libsigc++30 libsigc++30-devel libsigc++30-doc
+
+icu libicu libicu-devel libicu-doc
+
+openssl openssl-libs openssl-devel openssl-static
+openssl1.1 openssl1.1-devel
+
+curl libcurl libcurl-devel
+
+sqlite sqlite-libs sqlite-devel sqlite-doc
+
+community-mysql community-mysql-libs community-mysql-devel
+community-mysql-common community-mysql-server
+
+ncurses ncurses-libs ncurses-c++-libs ncurses-devel ncurses-static
+
+keyutils keyutils-libs keyutils-libs-devel
+\
+
+Note that while we support arbitrary \c{-debug*} sub-package names for
+consumption, we only generate \c{<main-package>-debug*}.
+
+Based on that, our approach when trying to automatically map a \c{bpkg}
+library package name to Fedora package names is to go for the \c{-devel}
+package first and figure out the shared library package from that based on the
+fact that the \c{-devel} package should have the \c{==} dependency on the
+shared library package with the same version and its name should normally
+start with the \c{-devel} package's stem and potentially end with the
+\c{-libs} suffix. If failed to find the \c{-devel} package, we re-try but now
+using the \c{bpkg} project name instead of the package name (see, for example,
+\c{openssl}, \c{sqlite}).
+
+The format of the \c{fedora-name} (or alike) manifest value value is a
+comma-separated list of one or more package groups:
+
+\
+<package-group> [, <package-group>...]
+\
+
+Where each \c{<package-group>} is the space-separated list of one or more
+package names:
+
+\
+<package-name> [ <package-name>...]
+\
+
+All the packages in the group should belong to the same \"logical package\",
+such as \c{-devel}, \c{-doc}, \c{-common} packages. They normally have the
+same version.
+
+The first group is called the main group and the first package in the
+group is called the main package. Note that all the groups are consumed
+(installed) but only the main group is produced (packaged).
+
+(Note that above we use the term \"logical package\" instead of \"base
+package\" since the main package may not be the base package, for example
+being the \c{-libs} subpackage.)
+
+We allow/recommend specifying the \c{-devel} package instead of the main
+package for libraries (see \l{#manifest-package-type-language \c{type}} for
+details), seeing that we are capable of detecting the main package
+automatically (see above). If the library name happens to end with \c{-devel}
+(which poses an ambiguity), then the \c{-devel} package should be specified
+explicitly as the second package to disambiguate this situation.
+
+The Fedora package version has the \c{[<epoch>:]<version>-<release>} form (see
+Fedora Package Versioning Guidelines for details). If no explicit mapping
+to the \c{bpkg} version is specified with the \c{fedora-to-downstream-version}
+(or alike) manifest values or none match, then we fallback to using the
+\c{<version>} part as the \c{bpkg} version. If explicit mapping is specified,
+then we match it against the \c{[<epoch>:]<version>} parts ignoring
+\c{<release>}.
+
+
+\h2#bindist-mapping-fedora-produce|Fedora Package Mapping for Production|
+
+The same \c{fedora-name} (or alike) manifest values as used for consumption
+are also used to derive the package names for production except here we have
+the option to specify alternative non-native package names using the special
+\c{fedora_0-name} (or alike) value. If only the \c{-devel} package is
+specified, then the main package name is derived from that by removing the
+\c{-devel} suffix. Note that regardless of whether the main package name is
+specified or not, the \l{bpkg-pkg-bindist(1)} command may omit generating the
+main package for a binless library.
+
+The generated binary package version can be specified with the
+\c{fedora-version} (or alike) manifest value. If it's not specified, then the
+\c{upstream-version} is used if specified. Otherwise, the \c{bpkg} version
+is translated to the Fedora version as described next.
+
+To recap, a Fedora package version has the following form:
+
+\
+[<epoch>:]<version>-<release>
+\
+
+Where <release> has the following form:
+
+\
+<release-number>[.<distribution-tag>]
+\
+
+For details on the ordering semantics, see the Fedora Versioning Guidelines.
+While overall unsurprising, the only notable exceptions are \c{~}, which sorts
+before anything else and is commonly used for upstream pre-releases, and
+\c{^}, which sorts after anything else and is supposedly used for upstream
+post-release snapshots. For example, \c{0.1.0~alpha.1-1.fc35} sorts earlier
+than \c{0.1.0-1.fc35}.
+
+To recap, the bpkg version has the following form (see
+\l{#package-version Package Version} for details):
+
+\
+[+<epoch>-]<upstream>[-<prerel>][+<revision>]
+\
+
+Let's start with the case where neither distribution (\c{fedora-version}) nor
+upstream version (\c{upstream-version}) is specified and we need to derive
+everything from the \c{bpkg} version (what follows is as much description as
+rationale).
+
+\dl|
+
+\li|\c{<epoch>}
+
+ On one hand, if we keep our (as in, \c{bpkg}) epoch, it won't necessarily
+ match Fedora's native package epoch. But on the other it will allow our
+ binary packages from different epochs to co-exist. Seeing that this can be
+ easily overridden with a custom distribution version (see below), we keep
+ it.
+
+ Note that while the Fedora start/default epoch is 0, ours is 1 (we use the 0
+ epoch for stub packages). So we shift this value range.|
+
+\li|\c{<upstream>[-<prerel>]}
+
+ Our upstream version maps naturally to Fedora's \c{<version>}. That is, our
+ upstream version format/semantics is a subset of Fedora's \c{<version>}.
+
+ If this is a pre-release, then we could fail (that is, don't allow
+ pre-releases) but then we won't be able to test on pre-release packages, for
+ example, to make sure the name mapping is correct. Plus sometimes it's
+ useful to publish pre-releases. We could ignore it, but then such packages
+ will be indistinguishable from each other and the final release, which is
+ not ideal. On the other hand, Fedora has the mechanism (\c{~}) which is
+ essentially meant for this, so we use it. We will use \c{<prerel>} as is
+ since its format is the same as \c{<upstream>} and thus should map
+ naturally.|
+
+\li|\c{<revision>}
+
+ Similar to epoch, our revision won't necessarily match Fedora's native
+ package release number. But on the other hand it will allow us to establish a
+ correspondence between source and binary packages. Plus, upgrades between
+ binary package releases will be handled naturally. Also note that the
+ revision is mandatory in Fedora. Seeing that we allow overriding the
+ releases with a custom distribution version (see below), we use it.
+
+ Note that the Fedora start release number is 1 and our revision is 0. So we
+ shift this value range.
+
+ Also we automatically add the trailing distribution tag (\c{.fc35},
+ \c{.el8}, etc) to the Fedora release. The tag is deduced automatically
+ unless overridden on the command line (see \l{bpkg-pkg-bindist(1)} command
+ for details).
+
+||
+
+The next case to consider is when we have the upstream version
+(\c{upstream-version} manifest value). After some rumination it feels correct
+to use it in place of the \c{<epoch>-<upstream>} components in the above
+mapping (upstream version itself cannot have epoch). In other words, we will
+add the pre-release and revision components from the \c{bpkg} version. If this
+is not the desired semantics, then it can always be overridden with the
+distribution version (see below).
+
+Finally, we have the distribution version. The Fedora \c{<epoch>} and
+\c{<version>} components are straightforward: they should be specified by the
+distribution version as required. This leaves pre-release and release. It
+feels like in most cases we would want these copied over from the \c{bpkg}
+version automatically \- it's too tedious and error-prone to maintain them
+manually. However, we want the user to have the full override ability. So
+instead, if empty release is specified, as in \c{1.2.3-}, then we
+automatically add the \c{bpkg} revision. Similarly, if empty pre-release is
+specified, as in \c{1.2.3~}, then we add the \c{bpkg} pre-release. To add both
+automatically, we would specify \c{1.2.3~-} (other combinations are
+\c{1.2.3~b.1-} and \c{1.2.3~-1}). If specified, the release must not contain
+the distribution tag, since it is deduced automatically unless overridden on
+the command line (see \l{bpkg-pkg-bindist(1)} command for details). Also,
+since the release component is mandatory in Fedora, if it is omitted together
+with the separating dash we will add the release 1 automatically.
+
+Note also that per the RPM spec file format documentation neither version nor
+release components may contain \c{:} or \c{-}. Note that the \c{bpkg} upstream
+version may not contain either.
"
//@@ TODO items (grep).
diff --git a/manifest b/manifest
index a945b92..e826689 100644
--- a/manifest
+++ b/manifest
@@ -1,6 +1,6 @@
: 1
name: bpkg
-version: 0.16.0-a.0.z
+version: 0.17.0-a.0.z
project: build2
summary: build2 package dependency manager
license: MIT
@@ -12,15 +12,15 @@ doc-url: https://build2.org/doc.xhtml
src-url: https://git.build2.org/cgit/bpkg/tree/
email: users@build2.org
build-warning-email: builds@build2.org
-builds: host
+builds: all : &host
requires: c++14
-depends: * build2 >= 0.15.0-
-depends: * bpkg >= 0.15.0-
+depends: * build2 >= 0.16.0-
+depends: * bpkg >= 0.16.0-
# @@ DEP Should probably become conditional dependency.
#requires: ? cli ; Only required if changing .cli files.
-depends: libodb [2.5.0-b.24.1 2.5.0-b.25)
-depends: libodb-sqlite [2.5.0-b.24.1 2.5.0-b.25)
+depends: libodb [2.5.0-b.26.1 2.5.0-b.27)
+depends: libodb-sqlite [2.5.0-b.26.1 2.5.0-b.27)
depends: libsqlite3 ^3.21.0 ; ATTACH in transaction
-depends: libbutl [0.16.0-a.0.1 0.16.0-a.1)
-depends: libbpkg [0.16.0-a.0.1 0.16.0-a.1)
-depends: build2 [0.16.0-a.0.1 0.16.0-a.1)
+depends: libbutl [0.17.0-a.0.1 0.17.0-a.1)
+depends: libbpkg [0.17.0-a.0.1 0.17.0-a.1)
+depends: build2 [0.17.0-a.0.1 0.17.0-a.1)
diff --git a/tests/build/root.build b/tests/build/root.build
index 4da21de..1d29eec 100644
--- a/tests/build/root.build
+++ b/tests/build/root.build
@@ -1,6 +1,10 @@
# file : tests/build/root.build
# license : MIT; see accompanying LICENSE file
+# Enable all tests, including those which takes a long time to execute.
+#
+config [bool] config.bpkg.tests.all ?= false
+
# Use remote instead of local repository locations for tests.
#
# Note that this is an "instead of" rather than "in addition to" configuration
@@ -19,6 +23,7 @@ config [bool] config.bpkg.tests.git.ssh ?= false
# Using the project configuration variables all over the testscripts makes
# them look hairy. Thus, let's provide short aliases for these variables.
#
+all = $config.bpkg.tests.all
remote = $config.bpkg.tests.remote
git_ssh = $config.bpkg.tests.git.ssh
diff --git a/tests/common.testscript b/tests/common.testscript
index 17174d9..30fcf7e 100644
--- a/tests/common.testscript
+++ b/tests/common.testscript
@@ -32,11 +32,13 @@ test.options += --default-options $options_guard \
# (for example, to make sure that configuration post-test state is valid and is
# as expected).
#
+# Disable the use of the system package manager for the pkg-build command.
+#
cfg_create = [cmdline] $* cfg-create
cfg_info = [cmdline] $* cfg-info
cfg_link = [cmdline] $* cfg-link
cfg_unlink = [cmdline] $* cfg-unlink
-pkg_build = [cmdline] $* pkg-build
+pkg_build = [cmdline] $* pkg-build --sys-no-query
pkg_checkout = [cmdline] $* pkg-checkout
pkg_configure = [cmdline] $* pkg-configure
pkg_disfigure = [cmdline] $* pkg-disfigure
diff --git a/tests/common/compatibility/t15/libbar-1.0.0.tar.gz b/tests/common/compatibility/t15/libbar-1.0.0.tar.gz
new file mode 100644
index 0000000..2c741b2
--- /dev/null
+++ b/tests/common/compatibility/t15/libbar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/compatibility/t15/libbaz-1.0.0.tar.gz b/tests/common/compatibility/t15/libbaz-1.0.0.tar.gz
new file mode 100644
index 0000000..07e6d04
--- /dev/null
+++ b/tests/common/compatibility/t15/libbaz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/compatibility/t15/libbiz-1.0.0.tar.gz b/tests/common/compatibility/t15/libbiz-1.0.0.tar.gz
new file mode 100644
index 0000000..52ee52a
--- /dev/null
+++ b/tests/common/compatibility/t15/libbiz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/compatibility/t15/libfoo-1.0.0.tar.gz b/tests/common/compatibility/t15/libfoo-1.0.0.tar.gz
new file mode 100644
index 0000000..be052c2
--- /dev/null
+++ b/tests/common/compatibility/t15/libfoo-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/compatibility/t15/repositories.manifest b/tests/common/compatibility/t15/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/compatibility/t15/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/dependency-alternatives/t11a/bax-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/bax-0.1.0.tar.gz
new file mode 100644
index 0000000..8ed7936
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/bax-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/bax-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/bax-1.0.0.tar.gz
index d488f1a..6c00903 100644
--- a/tests/common/dependency-alternatives/t11a/bax-1.0.0.tar.gz
+++ b/tests/common/dependency-alternatives/t11a/bax-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/biz-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/biz-0.1.0.tar.gz
new file mode 100644
index 0000000..b42dff0
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/biz-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/box-0.2.0.tar.gz b/tests/common/dependency-alternatives/t11a/box-0.2.0.tar.gz
new file mode 100644
index 0000000..fc22464
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/box-0.2.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/bus-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/bus-0.1.0.tar.gz
new file mode 100644
index 0000000..e3672b2
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/bus-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/fex-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/fex-0.1.0.tar.gz
new file mode 100644
index 0000000..160601b
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/fex-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/foo-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/foo-1.0.0.tar.gz
index c9a4d6d..42d9cc5 100644
--- a/tests/common/dependency-alternatives/t11a/foo-1.0.0.tar.gz
+++ b/tests/common/dependency-alternatives/t11a/foo-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/fox-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/fox-1.0.0.tar.gz
index 17b7278..159cfbd 100644
--- a/tests/common/dependency-alternatives/t11a/fox-1.0.0.tar.gz
+++ b/tests/common/dependency-alternatives/t11a/fox-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/fux-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/fux-0.1.0.tar.gz
new file mode 100644
index 0000000..563761e
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/fux-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/fux-0.1.1.tar.gz b/tests/common/dependency-alternatives/t11a/fux-0.1.1.tar.gz
new file mode 100644
index 0000000..22db443
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/fux-0.1.1.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/fux-0.2.0.tar.gz b/tests/common/dependency-alternatives/t11a/fux-0.2.0.tar.gz
new file mode 100644
index 0000000..4966b0d
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/fux-0.2.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/fux-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/fux-1.0.0.tar.gz
index b045fcd..c723ef9 100644
--- a/tests/common/dependency-alternatives/t11a/fux-1.0.0.tar.gz
+++ b/tests/common/dependency-alternatives/t11a/fux-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/libbiz-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/libbiz-0.1.0.tar.gz
new file mode 100644
index 0000000..429dc0d
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/libbiz-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/libbiz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/libbiz-1.0.0.tar.gz
new file mode 100644
index 0000000..250f110
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/libbiz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/libfoo-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/libfoo-1.0.0.tar.gz
index da545c1..e46178a 100644
--- a/tests/common/dependency-alternatives/t11a/libfoo-1.0.0.tar.gz
+++ b/tests/common/dependency-alternatives/t11a/libfoo-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/tex-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/tex-1.0.0.tar.gz
index 3c9093d..0c9e29d 100644
--- a/tests/common/dependency-alternatives/t11a/tex-1.0.0.tar.gz
+++ b/tests/common/dependency-alternatives/t11a/tex-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/tez-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/tez-0.1.0.tar.gz
new file mode 100644
index 0000000..208acfe
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/tez-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/tiz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/tiz-1.0.0.tar.gz
index 63c5876..8bfadcd 100644
--- a/tests/common/dependency-alternatives/t11a/tiz-1.0.0.tar.gz
+++ b/tests/common/dependency-alternatives/t11a/tiz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/tuz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/tuz-1.0.0.tar.gz
new file mode 100644
index 0000000..d4a8cdf
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/tuz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/tvz-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/tvz-0.1.0.tar.gz
new file mode 100644
index 0000000..55ef173
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/tvz-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/tvz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/tvz-1.0.0.tar.gz
new file mode 100644
index 0000000..0743be6
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/tvz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13a/box-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13a/box-1.0.0.tar.gz
new file mode 100644
index 0000000..be45865
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13a/box-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/bax-0.1.0.tar.gz b/tests/common/dependency-alternatives/t8a/bax-0.1.0.tar.gz
new file mode 100644
index 0000000..85a24ea
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/bax-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/bax-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/bax-1.0.0.tar.gz
new file mode 100644
index 0000000..204c335
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/bax-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/bix-0.1.0.tar.gz b/tests/common/dependency-alternatives/t8a/bix-0.1.0.tar.gz
new file mode 100644
index 0000000..d0cc912
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/bix-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/bix-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/bix-1.0.0.tar.gz
new file mode 100644
index 0000000..f1bab8d
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/bix-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/box-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/box-1.0.0.tar.gz
index babc96c..f266c46 100644
--- a/tests/common/dependency-alternatives/t8a/box-1.0.0.tar.gz
+++ b/tests/common/dependency-alternatives/t8a/box-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/bux-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/bux-1.0.0.tar.gz
new file mode 100644
index 0000000..9395a59
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/bux-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/dax-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/dax-1.0.0.tar.gz
new file mode 100644
index 0000000..0839f7b
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/dax-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/dix-0.1.0.tar.gz b/tests/common/dependency-alternatives/t8a/dix-0.1.0.tar.gz
new file mode 100644
index 0000000..706f068
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/dix-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/dix-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/dix-1.0.0.tar.gz
new file mode 100644
index 0000000..764e530
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/dix-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/dox-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/dox-1.0.0.tar.gz
new file mode 100644
index 0000000..475f7d6
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/dox-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/dux-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/dux-1.0.0.tar.gz
new file mode 100644
index 0000000..23f5505
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/dux-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/foz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/foz-1.0.0.tar.gz
new file mode 100644
index 0000000..90506c6
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/foz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/fuz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/fuz-1.0.0.tar.gz
new file mode 100644
index 0000000..03f8f1a
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/fuz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/libbar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/libbar-1.0.0.tar.gz
index ce7f270..badb970 100644
--- a/tests/common/dependency-alternatives/t8a/libbar-1.0.0.tar.gz
+++ b/tests/common/dependency-alternatives/t8a/libbar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/libbaz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/libbaz-1.0.0.tar.gz
index 1dd802e..2a24050 100644
--- a/tests/common/dependency-alternatives/t8a/libbaz-1.0.0.tar.gz
+++ b/tests/common/dependency-alternatives/t8a/libbaz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/libbaz-1.1.0.tar.gz b/tests/common/dependency-alternatives/t8a/libbaz-1.1.0.tar.gz
index 2427346..ddc5435 100644
--- a/tests/common/dependency-alternatives/t8a/libbaz-1.1.0.tar.gz
+++ b/tests/common/dependency-alternatives/t8a/libbaz-1.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/libfoo-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/libfoo-1.0.0.tar.gz
new file mode 100644
index 0000000..f2dcb15
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/libfoo-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/libfoo-2.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/libfoo-2.0.0.tar.gz
new file mode 100644
index 0000000..2b6f0f5
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/libfoo-2.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/libfox-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/libfox-1.0.0.tar.gz
new file mode 100644
index 0000000..68eee9d
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/libfox-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/tax-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/tax-1.0.0.tar.gz
new file mode 100644
index 0000000..7c2b99d
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/tax-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/tex-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/tex-1.0.0.tar.gz
new file mode 100644
index 0000000..663b09a
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/tex-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/tix-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/tix-1.0.0.tar.gz
new file mode 100644
index 0000000..34ea3da
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/tix-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/tox-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/tox-1.0.0.tar.gz
new file mode 100644
index 0000000..c767026
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/tox-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/tpx-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/tpx-1.0.0.tar.gz
new file mode 100644
index 0000000..aa8db1d
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/tpx-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/tux-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/tux-1.0.0.tar.gz
new file mode 100644
index 0000000..e171e87
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/tux-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/tvx-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/tvx-1.0.0.tar.gz
new file mode 100644
index 0000000..0d719a5
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/tvx-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t8a/twx-1.0.0.tar.gz b/tests/common/dependency-alternatives/t8a/twx-1.0.0.tar.gz
new file mode 100644
index 0000000..03e8fbb
--- /dev/null
+++ b/tests/common/dependency-alternatives/t8a/twx-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/git/README b/tests/common/git/README
index 737cd83..5b4781b 100644
--- a/tests/common/git/README
+++ b/tests/common/git/README
@@ -8,7 +8,7 @@ before modification, and
$ ./pack
-afterwrds.
+afterwards.
Also note that config files under .git/ subdirectory refer to the submodule
repositories using absolute paths. So prior to pulling in subproject directory
diff --git a/tests/common/git/state0/libbar.tar b/tests/common/git/state0/libbar.tar
index a06e98f..4312752 100644
--- a/tests/common/git/state0/libbar.tar
+++ b/tests/common/git/state0/libbar.tar
Binary files differ
diff --git a/tests/common/git/state0/libfoo.tar b/tests/common/git/state0/libfoo.tar
index b73307c..af2affc 100644
--- a/tests/common/git/state0/libfoo.tar
+++ b/tests/common/git/state0/libfoo.tar
Binary files differ
diff --git a/tests/common/git/state0/libfox.tar b/tests/common/git/state0/libfox.tar
index 641598d..d955085 100644
--- a/tests/common/git/state0/libfox.tar
+++ b/tests/common/git/state0/libfox.tar
Binary files differ
diff --git a/tests/common/git/state0/links.tar b/tests/common/git/state0/links.tar
index 360765e..3376bf7 100644
--- a/tests/common/git/state0/links.tar
+++ b/tests/common/git/state0/links.tar
Binary files differ
diff --git a/tests/common/git/state0/style-basic.tar b/tests/common/git/state0/style-basic.tar
index 344df4b..5f60782 100644
--- a/tests/common/git/state0/style-basic.tar
+++ b/tests/common/git/state0/style-basic.tar
Binary files differ
diff --git a/tests/common/git/state0/style.tar b/tests/common/git/state0/style.tar
index 293cea1..d95f00b 100644
--- a/tests/common/git/state0/style.tar
+++ b/tests/common/git/state0/style.tar
Binary files differ
diff --git a/tests/common/git/state1/libbaz.tar b/tests/common/git/state1/libbaz.tar
index 151bdb9..f10cc12 100644
--- a/tests/common/git/state1/libbaz.tar
+++ b/tests/common/git/state1/libbaz.tar
Binary files differ
diff --git a/tests/common/git/state1/libfoo.tar b/tests/common/git/state1/libfoo.tar
index 7e61ac6..4ce25d1 100644
--- a/tests/common/git/state1/libfoo.tar
+++ b/tests/common/git/state1/libfoo.tar
Binary files differ
diff --git a/tests/common/git/state1/libfox.tar b/tests/common/git/state1/libfox.tar
index 54485df..7de6ffa 100644
--- a/tests/common/git/state1/libfox.tar
+++ b/tests/common/git/state1/libfox.tar
Binary files differ
diff --git a/tests/common/git/state1/style-basic.tar b/tests/common/git/state1/style-basic.tar
index dd5ef5a..1693a33 100644
--- a/tests/common/git/state1/style-basic.tar
+++ b/tests/common/git/state1/style-basic.tar
Binary files differ
diff --git a/tests/common/git/state1/style.tar b/tests/common/git/state1/style.tar
index 14ee6c9..3fbf69e 100644
--- a/tests/common/git/state1/style.tar
+++ b/tests/common/git/state1/style.tar
Binary files differ
diff --git a/tests/common/linked/t7a/foo-1.0.0.tar.gz b/tests/common/linked/t7a/foo-1.0.0.tar.gz
index 1720e36..1fffa54 100644
--- a/tests/common/linked/t7a/foo-1.0.0.tar.gz
+++ b/tests/common/linked/t7a/foo-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/linked/t7a/libbar-1.0.0.tar.gz b/tests/common/linked/t7a/libbar-1.0.0.tar.gz
index 21940a3..9b0e0f6 100644
--- a/tests/common/linked/t7a/libbar-1.0.0.tar.gz
+++ b/tests/common/linked/t7a/libbar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/linked/t7a/libbaz-1.0.0.tar.gz b/tests/common/linked/t7a/libbaz-1.0.0.tar.gz
index 82d89fa..3cdd0b4 100644
--- a/tests/common/linked/t7a/libbaz-1.0.0.tar.gz
+++ b/tests/common/linked/t7a/libbaz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/linked/t7a/libbiz-1.0.0.tar.gz b/tests/common/linked/t7a/libbiz-1.0.0.tar.gz
index 1214925..30f7ba6 100644
--- a/tests/common/linked/t7a/libbiz-1.0.0.tar.gz
+++ b/tests/common/linked/t7a/libbiz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/linked/t7a/libbox-1.0.0.tar.gz b/tests/common/linked/t7a/libbox-1.0.0.tar.gz
index 7c293e0..cea6f6a 100644
--- a/tests/common/linked/t7a/libbox-1.0.0.tar.gz
+++ b/tests/common/linked/t7a/libbox-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/linked/t7a/libbuild2-bar-1.0.0.tar.gz b/tests/common/linked/t7a/libbuild2-bar-1.0.0.tar.gz
index 789b4e8..5f0b592 100644
--- a/tests/common/linked/t7a/libbuild2-bar-1.0.0.tar.gz
+++ b/tests/common/linked/t7a/libbuild2-bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/linked/t7a/libbuild2-foo-1.0.0.tar.gz b/tests/common/linked/t7a/libbuild2-foo-1.0.0.tar.gz
index 2a9ce1b..5d900ab 100644
--- a/tests/common/linked/t7a/libbuild2-foo-1.0.0.tar.gz
+++ b/tests/common/linked/t7a/libbuild2-foo-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/linked/t7a/libbuz-1.0.0.tar.gz b/tests/common/linked/t7a/libbuz-1.0.0.tar.gz
index 4d0ea38..c3344b6 100644
--- a/tests/common/linked/t7a/libbuz-1.0.0.tar.gz
+++ b/tests/common/linked/t7a/libbuz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/linked/t7a/libfax-1.0.0.tar.gz b/tests/common/linked/t7a/libfax-1.0.0.tar.gz
index a460e4a..ffb7257 100644
--- a/tests/common/linked/t7a/libfax-1.0.0.tar.gz
+++ b/tests/common/linked/t7a/libfax-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/linked/t7a/libfix-1.0.0.tar.gz b/tests/common/linked/t7a/libfix-1.0.0.tar.gz
index fbfadde..98d3499 100644
--- a/tests/common/linked/t7a/libfix-1.0.0.tar.gz
+++ b/tests/common/linked/t7a/libfix-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/linked/t7b/foo-1.1.0.tar.gz b/tests/common/linked/t7b/foo-1.1.0.tar.gz
index aa929fb..ff8dc1b 100644
--- a/tests/common/linked/t7b/foo-1.1.0.tar.gz
+++ b/tests/common/linked/t7b/foo-1.1.0.tar.gz
Binary files differ
diff --git a/tests/common/linked/t7b/libbar-1.1.0.tar.gz b/tests/common/linked/t7b/libbar-1.1.0.tar.gz
index 9926348..5d79594 100644
--- a/tests/common/linked/t7b/libbar-1.1.0.tar.gz
+++ b/tests/common/linked/t7b/libbar-1.1.0.tar.gz
Binary files differ
diff --git a/tests/common/linked/t7b/libbaz-1.1.0.tar.gz b/tests/common/linked/t7b/libbaz-1.1.0.tar.gz
index 6b12460..ec28e55 100644
--- a/tests/common/linked/t7b/libbaz-1.1.0.tar.gz
+++ b/tests/common/linked/t7b/libbaz-1.1.0.tar.gz
Binary files differ
diff --git a/tests/common/linked/t7b/libbox-1.1.0.tar.gz b/tests/common/linked/t7b/libbox-1.1.0.tar.gz
index 698661d..4365901 100644
--- a/tests/common/linked/t7b/libbox-1.1.0.tar.gz
+++ b/tests/common/linked/t7b/libbox-1.1.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbar-0.1.0.tar.gz b/tests/common/satisfy/libbar-0.1.0.tar.gz
new file mode 100644
index 0000000..f072c11
--- /dev/null
+++ b/tests/common/satisfy/libbar-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbar-1.0.0.tar.gz b/tests/common/satisfy/libbar-1.0.0.tar.gz
index 5dc3a9b..00220d7 100644
--- a/tests/common/satisfy/libbar-1.0.0.tar.gz
+++ b/tests/common/satisfy/libbar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbar-1.1.0.tar.gz b/tests/common/satisfy/libbar-1.1.0.tar.gz
index 16a8b47..b3dcf28 100644
--- a/tests/common/satisfy/libbar-1.1.0.tar.gz
+++ b/tests/common/satisfy/libbar-1.1.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbar-1.2.0.tar.gz b/tests/common/satisfy/libbar-1.2.0.tar.gz
index 4572395..51d997f 100644
--- a/tests/common/satisfy/libbar-1.2.0.tar.gz
+++ b/tests/common/satisfy/libbar-1.2.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbar-2.1.0.tar.gz b/tests/common/satisfy/libbar-2.1.0.tar.gz
new file mode 100644
index 0000000..0ff50c5
--- /dev/null
+++ b/tests/common/satisfy/libbar-2.1.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbax-1.0.0.tar.gz b/tests/common/satisfy/libbax-1.0.0.tar.gz
new file mode 100644
index 0000000..7f4dfd0
--- /dev/null
+++ b/tests/common/satisfy/libbax-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbax-2.0.0.tar.gz b/tests/common/satisfy/libbax-2.0.0.tar.gz
new file mode 100644
index 0000000..f130da0
--- /dev/null
+++ b/tests/common/satisfy/libbax-2.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbaz-1.1.0.tar.gz b/tests/common/satisfy/libbaz-1.1.0.tar.gz
index 1aa72a8..5838bf7 100644
--- a/tests/common/satisfy/libbaz-1.1.0.tar.gz
+++ b/tests/common/satisfy/libbaz-1.1.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbaz-1.2.0.tar.gz b/tests/common/satisfy/libbaz-1.2.0.tar.gz
new file mode 100644
index 0000000..3d07d88
--- /dev/null
+++ b/tests/common/satisfy/libbaz-1.2.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbaz-2.0.0.tar.gz b/tests/common/satisfy/libbaz-2.0.0.tar.gz
new file mode 100644
index 0000000..dec93bf
--- /dev/null
+++ b/tests/common/satisfy/libbaz-2.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbaz-2.1.0.tar.gz b/tests/common/satisfy/libbaz-2.1.0.tar.gz
new file mode 100644
index 0000000..4133df8
--- /dev/null
+++ b/tests/common/satisfy/libbaz-2.1.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbix-1.0.0.tar.gz b/tests/common/satisfy/libbix-1.0.0.tar.gz
new file mode 100644
index 0000000..9dfe541
--- /dev/null
+++ b/tests/common/satisfy/libbix-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbix-2.0.0.tar.gz b/tests/common/satisfy/libbix-2.0.0.tar.gz
new file mode 100644
index 0000000..ca7bd95
--- /dev/null
+++ b/tests/common/satisfy/libbix-2.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbox-1.0.0.tar.gz b/tests/common/satisfy/libbox-1.0.0.tar.gz
new file mode 100644
index 0000000..90227f7
--- /dev/null
+++ b/tests/common/satisfy/libbox-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbox-1.2.0.tar.gz b/tests/common/satisfy/libbox-1.2.0.tar.gz
new file mode 100644
index 0000000..1f8675a
--- /dev/null
+++ b/tests/common/satisfy/libbox-1.2.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbox-2.0.0.tar.gz b/tests/common/satisfy/libbox-2.0.0.tar.gz
new file mode 100644
index 0000000..15d457f
--- /dev/null
+++ b/tests/common/satisfy/libbox-2.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libbux-1.0.0.tar.gz b/tests/common/satisfy/libbux-1.0.0.tar.gz
new file mode 100644
index 0000000..51960f9
--- /dev/null
+++ b/tests/common/satisfy/libbux-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libfix-1.0.0.tar.gz b/tests/common/satisfy/libfix-1.0.0.tar.gz
new file mode 100644
index 0000000..ed2d78f
--- /dev/null
+++ b/tests/common/satisfy/libfix-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libfoo-0.1.0.tar.gz b/tests/common/satisfy/libfoo-0.1.0.tar.gz
new file mode 100644
index 0000000..b1c1ff2
--- /dev/null
+++ b/tests/common/satisfy/libfoo-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libfoo-1.0.0.tar.gz b/tests/common/satisfy/libfoo-1.0.0.tar.gz
index 41da9a0..be052c2 100644
--- a/tests/common/satisfy/libfoo-1.0.0.tar.gz
+++ b/tests/common/satisfy/libfoo-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libfoo-1.1.0+1.tar.gz b/tests/common/satisfy/libfoo-1.1.0+1.tar.gz
index 8cc49aa..3eb8670 100644
--- a/tests/common/satisfy/libfoo-1.1.0+1.tar.gz
+++ b/tests/common/satisfy/libfoo-1.1.0+1.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libfoo-1.1.0+2.tar.gz b/tests/common/satisfy/libfoo-1.1.0+2.tar.gz
new file mode 100644
index 0000000..1ffeaea
--- /dev/null
+++ b/tests/common/satisfy/libfoo-1.1.0+2.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libfoo-1.1.0+3.tar.gz b/tests/common/satisfy/libfoo-1.1.0+3.tar.gz
new file mode 100644
index 0000000..8892b7b
--- /dev/null
+++ b/tests/common/satisfy/libfoo-1.1.0+3.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libfoo-1.1.0.tar.gz b/tests/common/satisfy/libfoo-1.1.0.tar.gz
index e03481f..2b95877 100644
--- a/tests/common/satisfy/libfoo-1.1.0.tar.gz
+++ b/tests/common/satisfy/libfoo-1.1.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libfoo-1.1.1.tar.gz b/tests/common/satisfy/libfoo-1.1.1.tar.gz
new file mode 100644
index 0000000..2e3a1f8
--- /dev/null
+++ b/tests/common/satisfy/libfoo-1.1.1.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libfoo-2.0.0.tar.gz b/tests/common/satisfy/libfoo-2.0.0.tar.gz
new file mode 100644
index 0000000..fd8eeb3
--- /dev/null
+++ b/tests/common/satisfy/libfoo-2.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libfoo-3.0.0.tar.gz b/tests/common/satisfy/libfoo-3.0.0.tar.gz
new file mode 100644
index 0000000..3ef4fdf
--- /dev/null
+++ b/tests/common/satisfy/libfoo-3.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libfox-1.1.0.tar.gz b/tests/common/satisfy/libfox-1.1.0.tar.gz
new file mode 100644
index 0000000..c626d72
--- /dev/null
+++ b/tests/common/satisfy/libfox-1.1.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libfox-2.0.0.tar.gz b/tests/common/satisfy/libfox-2.0.0.tar.gz
new file mode 100644
index 0000000..1297cda
--- /dev/null
+++ b/tests/common/satisfy/libfox-2.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libfox-2.1.0.tar.gz b/tests/common/satisfy/libfox-2.1.0.tar.gz
new file mode 100644
index 0000000..60a4cce
--- /dev/null
+++ b/tests/common/satisfy/libfox-2.1.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/libfox-3.0.0.tar.gz b/tests/common/satisfy/libfox-3.0.0.tar.gz
new file mode 100644
index 0000000..0bc246e
--- /dev/null
+++ b/tests/common/satisfy/libfox-3.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t10/libbar-baz-1.0.0.tar.gz b/tests/common/satisfy/t10/libbar-baz-1.0.0.tar.gz
new file mode 100644
index 0000000..9075ee4
--- /dev/null
+++ b/tests/common/satisfy/t10/libbar-baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t10/libbar-foo-1.0.0.tar.gz b/tests/common/satisfy/t10/libbar-foo-1.0.0.tar.gz
new file mode 100644
index 0000000..2dd5e69
--- /dev/null
+++ b/tests/common/satisfy/t10/libbar-foo-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t10/libbar-tests-1.0.0.tar.gz b/tests/common/satisfy/t10/libbar-tests-1.0.0.tar.gz
new file mode 100644
index 0000000..7f587d9
--- /dev/null
+++ b/tests/common/satisfy/t10/libbar-tests-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t10/libfoo-tests-1.0.0.tar.gz b/tests/common/satisfy/t10/libfoo-tests-1.0.0.tar.gz
index 594a9b8..bc58a14 100644
--- a/tests/common/satisfy/t10/libfoo-tests-1.0.0.tar.gz
+++ b/tests/common/satisfy/t10/libfoo-tests-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t14a/libfoo-1.0.0.tar.gz b/tests/common/satisfy/t14a/libfoo-1.0.0.tar.gz
new file mode 120000
index 0000000..32e5a3c
--- /dev/null
+++ b/tests/common/satisfy/t14a/libfoo-1.0.0.tar.gz
@@ -0,0 +1 @@
+../libfoo-1.0.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t14a/repositories.manifest b/tests/common/satisfy/t14a/repositories.manifest
new file mode 120000
index 0000000..0d4767a
--- /dev/null
+++ b/tests/common/satisfy/t14a/repositories.manifest
@@ -0,0 +1 @@
+../repositories.manifest \ No newline at end of file
diff --git a/tests/common/satisfy/t14b/libfoo-1.1.0.tar.gz b/tests/common/satisfy/t14b/libfoo-1.1.0.tar.gz
new file mode 120000
index 0000000..c004b2a
--- /dev/null
+++ b/tests/common/satisfy/t14b/libfoo-1.1.0.tar.gz
@@ -0,0 +1 @@
+../libfoo-1.1.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t14b/repositories.manifest b/tests/common/satisfy/t14b/repositories.manifest
new file mode 120000
index 0000000..0d4767a
--- /dev/null
+++ b/tests/common/satisfy/t14b/repositories.manifest
@@ -0,0 +1 @@
+../repositories.manifest \ No newline at end of file
diff --git a/tests/common/satisfy/t14c/libfoo-1.1.0+1.tar.gz b/tests/common/satisfy/t14c/libfoo-1.1.0+1.tar.gz
new file mode 120000
index 0000000..ca9c01a
--- /dev/null
+++ b/tests/common/satisfy/t14c/libfoo-1.1.0+1.tar.gz
@@ -0,0 +1 @@
+../libfoo-1.1.0+1.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t14c/repositories.manifest b/tests/common/satisfy/t14c/repositories.manifest
new file mode 120000
index 0000000..0d4767a
--- /dev/null
+++ b/tests/common/satisfy/t14c/repositories.manifest
@@ -0,0 +1 @@
+../repositories.manifest \ No newline at end of file
diff --git a/tests/common/satisfy/t14d/libfoo-1.1.0+2.tar.gz b/tests/common/satisfy/t14d/libfoo-1.1.0+2.tar.gz
new file mode 120000
index 0000000..a89d2cc
--- /dev/null
+++ b/tests/common/satisfy/t14d/libfoo-1.1.0+2.tar.gz
@@ -0,0 +1 @@
+../libfoo-1.1.0+2.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t14d/repositories.manifest b/tests/common/satisfy/t14d/repositories.manifest
new file mode 120000
index 0000000..0d4767a
--- /dev/null
+++ b/tests/common/satisfy/t14d/repositories.manifest
@@ -0,0 +1 @@
+../repositories.manifest \ No newline at end of file
diff --git a/tests/common/satisfy/t14e/libfoo-1.1.0+3.tar.gz b/tests/common/satisfy/t14e/libfoo-1.1.0+3.tar.gz
new file mode 120000
index 0000000..616029d
--- /dev/null
+++ b/tests/common/satisfy/t14e/libfoo-1.1.0+3.tar.gz
@@ -0,0 +1 @@
+../libfoo-1.1.0+3.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t14e/repositories.manifest b/tests/common/satisfy/t14e/repositories.manifest
new file mode 120000
index 0000000..0d4767a
--- /dev/null
+++ b/tests/common/satisfy/t14e/repositories.manifest
@@ -0,0 +1 @@
+../repositories.manifest \ No newline at end of file
diff --git a/tests/common/satisfy/t14f/libfoo-1.1.1.tar.gz b/tests/common/satisfy/t14f/libfoo-1.1.1.tar.gz
new file mode 120000
index 0000000..b9ba788
--- /dev/null
+++ b/tests/common/satisfy/t14f/libfoo-1.1.1.tar.gz
@@ -0,0 +1 @@
+../libfoo-1.1.1.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t14f/repositories.manifest b/tests/common/satisfy/t14f/repositories.manifest
new file mode 120000
index 0000000..0d4767a
--- /dev/null
+++ b/tests/common/satisfy/t14f/repositories.manifest
@@ -0,0 +1 @@
+../repositories.manifest \ No newline at end of file
diff --git a/tests/common/satisfy/t14i/libfoo-1.2.0.tar.gz b/tests/common/satisfy/t14i/libfoo-1.2.0.tar.gz
new file mode 120000
index 0000000..55398c5
--- /dev/null
+++ b/tests/common/satisfy/t14i/libfoo-1.2.0.tar.gz
@@ -0,0 +1 @@
+../libfoo-1.2.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t14i/repositories.manifest b/tests/common/satisfy/t14i/repositories.manifest
new file mode 120000
index 0000000..0d4767a
--- /dev/null
+++ b/tests/common/satisfy/t14i/repositories.manifest
@@ -0,0 +1 @@
+../repositories.manifest \ No newline at end of file
diff --git a/tests/common/satisfy/t2/libfoo-0.1.0.tar.gz b/tests/common/satisfy/t2/libfoo-0.1.0.tar.gz
new file mode 120000
index 0000000..1e2ede1
--- /dev/null
+++ b/tests/common/satisfy/t2/libfoo-0.1.0.tar.gz
@@ -0,0 +1 @@
+../libfoo-0.1.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4f/libbar-1.2.0.tar.gz b/tests/common/satisfy/t4f/libbar-1.2.0.tar.gz
new file mode 120000
index 0000000..b4a7773
--- /dev/null
+++ b/tests/common/satisfy/t4f/libbar-1.2.0.tar.gz
@@ -0,0 +1 @@
+../libbar-1.2.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4f/libbar-2.1.0.tar.gz b/tests/common/satisfy/t4f/libbar-2.1.0.tar.gz
new file mode 120000
index 0000000..0df079a
--- /dev/null
+++ b/tests/common/satisfy/t4f/libbar-2.1.0.tar.gz
@@ -0,0 +1 @@
+../libbar-2.1.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4f/libbax-1.0.0.tar.gz b/tests/common/satisfy/t4f/libbax-1.0.0.tar.gz
new file mode 120000
index 0000000..137b938
--- /dev/null
+++ b/tests/common/satisfy/t4f/libbax-1.0.0.tar.gz
@@ -0,0 +1 @@
+../libbax-1.0.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4f/libbax-2.0.0.tar.gz b/tests/common/satisfy/t4f/libbax-2.0.0.tar.gz
new file mode 120000
index 0000000..465832f
--- /dev/null
+++ b/tests/common/satisfy/t4f/libbax-2.0.0.tar.gz
@@ -0,0 +1 @@
+../libbax-2.0.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4f/libbix-1.0.0.tar.gz b/tests/common/satisfy/t4f/libbix-1.0.0.tar.gz
new file mode 120000
index 0000000..acf87bf
--- /dev/null
+++ b/tests/common/satisfy/t4f/libbix-1.0.0.tar.gz
@@ -0,0 +1 @@
+../libbix-1.0.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4f/libbix-2.0.0.tar.gz b/tests/common/satisfy/t4f/libbix-2.0.0.tar.gz
new file mode 120000
index 0000000..26683f9
--- /dev/null
+++ b/tests/common/satisfy/t4f/libbix-2.0.0.tar.gz
@@ -0,0 +1 @@
+../libbix-2.0.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4f/libbox-1.0.0.tar.gz b/tests/common/satisfy/t4f/libbox-1.0.0.tar.gz
new file mode 120000
index 0000000..3bc2a0c
--- /dev/null
+++ b/tests/common/satisfy/t4f/libbox-1.0.0.tar.gz
@@ -0,0 +1 @@
+../libbox-1.0.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4f/libbox-2.0.0.tar.gz b/tests/common/satisfy/t4f/libbox-2.0.0.tar.gz
new file mode 120000
index 0000000..1ec50e6
--- /dev/null
+++ b/tests/common/satisfy/t4f/libbox-2.0.0.tar.gz
@@ -0,0 +1 @@
+../libbox-2.0.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4f/libbux-1.0.0.tar.gz b/tests/common/satisfy/t4f/libbux-1.0.0.tar.gz
new file mode 120000
index 0000000..8718789
--- /dev/null
+++ b/tests/common/satisfy/t4f/libbux-1.0.0.tar.gz
@@ -0,0 +1 @@
+../libbux-1.0.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4f/libfix-1.0.0.tar.gz b/tests/common/satisfy/t4f/libfix-1.0.0.tar.gz
new file mode 120000
index 0000000..aad4c49
--- /dev/null
+++ b/tests/common/satisfy/t4f/libfix-1.0.0.tar.gz
@@ -0,0 +1 @@
+../libfix-1.0.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4f/libfoo-2.0.0.tar.gz b/tests/common/satisfy/t4f/libfoo-2.0.0.tar.gz
new file mode 120000
index 0000000..406696d
--- /dev/null
+++ b/tests/common/satisfy/t4f/libfoo-2.0.0.tar.gz
@@ -0,0 +1 @@
+../libfoo-2.0.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4f/libfox-1.1.0.tar.gz b/tests/common/satisfy/t4f/libfox-1.1.0.tar.gz
new file mode 120000
index 0000000..97bb68b
--- /dev/null
+++ b/tests/common/satisfy/t4f/libfox-1.1.0.tar.gz
@@ -0,0 +1 @@
+../libfox-1.1.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4f/libfox-2.0.0.tar.gz b/tests/common/satisfy/t4f/libfox-2.0.0.tar.gz
new file mode 120000
index 0000000..2996971
--- /dev/null
+++ b/tests/common/satisfy/t4f/libfox-2.0.0.tar.gz
@@ -0,0 +1 @@
+../libfox-2.0.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4f/repositories.manifest b/tests/common/satisfy/t4f/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/satisfy/t4f/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/satisfy/t4i/libbar-0.1.0.tar.gz b/tests/common/satisfy/t4i/libbar-0.1.0.tar.gz
new file mode 120000
index 0000000..f622e36
--- /dev/null
+++ b/tests/common/satisfy/t4i/libbar-0.1.0.tar.gz
@@ -0,0 +1 @@
+../libbar-0.1.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4i/libbaz-2.0.0.tar.gz b/tests/common/satisfy/t4i/libbaz-2.0.0.tar.gz
new file mode 120000
index 0000000..8787403
--- /dev/null
+++ b/tests/common/satisfy/t4i/libbaz-2.0.0.tar.gz
@@ -0,0 +1 @@
+../libbaz-2.0.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4i/repositories.manifest b/tests/common/satisfy/t4i/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/satisfy/t4i/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/satisfy/t4j/libbar-0.1.0.tar.gz b/tests/common/satisfy/t4j/libbar-0.1.0.tar.gz
new file mode 120000
index 0000000..f622e36
--- /dev/null
+++ b/tests/common/satisfy/t4j/libbar-0.1.0.tar.gz
@@ -0,0 +1 @@
+../libbar-0.1.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4j/libbar-1.2.0.tar.gz b/tests/common/satisfy/t4j/libbar-1.2.0.tar.gz
new file mode 120000
index 0000000..b4a7773
--- /dev/null
+++ b/tests/common/satisfy/t4j/libbar-1.2.0.tar.gz
@@ -0,0 +1 @@
+../libbar-1.2.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4j/libbaz-1.2.0.tar.gz b/tests/common/satisfy/t4j/libbaz-1.2.0.tar.gz
new file mode 120000
index 0000000..d43cdcd
--- /dev/null
+++ b/tests/common/satisfy/t4j/libbaz-1.2.0.tar.gz
@@ -0,0 +1 @@
+../libbaz-1.2.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4j/libbaz-2.1.0.tar.gz b/tests/common/satisfy/t4j/libbaz-2.1.0.tar.gz
new file mode 120000
index 0000000..11cd8c8
--- /dev/null
+++ b/tests/common/satisfy/t4j/libbaz-2.1.0.tar.gz
@@ -0,0 +1 @@
+../libbaz-2.1.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4j/libfix-1.0.0.tar.gz b/tests/common/satisfy/t4j/libfix-1.0.0.tar.gz
new file mode 120000
index 0000000..aad4c49
--- /dev/null
+++ b/tests/common/satisfy/t4j/libfix-1.0.0.tar.gz
@@ -0,0 +1 @@
+../libfix-1.0.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4j/libfoo-3.0.0.tar.gz b/tests/common/satisfy/t4j/libfoo-3.0.0.tar.gz
new file mode 120000
index 0000000..7678898
--- /dev/null
+++ b/tests/common/satisfy/t4j/libfoo-3.0.0.tar.gz
@@ -0,0 +1 @@
+../libfoo-3.0.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4j/libfox-0.0.1.tar.gz b/tests/common/satisfy/t4j/libfox-0.0.1.tar.gz
new file mode 120000
index 0000000..674ac04
--- /dev/null
+++ b/tests/common/satisfy/t4j/libfox-0.0.1.tar.gz
@@ -0,0 +1 @@
+../libfox-0.0.1.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4j/libfox-2.1.0.tar.gz b/tests/common/satisfy/t4j/libfox-2.1.0.tar.gz
new file mode 120000
index 0000000..157a046
--- /dev/null
+++ b/tests/common/satisfy/t4j/libfox-2.1.0.tar.gz
@@ -0,0 +1 @@
+../libfox-2.1.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4j/libfox-3.0.0.tar.gz b/tests/common/satisfy/t4j/libfox-3.0.0.tar.gz
new file mode 120000
index 0000000..2aef930
--- /dev/null
+++ b/tests/common/satisfy/t4j/libfox-3.0.0.tar.gz
@@ -0,0 +1 @@
+../libfox-3.0.0.tar.gz \ No newline at end of file
diff --git a/tests/common/satisfy/t4j/repositories.manifest b/tests/common/satisfy/t4j/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/satisfy/t4j/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/satisfy/t4k/libbar-1.0.0.tar.gz b/tests/common/satisfy/t4k/libbar-1.0.0.tar.gz
new file mode 100644
index 0000000..4fbd21e
--- /dev/null
+++ b/tests/common/satisfy/t4k/libbar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libbaz-1.0.0.tar.gz b/tests/common/satisfy/t4k/libbaz-1.0.0.tar.gz
new file mode 100644
index 0000000..dc17b9f
--- /dev/null
+++ b/tests/common/satisfy/t4k/libbaz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfax-1.0.0.tar.gz b/tests/common/satisfy/t4k/libfax-1.0.0.tar.gz
new file mode 100644
index 0000000..8145884
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfax-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfax-2.0.0.tar.gz b/tests/common/satisfy/t4k/libfax-2.0.0.tar.gz
new file mode 100644
index 0000000..7ab921f
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfax-2.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfaz-1.0.0.tar.gz b/tests/common/satisfy/t4k/libfaz-1.0.0.tar.gz
new file mode 100644
index 0000000..3ab004a
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfaz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfaz-2.0.0.tar.gz b/tests/common/satisfy/t4k/libfaz-2.0.0.tar.gz
new file mode 100644
index 0000000..1c3d003
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfaz-2.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfex-1.0.0.tar.gz b/tests/common/satisfy/t4k/libfex-1.0.0.tar.gz
new file mode 100644
index 0000000..f008cc0
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfex-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfex-2.0.0.tar.gz b/tests/common/satisfy/t4k/libfex-2.0.0.tar.gz
new file mode 100644
index 0000000..9cefe9f
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfex-2.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfix-1.0.0.tar.gz b/tests/common/satisfy/t4k/libfix-1.0.0.tar.gz
new file mode 100644
index 0000000..fe1a6e9
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfix-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfix-2.0.0.tar.gz b/tests/common/satisfy/t4k/libfix-2.0.0.tar.gz
new file mode 100644
index 0000000..7b09f8b
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfix-2.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfoo-1.0.0.tar.gz b/tests/common/satisfy/t4k/libfoo-1.0.0.tar.gz
new file mode 100644
index 0000000..38bb25b
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfoo-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfoo-2.0.0.tar.gz b/tests/common/satisfy/t4k/libfoo-2.0.0.tar.gz
new file mode 100644
index 0000000..b868a61
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfoo-2.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfox-1.0.0.tar.gz b/tests/common/satisfy/t4k/libfox-1.0.0.tar.gz
new file mode 100644
index 0000000..0a1e328
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfox-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfox-1.2.0.tar.gz b/tests/common/satisfy/t4k/libfox-1.2.0.tar.gz
new file mode 100644
index 0000000..34efae0
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfox-1.2.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfox-2.0.0.tar.gz b/tests/common/satisfy/t4k/libfox-2.0.0.tar.gz
new file mode 100644
index 0000000..ce73b71
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfox-2.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfux-1.0.0.tar.gz b/tests/common/satisfy/t4k/libfux-1.0.0.tar.gz
new file mode 100644
index 0000000..983cda7
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfux-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfux-2.0.0.tar.gz b/tests/common/satisfy/t4k/libfux-2.0.0.tar.gz
new file mode 100644
index 0000000..0f63133
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfux-2.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfuz-1.0.0.tar.gz b/tests/common/satisfy/t4k/libfuz-1.0.0.tar.gz
new file mode 100644
index 0000000..42b2c0e
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfuz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/libfuz-2.0.0.tar.gz b/tests/common/satisfy/t4k/libfuz-2.0.0.tar.gz
new file mode 100644
index 0000000..c31d82a
--- /dev/null
+++ b/tests/common/satisfy/t4k/libfuz-2.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t4k/repositories.manifest b/tests/common/satisfy/t4k/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/satisfy/t4k/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/satisfy/t5/libbox-1.2.0.tar.gz b/tests/common/satisfy/t5/libbox-1.2.0.tar.gz
new file mode 120000
index 0000000..3d49749
--- /dev/null
+++ b/tests/common/satisfy/t5/libbox-1.2.0.tar.gz
@@ -0,0 +1 @@
+../libbox-1.2.0.tar.gz \ No newline at end of file
diff --git a/tests/config.testscript b/tests/config.testscript
index 70eef42..442cf36 100644
--- a/tests/config.testscript
+++ b/tests/config.testscript
@@ -9,7 +9,8 @@
# shared between multiple bpkg processes. Also we need to make sure that
# configurations are not cloned while being used by bpkg.
#
-+$cfg_create -d cfg 2>- &cfg/***
+cfg_uuid = "00000000-0000-0000-0000-000000000001"
++$cfg_create -d cfg --uuid $cfg_uuid 2>- &cfg/***
# The most commonly used configuration cloning command that copies it from the
# parent scope working directory.
diff --git a/tests/pkg-build.testscript b/tests/pkg-build.testscript
index 198e319..9d19846 100644
--- a/tests/pkg-build.testscript
+++ b/tests/pkg-build.testscript
@@ -75,6 +75,7 @@
# |
# |-- t2
# | |-- libbar-1.0.0.tar.gz -> libfoo
+# | |-- libfoo-0.1.0.tar.gz
# | |-- libfoo-1.0.0.tar.gz
# | `-- repositories.manifest
# |
@@ -101,12 +102,67 @@
# | |-- libfox-1.0.0.tar.gz
# | `-- repositories.manifest
# |
-# |-- t4e
+# |-- t4e -> t4a (complement repository)
# | |-- libfoo-1.1.0+1.tar.gz
# | `-- repositories.manifest
# |
+# |-- t4f
+# | |-- libfoo-2.0.0.tar.gz -> libbar == 1.2.0
+# | |-- libbar-1.2.0.tar.gz
+# | |-- libbar-2.1.0.tar.gz -> libbox
+# | |-- libbox-1.0.0.tar.gz -> libbax
+# | |-- libbox-2.0.0.tar.gz -> libbax == 1.0.0
+# | |-- libbax-1.0.0.tar.gz
+# | |-- libbax-2.0.0.tar.gz
+# | |-- libbix-1.0.0.tar.gz -> libbax == 1.0.0
+# | |-- libbix-2.0.0.tar.gz -> libbax == 2.0.0
+# | |-- libbux-1.0.0.tar.gz -> libbix
+# | |-- libfix-1.0.0.tar.gz -> libfox
+# | |-- libfox-1.1.0.tar.gz -> libbar >= 1.0.0
+# | |-- libfox-2.0.0.tar.gz -> libbar >= 2.0.0
+# | `-- repositories.manifest
+# |
+# |-- t4i
+# | |-- libbaz-2.0.0.tar.gz -> libbar < 2.1.0
+# | |-- libbar-0.1.0.tar.gz
+# | `-- repositories.manifest
+# |
+# |-- t4j
+# | |-- libbar-0.1.0.tar.gz
+# | |-- libbar-1.2.0.tar.gz
+# | |-- libfoo-3.0.0.tar.gz -> libbar
+# | |-- libfox-0.0.1.tar.gz
+# | |-- libfox-2.1.0.tar.gz -> libbar, libbaz == 1.2.0
+# | |-- libfox-3.0.0.tar.gz -> libbar == 0.1.0, libbaz == 1.2.0
+# | |-- libbaz-1.2.0.tar.gz -> libbar == 1.2.0
+# | |-- libbaz-2.1.0.tar.gz
+# | `-- repositories.manifest
+# |
+# |-- t4k
+# | |-- libbar-1.0.0.tar.gz -> libfoo == 1.0.0
+# | |-- libbaz-1.0.0.tar.gz -> libfox
+# | |-- libfoo-1.0.0.tar.gz -> libfix == 1.0.0
+# | |-- libfoo-2.0.0.tar.gz -> libfix == 2.0.0
+# | |-- libfox-1.0.0.tar.gz -> libfux == 1.0.0
+# | |-- libfox-1.2.0.tar.gz -> libfux == 1.0.0, libfex >= 2.0.0
+# | |-- libfox-2.0.0.tar.gz -> libfux == 2.0.0
+# | |-- libfix-1.0.0.tar.gz -> libfax == 1.0.0
+# | |-- libfix-2.0.0.tar.gz -> libfax == 2.0.0
+# | |-- libfux-1.0.0.tar.gz -> libfaz == 1.0.0, libfex == 1.0.0
+# | |-- libfux-2.0.0.tar.gz -> libfaz == 2.0.0, libfex == 2.0.0
+# | |-- libfex-1.0.0.tar.gz -> libfaz == 1.0.0
+# | |-- libfex-2.0.0.tar.gz -> libfaz == 2.0.0
+# | |-- libfax-1.0.0.tar.gz -> libfuz == 1.0.0
+# | |-- libfax-2.0.0.tar.gz -> libfuz == 2.0.0
+# | |-- libfaz-1.0.0.tar.gz -> libfuz == 1.0.0
+# | |-- libfaz-2.0.0.tar.gz -> libfuz == 2.0.0
+# | |-- libfuz-1.0.0.tar.gz
+# | |-- libfuz-2.0.0.tar.gz
+# | `-- repositories.manifest
+# |
# |-- t5
# | |-- libbar-1.2.0.tar.gz
+# | |-- libbox-1.2.0.tar.gz
# | `-- repositories.manifest
# |
# |-- t6
@@ -145,17 +201,46 @@
# | |-- libbox-0.1.0.tar.gz
# | |-- libbox-0.1.1.tar.gz
# | |-- libbox-1.0.0.tar.gz
-# | |-- foo-1.0.0.tar.gz -> {libbar libbaz} ^1.0.0
-# | |-- fox-1.0.0.tar.gz -> libbar ^1.0.0 | libbaz ^1.0.0
-# | |-- fix-1.0.0.tar.gz -> libbaz ^1.0.0 | libbar ^1.0.0
+# | |-- libfoo-1.0.0.tar.gz
+# | |-- libfoo-2.0.0.tar.gz
+# | |-- bar-1.0.0.tar.gz -> libbar
+# | |-- baz-1.0.0.tar.gz -> libbaz
+# | |-- bax-0.1.0.tar.gz -> libbox config.bax.backend=libbox
+# | |-- bax-1.0.0.tar.gz -> libbox >= 0.1.1 config.bax.backend=libbox
+# | |-- bix-0.1.0.tar.gz
+# | |-- bix-1.0.0.tar.gz -> bax == 0.1.0
+# | |-- box-1.0.0.tar.gz -> libbiz ^1.0.0 config.box.backend=libbiz |
+# | | libbox >= 0.1.1 config.box.backend=libbox,
+# | | libbaz
+# | |-- bux-1.0.0.tar.gz -> bix
+# | |-- dax-1.0.0.tar.gz -> libbar ? ($config.dax.extras)
+# | | libbaz
+# | |-- dix-0.1.0.tar.gz
+# | |-- dix-1.0.0.tar.gz -> dax require {config.dax.extras=true}
+# | |-- dox-1.0.0.tar.gz -> dax
+# | |-- dux-1.0.0.tar.gz -> dix
# | |-- fax-1.0.0.tar.gz -> libbar ^1.0.0 ? ($cxx.target.class == 'windows') config.fax.backend=libbar |
# | | libbaz ^1.0.0 ? ($cxx.target.class != 'windows') config.fax.backend=libbaz,
# | | libbiz ? ($config.fax.libbiz) config.fax.extras='[b\i$z]',
# | | libbox ? ($config.fax.libbox && $config.fax.backend == libbaz && $config.fax.extras == '[b\i$z]')
-# | |-- fux -> libbiz ? (!$config.fux.libbiz_old) | libbiz ^0.1.0 ? ($config.fux.libbiz_old)
-# | |-- box -> libbiz ^1.0.0 config.box.backend=libbiz |
-# | | libbox >= 0.1.1 config.box.backend=libbox,
-# | | libbaz
+# | |-- fix-1.0.0.tar.gz -> libbaz ^1.0.0 | libbar ^1.0.0
+# | |-- foo-1.0.0.tar.gz -> {libbar libbaz} ^1.0.0
+# | |-- fox-1.0.0.tar.gz -> libbar ^1.0.0 | libbaz ^1.0.0
+# | |-- fux-1.0.0.tar.gz -> libbiz ? (!$config.fux.libbiz_old) | libbiz ^0.1.0 ? ($config.fux.libbiz_old)
+# | |-- fuz-1.0.0.tar.gz -> libfoo
+# | |-- foz-1.0.0.tar.gz -> fuz
+# | |-- tax-1.0.0.tar.gz -> libfoo == 1.0.0 | libfoo == 2.0.0
+# | |-- tex-1.0.0.tar.gz -> libfoo prefer{} accept(true) reflect {...}
+# | |-- tix-1.0.0.tar.gz -> libfoo >= 2.0.0 reflect {...} | libfoo >= 1.0.0 reflect {...}
+# | |-- tox-1.0.0.tar.gz -> libfoo >= 2.0.0 prefer{} accept(true) reflect {...} | libfoo >= 1.0.0 reflect {...}
+# | |-- tpx-1.0.0.tar.gz -> libfoo >= 2.0.0 prefer{...} accept(true) reflect {...} | libfoo >= 1.0.0 prefer{...} accept(true) reflect {...}
+# | |-- tux-1.0.0.tar.gz -> libfoo prefer{config.libfoo.protocol = "1"} accept(true),
+# | | libbox ? (config.libfoo.protocol == "1")
+# | |-- twx-1.0.0.tar.gz -> libbiz,
+# | | libfoo prefer{config.libfoo.protocol = "1"} accept(true),
+# | | libbox ? (config.libfoo.protocol == "1")
+# | |-- tvx-1.0.0.tar.gz -> libfoo >= 2.0.0 reflect {...} | libfoo >= 1.0.0 reflect {...},
+# | | libfox prefer{config.libfox.level = $config.tvx.reflect} accept(true)
# | `-- repositories.manifest
# |
# |-- t9
@@ -166,11 +251,18 @@
# | `-- repositories.manifest
# |
# |-- t10
-# | |-- libfoo-bar-1.0.0.tar.gz -> libfoo-tests
-# | |-- libfoo-baz-1.0.0.tar.gz -> libfoo-tests
+# | |-- libfoo-bar-1.0.0.tar.gz (tests) -> libfoo-tests
+# | |-- libfoo-baz-1.0.0.tar.gz (tests) -> libfoo-tests
# | |-- libfoo-tests-1.0.0.tar.gz
+# | |-- libbar-foo-1.0.0.tar.gz (tests) -> libbar-tests
+# | |-- libbar-baz-1.0.0.tar.gz (tests) -> libbar-tests
+# | |-- libbar-tests-1.0.0.tar.gz -> ? libbar-foo, ? libbar-baz
# | `-- repositories.manifest
# |
+# | NOTE: remember to update
+# | pkg-build/dependency/config-negotiation-order/repo-packages/*
+# | tests if adding any packages to the below repository.
+# |
# |-- t11a
# | |-- libfoo-0.1.0.tar.gz
# | |-- libfoo-1.0.0.tar.gz
@@ -180,17 +272,24 @@
# | |-- libbaz-1.0.0.tar.gz
# | |-- libbox-0.1.0.tar.gz
# | |-- libbox-1.0.0.tar.gz
+# | |-- libbiz-0.1.0.tar.gz
+# | |-- libbiz-1.0.0.tar.gz -> libbar
# | |-- foo-0.1.0.tar.gz -> libfoo {require {config.libfoo.extras=true}}
# | |-- foo-0.2.0.tar.gz -> libfoo {require {config.libfoo.extras=true}} | libbar
-# | |-- foo-1.0.0.tar.gz -> libfoo {require {config.libfoo.extras=true}}
+# | |-- foo-1.0.0.tar.gz -> libfoo {require {config.libfoo.extras=true} reflect {...}}
# | |-- fox-0.1.0.tar.gz -> libfoo {prefer {config.libfoo.extras=true} accept (false)} |
# | | libbar
# | |-- fox-0.2.0.tar.gz -> libfoo {prefer {config.libfoo.extras=false} accept (!$config.libfoo.extras)} |
# | | libfoo {prefer {config.libfoo.extras=true} accept (true)} |
# | | libbar {require {config.libbar.extras=true}}
# | |-- fox-1.0.0.tar.gz -> libfoo {require {config.libfoo.extras=true}}
+# | |-- fux-0.1.0.tar.gz -> libfoo ? ($config.fux.extras=true)
+# | |-- fux-0.1.1.tar.gz -> libfoo ? ($config.fux.extras=true)
+# | |-- fux-0.2.0.tar.gz -> libfoo {enable($config.fux.extras=true) require {config.libfoo.extras=true}}
# | |-- fux-1.0.0.tar.gz -> libfoo
+# | |-- fix-0.1.0.tar.gz -> foo == 0.1.0
# | |-- fix-1.0.0.tar.gz -> foo {require {config.foo.extras=true}}
+# | |-- fex-0.1.0.tar.gz -> fux {require {config.fux.extras=true}}
# | |-- fex-1.0.0.tar.gz -> foo, libfoo {require {config.libfoo.extras=true}}
# | |-- bar-0.1.0.tar.gz -> libbar == 0.1.0 {require {config.libbar.extras=true}}
# | |-- bar-1.0.0.tar.gz -> libbar {require {config.libbar.extras=true}}
@@ -202,18 +301,22 @@
# | |-- bat-1.0.0.tar.gz -> libbaz {require {config.libbaz.extras=true}}
# | |-- bas-1.0.0.tar.gz -> libbar {require {config.libbar.extras=true}},
# | | bus {require {config.bus.extras=true}}
-# | |-- bus-1.0.0.tar.gz -> libaz {require {config.libbox.extras=true}},
+# | |-- bus-0.1.0.tar.gz -> foo {require {config.foo.extras=true} reflect {...}}
+# | |-- bus-1.0.0.tar.gz -> libaz {require {config.libbaz.extras=true}},
# | | foo {require {config.foo.extras=true}}
-# | |-- box-0.1.0.tar.gz -> libbox {require {config.libbox.extras=true}}
+# | |-- box-0.1.0.tar.gz -> libbox == 0.1.0 {require {config.libbox.extras=true}}
+# | |-- box-0.2.0.tar.gz -> libbox {require {config.libbox.extras=true}}
# | |-- box-1.0.0.tar.gz -> {libbar libfoo} {require {config.libbar.extras=true config.libfoo.extras=true}} |
# | | libbox
-# | |-- bax-1.0.0.tar.gz -> libfoo {require {config.libfoo.extras=true}},
+# | |-- bax-0.1.0.tar.gz -> {libbox libbar} {require {config.libbox.extras=true}}
+# | |-- bax-1.0.0.tar.gz -> libfoo {require {config.libfoo.extras=true} reflect {...}},
# | | {libbox libbar} {require {config.libbox.extras=true config.libbar.extras=true}}
# | |-- bux-1.0.0.tar.gz -> libbar {require {config.libbar.extras=true}}
# | |-- bix-1.0.0.tar.gz -> {libbar bar} {require {config.libbar.extras=true config.bar.extras=true}},
# | | bux
# | |-- bex-1.0.0.tar.gz -> libbar
# | |-- boo-1.0.0.tar.gz -> libbar | libfoo {require {config.libfoo.extras=true}} | libbox
+# | |-- biz-0.1.0.tar.gz -> libbiz == 0.1.0
# | |-- biz-1.0.0.tar.gz -> boo {require {config.boo.extras=true}}
# | |-- buz-1.0.0.tar.gz -> bux {require {config.bux.extras=true}}
# | |-- buc-1.0.0.tar.gz -> libfoo {require {config.libfoo.extras=true}},
@@ -226,11 +329,11 @@
# | |-- tex-0.3.0.tar.gz -> libbar {require {config.libbar.extras=true}},
# | | libfoo {require {config.libfoo.extras=true}}
# | |-- tex-1.0.0.tar.gz -> libbar {require {config.libbar.extras=true}},
-# | | libfoo {require {config.libfoo.extras=true}}
+# | | libfoo {require {config.libfoo.extras=true} reflect {...}}
# | |-- tix-0.1.0.tar.gz
# | |-- tix-1.0.0.tar.gz -> libbar {require {config.libbar.extras=true}},
# | | tex {require {config.tex.extras=true}}
-# | |-- tiz-1.0.0.tar.gz -> tex {require {config.tex.extras=true}},
+# | |-- tiz-1.0.0.tar.gz -> tex {require {config.tex.extras=true}, reflect {...}},
# | | libbar {require {config.libbar.extras=true}}
# | |-- toz-0.1.0.tar.gz
# | |-- toz-0.2.0.tar.gz -> libfoo {require {config.libfoo.extras=true}},
@@ -238,11 +341,18 @@
# | |-- toz-1.0.0.tar.gz -> libbaz {require {config.libbaz.extras=true}},
# | | libfoo {require {config.libfoo.extras=true}},
# | | libbar {require {config.libbar.extras=true}}
+# | |-- tez-0.1.0.tar.gz -> libbox {require {config.libbox.extras=true}},
+# | | toz == 0.1.0 {require {config.toz.extras=true}}
# | |-- tez-1.0.0.tar.gz -> libbox {require {config.libbox.extras=true}},
# | | toz == 0.1.0 {require {config.toz.extras=true}},
# | | libbar {require {config.libbar.extras=true}}
+# | |-- tuz-1.0.0.tar.gz -> toz {require {config.toz.extras=true}}
# | |-- tux-1.0.0.tar.gz -> libbox {require {config.libbox.extras=true}},
# | | tix == 0.1.0
+# | |-- tvz-0.1.0.tar.gz -> toz == 0.2.0 {require {config.toz.extras=true}},
+# | | bax,
+# | | libfoo {require {config.libfoo.network=true}}
+# | |-- tvz-1.0.0.tar.gz -> toz == 0.2.0 {require {config.toz.extras=true}}
# | |-- dex-1.0.0.tar.gz -> bar {require {config.bar.extras=true}},
# | | libfoo {require {config.libfoo.extras=true}}
# | |-- dix-1.0.0.tar.gz -> libbar {require {config.libbar.extras=true}},
@@ -259,7 +369,7 @@
# | |-- libbar-0.1.0.tar.gz -> libbaz
# | `-- repositories.manifest
# |
-# |-- t12b -> t12b (prerequisite repository)
+# |-- t12b -> t12a (prerequisite repository)
# | |-- libbaz-0.1.0.tar.gz
# | |-- libbar-1.0.0.tar.gz -> libbaz == 0.1.0
# | |-- foo-0.1.0.tar.gz
@@ -274,6 +384,7 @@
# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
# | |-- baz-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
# | |-- biz-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
+# | |-- box-1.0.0.tar.gz -> liba {prefer {} accept (true) reflect {...}}
# | `-- repositories.manifest
# |
# |-- t13b
@@ -285,14 +396,14 @@
# |
# |-- t13c
# | |-- liba-0.1.0.tar.gz
-# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect (...)}
+# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect {...}}
# | |-- baz-1.0.0.tar.gz -> liba {require {...}}
# | `-- repositories.manifest
# |
# |-- t13d
# | |-- liba-0.1.0.tar.gz
# | |-- libb-0.1.0.tar.gz
-# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect (...)},
+# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect {...}},
# | | libb ? (...)
# | |-- baz-1.0.0.tar.gz -> bar, liba {require {...}}
# | `-- repositories.manifest
@@ -315,14 +426,14 @@
# |-- t13g
# | |-- liba-0.1.0.tar.gz
# | |-- libb-0.1.0.tar.gz
-# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect (...)},
-# | | libb {prefer {...} accept (...) reflect (...)}
-# | |-- baz-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect (...)},
+# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect {...}},
+# | | libb {prefer {...} accept (...) reflect {...}}
+# | |-- baz-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect {...}},
# | | libb ? (...)
-# | |-- biz-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect (...)},
-# | | libb {prefer {...} accept (...) reflect (...)}
-# | |-- box-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect (...)},
-# | | libb {prefer {...} accept (...) reflect (...)}
+# | |-- biz-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect {...}},
+# | | libb {prefer {...} accept (...) reflect {...}}
+# | |-- box-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect {...}},
+# | | libb {prefer {...} accept (...) reflect {...}}
# | `-- repositories.manifest
# |
# |-- t13h
@@ -333,7 +444,7 @@
# |
# |-- t13i
# | |-- liba-0.1.0.tar.gz
-# | |-- bar-1.0.0.tar.gz -> liba {require {...} reflect (...)}
+# | |-- bar-1.0.0.tar.gz -> liba {require {...} reflect {...}}
# | `-- repositories.manifest
# |
# |-- t13j
@@ -383,6 +494,34 @@
# | |-- bix-1.0.0.tar.gz -> bar {prefer {...} accept (...)}
# | `-- repositories.manifest
# |
+# |-- t14a
+# | |-- libfoo-1.0.0.tar.gz
+# | `-- repositories.manifest
+# |
+# |-- t14b
+# | |-- libfoo-1.1.0.tar.gz
+# | `-- repositories.manifest
+# |
+# |-- t14c
+# | |-- libfoo-1.1.0+1.tar.gz
+# | `-- repositories.manifest
+# |
+# |-- t14d
+# | |-- libfoo-1.1.0+2.tar.gz
+# | `-- repositories.manifest
+# |
+# |-- t14e
+# | |-- libfoo-1.1.0+3.tar.gz
+# | `-- repositories.manifest
+# |
+# |-- t14f
+# | |-- libfoo-1.1.1.tar.gz
+# | `-- repositories.manifest
+# |
+# |-- t14i
+# | |-- libfoo-1.2.0.tar.gz
+# | `-- repositories.manifest
+# |
# `-- git
# |-- libbar.git -> style-basic.git (prerequisite repository)
# |-- libbaz.git
@@ -407,6 +546,10 @@ posix = ($cxx.target.class != 'windows')
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/t4e $out/t4e && $rep_create $out/t4e &$out/t4e/packages.manifest
+ cp -r $src/t4f $out/t4f && $rep_create $out/t4f &$out/t4f/packages.manifest
+ cp -r $src/t4i $out/t4i && $rep_create $out/t4i &$out/t4i/packages.manifest
+ cp -r $src/t4j $out/t4j && $rep_create $out/t4j &$out/t4j/packages.manifest
+ cp -r $src/t4k $out/t4k && $rep_create $out/t4k &$out/t4k/packages.manifest
cp -r $src/t5 $out/t5 && $rep_create $out/t5 &$out/t5/packages.manifest
cp -r $src/t6 $out/t6 && $rep_create $out/t6 &$out/t6/packages.manifest
cp -r $src/t7a $out/t7a && $rep_create $out/t7a &$out/t7a/packages.manifest
@@ -432,6 +575,14 @@ posix = ($cxx.target.class != 'windows')
cp -r $src/t13m $out/t13m && $rep_create $out/t13m &$out/t13m/packages.manifest
cp -r $src/t13n $out/t13n && $rep_create $out/t13n &$out/t13n/packages.manifest
cp -r $src/t13o $out/t13o && $rep_create $out/t13o &$out/t13o/packages.manifest
+ cp -r $src/t14a $out/t14a && $rep_create $out/t14a &$out/t14a/packages.manifest
+ cp -r $src/t14b $out/t14b && $rep_create $out/t14b &$out/t14b/packages.manifest
+ cp -r $src/t14c $out/t14c && $rep_create $out/t14c &$out/t14c/packages.manifest
+ cp -r $src/t14d $out/t14d && $rep_create $out/t14d &$out/t14d/packages.manifest
+ cp -r $src/t14e $out/t14e && $rep_create $out/t14e &$out/t14e/packages.manifest
+ cp -r $src/t14f $out/t14f && $rep_create $out/t14f &$out/t14f/packages.manifest
+ cp -r $src/t14i $out/t14i && $rep_create $out/t14i &$out/t14i/packages.manifest
+ cp -r $src/t15 $out/t15 && $rep_create $out/t15 &$out/t15/packages.manifest --ignore-unknown
# Create git repositories.
#
@@ -442,9 +593,11 @@ end
config_cxx = [cmdline] config.cxx=$quote($recall($cxx.path) $cxx.config.mode, true)
+tar = [cmdline] ($posix ? tar : bsdtar)
+
cfg_create += 2>!
cfg_link += 2>!
-pkg_configure += -d cfg $config_cxx 2>!
+pkg_configure += -d cfg 2>!
pkg_disfigure += -d cfg
pkg_drop += -d cfg --yes 2>!
pkg_fetch += -d cfg 2>!
@@ -461,6 +614,10 @@ rep_list += -d cfg
#
test.options += --no-progress
+# Disable the use of the system package manager.
+#
+test.arguments += --sys-no-query
+
: libfoo
:
: Test building different versions of libfoo.
@@ -542,6 +699,41 @@ test.options += --no-progress
info: use 'bpkg rep-add' to add a repository
EOE
+ : mask-repository-not-found
+ :
+ $clone_root_cfg;
+ $* --mask-repository 'https://example.com/1' libfoo 2>>EOE != 0
+ error: repository 'https://example.com/1' cannot be masked: not found
+ EOE
+
+ : mask-repository-empty
+ :
+ $clone_root_cfg;
+ $* --mask-repository '' libfoo 2>>EOE != 0
+ error: repository '' cannot be masked: invalid repository location: empty URL
+ EOE
+
+ : mask-repository-uuid-db-not-found
+ :
+ $clone_root_cfg;
+ $* --mask-repository-uuid '00000000-0000-0000-0000-123456789012=repo' libfoo 2>>/EOE != 0
+ error: configuration repository '00000000-0000-0000-0000-123456789012=repo' cannot be masked: no configuration with uuid 00000000-0000-0000-0000-123456789012 is linked with cfg/
+ EOE
+
+ : mask-repository-uuid-empty
+ :
+ $clone_root_cfg;
+ $* --mask-repository-uuid "$cfg_uuid=" libfoo 2>>EOE != 0
+ error: configuration repository '00000000-0000-0000-0000-000000000001=' cannot be masked: invalid repository location '': empty URL
+ EOE
+
+ : mask-repository-uuid-not-found
+ :
+ $clone_root_cfg;
+ $* --mask-repository-uuid "$cfg_uuid=https://example.com/1" libfoo 2>>EOE != 0
+ error: configuration repository '00000000-0000-0000-0000-000000000001=https://example.com/1' cannot be masked: repository location 'https://example.com/1' not found in configuration 00000000-0000-0000-0000-000000000001
+ EOE
+
: archive
:
$clone_root_cfg;
@@ -1063,38 +1255,146 @@ test.options += --no-progress
new libbaz/1.1.0
EOO
- : unable-satisfy
+ : libbaz-unable-satisfy
:
- $clone_cfg;
- $* libfoo/1.0.0 libbaz 2>>EOE != 0
- error: unable to satisfy constraints on package libfoo
- info: command line depends on (libfoo == 1.0.0)
- info: libbar depends on (libfoo == 1.1.0)
- info: available libfoo/1.0.0
- info: available libfoo/1.1.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
+ {
+ +$clone_cfg
- : unable-satisfy-config
- :
- : As above but with a linked configuration.
+ : basic
+ :
+ {
+ $clone_cfg;
+
+ $* libfoo/1.0.0 libbaz 2>>EOE != 0
+ error: unable to satisfy constraints on package libfoo
+ info: command line depends on (libfoo == 1.0.0)
+ info: libbar/1.1.0 depends on (libfoo == 1.1.0)
+ info: available libfoo/1.0.0
+ info: available libfoo/1.1.0
+ info: while satisfying libbar/1.1.0
+ info: while satisfying libbaz/1.1.0
+ info: explicitly specify libfoo version to manually satisfy both constraints
+ EOE
+ }
+
+ : unable-satisfy-reorder
+ :
+ : As above but the packages are specified in a different order on the
+ : command line.
+ :
+ {
+ $clone_cfg;
+
+ $* libbaz libfoo/1.0.0 2>>EOE != 0
+ error: unable to satisfy constraints on package libfoo
+ info: command line depends on (libfoo == 1.0.0)
+ info: libbar/1.1.0 depends on (libfoo == 1.1.0)
+ info: available libfoo/1.0.0
+ info: available libfoo/1.1.0
+ info: while satisfying libbar/1.1.0
+ info: while satisfying libbaz/1.1.0
+ info: explicitly specify libfoo version to manually satisfy both constraints
+ EOE
+ }
+
+ : unable-satisfy-dependency
+ :
+ : As above but specify libfoo as a dependency.
+ :
+ {
+ $clone_cfg;
+
+ $* libbaz ?libfoo/1.0.0 2>>EOE != 0
+ error: unable to satisfy constraints on package libfoo
+ info: libbaz/1.1.0 depends on (libfoo == 1.0.0)
+ info: libbar/1.1.0 depends on (libfoo == 1.1.0)
+ info: available libfoo/1.0.0
+ info: available libfoo/1.1.0
+ info: while satisfying libbar/1.1.0
+ info: while satisfying libbaz/1.1.0
+ info: explicitly specify libfoo version to manually satisfy both constraints
+ EOE
+ }
+
+ : unable-satisfy-config
+ :
+ : As above but with a linked configuration.
+ :
+ {
+ $clone_cfg;
+ $cfg_create -d cfg2 &cfg2/***;
+ $cfg_link -d cfg cfg2;
+ $rep_add -d cfg2 $rep/t4c && $rep_fetch -d cfg2;
+ $* libbaz ?libbar +{ --config-id 1 } libfoo/1.0.0 +{ --config-id 1 } 2>>~%EOE% != 0
+ error: unable to satisfy constraints on package libfoo
+ info: command line depends on (libfoo == 1.0.0)
+ % info: libbar/1.1.0 \[cfg2.\] depends on \(libfoo == 1.1.0\)%
+ info: available libfoo/1.0.0
+ info: available libfoo/1.1.0
+ % info: while satisfying libbar/1.1.0 \[cfg2.\]%
+ info: while satisfying libbaz/1.1.0
+ info: explicitly specify libfoo version to manually satisfy both constraints
+ EOE
+ }
+ }
+
+ : libbar-unable-satisfy
:
- $clone_cfg;
- $cfg_create -d cfg2 &cfg2/***;
- $cfg_link -d cfg cfg2;
- $rep_add -d cfg2 $rep/t4c && $rep_fetch -d cfg2;
- $* libbaz ?libbar +{ --config-id 1 } libfoo/1.0.0 +{ --config-id 1 } 2>>~%EOE% != 0
- error: unable to satisfy constraints on package libfoo
- info: command line depends on (libfoo == 1.0.0)
- % info: libbar \[cfg2.\] depends on \(libfoo == 1.1.0\)%
- info: available libfoo/1.0.0
- info: available libfoo/1.1.0
- info: explicitly specify libfoo version to manually satisfy both constraints
- %info: while satisfying libbar/1.1.0 \[cfg2.\]%
- info: while satisfying libbaz/1.1.0
- EOE
+ {
+ +$clone_cfg
+ +$rep_add $rep/t4b && $rep_fetch
+
+ : basic
+ :
+ {
+ $clone_cfg;
+
+ $* libfoo/1.0.0 libbar 2>>EOE != 0
+ error: unable to satisfy constraints on package libfoo
+ info: command line depends on (libfoo == 1.0.0)
+ info: libbar/1.1.0 depends on (libfoo == 1.1.0)
+ info: available libfoo/1.0.0
+ info: available libfoo/1.1.0
+ info: while satisfying libbar/1.1.0
+ info: explicitly specify libfoo version to manually satisfy both constraints
+ EOE
+ }
+
+ : unable-satisfy-reorder
+ :
+ : As above but the packages are specified in a different order on the
+ : command line.
+ :
+ {
+ $clone_cfg;
+
+ $* libbar libfoo/1.0.0 2>>EOE != 0
+ error: unable to satisfy constraints on package libfoo
+ info: command line depends on (libfoo == 1.0.0)
+ info: libbar/1.1.0 depends on (libfoo == 1.1.0)
+ info: available libfoo/1.0.0
+ info: available libfoo/1.1.0
+ info: while satisfying libbar/1.1.0
+ info: explicitly specify libfoo version to manually satisfy both constraints
+ EOE
+ }
+
+ : unable-satisfy-dependency
+ :
+ : Similar to the above, but specify libfoo as a dependency.
+ :
+ {
+ $clone_cfg;
+
+ # Add libbaz, so that libfoo package is available from its dependents
+ # (libbaz) repositories.
+ #
+ $* libbar ?libfoo/1.0.0 libbaz 2>>EOE != 0
+ error: package libfoo doesn't satisfy its dependents
+ info: libfoo/1.0.0 doesn't satisfy libbar/1.1.0
+ EOE
+ }
+ }
: not-available
:
@@ -1151,8 +1451,9 @@ test.options += --no-progress
:
{
$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;
+
+ $rep_add $rep/t4a $rep/t4b && $rep_fetch;
+ $pkg_build libfoo/1.1.0 libbar/1.1.0 -d cfg 2>!;
$* libfoo-1.2.0.tar.gz 2>>EOE != 0;
error: unknown package libfoo-1.2.0.tar.gz
@@ -1160,8 +1461,10 @@ test.options += --no-progress
$* 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: because configured package libbar/1.1.0 depends on (libfoo == 1.1.0)
+ info: re-run with -v for additional dependency information
+ info: consider re-trying with --upgrade|-u potentially combined with --recursive|-r
+ info: or explicitly request up/downgrade of package libbar
info: or explicitly specify package libfoo version to manually satisfy these constraints
EOE
@@ -1181,10 +1484,11 @@ test.options += --no-progress
{
$clone_cfg;
$cfg_create -d cfg2 &cfg2/***;
- $rep_add -d cfg2 $rep/t4c && $rep_fetch -d cfg2;
+ $rep_add -d cfg2 $rep/t4a $rep/t4b $rep/t4c && $rep_fetch -d cfg2;
$cfg_link -d cfg2 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;
+
+ $rep_add $rep/t4a $rep/t4b && $rep_fetch;
+ $pkg_build libfoo/1.1.0 libbar/1.1.0 -d cfg 2>!;
$* libfoo-1.2.0.tar.gz 2>>EOE != 0;
error: unknown package libfoo-1.2.0.tar.gz
@@ -1194,8 +1498,10 @@ test.options += --no-progress
$* libfoo/1.0.0 +{ --config-id 1 } 2>>~%EOE% != 0;
%error: unable to downgrade package libfoo/1.1.0 \[cfg.\] to 1.0.0%
- % info: because package libbar \[cfg.\] depends on \(libfoo == 1.1.0\)%
- info: explicitly request up/downgrade of package libbar
+ % info: because configured package libbar/1.1.0 \[cfg.\] depends on \(libfoo == 1.1.0\)%
+ info: re-run with -v for additional dependency information
+ info: consider re-trying with --upgrade|-u potentially combined with --recursive|-r
+ info: or explicitly request up/downgrade of package libbar
info: or explicitly specify package libfoo version to manually satisfy these constraints
EOE
@@ -1209,6 +1515,49 @@ test.options += --no-progress
$pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0';
$pkg_purge libfoo 2>'purged libfoo/1.1.0'
}
+
+ : able-downgrade
+ :
+ : Similar to the above unable-downgrade, but this time libfoo and libbar
+ : are configured manually and so are not held. Thus, libfoo downgrades
+ : successfully since libbar is just dropped having no dependents.
+ :
+ {
+ $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.0.0 >>EOO;
+ downgrade libfoo/1.0.0
+ drop libbar/1.1.0 (unused)
+ EOO
+
+ $pkg_drop libbar libfoo
+ }
+
+ : able-downgrade-config
+ :
+ : As above but with a linked configuration.
+ :
+ {
+ $clone_cfg;
+ $cfg_create -d cfg2 &cfg2/***;
+ $rep_add -d cfg2 $rep/t4c && $rep_fetch -d cfg2;
+ $cfg_link -d cfg2 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;
+
+ test.arguments = $regex.apply($test.arguments, cfg, cfg2);
+
+ $* libfoo/1.0.0 +{ --config-id 1 } >>~%EOO%;
+ %downgrade libfoo/1.0.0 \[cfg.\]%
+ %drop libbar/1.1.0 \[cfg.\] \(unused\)%
+ EOO
+
+ $pkg_drop libbar libfoo
+ }
}
: dependent-reconfiguration
@@ -1490,7 +1839,6 @@ test.options += --no-progress
$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
@@ -1609,7 +1957,7 @@ test.options += --no-progress
updated libbar/1.2.0
EOE
- $pkg_status libfoo >'libfoo available 1.0.0';
+ $pkg_status libfoo >'libfoo available 1.0.0 0.1.0';
$pkg_status libbar >'!libbar configured 1.2.0';
$* libbar/1.0.0 libfoo 2>>~%EOE%;
@@ -1726,6 +2074,17 @@ test.options += --no-progress
$pkg_status libbar >'!libbar configured 1.2.0';
+ # While at it, test using --mask-repository* instead of rep-remove.
+ #
+ $* --upgrade --mask-repository $rep/t2 --mask-repository $rep/t5 2>>/EOE != 0;
+ error: libbar is not available
+ EOE
+
+ $* --upgrade --mask-repository-uuid "$cfg_uuid=($rep/t2)" \
+ --mask-repository-uuid "$cfg_uuid=($rep/t5)" 2>>/EOE != 0;
+ error: libbar is not available
+ EOE
+
$rep_remove $rep/t2 $rep/t5;
$* --upgrade 2>>/EOE != 0;
@@ -1742,10 +2101,7 @@ test.options += --no-progress
: Test build scenarios described in
: https://github.com/conan-io/conan/issues/9547.
:
- : Note: using tar on Windows is a bit hairy (needs --force-local, etc), so
- : we do not run this test on Windows.
- :
- if ($posix && !$remote)
+ if (!$remote)
{
+mkdir 1/
@@ -1755,10 +2111,10 @@ test.options += --no-progress
#
r = 1/t9-1
+cp -r $rep/t9 $r && \
- tar xzf $r/libbar-1.0.0.tar.gz -C $r && \
+ $tar xzf $r/libbar-1.0.0.tar.gz -C $r && \
mv $r/libbar-1.0.0 $r/libbar-2.0.0 && \
sed -i -e 's/(version:).+/\1 2.0.0/' $r/libbar-2.0.0/manifest && \
- tar cfz $r/libbar-2.0.0.tar.gz -C $r libbar-2.0.0 &$r/libbar-2.0.0.tar.gz && \
+ $tar cfz $r/libbar-2.0.0.tar.gz -C $r libbar-2.0.0 &$r/libbar-2.0.0.tar.gz && \
rm -r $r/libbar-2.0.0 && \
$rep_create $r &$r/packages.manifest
@@ -1767,10 +2123,10 @@ test.options += --no-progress
#
r = 1/t9-2
+cp -r 1/t9-1 $r && \
- tar xzf $r/libbaz-1.0.0.tar.gz -C $r && \
+ $tar xzf $r/libbaz-1.0.0.tar.gz -C $r && \
mv $r/libbaz-1.0.0 $r/libbaz-2.0.0 && \
sed -i -e 's/(version:).+/\1 2.0.0/' -e 's/(depends: libbar).+/\1 ^2.0.0/' $r/libbaz-2.0.0/manifest && \
- tar cfz $r/libbaz-2.0.0.tar.gz -C $r libbaz-2.0.0 &$r/libbaz-2.0.0.tar.gz && \
+ $tar cfz $r/libbaz-2.0.0.tar.gz -C $r libbaz-2.0.0 &$r/libbaz-2.0.0.tar.gz && \
rm -r $r/libbaz-2.0.0 && \
$rep_create $r &$r/packages.manifest
@@ -1779,10 +2135,10 @@ test.options += --no-progress
#
r = 1/t9-3
+cp -r 1/t9-2 $r && \
- tar xzf $r/libbox-1.0.0.tar.gz -C $r && \
+ $tar xzf $r/libbox-1.0.0.tar.gz -C $r && \
mv $r/libbox-1.0.0 $r/libbox-1.1.0 && \
sed -i -e 's/(version:).+/\1 1.1.0/' $r/libbox-1.1.0/manifest && \
- tar cfz $r/libbox-1.1.0.tar.gz -C $r libbox-1.1.0 &$r/libbox-1.1.0.tar.gz && \
+ $tar cfz $r/libbox-1.1.0.tar.gz -C $r libbox-1.1.0 &$r/libbox-1.1.0.tar.gz && \
rm -r $r/libbox-1.1.0 && \
$rep_create $r &$r/packages.manifest
@@ -1876,22 +2232,65 @@ test.options += --no-progress
# Picks up the latest libbaz (2.0.0) as a prerequisite for foo, which
# leads to the conflict between libbaz/2.0.0 and libbox/1.0.0 about
# prerequisite libbar because of the incompatible version constraints.
+ # This get automatically resolved by the unsatisfied constraints
+ # resolution machinery.
#
- $* foo 2>>EOE != 0;
- error: unable to satisfy constraints on package libbar
- info: libbaz depends on (libbar ^2.0.0)
- info: libbox depends on (libbar ^1.0.0)
- info: available libbar/2.0.0
- info: available libbar/1.0.0
- info: explicitly specify libbar version to manually satisfy both constraints
- info: while satisfying libbox/1.0.0
- info: while satisfying foo/1.0.0
+ $* foo --plan '' --verbose 5 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/2.0.0 of dependent foo/1.0.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: add libbar/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.0.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libbar/2.0.0
+ trace: collect_build_prerequisites: end libbar/2.0.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbox/1.0.0 of dependent foo/1.0.0
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build: postpone failure for dependent libbox unsatisfied with dependency libbar/2.0.0 (^1.0.0)
+ trace: collect_build: pick libbar/2.0.0 over libbar/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.0.0 of dependent libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent libbox/1.0.0 of dependency libbar/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace conflicting dependent libbaz/2.0.0 of dependency libbar/2.0.0 with some other version
+ trace: try_replace_dependency: replace conflicting dependent version libbaz/2.0.0 with 1.0.0 by adding package spec '?libbaz == 1.0.0' to command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/1.0.0 of dependent foo/1.0.0
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent libbaz/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbox/1.0.0 of dependent foo/1.0.0
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ new libbar/1.0.0 (required by libbaz, libbox)
+ new libbaz/1.0.0 (required by foo)
+ new libbox/1.0.0 (required by foo)
+ new foo/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
EOE
- $* foo ?libbaz/1.0.0 2>!;
$pkg_status -r >>EOO;
!foo configured 1.0.0
- libbaz configured !1.0.0 available 2.0.0
+ libbaz configured 1.0.0 available 2.0.0
libbar configured 1.0.0 available 2.0.0
libbox configured 1.0.0
libbar configured 1.0.0 available 2.0.0
@@ -1944,17 +2343,49 @@ test.options += --no-progress
libbar configured 1.0.0 available 2.0.0
EOO
- # Unable to satisfy the dependent libbox with an upgraded (due to
- # libbaz 2.0.0) prerequisite libbar/2.0.0.
+ # Initially unable to satisfy the dependent libbox with an upgraded
+ # (due to libbaz 2.0.0) prerequisite libbar/2.0.0. But this get
+ # automatically resolved by the unsatisfied constraints resolution
+ # machinery.
#
- $* ?libbaz 2>>EOE != 0;
- error: unable to upgrade package libbar/1.0.0 to 2.0.0
- info: because package libbox depends on (libbar ^1.0.0)
- info: package libbar/2.0.0 required by libbaz
- info: explicitly request up/downgrade of package libbox
- info: or explicitly specify package libbar version to manually satisfy these constraints
+ $* ?libbaz --plan '' --verbose 5 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: execute_plan: simulate: yes
+ trace: evaluate_dependency: libbaz/1.0.0: update to libbaz/2.0.0
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: end reached
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: add libbar/2.0.0
+ info: package libbaz dependency on (libbar ^2.0.0) is forcing upgrade of libbar/1.0.0 to 2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.0.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: skip being built existing dependent libbaz of dependency libbar
+ trace: collect_build_prerequisites: skip unsatisfied existing dependent libbox of dependency libbar/2.0.0 due to constraint (libbar ^1.0.0)
+ trace: collect_build_prerequisites: begin libbar/2.0.0
+ trace: collect_build_prerequisites: end libbar/2.0.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_dependents: postpone failure for existing dependent libbox unsatisfied with dependency libbar/2.0.0 (^1.0.0)
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfiable dependent libbaz/2.0.0 of dependency libbar/2.0.0 with some other version
+ trace: try_replace_dependency: replace unsatisfiable dependent version libbaz/2.0.0 with 1.0.0 by adding constraint '?libbaz' -> '?libbaz == 1.0.0' on command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: execute_plan: simulate: no
+ %.*
EOE
+ $pkg_status -r >>EOO;
+ !foo configured 1.0.0
+ libbaz configured 1.0.0 available 2.0.0
+ libbar configured 1.0.0 available 2.0.0
+ libbox configured 1.0.0
+ libbar configured 1.0.0 available 2.0.0
+ EOO
+
$pkg_drop foo
}
}
@@ -1968,24 +2399,109 @@ test.options += --no-progress
$clone_root_cfg;
$rep_add ../../1/t9-3 && $rep_fetch;
- # Similar to the repository state 2, picks up the latest libbaz (2.0.0)
- # as a prerequisite for foo, which leads to the conflict.
+ # Similar to the repository state 2, picks up the latest libbaz
+ # (2.0.0) as a prerequisite for foo, which leads to the conflict,
+ # which is resolved automatically.
#
- $* foo 2>>EOE != 0;
- error: unable to satisfy constraints on package libbar
- info: libbaz depends on (libbar ^2.0.0)
- info: libbox depends on (libbar ^1.0.0)
- info: available libbar/2.0.0
- info: available libbar/1.0.0
- info: explicitly specify libbar version to manually satisfy both constraints
- info: while satisfying libbox/1.1.0
- info: while satisfying foo/1.0.0
+ $* foo --plan '' --verbose 5 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/2.0.0 of dependent foo/1.0.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: add libbar/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.0.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libbar/2.0.0
+ trace: collect_build_prerequisites: end libbar/2.0.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_build: add libbox/1.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbox/1.1.0 of dependent foo/1.0.0
+ trace: collect_build_prerequisites: begin libbox/1.1.0
+ trace: collect_build: postpone failure for dependent libbox unsatisfied with dependency libbar/2.0.0 (^1.0.0)
+ trace: collect_build: pick libbar/2.0.0 over libbar/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.0.0 of dependent libbox/1.1.0
+ trace: collect_build_prerequisites: end libbox/1.1.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent libbox/1.1.0 of dependency libbar/2.0.0 with some other version
+ trace: try_replace_dependency: replace unsatisfied dependent version libbox/1.1.0 with 1.0.0 by adding package spec '?libbox == 1.0.0' to command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/2.0.0 of dependent foo/1.0.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: add libbar/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.0.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libbar/2.0.0
+ trace: collect_build_prerequisites: end libbar/2.0.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbox/1.0.0 of dependent foo/1.0.0
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build: postpone failure for dependent libbox unsatisfied with dependency libbar/2.0.0 (^1.0.0)
+ trace: collect_build: pick libbar/2.0.0 over libbar/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.0.0 of dependent libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent libbox/1.0.0 of dependency libbar/2.0.0 with some other version
+ trace: try_replace_dependency: replacement of unsatisfied dependent version libbox/1.0.0 is denied since it is specified on command line as '?libbox == 1.0.0'
+ trace: try_replace_dependent: try to replace conflicting dependent libbaz/2.0.0 of dependency libbar/2.0.0 with some other version
+ trace: try_replace_dependency: replace conflicting dependent version libbaz/2.0.0 with 1.0.0 by adding package spec '?libbaz == 1.0.0' to command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/1.0.0 of dependent foo/1.0.0
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent libbaz/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbox/1.0.0 of dependent foo/1.0.0
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: start command line adjustments refinement cycle by rolling back first adjustment ('?libbox == 1.0.0')
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/1.0.0 of dependent foo/1.0.0
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent libbaz/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build: add libbox/1.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbox/1.1.0 of dependent foo/1.0.0
+ trace: collect_build_prerequisites: begin libbox/1.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent libbox/1.1.0
+ trace: collect_build_prerequisites: end libbox/1.1.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: command line adjustment '?libbox == 1.0.0' is redundant, dropping it
+ new libbar/1.0.0 (required by libbaz, libbox)
+ new libbaz/1.0.0 (required by foo)
+ new libbox/1.1.0 (required by foo)
+ new foo/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
EOE
- $* foo ?libbaz/1.0.0 2>!;
$pkg_status -r >>EOO;
!foo configured 1.0.0
- libbaz configured !1.0.0 available 2.0.0
+ libbaz configured 1.0.0 available 2.0.0
libbar configured 1.0.0 available 2.0.0
libbox configured 1.1.0
libbar configured 1.0.0 available 2.0.0
@@ -2038,31 +2554,146 @@ test.options += --no-progress
libbar configured 1.0.0 available 2.0.0
EOO
- # Unable to satisfy the dependent libbox with an upgraded (due to
- # libbaz 2.0.0) prerequisite libbar/2.0.0.
+ test.arguments += --plan '' --verbose 5;
+
+ # Initially, unable to satisfy the dependent libbox with an upgraded
+ # (due to libbaz 2.0.0) prerequisite libbar/2.0.0. But this get
+ # automatically resolved by the unsatisfied constraints resolution
+ # machinery.
#
- $* foo ?libbaz 2>>EOE != 0;
- error: unable to upgrade package libbar/1.0.0 to 2.0.0
- info: because package libbox depends on (libbar ^1.0.0)
- info: package libbar/2.0.0 required by libbaz
- info: explicitly request up/downgrade of package libbox
- info: or explicitly specify package libbar version to manually satisfy these constraints
+ $* foo ?libbaz 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: skip configured foo/1.0.0
+ trace: execute_plan: simulate: yes
+ trace: evaluate_dependency: libbaz/1.0.0: update to libbaz/2.0.0
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: end reached
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: add libbar/2.0.0
+ info: package libbaz dependency on (libbar ^2.0.0) is forcing upgrade of libbar/1.0.0 to 2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.0.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: skip being built existing dependent libbaz of dependency libbar
+ trace: collect_build_prerequisites: skip unsatisfied existing dependent libbox of dependency libbar/2.0.0 due to constraint (libbar ^1.0.0)
+ trace: collect_build_prerequisites: begin libbar/2.0.0
+ trace: collect_build_prerequisites: end libbar/2.0.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_dependents: postpone failure for existing dependent libbox unsatisfied with dependency libbar/2.0.0 (^1.0.0)
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfiable dependent libbaz/2.0.0 of dependency libbar/2.0.0 with some other version
+ trace: try_replace_dependency: replace unsatisfiable dependent version libbaz/2.0.0 with 1.0.0 by adding constraint '?libbaz' -> '?libbaz == 1.0.0' on command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: skip configured foo/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ update foo/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
EOE
- # libbar/2.0.0 is still unsatisfactory as a prerequisite for libbox,
- # even after libbox upgrade is requested on the command line.
+ $pkg_status -r >>EOO;
+ !foo configured 1.0.0
+ libbaz configured 1.0.0 available 2.0.0
+ libbar configured 1.0.0 available 2.0.0
+ libbox configured 1.0.0 available 1.1.0
+ libbar configured 1.0.0 available 2.0.0
+ EOO
+
+ # libbar/2.0.0 is still unsatisfactory, initially, as a prerequisite
+ # for libbox, even after libbox upgrade is requested on the command
+ # line. This get automatically resolved by the unsatisfied constraints
+ # resolution machinery.
#
- $* foo ?libbaz ?libbox 2>>EOE != 0;
- error: unable to satisfy constraints on package libbar
- info: libbaz depends on (libbar ^2.0.0)
- info: libbox depends on (libbar ^1.0.0)
- info: available libbar/2.0.0
- info: available libbar/1.0.0
- info: explicitly specify libbar version to manually satisfy both constraints
- info: while satisfying libbox/1.1.0
+ $* foo ?libbaz ?libbox 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: skip configured foo/1.0.0
+ trace: execute_plan: simulate: yes
+ trace: evaluate_dependency: libbaz/1.0.0: update to libbaz/2.0.0
+ trace: evaluate_dependency: libbox/1.0.0: update to libbox/1.1.0
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: end reached
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: add libbar/2.0.0
+ info: package libbaz dependency on (libbar ^2.0.0) is forcing upgrade of libbar/1.0.0 to 2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.0.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: skip being built existing dependent libbaz of dependency libbar
+ trace: collect_build_prerequisites: skip unsatisfied existing dependent libbox of dependency libbar/2.0.0 due to constraint (libbar ^1.0.0)
+ trace: collect_build_prerequisites: begin libbar/2.0.0
+ trace: collect_build_prerequisites: end libbar/2.0.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: end reached
+ trace: collect_build_prerequisites: begin libbox/1.1.0
+ trace: collect_build: postpone failure for dependent libbox unsatisfied with dependency libbar/2.0.0 (^1.0.0)
+ trace: collect_build: pick libbar/2.0.0 over libbar/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.0.0 of dependent libbox/1.1.0
+ trace: collect_build_prerequisites: end libbox/1.1.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent libbox/1.1.0 of dependency libbar/2.0.0 with some other version
+ trace: try_replace_dependency: replace unsatisfied dependent version libbox/1.1.0 with 1.0.0 by adding constraint '?libbox' -> '?libbox == 1.0.0' on command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: skip configured foo/1.0.0
+ trace: execute_plan: simulate: yes
+ trace: evaluate_dependency: libbaz/1.0.0: update to libbaz/2.0.0
+ %.*
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: end reached
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: add libbar/2.0.0
+ info: package libbaz dependency on (libbar ^2.0.0) is forcing upgrade of libbar/1.0.0 to 2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.0.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: skip being built existing dependent libbaz of dependency libbar
+ trace: collect_build_prerequisites: skip unsatisfied existing dependent libbox of dependency libbar/2.0.0 due to constraint (libbar ^1.0.0)
+ trace: collect_build_prerequisites: begin libbar/2.0.0
+ trace: collect_build_prerequisites: end libbar/2.0.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_dependents: postpone failure for existing dependent libbox unsatisfied with dependency libbar/2.0.0 (^1.0.0)
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfiable dependent libbaz/2.0.0 of dependency libbar/2.0.0 with some other version
+ trace: try_replace_dependency: replace unsatisfiable dependent version libbaz/2.0.0 with 1.0.0 by adding constraint '?libbaz' -> '?libbaz == 1.0.0' on command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: skip configured foo/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: start command line adjustments refinement cycle by rolling back first adjustment ('?libbox' -> '?libbox == 1.0.0')
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: skip configured foo/1.0.0
+ trace: execute_plan: simulate: yes
+ trace: evaluate_dependency: libbaz/1.0.0: unchanged
+ trace: evaluate_dependency: libbox/1.0.0: update to libbox/1.1.0
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: end reached
+ trace: collect_build_prerequisites: begin libbox/1.1.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent libbox/1.1.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.1.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: command line adjustment '?libbox' -> '?libbox == 1.0.0' is redundant, dropping it
+ upgrade libbox/1.1.0
+ reconfigure/update foo/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
EOE
- $* ?libbox 2>!;
$pkg_status -r >>EOO;
!foo configured 1.0.0
libbaz configured 1.0.0 available 2.0.0
@@ -2075,6 +2706,76 @@ test.options += --no-progress
}
}
}
+
+ : config-vars
+ :
+ {
+ +$cfg_create -d cfg cc config.cc.coptions=-Wall 2>- &cfg/***
+ +$rep_add $rep/t5 && $rep_fetch
+
+ : override-package-specific
+ :
+ {
+ $clone_cfg;
+
+ $* --configure-only { config.cc.coptions+=-g }+ libbar \
+ { config.cc.coptions+=-O }+ libbox 2>>EOE;
+ fetched libbar/1.2.0
+ unpacked libbar/1.2.0
+ fetched libbox/1.2.0
+ unpacked libbox/1.2.0
+ configured libbar/1.2.0
+ configured libbox/1.2.0
+ EOE
+
+ cat cfg/build/config.build >>~%EOO%;
+ %.*
+ config.cc.coptions = -Wall
+ %.*
+ EOO
+
+ cat cfg/libbar-1.2.0/build/config.build >>~%EOO%;
+ %.*
+ config.cc.coptions = -Wall -g
+ %.*
+ EOO
+
+ cat cfg/libbox-1.2.0/build/config.build >>~%EOO%;
+ %.*
+ config.cc.coptions = -Wall -O
+ %.*
+ EOO
+
+ $pkg_drop libbar libbox
+ }
+
+ : override-globally
+ :
+ {
+ $clone_cfg;
+
+ $* --configure-only config.cc.coptions+=-g \
+ config.cc.coptions+=-O -- libbar 2>>EOE;
+ fetched libbar/1.2.0
+ unpacked libbar/1.2.0
+ configured libbar/1.2.0
+ EOE
+
+ cat cfg/build/config.build >>~%EOO%;
+ %.*
+ config.cc.coptions = -Wall
+ %.*
+ EOO
+
+ cat cfg/libbar-1.2.0/build/config.build >>~%EOO%;
+ %.*
+ config.cc.coptions = -Wall -g -O
+ %.*
+ EOO
+
+ $pkg_drop libbar
+ }
+ }
}
: dependency
@@ -2255,9 +2956,12 @@ test.options += --no-progress
%error: package sys:libhello/2\.0 is not found in .+t0a%
EOE
- $* libfoo '?sys:libhello/0.1' 2>>~%EOE% != 0;
+ $* libfoo '?sys:libhello/0.1' 2>>EOE != 0;
error: unable to satisfy constraints on package libhello
- %.+
+ info: libfoo depends on (libhello >= 1.0)
+ info: command line depends on (libhello == 0.1)
+ info: specify libhello version to satisfy libfoo constraint
+ info: while satisfying libfoo/1.1.0
EOE
$* libfoo '?sys:libhello/*' 2>>~%EOE%;
@@ -2322,7 +3026,7 @@ test.options += --no-progress
configured libbar/1.2.0
EOE
- $pkg_status libfoo >'libfoo available 1.0.0';
+ $pkg_status libfoo >'libfoo available 1.0.0 0.1.0';
$pkg_disfigure libbar 2>'disfigured libbar/1.2.0';
$pkg_purge libbar 2>'purged libbar/1.2.0'
@@ -2361,6 +3065,43 @@ test.options += --no-progress
$pkg_purge libfoo 2>'purged libfoo/1.0.0'
}
+ : order-drop
+ :
+ {
+ test.arguments += --yes
+
+ $clone_root_cfg;
+ $rep_fetch $rep/t2 $rep/t3;
+
+ $* libbaz libbar 2>!;
+
+ $pkg_status -r >>EOO;
+ !libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !libbaz configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $* ?libbaz ?libfoo/0.1.0 2>>EOE;
+ disfigured libbaz/1.0.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/0.1.0
+ unpacked libfoo/0.1.0
+ purged libbaz/1.0.0
+ configured libfoo/0.1.0
+ configured libbar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !libbar configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ $pkg_drop libbar
+ }
+
: drop-recursive
:
{
@@ -2378,10 +3119,10 @@ test.options += --no-progress
disfigured libbar/0.0.1
disfigured libbaz/0.0.1
disfigured libfox/0.0.1
- fetched libfoo/1.0.0
- unpacked libfoo/1.0.0
purged libfox/0.0.1
purged libbaz/0.0.1
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
fetched libbar/1.0.0
unpacked libbar/1.0.0
configured libfoo/1.0.0
@@ -2441,20 +3182,33 @@ test.options += --no-progress
$clone_root_cfg;
$rep_fetch $rep/t0a $rep/t0b;
+ # Note that before we have implemented the unsatisfied constraints
+ # resolution this command has failed as follows:
+ #
+ # error: unable to satisfy constraints on package libbaz
+ # info: libbar depends on (libbaz == 0.0.1)
+ # command line requires (libbar == 0.0.1)
+ # info: command line depends on (libbaz == 0.0.2)
+ # info: specify libbaz version to satisfy libbar constraint
+ # info: while satisfying libbar/0.0.1
+ #
$* libbar/0.0.1 ?libbaz/0.0.2 2>>EOE != 0;
- error: unable to satisfy constraints on package libbaz
- info: libbar depends on (libbaz == 0.0.1)
- info: command line depends on (libbaz == 0.0.2)
- info: specify libbaz version to satisfy libbar constraint
- info: while satisfying libbar/0.0.1
+ error: libbaz/0.0.2 is not available from its dependents' repositories
EOE
+ # Note that before we have implemented the unsatisfied constraints
+ # resolution this command has failed as follows:
+ #
+ # error: unable to satisfy constraints on package libbaz
+ # info: libbar depends on (libbaz == 0.0.1)
+ # command line requires (libbar == 0.0.1)
+ # info: command line depends on (libbaz >= 0.0.2)
+ # info: specify libbaz version to satisfy libbar constraint
+ # info: while satisfying libbar/0.0.1
+ #
$* -- libbar/0.0.1 '?libbaz>=0.0.2' 2>>EOE != 0
- error: unable to satisfy constraints on package libbaz
- info: libbar depends on (libbaz == 0.0.1)
- info: command line depends on (libbaz >= 0.0.2)
- info: specify libbaz version to satisfy libbar constraint
- info: while satisfying libbar/0.0.1
+ error: package libbaz doesn't satisfy its dependents
+ info: libbaz/0.0.3 doesn't satisfy libbar/0.0.1
EOE
}
@@ -2464,40 +3218,61 @@ test.options += --no-progress
: satisfy-dependents
:
: Test resolving a conflict when libfix and libbiz have selected such
- : versions of their dependency libbaz, that do not satisfy each other
- : constraints. We resolve the conflict explicitly specifying
+ : versions of their dependency libbaz, that don't satisfy each other
+ : constraints. We resolve the conflict automatically as if by specifying
: ?libbaz/0.0.3 on the command line, which satisfies both constraints.
:
{
$clone_root_cfg;
$rep_fetch $rep/t0b $rep/t0c;
- $* libfix libbiz 2>>EOE != 0;
- error: unable to satisfy constraints on package libbaz
- info: libfix depends on (libbaz >= 0.0.3)
- info: libbiz depends on (libbaz <= 0.0.3)
- info: available libbaz/0.1.0
- info: available libbaz/0.0.2
- info: explicitly specify libbaz version to manually satisfy both constraints
- info: while satisfying libbiz/0.0.2
- EOE
-
- $* libfix libbiz ?libbaz/0.0.3 2>>EOE;
- fetched libfoo/1.0.0
- unpacked libfoo/1.0.0
- fetched libbaz/0.0.3
- unpacked libbaz/0.0.3
- fetched libfix/0.0.3
- unpacked libfix/0.0.3
- fetched libbiz/0.0.2
- unpacked libbiz/0.0.2
- configured libfoo/1.0.0
- configured libbaz/0.0.3
- configured libfix/0.0.3
- configured libbiz/0.0.2
+ $* libfix libbiz --plan '' --verbose 5 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfix/0.0.3
+ trace: collect_build: add libbiz/0.0.2
+ trace: collect_build_prerequisites: begin libfix/0.0.3
+ trace: collect_build: add libbaz/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/0.1.0 of dependent libfix/0.0.3
+ trace: collect_build_prerequisites: begin libbaz/0.1.0
+ trace: collect_build_prerequisites: end libbaz/0.1.0
+ trace: collect_build_prerequisites: end libfix/0.0.3
+ trace: collect_build_prerequisites: begin libbiz/0.0.2
+ trace: collect_build: postpone failure for dependent libbiz unsatisfied with dependency libbaz/0.1.0 (<= 0.0.3)
+ trace: collect_build: pick libbaz/0.1.0 over libbaz/0.0.2
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/0.1.0 of dependent libbiz/0.0.2
+ trace: collect_build_prerequisites: end libbiz/0.0.2
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbaz/0.1.0 with some other version
+ trace: try_replace_dependency: replace unsatisfactory dependency version libbaz/0.1.0 with 0.0.3 by adding package spec '?libbaz == 0.0.3' to command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfix/0.0.3
+ trace: collect_build: add libbiz/0.0.2
+ trace: collect_build_prerequisites: begin libfix/0.0.3
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/0.0.3 of dependent libfix/0.0.3
+ trace: collect_build_prerequisites: begin libbaz/0.0.3
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent libbaz/0.0.3
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end libbaz/0.0.3
+ trace: collect_build_prerequisites: end libfix/0.0.3
+ trace: collect_build_prerequisites: begin libbiz/0.0.2
+ trace: collect_build: pick libbaz/0.0.3 over libbaz/0.0.2
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/0.0.3 of dependent libbiz/0.0.2
+ trace: collect_build_prerequisites: end libbiz/0.0.2
+ trace: execute_plan: simulate: yes
+ %.*
+ new libfoo/1.0.0 (required by libbaz)
+ new libbaz/0.0.3 (required by libbiz, libfix)
+ new libfix/0.0.3
+ new libbiz/0.0.2
+ trace: execute_plan: simulate: no
+ %.*
EOE
- $pkg_status libbaz >'libbaz configured !0.0.3 available 0.1.0 0.0.4';
+ $pkg_status libbaz >'libbaz configured 0.0.3 available 0.1.0 0.0.4';
$pkg_drop libbiz libfix
}
@@ -2539,40 +3314,71 @@ test.options += --no-progress
: Test resolving a conflict when libbox and libfox have selected such
: versions of their dependency libfoo, that do not satisfy each other
: constraints. Note that these constraints are incompatible, so we
- : resolve the conflict explicitly specifying ?libfox/0.0.1 on the
- : command line, to replace one of the conflicting dependents.
+ : automatically resolve the conflict by implicitly specifying
+ : ?libfox/0.0.1 on the command line, to replace one of the conflicting
+ : dependents.
:
{
$clone_root_cfg;
$rep_fetch $rep/t0d;
- $* libbiz 2>>EOE != 0;
- error: unable to satisfy constraints on package libfoo
- info: libfox depends on (libfoo == 0.0.1)
- info: libbox depends on (libfoo == 1.0.0)
- info: available libfoo/0.0.1
- info: available libfoo/1.0.0
- info: explicitly specify libfoo version to manually satisfy both constraints
- info: while satisfying libbox/0.0.2
- info: while satisfying libbiz/0.0.1
- EOE
-
- $* libbiz ?libfox/0.0.1 2>>EOE;
- fetched libfox/0.0.1
- unpacked libfox/0.0.1
- fetched libfoo/1.0.0
- unpacked libfoo/1.0.0
- fetched libbox/0.0.2
- unpacked libbox/0.0.2
- fetched libbiz/0.0.1
- unpacked libbiz/0.0.1
- configured libfox/0.0.1
- configured libfoo/1.0.0
- configured libbox/0.0.2
- configured libbiz/0.0.1
+ $* libbiz --plan "" --verbose 5 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbiz/0.0.1
+ trace: collect_build_prerequisites: begin libbiz/0.0.1
+ trace: collect_build: add libfox/0.0.2
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfox/0.0.2 of dependent libbiz/0.0.1
+ trace: collect_build_prerequisites: begin libfox/0.0.2
+ trace: collect_build: add libfoo/0.0.1
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/0.0.1 of dependent libfox/0.0.2
+ trace: collect_build_prerequisites: begin libfoo/0.0.1
+ trace: collect_build: add libfix/0.0.1
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfix/0.0.1 of dependent libfoo/0.0.1
+ trace: collect_build_prerequisites: begin libfix/0.0.1
+ trace: collect_build_prerequisites: end libfix/0.0.1
+ trace: collect_build_prerequisites: end libfoo/0.0.1
+ trace: collect_build_prerequisites: end libfox/0.0.2
+ trace: collect_build: add libbox/0.0.2
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbox/0.0.2 of dependent libbiz/0.0.1
+ trace: collect_build_prerequisites: begin libbox/0.0.2
+ trace: collect_build: postpone failure for dependent libbox unsatisfied with dependency libfoo/0.0.1 (== 1.0.0)
+ trace: collect_build: pick libfoo/0.0.1 over libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/0.0.1 of dependent libbox/0.0.2
+ trace: collect_build_prerequisites: end libbox/0.0.2
+ trace: collect_build_prerequisites: end libbiz/0.0.1
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libfoo/0.0.1 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent libbox/0.0.2 of dependency libfoo/0.0.1 with some other version
+ trace: try_replace_dependent: try to replace conflicting dependent libfox/0.0.2 of dependency libfoo/0.0.1 with some other version
+ trace: try_replace_dependency: replace conflicting dependent version libfox/0.0.2 with 0.0.1 by adding package spec '?libfox == 0.0.1' to command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbiz/0.0.1
+ trace: collect_build_prerequisites: begin libbiz/0.0.1
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfox/0.0.1 of dependent libbiz/0.0.1
+ trace: collect_build_prerequisites: begin libfox/0.0.1
+ trace: collect_build_prerequisites: end libfox/0.0.1
+ trace: collect_build: add libbox/0.0.2
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbox/0.0.2 of dependent libbiz/0.0.1
+ trace: collect_build_prerequisites: begin libbox/0.0.2
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent libbox/0.0.2
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end libbox/0.0.2
+ trace: collect_build_prerequisites: end libbiz/0.0.1
+ trace: execute_plan: simulate: yes
+ %.*
+ new libfox/0.0.1 (required by libbiz)
+ new libfoo/1.0.0 (required by libbox)
+ new libbox/0.0.2 (required by libbiz)
+ new libbiz/0.0.1
+ trace: execute_plan: simulate: no
+ %.*
EOE
- $pkg_status libfox >'libfox configured !0.0.1 available 0.0.2';
+ $pkg_status libfox >'libfox configured 0.0.1 available 0.0.2';
$pkg_drop libbiz
}
@@ -2670,6 +3476,266 @@ test.options += --no-progress
}
}
+ : reconfigure
+ :
+ {
+ test.arguments += --yes --configure-only
+
+ +$clone_root_cfg
+ +$rep_fetch $rep/t8a
+
+ : deps-with-buildfile-clause
+ :
+ {
+ $clone_cfg;
+
+ $* dox 2>!;
+
+ $pkg_status -r >>EOO;
+ !dox configured 1.0.0
+ dax configured 1.0.0
+ libbaz configured 1.1.0
+ EOO
+
+ $* ?dax; # Noop.
+
+ $* { config.dax.extras=true }+ ?dax 2>>EOE;
+ disfigured dox/1.0.0
+ disfigured dax/1.0.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ configured libbar/1.0.0
+ configured dax/1.0.0
+ configured dox/1.0.0
+ EOE
+
+ cat cfg/dax-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.dax.extras = true
+ %.*
+ EOO
+
+ $* ?dax; # Noop.
+
+ cat cfg/dax-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.dax.extras = true
+ %.*
+ EOO
+
+ $pkg_status -r >>EOO;
+ !dox configured 1.0.0
+ dax configured 1.0.0
+ libbar configured 1.0.0
+ libbaz configured 1.1.0
+ EOO
+
+ $* { config.dax.extras=true }+ ?dax 2>>EOE;
+ disfigured dox/1.0.0
+ disfigured dax/1.0.0
+ configured dax/1.0.0
+ configured dox/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !dox configured 1.0.0
+ dax configured 1.0.0
+ libbar configured 1.0.0
+ libbaz configured 1.1.0
+ EOO
+
+ $* { config.dax.extras=false }+ ?dax 2>>EOE;
+ disfigured dox/1.0.0
+ disfigured dax/1.0.0
+ disfigured libbar/1.0.0
+ purged libbar/1.0.0
+ configured dax/1.0.0
+ configured dox/1.0.0
+ EOE
+
+ cat cfg/dax-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.dax.extras = false
+ %.*
+ EOO
+
+ $pkg_status -r >>EOO;
+ !dox configured 1.0.0
+ dax configured 1.0.0
+ libbaz configured 1.1.0
+ EOO
+
+ # While at it, test that an attempt to reconfigure an orphan dependency
+ # which has its own dependencies with buildfile clauses fails.
+ #
+ $rep_remove $rep/t8a;
+
+ $* { config.dax.extras=true }+ ?dax 2>>/EOE != 0;
+ error: unknown package dax
+ info: configuration cfg/ has no repositories
+ info: use 'bpkg rep-add' to add a repository
+ EOE
+
+ cp -rp cfg/dax-1.0.0/ dax;
+
+ $rep_add --type dir "$~/dax";
+ $rep_fetch;
+
+ $* { config.dax.extras=true }+ ?dax 2>>EOE != 0;
+ error: package dax/1.0.0 is orphaned
+ info: explicitly upgrade it to a new version
+ info: while satisfying dax/1.0.0
+ EOE
+
+ $pkg_drop dox
+ }
+
+ : deps-without-buildfile-clause
+ :
+ {
+ $clone_cfg;
+
+ $* foz 2>!;
+
+ $pkg_status -r >>EOO;
+ !foz configured 1.0.0
+ fuz configured 1.0.0
+ libfoo configured 2.0.0
+ EOO
+
+ $* ?fuz; # Noop.
+
+ cat cfg/fuz-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.fuz.extras = false
+ %.*
+ EOO
+
+ $* { config.fuz.extras=true }+ ?fuz 2>>EOE;
+ disfigured foz/1.0.0
+ disfigured fuz/1.0.0
+ configured fuz/1.0.0
+ configured foz/1.0.0
+ EOE
+
+ cat cfg/fuz-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.fuz.extras = true
+ %.*
+ EOO
+
+ $* ?fuz; # Noop.
+
+ cat cfg/fuz-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.fuz.extras = true
+ %.*
+ EOO
+
+ $* { config.fuz.extras=false }+ ?fuz 2>>EOE;
+ disfigured foz/1.0.0
+ disfigured fuz/1.0.0
+ configured fuz/1.0.0
+ configured foz/1.0.0
+ EOE
+
+ cat cfg/fuz-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.fuz.extras = false
+ %.*
+ EOO
+
+ # While at it, test that we can also reconfigure an orphan with its own
+ # dependencies but without buildfile clauses.
+ #
+ $rep_remove $rep/t8a;
+
+ cp -rp cfg/fuz-1.0.0/ fuz;
+ sed -i -e 's/(version:) 1.0.0/\1 2.0.0/' fuz/manifest;
+
+ $rep_add --type dir "$~/fuz";
+ $rep_fetch;
+
+ $* { config.fuz.extras=true }+ ?fuz 2>>EOE;
+ disfigured foz/1.0.0
+ disfigured fuz/1.0.0
+ configured fuz/1.0.0
+ configured foz/1.0.0
+ EOE
+
+ cat cfg/fuz-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.fuz.extras = true
+ %.*
+ EOO
+
+ $pkg_status -r >>EOO;
+ !foz configured 1.0.0
+ fuz configured 1.0.0 available 2.0.0
+ libfoo configured 2.0.0
+ EOO
+
+ $pkg_drop foz
+ }
+
+ : no-deps
+ :
+ {
+ $clone_cfg;
+
+ $* fuz 2>!;
+
+ $* ?libfoo; # Noop.
+
+ cat cfg/libfoo-2.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.libfoo.protocol = 2
+ %.*
+ EOO
+
+ $* { config.libfoo.protocol=1 }+ ?libfoo 2>>EOE;
+ disfigured fuz/1.0.0
+ disfigured libfoo/2.0.0
+ configured libfoo/2.0.0
+ configured fuz/1.0.0
+ EOE
+
+ cat cfg/libfoo-2.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.libfoo.protocol = 1
+ %.*
+ EOO
+
+ $* ?libfoo; # Noop.
+
+ # While at it, test that we can also reconfigure an orphan without
+ # dependencies.
+ #
+ $rep_remove $rep/t8a;
+
+ cp -rp cfg/libfoo-2.0.0/ libfoo;
+ sed -i -e 's/(version:) 2.0.0/\1 3.0.0/' libfoo/manifest;
+
+ $rep_add --type dir "$~/libfoo";
+ $rep_fetch;
+
+ $* { config.libfoo.protocol=3 }+ ?libfoo 2>>EOE;
+ disfigured fuz/1.0.0
+ disfigured libfoo/2.0.0
+ configured libfoo/2.0.0
+ configured fuz/1.0.0
+ EOE
+
+ cat cfg/libfoo-2.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.libfoo.protocol = 3
+ %.*
+ EOO
+
+ $pkg_drop fuz
+ }
+ }
+
: refine
:
{
@@ -3085,6 +4151,71 @@ test.options += --no-progress
$pkg_drop libbar libbox
}
+ : satisfy-masked
+ :
+ : As above but using --mask-repository* instead of rep-remove.
+ :
+ {
+ $clone_cfg;
+ $rep_fetch $rep/t0b;
+
+ $* libbar/0.0.1 2>!;
+
+ $pkg_status libbaz >'libbaz configured 0.0.1 available 0.1.0 0.0.4 0.0.3 0.0.2';
+
+ $* libbar/0.0.2 ?libbaz 2>>EOE;
+ disfigured libbar/0.0.1
+ disfigured libbaz/0.0.1
+ disfigured libfox/0.0.1
+ purged libfox/0.0.1
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ fetched libbaz/0.0.2
+ unpacked libbaz/0.0.2
+ fetched libbar/0.0.2
+ unpacked libbar/0.0.2
+ configured libfoo/1.0.0
+ configured libbaz/0.0.2
+ configured libbar/0.0.2
+ EOE
+
+ $pkg_status libbaz >'libbaz configured 0.0.2 available 0.1.0 0.0.4 0.0.3';
+
+ # Test that the selected package, that is "better" than the available
+ # one, is left.
+ #
+ $* --mask-repository $rep/t0b libbox ?libbaz 2>>EOE;
+ fetched libbox/0.0.1
+ unpacked libbox/0.0.1
+ configured libbox/0.0.1
+ EOE
+
+ $pkg_status libbaz >'libbaz configured 0.0.2 available 0.1.0 0.0.4 0.0.3';
+
+ # Test that the selected package is left as there is no satisfactory
+ # available package.
+ #
+ $* --mask-repository $rep/t0b --mask-repository-uuid "$cfg_uuid=($rep/t0a)" ?libbaz;
+
+ # Test that the above behavior is not triggered for the system package.
+ #
+ $* --mask-repository $rep/t0b --mask-repository $rep/t0a '?sys:libbaz' 2>>EOE;
+ disfigured libbar/0.0.2
+ disfigured libbox/0.0.1
+ disfigured libbaz/0.0.2
+ disfigured libfoo/1.0.0
+ purged libfoo/1.0.0
+ purged libbaz/0.0.2
+ configured sys:libbaz/*
+ configured libbox/0.0.1
+ configured libbar/0.0.2
+ EOE
+
+ $pkg_status libbaz >'libbaz configured,system !* available 0.1.0 0.0.4 0.0.3 0.0.2 0.0.1';
+
+ $pkg_drop libbar libbox
+ }
+
: unsatisfied
:
{
@@ -3117,12 +4248,9 @@ test.options += --no-progress
$pkg_status libbaz >'libbaz configured 0.0.1 available 0.1.0 0.0.4 0.0.3';
- $* ?libbaz/0.0.3 +{ --config-id 1 } 2>>EOE != 0;
- error: unable to satisfy constraints on package libbaz
- info: libbar depends on (libbaz == 0.0.1)
- info: command line depends on (libbaz == 0.0.3)
- info: specify libbaz version to satisfy libbar constraint
- info: while satisfying libbar/0.0.1
+ $* ?libbaz/0.0.3 +{ --config-id 1 } 2>>~%EOE% != 0;
+ %error: package libbaz \[cfg2.\] doesn't satisfy its dependents%
+ info: libbaz/0.0.3 doesn't satisfy libbar/0.0.1
EOE
$pkg_status libbaz >'libbaz configured 0.0.1 available 0.1.0 0.0.4 0.0.3';
@@ -3377,10 +4505,9 @@ test.options += --no-progress
: adjust-merge-build
:
- : Test that the registered in the map but not ordered package build
- : (libfoo) is properly merged into the reconfigure adjustment as a
- : dependent of the reconfigured dependency (see collect_order_dependents()
- : for more details).
+ : Test that the registered in the map package build (libfoo) is properly
+ : merged into the reconfigure adjustment as a dependent of the
+ : reconfigured dependency (see collect_dependents() for more details).
:
{
$clone_root_cfg;
@@ -3414,6 +4541,1564 @@ test.options += --no-progress
$pkg_drop libbaz libbar libfoo
}
+
+ : reconfiguration
+ :
+ {
+ +$clone_root_cfg
+ +$rep_add $rep/t4f && $rep_fetch
+
+ : re-order
+ :
+ : This test reproduced a failure of the collect_order_dependents()
+ : function (now turned into collect_dependents()) to properly order
+ : dependents of a being upgraded package, if the current version of this
+ : package is a dependent of a being reconfigured dependency. The now
+ : fixed bug ended up with the 'unable to satisfy dependency' failure of
+ : the subsequent pkg_configure() function call for the described case.
+ :
+ {
+ $clone_cfg;
+
+ $* libbar libbox/1.0.0 ?libbax/1.0.0 2>!;
+
+ $pkg_status -ar >>EOO;
+ libbax configured !1.0.0 available 2.0.0
+ !libbox configured !1.0.0 available 2.0.0
+ libbax configured !1.0.0 available 2.0.0
+ !libbar configured 2.1.0
+ !libbox configured !1.0.0 available 2.0.0
+ libbax configured !1.0.0 available 2.0.0
+ EOO
+
+ $* libfoo libbax 2>>EOE;
+ warning: package libfoo dependency on (libbar == 1.2.0) is forcing downgrade of libbar/2.1.0 to 1.2.0
+ disfigured libbar/2.1.0
+ disfigured libbox/1.0.0
+ disfigured libbax/1.0.0
+ fetched libbax/2.0.0
+ unpacked libbax/2.0.0
+ fetched libbar/1.2.0
+ unpacked libbar/1.2.0
+ fetched libfoo/2.0.0
+ unpacked libfoo/2.0.0
+ configured libbax/2.0.0
+ configured libbox/1.0.0
+ configured libbar/1.2.0
+ configured libfoo/2.0.0
+ EOE
+
+ $pkg_status -ar >>EOO;
+ !libbax configured 2.0.0
+ !libbox configured !1.0.0 available 2.0.0
+ !libbax configured 2.0.0
+ !libbar configured 1.2.0 available 2.1.0
+ !libfoo configured 2.0.0
+ !libbar configured 1.2.0 available 2.1.0
+ EOO
+
+ $pkg_drop libbax libbox libbar libfoo
+ }
+
+ : re-order-unsatisfied
+ :
+ : Similar to the above but the dependent of the mentioned package is
+ : unsatisfied with its dependencies.
+ :
+ {
+ $clone_cfg;
+
+ $* libbar libbox ?libbax/1.0.0 2>!;
+
+ $pkg_status -ar >>EOO;
+ libbax configured !1.0.0 available 2.0.0
+ !libbox configured 2.0.0
+ libbax configured !1.0.0 available 2.0.0
+ !libbar configured 2.1.0
+ !libbox configured 2.0.0
+ libbax configured !1.0.0 available 2.0.0
+ EOO
+
+ $* libfoo libbax/2.0.0 --verbose 5 2>>~%EOE% != 0;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfoo/2.0.0
+ trace: collect_build: add libbax/2.0.0
+ trace: collect_build_prerequisites: begin libfoo/2.0.0
+ trace: collect_build: add libbar/1.2.0
+ warning: package libfoo dependency on (libbar == 1.2.0) is forcing downgrade of libbar/2.1.0 to 1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfoo/2.0.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libfoo/2.0.0
+ trace: collect_build_prerequisites: skip unsatisfied existing dependent libbox of dependency libbax/2.0.0 due to constraint (libbax == 1.0.0)
+ trace: collect_build_prerequisites: begin libbax/2.0.0
+ trace: collect_build_prerequisites: end libbax/2.0.0
+ trace: collect_dependents: postpone failure for existing dependent libbox unsatisfied with dependency libbax/2.0.0 (== 1.0.0)
+ trace: execute_plan: simulate: yes
+ %.*
+ error: unable to upgrade package libbax/1.0.0 to 2.0.0
+ info: because configured package libbox/2.0.0 depends on (libbax == 1.0.0)
+ info: consider re-trying with --upgrade|-u potentially combined with --recursive|-r
+ info: or explicitly request up/downgrade of package libbox
+ info: or explicitly specify package libbax version to manually satisfy these constraints
+ %.*
+ EOE
+
+ $pkg_drop libbox libbar
+ }
+ }
+
+ : denied-version-replacements
+ :
+ {
+ +$clone_root_cfg
+ +$rep_add $rep/t4j && $rep_fetch
+
+ : unsatisfactory-version
+ :
+ {
+ $clone_cfg;
+
+ $* libbaz libfoo libfox --plan "" --verbose 5 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/2.1.0
+ trace: collect_build: add libfoo/3.0.0
+ trace: collect_build: add libfox/3.0.0
+ trace: collect_build_prerequisites: begin libbaz/2.1.0
+ trace: collect_build_prerequisites: end libbaz/2.1.0
+ trace: collect_build_prerequisites: begin libfoo/3.0.0
+ trace: collect_build: add libbar/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfoo/3.0.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libfoo/3.0.0
+ trace: collect_build_prerequisites: begin libfox/3.0.0
+ trace: collect_build: pick libbar/0.1.0 over libbar/1.2.0
+ trace: collect_build: libbar/1.2.0 package version needs to be replaced with libbar/0.1.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/2.1.0
+ trace: collect_build: add libfoo/3.0.0
+ trace: collect_build: add libfox/3.0.0
+ trace: collect_build_prerequisites: begin libbaz/2.1.0
+ trace: collect_build_prerequisites: end libbaz/2.1.0
+ trace: collect_build_prerequisites: begin libfoo/3.0.0
+ trace: collect_build: apply version replacement for libbar/1.2.0
+ trace: collect_build: replacement: libbar/0.1.0
+ trace: collect_build: add libbar/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/0.1.0 of dependent libfoo/3.0.0
+ trace: collect_build_prerequisites: begin libbar/0.1.0
+ trace: collect_build_prerequisites: end libbar/0.1.0
+ trace: collect_build_prerequisites: end libfoo/3.0.0
+ trace: collect_build_prerequisites: begin libfox/3.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/0.1.0 of dependent libfox/3.0.0
+ trace: collect_build: pick libbaz/1.2.0 over libbaz/2.1.0
+ trace: collect_build: libbaz/2.1.0 package version needs to be replaced with libbaz/1.2.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: apply version replacement for libbaz/2.1.0
+ trace: collect_build: replacement: libbaz/1.2.0
+ trace: collect_build: add libbaz/1.2.0
+ trace: collect_build: add libfoo/3.0.0
+ trace: collect_build: add libfox/3.0.0
+ trace: collect_build_prerequisites: begin libbaz/1.2.0
+ trace: collect_build: apply version replacement for libbar/1.2.0
+ trace: collect_build: replacement to 0.1.0 is denied since libbaz/1.2.0 depends on (libbar == 1.2.0)
+ trace: collect_build: add libbar/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libbaz/1.2.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libbaz/1.2.0
+ trace: collect_build_prerequisites: begin libfoo/3.0.0
+ trace: collect_build: apply version replacement for libbar/1.2.0
+ trace: collect_build: replacement: libbar/0.1.0
+ trace: collect_build: pick libbar/1.2.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfoo/3.0.0
+ trace: collect_build_prerequisites: end libfoo/3.0.0
+ trace: collect_build_prerequisites: begin libfox/3.0.0
+ trace: collect_build: postpone failure for dependent libfox unsatisfied with dependency libbar/1.2.0 (== 0.1.0)
+ trace: collect_build: pick libbar/1.2.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/3.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/1.2.0 of dependent libfox/3.0.0
+ trace: collect_build_prerequisites: end libfox/3.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/1.2.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent libfox/3.0.0 of dependency libbar/1.2.0 with some other version
+ trace: try_replace_dependency: replace unsatisfied dependent version libfox/3.0.0 with 2.1.0 by adding constraint 'libfox' -> 'libfox == 2.1.0' on command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/2.1.0
+ trace: collect_build: add libfoo/3.0.0
+ trace: collect_build: add libfox/2.1.0
+ trace: collect_build_prerequisites: begin libbaz/2.1.0
+ trace: collect_build_prerequisites: end libbaz/2.1.0
+ trace: collect_build_prerequisites: begin libfoo/3.0.0
+ trace: collect_build: add libbar/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfoo/3.0.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libfoo/3.0.0
+ trace: collect_build_prerequisites: begin libfox/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/2.1.0
+ trace: collect_build: pick libbaz/1.2.0 over libbaz/2.1.0
+ trace: collect_build: libbaz/2.1.0 package version needs to be replaced with libbaz/1.2.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: apply version replacement for libbaz/2.1.0
+ trace: collect_build: replacement: libbaz/1.2.0
+ trace: collect_build: add libbaz/1.2.0
+ trace: collect_build: add libfoo/3.0.0
+ trace: collect_build: add libfox/2.1.0
+ trace: collect_build_prerequisites: begin libbaz/1.2.0
+ trace: collect_build: add libbar/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libbaz/1.2.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libbaz/1.2.0
+ trace: collect_build_prerequisites: begin libfoo/3.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfoo/3.0.0
+ trace: collect_build_prerequisites: end libfoo/3.0.0
+ trace: collect_build_prerequisites: begin libfox/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/1.2.0 of dependent libfox/2.1.0
+ trace: collect_build_prerequisites: end libfox/2.1.0
+ trace: execute_plan: simulate: yes
+ %.*
+ new libbar/1.2.0 (required by libbaz, libfoo, libfox)
+ new libbaz/1.2.0
+ new libfoo/3.0.0
+ new libfox/2.1.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -ar >>EOO;
+ libbar configured 1.2.0
+ !libbaz configured 1.2.0 available 2.1.0
+ libbar configured 1.2.0
+ !libfoo configured 3.0.0
+ libbar configured 1.2.0
+ !libfox configured 2.1.0 available 3.0.0
+ libbar configured 1.2.0
+ !libbaz configured 1.2.0 available 2.1.0
+ libbar configured 1.2.0
+ EOO
+
+ $pkg_drop libbaz libfoo libfox
+ }
+
+ : collect-drop
+ :
+ {
+ $clone_cfg;
+
+ $* libfix ?libfox/0.0.1 libbaz 2>!;
+
+ $pkg_status -ar >>EOO;
+ libfox configured !0.0.1 available 3.0.0 2.1.0
+ !libfix configured 1.0.0
+ libfox configured !0.0.1 available 3.0.0 2.1.0
+ !libbaz configured 2.1.0
+ EOO
+
+ $* ?libbaz ?libfox/2.1.0 --verbose 5 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: execute_plan: simulate: yes
+ trace: evaluate_dependency: libfox/0.0.1: update to libfox/2.1.0
+ trace: evaluate_dependency: libbaz/2.1.0: unused
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_build_prerequisites: pre-reeval libfix/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated libfix/1.0.0: end reached
+ trace: collect_build_prerequisites: begin libfox/2.1.0
+ trace: collect_build: add libbar/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/2.1.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ warning: package libfox dependency on (libbaz == 1.2.0) is forcing downgrade of libbaz/2.1.0 to 1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/1.2.0 of dependent libfox/2.1.0
+ trace: collect_build_prerequisites: begin libbaz/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libbaz/1.2.0
+ trace: collect_build_prerequisites: end libbaz/1.2.0
+ trace: collect_build_prerequisites: end libfox/2.1.0
+ trace: collect_drop: libbaz cannot be dropped since it is required by command line, libfox/2.1.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: one of dependency evaluation decisions has changed, re-collecting from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build_prerequisites: pre-reeval libfix/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated libfix/1.0.0: end reached
+ trace: collect_build_prerequisites: begin libfox/2.1.0
+ trace: collect_build: add libbar/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/2.1.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ warning: package libfox dependency on (libbaz == 1.2.0) is forcing downgrade of libbaz/2.1.0 to 1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/1.2.0 of dependent libfox/2.1.0
+ trace: collect_build_prerequisites: begin libbaz/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libbaz/1.2.0
+ trace: collect_build_prerequisites: end libbaz/1.2.0
+ trace: collect_build_prerequisites: end libfox/2.1.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -ar >>EOO;
+ libfox configured !2.1.0 available 3.0.0
+ libbar configured 1.2.0
+ libbaz configured 1.2.0 available 2.1.0
+ libbar configured 1.2.0
+ !libfix configured 1.0.0
+ libfox configured !2.1.0 available 3.0.0
+ libbar configured 1.2.0
+ libbaz configured 1.2.0 available 2.1.0
+ libbar configured 1.2.0
+ libbaz configured 1.2.0 available 2.1.0
+ libbar configured 1.2.0
+ libbar configured 1.2.0
+ EOO
+
+ $pkg_drop libfix
+ }
+ }
+
+ : constraint-resolution
+ :
+ {
+ +$clone_root_cfg
+ +$rep_add $rep/t4f && $rep_fetch
+
+ test.arguments += --plan "" --verbose 5
+
+ : replace-dependent
+ :
+ {
+ +$clone_cfg
+
+ : basics
+ :
+ : This test demonstrates a case when the dependency resolution
+ : machinery resolves unsatisfied dependency constraints by adding the
+ : package spec to the command line for an unsatisfied dependent
+ : version.
+ :
+ {
+ $clone_cfg;
+
+ $* libfoo libfix 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfoo/2.0.0
+ trace: collect_build: add libfix/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/2.0.0
+ trace: collect_build: add libbar/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfoo/2.0.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libfoo/2.0.0
+ trace: collect_build_prerequisites: begin libfix/1.0.0
+ trace: collect_build: add libfox/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfox/2.0.0 of dependent libfix/1.0.0
+ trace: collect_build_prerequisites: begin libfox/2.0.0
+ trace: collect_build: postpone failure for dependent libfox unsatisfied with dependency libbar/1.2.0 (>= 2.0.0)
+ trace: collect_build: pick libbar/1.2.0 over libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/2.0.0
+ trace: collect_build_prerequisites: end libfox/2.0.0
+ trace: collect_build_prerequisites: end libfix/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/1.2.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent libfox/2.0.0 of dependency libbar/1.2.0 with some other version
+ trace: try_replace_dependency: replace unsatisfied dependent version libfox/2.0.0 with 1.1.0 by adding package spec '?libfox == 1.1.0' to command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfoo/2.0.0
+ trace: collect_build: add libfix/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/2.0.0
+ trace: collect_build: add libbar/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfoo/2.0.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libfoo/2.0.0
+ trace: collect_build_prerequisites: begin libfix/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfox/1.1.0 of dependent libfix/1.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: pick libbar/1.2.0 over libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: collect_build_prerequisites: end libfix/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ new libbar/1.2.0 (required by libfoo, libfox)
+ new libfoo/2.0.0
+ new libfox/1.1.0 (required by libfix)
+ new libfix/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -ar >>EOO;
+ libbar configured 1.2.0 available 2.1.0
+ !libfoo configured 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ libfox configured 1.1.0 available 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ !libfix configured 1.0.0
+ libfox configured 1.1.0 available 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ EOO
+
+ $pkg_drop libfoo libfix
+ }
+
+ : reorder
+ :
+ : Similar to the above, but the unsatisfied dependent which needs to be
+ : replaced differs from the one added to the unsatisfied dependents
+ : list.
+ :
+ {
+ $clone_cfg;
+
+ $* libfix libfoo 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfix/1.0.0
+ trace: collect_build: add libfoo/2.0.0
+ trace: collect_build_prerequisites: begin libfix/1.0.0
+ trace: collect_build: add libfox/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfox/2.0.0 of dependent libfix/1.0.0
+ trace: collect_build_prerequisites: begin libfox/2.0.0
+ trace: collect_build: add libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.1.0 of dependent libfox/2.0.0
+ trace: collect_build_prerequisites: begin libbar/2.1.0
+ trace: collect_build: add libbox/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbox/2.0.0 of dependent libbar/2.1.0
+ trace: collect_build_prerequisites: begin libbox/2.0.0
+ trace: collect_build: add libbax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbax/1.0.0 of dependent libbox/2.0.0
+ trace: collect_build_prerequisites: begin libbax/1.0.0
+ trace: collect_build_prerequisites: end libbax/1.0.0
+ trace: collect_build_prerequisites: end libbox/2.0.0
+ trace: collect_build_prerequisites: end libbar/2.1.0
+ trace: collect_build_prerequisites: end libfox/2.0.0
+ trace: collect_build_prerequisites: end libfix/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/2.0.0
+ trace: collect_build: postpone failure for dependent libfoo unsatisfied with dependency libbar/2.1.0 (== 1.2.0)
+ trace: collect_build: pick libbar/2.1.0 over libbar/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.1.0 of dependent libfoo/2.0.0
+ trace: collect_build_prerequisites: end libfoo/2.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/2.1.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent libfoo/2.0.0 of dependency libbar/2.1.0 with some other version
+ trace: try_replace_dependent: try to replace conflicting dependent libfox/2.0.0 of dependency libbar/2.1.0 with some other version
+ trace: try_replace_dependency: replace conflicting dependent version libfox/2.0.0 with 1.1.0 by adding package spec '?libfox == 1.1.0' to command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfix/1.0.0
+ trace: collect_build: add libfoo/2.0.0
+ trace: collect_build_prerequisites: begin libfix/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfox/1.1.0 of dependent libfix/1.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: add libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.1.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbar/2.1.0
+ trace: collect_build: add libbox/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbox/2.0.0 of dependent libbar/2.1.0
+ trace: collect_build_prerequisites: begin libbox/2.0.0
+ trace: collect_build: add libbax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbax/1.0.0 of dependent libbox/2.0.0
+ trace: collect_build_prerequisites: begin libbax/1.0.0
+ trace: collect_build_prerequisites: end libbax/1.0.0
+ trace: collect_build_prerequisites: end libbox/2.0.0
+ trace: collect_build_prerequisites: end libbar/2.1.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: collect_build_prerequisites: end libfix/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/2.0.0
+ trace: collect_build: pick libbar/1.2.0 over libbar/2.1.0
+ trace: collect_build: libbar/2.1.0 package version needs to be replaced with libbar/1.2.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfix/1.0.0
+ trace: collect_build: add libfoo/2.0.0
+ trace: collect_build_prerequisites: begin libfix/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfox/1.1.0 of dependent libfix/1.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: apply version replacement for libbar/2.1.0
+ trace: collect_build: replacement: libbar/1.2.0
+ trace: collect_build: add libbar/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: collect_build_prerequisites: end libfix/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfoo/2.0.0
+ trace: collect_build_prerequisites: end libfoo/2.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ new libbar/1.2.0 (required by libfoo, libfox)
+ new libfox/1.1.0 (required by libfix)
+ new libfix/1.0.0
+ new libfoo/2.0.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -ar >>EOO;
+ libbar configured 1.2.0 available 2.1.0
+ libfox configured 1.1.0 available 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ !libfix configured 1.0.0
+ libfox configured 1.1.0 available 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ !libfoo configured 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ EOO
+
+ $pkg_drop libfoo libfix
+ }
+
+ : to-hold
+ :
+ : Similar to the basics test, but the unsatisfied dependent is being
+ : built to hold rather than as a dependency.
+ :
+ {
+ $clone_cfg;
+
+ $* libfoo libfox 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfoo/2.0.0
+ trace: collect_build: add libfox/2.0.0
+ trace: collect_build_prerequisites: begin libfoo/2.0.0
+ trace: collect_build: add libbar/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfoo/2.0.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libfoo/2.0.0
+ trace: collect_build_prerequisites: begin libfox/2.0.0
+ trace: collect_build: postpone failure for dependent libfox unsatisfied with dependency libbar/1.2.0 (>= 2.0.0)
+ trace: collect_build: pick libbar/1.2.0 over libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/2.0.0
+ trace: collect_build_prerequisites: end libfox/2.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: try_replace_dependent: try to replace unsatisfied dependent libfox/2.0.0 of dependency libbar/1.2.0 with some other version
+ trace: try_replace_dependency: replace unsatisfied dependent version libfox/2.0.0 with 1.1.0 by adding constraint 'libfox' -> 'libfox == 1.1.0' on command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfoo/2.0.0
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build_prerequisites: begin libfoo/2.0.0
+ trace: collect_build: add libbar/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfoo/2.0.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libfoo/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: pick libbar/1.2.0 over libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: execute_plan: simulate: yes
+ %.*
+ new libbar/1.2.0 (required by libfoo, libfox)
+ new libfoo/2.0.0
+ new libfox/1.1.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -ar >>EOO;
+ libbar configured 1.2.0 available 2.1.0
+ !libfoo configured 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ !libfox configured 1.1.0 available 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ EOO
+
+ $pkg_drop libfoo libfox
+ }
+
+ : to-hold-reorder
+ :
+ : Similar to the above, but the unsatisfied dependent which needs to be
+ : replaced differs from the one added to the unsatisfied dependents
+ : list.
+ :
+ {
+ $clone_cfg;
+
+ $* libfox libfoo 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfox/2.0.0
+ trace: collect_build: add libfoo/2.0.0
+ trace: collect_build_prerequisites: begin libfox/2.0.0
+ trace: collect_build: add libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.1.0 of dependent libfox/2.0.0
+ trace: collect_build_prerequisites: begin libbar/2.1.0
+ trace: collect_build: add libbox/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbox/2.0.0 of dependent libbar/2.1.0
+ trace: collect_build_prerequisites: begin libbox/2.0.0
+ trace: collect_build: add libbax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbax/1.0.0 of dependent libbox/2.0.0
+ trace: collect_build_prerequisites: begin libbax/1.0.0
+ trace: collect_build_prerequisites: end libbax/1.0.0
+ trace: collect_build_prerequisites: end libbox/2.0.0
+ trace: collect_build_prerequisites: end libbar/2.1.0
+ trace: collect_build_prerequisites: end libfox/2.0.0
+ trace: collect_build_prerequisites: begin libfoo/2.0.0
+ trace: collect_build: postpone failure for dependent libfoo unsatisfied with dependency libbar/2.1.0 (== 1.2.0)
+ trace: collect_build: pick libbar/2.1.0 over libbar/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.1.0 of dependent libfoo/2.0.0
+ trace: collect_build_prerequisites: end libfoo/2.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/2.1.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent libfoo/2.0.0 of dependency libbar/2.1.0 with some other version
+ trace: try_replace_dependent: try to replace conflicting dependent libfox/2.0.0 of dependency libbar/2.1.0 with some other version
+ trace: try_replace_dependency: replace conflicting dependent version libfox/2.0.0 with 1.1.0 by adding constraint 'libfox' -> 'libfox == 1.1.0' on command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build: add libfoo/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: add libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.1.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbar/2.1.0
+ trace: collect_build: add libbox/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbox/2.0.0 of dependent libbar/2.1.0
+ trace: collect_build_prerequisites: begin libbox/2.0.0
+ trace: collect_build: add libbax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbax/1.0.0 of dependent libbox/2.0.0
+ trace: collect_build_prerequisites: begin libbax/1.0.0
+ trace: collect_build_prerequisites: end libbax/1.0.0
+ trace: collect_build_prerequisites: end libbox/2.0.0
+ trace: collect_build_prerequisites: end libbar/2.1.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: collect_build_prerequisites: begin libfoo/2.0.0
+ trace: collect_build: pick libbar/1.2.0 over libbar/2.1.0
+ trace: collect_build: libbar/2.1.0 package version needs to be replaced with libbar/1.2.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build: add libfoo/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: apply version replacement for libbar/2.1.0
+ trace: collect_build: replacement: libbar/1.2.0
+ trace: collect_build: add libbar/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: collect_build_prerequisites: begin libfoo/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfoo/2.0.0
+ trace: collect_build_prerequisites: end libfoo/2.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ new libbar/1.2.0 (required by libfoo, libfox)
+ new libfox/1.1.0
+ new libfoo/2.0.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -ar >>EOO;
+ libbar configured 1.2.0 available 2.1.0
+ !libfox configured 1.1.0 available 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ !libfoo configured 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ EOO
+
+ $pkg_drop libfoo libfox
+ }
+
+ : unsatisfied-dependent
+ :
+ : This test demonstrates a case when the dependency resolution
+ : machinery resolves unsatisfied dependency constraints by
+ : enforcing noop.
+ :
+ : Note that there is no version constraints are specified on the
+ : command line, the request is to upgrade all packages to the latest
+ : possible versions, and thus noop in this case is an appropriate
+ : outcome.
+ :
+ {
+ $clone_cfg;
+
+ $* libbox ?libbix/1.0.0 libbux 2>!;
+
+ $pkg_status -ar >>EOO;
+ libbax configured 1.0.0 available 2.0.0
+ !libbox configured 2.0.0
+ libbax configured 1.0.0 available 2.0.0
+ libbix configured !1.0.0 available 2.0.0
+ libbax configured 1.0.0 available 2.0.0
+ !libbux configured 1.0.0
+ libbix configured !1.0.0 available 2.0.0
+ libbax configured 1.0.0 available 2.0.0
+ EOO
+
+ $* --upgrade --recursive 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbox/2.0.0
+ trace: collect_build: add libbux/1.0.0
+ trace: collect_build_prerequisites: skip configured libbox/2.0.0
+ trace: collect_build_prerequisites: skip configured libbux/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: libbix/1.0.0: update to libbix/2.0.0
+ %.*
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_build: add libbix/2.0.0
+ trace: collect_build_prerequisites: pre-reeval libbux/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated libbux/1.0.0: end reached
+ trace: collect_build_prerequisites: begin libbix/2.0.0
+ trace: collect_build: add libbax/2.0.0
+ info: package libbix dependency on (libbax == 2.0.0) is forcing upgrade of libbax/1.0.0 to 2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbax/2.0.0 of dependent libbix/2.0.0
+ trace: collect_build_prerequisites: skip unsatisfied existing dependent libbox of dependency libbax/2.0.0 due to constraint (libbax == 1.0.0)
+ trace: collect_build_prerequisites: skip being built existing dependent libbix of dependency libbax
+ trace: collect_build_prerequisites: begin libbax/2.0.0
+ trace: collect_build_prerequisites: end libbax/2.0.0
+ trace: collect_build_prerequisites: end libbix/2.0.0
+ trace: collect_dependents: postpone failure for existing dependent libbox unsatisfied with dependency libbax/2.0.0 (== 1.0.0)
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbax/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfiable dependent libbix/2.0.0 of dependency libbax/2.0.0 with some other version
+ trace: try_replace_dependency: replace unsatisfiable dependent version libbix/2.0.0 with 1.0.0 by adding package spec '?libbix == 1.0.0' to command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbox/2.0.0
+ trace: collect_build: add libbux/1.0.0
+ trace: collect_build_prerequisites: skip configured libbox/2.0.0
+ trace: collect_build_prerequisites: skip configured libbux/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -ar >>EOO;
+ libbax configured 1.0.0 available 2.0.0
+ !libbox configured 2.0.0
+ libbax configured 1.0.0 available 2.0.0
+ libbix configured !1.0.0 available 2.0.0
+ libbax configured 1.0.0 available 2.0.0
+ !libbux configured 1.0.0
+ libbix configured !1.0.0 available 2.0.0
+ libbax configured 1.0.0 available 2.0.0
+ EOO
+
+ $pkg_drop libbox libbux
+ }
+
+ : indirect
+ :
+ : Test replacement of indirect dependents of an unsatisfactory
+ : dependency.
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t4k && $rep_fetch;
+
+ $* libbaz libbar 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ trace: collect_build: add libfox/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfox/2.0.0 of dependent libbaz/1.0.0
+ trace: collect_build_prerequisites: begin libfox/2.0.0
+ trace: collect_build: add libfux/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfux/2.0.0 of dependent libfox/2.0.0
+ trace: collect_build_prerequisites: begin libfux/2.0.0
+ trace: collect_build: add libfaz/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfaz/2.0.0 of dependent libfux/2.0.0
+ trace: collect_build_prerequisites: begin libfaz/2.0.0
+ trace: collect_build: add libfuz/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfuz/2.0.0 of dependent libfaz/2.0.0
+ trace: collect_build_prerequisites: begin libfuz/2.0.0
+ trace: collect_build_prerequisites: end libfuz/2.0.0
+ trace: collect_build_prerequisites: end libfaz/2.0.0
+ trace: collect_build: add libfex/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfex/2.0.0 of dependent libfux/2.0.0
+ trace: collect_build_prerequisites: begin libfex/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfaz/2.0.0 of dependent libfex/2.0.0
+ trace: collect_build_prerequisites: end libfex/2.0.0
+ trace: collect_build_prerequisites: end libfux/2.0.0
+ trace: collect_build_prerequisites: end libfox/2.0.0
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent libbar/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build: add libfix/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfix/1.0.0 of dependent libfoo/1.0.0
+ trace: collect_build_prerequisites: begin libfix/1.0.0
+ trace: collect_build: add libfax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfax/1.0.0 of dependent libfix/1.0.0
+ trace: collect_build_prerequisites: begin libfax/1.0.0
+ trace: collect_build: postpone failure for dependent libfax unsatisfied with dependency libfuz/2.0.0 (== 1.0.0)
+ trace: collect_build: pick libfuz/2.0.0 over libfuz/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfuz/2.0.0 of dependent libfax/1.0.0
+ trace: collect_build_prerequisites: end libfax/1.0.0
+ trace: collect_build_prerequisites: end libfix/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libfuz/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent libfax/1.0.0 of dependency libfuz/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace conflicting dependent libfaz/2.0.0 of dependency libfuz/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace constraining dependent libfix/1.0.0 of dependency libfax/1.0.0 with some other version
+ trace: try_replace_dependent: try to replace constraining dependent libfoo/1.0.0 of dependency libfix/1.0.0 with some other version
+ trace: try_replace_dependent: try to replace constraining dependent libbar/1.0.0 of dependency libfoo/1.0.0 with some other version
+ trace: try_replace_dependent: try to replace constraining dependent libfux/2.0.0 of dependency libfaz/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace constraining dependent libfex/2.0.0 of dependency libfaz/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace constraining dependent libfox/2.0.0 of dependency libfux/2.0.0 with some other version
+ trace: try_replace_dependency: replace constraining dependent version libfox/2.0.0 with 1.2.0 by adding package spec '?libfox == 1.2.0' to command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfox/1.2.0 of dependent libbaz/1.0.0
+ trace: collect_build_prerequisites: begin libfox/1.2.0
+ trace: collect_build: add libfux/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfux/1.0.0 of dependent libfox/1.2.0
+ trace: collect_build_prerequisites: begin libfux/1.0.0
+ trace: collect_build: add libfaz/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfaz/1.0.0 of dependent libfux/1.0.0
+ trace: collect_build_prerequisites: begin libfaz/1.0.0
+ trace: collect_build: add libfuz/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfuz/1.0.0 of dependent libfaz/1.0.0
+ trace: collect_build_prerequisites: begin libfuz/1.0.0
+ trace: collect_build_prerequisites: end libfuz/1.0.0
+ trace: collect_build_prerequisites: end libfaz/1.0.0
+ trace: collect_build: add libfex/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfex/1.0.0 of dependent libfux/1.0.0
+ trace: collect_build_prerequisites: begin libfex/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfaz/1.0.0 of dependent libfex/1.0.0
+ trace: collect_build_prerequisites: end libfex/1.0.0
+ trace: collect_build_prerequisites: end libfux/1.0.0
+ trace: collect_build: postpone failure for dependent libfox unsatisfied with dependency libfex/1.0.0 (>= 2.0.0)
+ trace: collect_build: pick libfex/1.0.0 over libfex/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfex/1.0.0 of dependent libfox/1.2.0
+ trace: collect_build_prerequisites: end libfox/1.2.0
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent libbar/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build: add libfix/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfix/1.0.0 of dependent libfoo/1.0.0
+ trace: collect_build_prerequisites: begin libfix/1.0.0
+ trace: collect_build: add libfax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfax/1.0.0 of dependent libfix/1.0.0
+ trace: collect_build_prerequisites: begin libfax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfuz/1.0.0 of dependent libfax/1.0.0
+ trace: collect_build_prerequisites: end libfax/1.0.0
+ trace: collect_build_prerequisites: end libfix/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libfex/1.0.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent libfox/1.2.0 of dependency libfex/1.0.0 with some other version
+ trace: try_replace_dependency: replacement of unsatisfied dependent version libfox/1.2.0 is denied since it is specified on command line as '?libfox == 1.2.0'
+ trace: try_replace_dependent: try to replace conflicting dependent libfux/1.0.0 of dependency libfex/1.0.0 with some other version
+ trace: pkg_build: cannot replace any package, rolling back latest command line adjustment ('?libfox == 1.2.0')
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ trace: collect_build: add libfox/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfox/2.0.0 of dependent libbaz/1.0.0
+ trace: collect_build_prerequisites: begin libfox/2.0.0
+ trace: collect_build: add libfux/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfux/2.0.0 of dependent libfox/2.0.0
+ trace: collect_build_prerequisites: begin libfux/2.0.0
+ trace: collect_build: add libfaz/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfaz/2.0.0 of dependent libfux/2.0.0
+ trace: collect_build_prerequisites: begin libfaz/2.0.0
+ trace: collect_build: add libfuz/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfuz/2.0.0 of dependent libfaz/2.0.0
+ trace: collect_build_prerequisites: begin libfuz/2.0.0
+ trace: collect_build_prerequisites: end libfuz/2.0.0
+ trace: collect_build_prerequisites: end libfaz/2.0.0
+ trace: collect_build: add libfex/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfex/2.0.0 of dependent libfux/2.0.0
+ trace: collect_build_prerequisites: begin libfex/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfaz/2.0.0 of dependent libfex/2.0.0
+ trace: collect_build_prerequisites: end libfex/2.0.0
+ trace: collect_build_prerequisites: end libfux/2.0.0
+ trace: collect_build_prerequisites: end libfox/2.0.0
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent libbar/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build: add libfix/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfix/1.0.0 of dependent libfoo/1.0.0
+ trace: collect_build_prerequisites: begin libfix/1.0.0
+ trace: collect_build: add libfax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfax/1.0.0 of dependent libfix/1.0.0
+ trace: collect_build_prerequisites: begin libfax/1.0.0
+ trace: collect_build: postpone failure for dependent libfax unsatisfied with dependency libfuz/2.0.0 (== 1.0.0)
+ trace: collect_build: pick libfuz/2.0.0 over libfuz/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfuz/2.0.0 of dependent libfax/1.0.0
+ trace: collect_build_prerequisites: end libfax/1.0.0
+ trace: collect_build_prerequisites: end libfix/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libfuz/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent libfax/1.0.0 of dependency libfuz/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace conflicting dependent libfaz/2.0.0 of dependency libfuz/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace constraining dependent libfix/1.0.0 of dependency libfax/1.0.0 with some other version
+ trace: try_replace_dependent: try to replace constraining dependent libfoo/1.0.0 of dependency libfix/1.0.0 with some other version
+ trace: try_replace_dependent: try to replace constraining dependent libbar/1.0.0 of dependency libfoo/1.0.0 with some other version
+ trace: try_replace_dependent: try to replace constraining dependent libfux/2.0.0 of dependency libfaz/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace constraining dependent libfex/2.0.0 of dependency libfaz/2.0.0 with some other version
+ trace: try_replace_dependent: try to replace constraining dependent libfox/2.0.0 of dependency libfux/2.0.0 with some other version
+ trace: try_replace_dependency: replacement libfox/1.2.0 tried earlier for same command line, skipping
+ trace: try_replace_dependency: replace constraining dependent version libfox/2.0.0 with 1.0.0 by adding package spec '?libfox == 1.0.0' to command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfox/1.0.0 of dependent libbaz/1.0.0
+ trace: collect_build_prerequisites: begin libfox/1.0.0
+ trace: collect_build: add libfux/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfux/1.0.0 of dependent libfox/1.0.0
+ trace: collect_build_prerequisites: begin libfux/1.0.0
+ trace: collect_build: add libfaz/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfaz/1.0.0 of dependent libfux/1.0.0
+ trace: collect_build_prerequisites: begin libfaz/1.0.0
+ trace: collect_build: add libfuz/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfuz/1.0.0 of dependent libfaz/1.0.0
+ trace: collect_build_prerequisites: begin libfuz/1.0.0
+ trace: collect_build_prerequisites: end libfuz/1.0.0
+ trace: collect_build_prerequisites: end libfaz/1.0.0
+ trace: collect_build: add libfex/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfex/1.0.0 of dependent libfux/1.0.0
+ trace: collect_build_prerequisites: begin libfex/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfaz/1.0.0 of dependent libfex/1.0.0
+ trace: collect_build_prerequisites: end libfex/1.0.0
+ trace: collect_build_prerequisites: end libfux/1.0.0
+ trace: collect_build_prerequisites: end libfox/1.0.0
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent libbar/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build: add libfix/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfix/1.0.0 of dependent libfoo/1.0.0
+ trace: collect_build_prerequisites: begin libfix/1.0.0
+ trace: collect_build: add libfax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfax/1.0.0 of dependent libfix/1.0.0
+ trace: collect_build_prerequisites: begin libfax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfuz/1.0.0 of dependent libfax/1.0.0
+ trace: collect_build_prerequisites: end libfax/1.0.0
+ trace: collect_build_prerequisites: end libfix/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ new libfuz/1.0.0 (required by libfax, libfaz)
+ new libfaz/1.0.0 (required by libfex, libfux)
+ new libfex/1.0.0 (required by libfux)
+ new libfux/1.0.0 (required by libfox)
+ new libfox/1.0.0 (required by libbaz)
+ new libbaz/1.0.0
+ new libfax/1.0.0 (required by libfix)
+ new libfix/1.0.0 (required by libfoo)
+ new libfoo/1.0.0 (required by libbar)
+ new libbar/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r libbaz libbar >>EOO;
+ !libbaz configured 1.0.0
+ libfox configured 1.0.0 available 2.0.0 1.2.0
+ libfux configured 1.0.0 available 2.0.0
+ libfaz configured 1.0.0 available 2.0.0
+ libfuz configured 1.0.0 available 2.0.0
+ libfex configured 1.0.0 available 2.0.0
+ libfaz configured 1.0.0 available 2.0.0
+ libfuz configured 1.0.0 available 2.0.0
+ !libbar configured 1.0.0
+ libfoo configured 1.0.0 available 2.0.0
+ libfix configured 1.0.0 available 2.0.0
+ libfax configured 1.0.0 available 2.0.0
+ libfuz configured 1.0.0 available 2.0.0
+ EOO
+
+ $pkg_drop libbaz libbar
+ }
+ }
+
+ : replace-dependency
+ :
+ {
+ +$clone_cfg
+ +$rep_add $rep/t4i && $rep_fetch
+
+ : basics
+ :
+ : This test demonstrates a case when the dependency resolution
+ : machinery resolves unsatisfied dependency constraints by adding the
+ : package spec to the command line for an unsatisfactory dependency
+ : version.
+ :
+ {
+ $clone_cfg;
+
+ $* libfox/1.1.0 libbaz 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: add libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.1.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbar/2.1.0
+ trace: collect_build: add libbox/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbox/2.0.0 of dependent libbar/2.1.0
+ trace: collect_build_prerequisites: begin libbox/2.0.0
+ trace: collect_build: add libbax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbax/1.0.0 of dependent libbox/2.0.0
+ trace: collect_build_prerequisites: begin libbax/1.0.0
+ trace: collect_build_prerequisites: end libbax/1.0.0
+ trace: collect_build_prerequisites: end libbox/2.0.0
+ trace: collect_build_prerequisites: end libbar/2.1.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: postpone failure for dependent libbaz unsatisfied with dependency libbar/2.1.0 (< 2.1.0)
+ trace: collect_build: pick libbar/2.1.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.1.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/2.1.0 with some other version
+ trace: try_replace_dependency: replace unsatisfactory dependency version libbar/2.1.0 with 1.2.0 by adding package spec '?libbar == 1.2.0' to command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: pick libbar/1.2.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -ar >>EOO;
+ libbar configured 1.2.0 available 2.1.0
+ !libfox configured !1.1.0 available 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ !libbaz configured 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ EOO
+
+ $pkg_drop libfox libbaz
+ }
+
+ : reorder
+ :
+ : Similar to the above, but the order of the dependents on the command
+ : line is swapped.
+ :
+ {
+ $clone_cfg;
+
+ $* libbaz libfox/1.1.0 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: add libbar/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/0.1.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libbar/0.1.0
+ trace: collect_build_prerequisites: end libbar/0.1.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: postpone failure for dependent libfox unsatisfied with dependency libbar/0.1.0 (>= 1.0.0)
+ trace: collect_build: pick libbar/0.1.0 over libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/0.1.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/0.1.0 with some other version
+ trace: try_replace_dependency: replace unsatisfactory dependency version libbar/0.1.0 with 1.2.0 by adding package spec '?libbar == 1.2.0' to command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build_prerequisites: rep-postpone dependent libbaz/2.0.0 due to dependency libbar < 2.1.0 and user-specified constraint == 1.2.0
+ trace: collect_build_prerequisites: postpone libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (0): collect rep-postponed libbaz/2.0.0
+ trace: collect_build_prerequisites: resume libbaz/2.0.0
+ trace: collect_build: pick libbar/1.2.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -ar >>EOO;
+ libbar configured 1.2.0 available 2.1.0
+ !libbaz configured 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ !libfox configured !1.1.0 available 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ EOO
+
+ $pkg_drop libfox libbaz
+ }
+
+ : dependency
+ :
+ : Similar to the above, but the dependency is also specified on the
+ : command line.
+ :
+ {
+ $clone_cfg;
+
+ $* libbaz libfox/1.1.0 '?libbar' 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/0.1.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libbar/0.1.0
+ trace: collect_build_prerequisites: end libbar/0.1.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: postpone failure for dependent libfox unsatisfied with dependency libbar/0.1.0 (>= 1.0.0)
+ trace: collect_build: pick libbar/0.1.0 over libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/0.1.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: libbar/0.1.0: update to libbar/1.2.0
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/0.1.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libbar/0.1.0
+ trace: collect_build_prerequisites: end libbar/0.1.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: postpone failure for dependent libfox unsatisfied with dependency libbar/0.1.0 (>= 1.0.0)
+ trace: collect_build: pick libbar/0.1.0 over libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/0.1.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: collect_build: pick libbar/1.2.0 over libbar/0.1.0
+ trace: collect_build: libbar/0.1.0 package version needs to be replaced with libbar/1.2.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: apply version replacement for libbar/0.1.0
+ trace: collect_build: replacement: libbar/1.2.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: pick libbar/1.2.0 over libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: execute_plan: simulate: yes
+ %.*
+ new libbar/1.2.0 (required by libbaz, libfox)
+ new libbaz/2.0.0
+ new libfox/1.1.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -ar >>EOO;
+ libbar configured 1.2.0 available 2.1.0
+ !libbaz configured 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ !libfox configured !1.1.0 available 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ EOO
+
+ $pkg_drop libfox libbaz libbar
+ }
+
+ : dependency-constr
+ :
+ : Similar to the above, but also specify the version constraint.
+ :
+ {
+ $clone_cfg;
+
+ $* libbaz libfox/1.1.0 '?libbar < 3.0.0' 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/0.1.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libbar/0.1.0
+ trace: collect_build_prerequisites: end libbar/0.1.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: postpone failure for dependent libfox unsatisfied with dependency libbar/0.1.0 (>= 1.0.0)
+ trace: collect_build: pick libbar/0.1.0 over libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/0.1.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/0.1.0 with some other version
+ trace: try_replace_dependency: replace unsatisfactory dependency version libbar/0.1.0 with 1.2.0 by overwriting constraint '?libbar < 3.0.0' -> '?libbar == 1.2.0' on command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build_prerequisites: rep-postpone dependent libbaz/2.0.0 due to dependency libbar < 2.1.0 and user-specified constraint == 1.2.0
+ trace: collect_build_prerequisites: postpone libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (0): collect rep-postponed libbaz/2.0.0
+ trace: collect_build_prerequisites: resume libbaz/2.0.0
+ trace: collect_build: pick libbar/1.2.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ new libbar/1.2.0 (required by libbaz, libfox)
+ new libbaz/2.0.0
+ new libfox/1.1.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -ar >>EOO;
+ libbar configured !1.2.0 available 2.1.0
+ !libbaz configured 2.0.0
+ libbar configured !1.2.0 available 2.1.0
+ !libfox configured !1.1.0 available 2.0.0
+ libbar configured !1.2.0 available 2.1.0
+ EOO
+
+ $pkg_drop libfox libbaz libbar
+ }
+
+ : to-hold
+ :
+ : Similar to the dependency test, but the dependency is specified as
+ : build-to-hold.
+ :
+ {
+ $clone_cfg;
+
+ $* libbaz libfox/1.1.0 libbar 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build: add libbar/2.1.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: pick libbar/0.1.0 over libbar/2.1.0
+ trace: collect_build: libbar/2.1.0 package version needs to be replaced with libbar/0.1.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build: apply version replacement for libbar/2.1.0
+ trace: collect_build: replacement: libbar/0.1.0
+ trace: collect_build: add libbar/0.1.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/0.1.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libbar/0.1.0
+ trace: collect_build_prerequisites: end libbar/0.1.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: postpone failure for dependent libfox unsatisfied with dependency libbar/0.1.0 (>= 1.0.0)
+ trace: collect_build: pick libbar/0.1.0 over libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/0.1.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: collect_build_prerequisites: resume libbar/0.1.0
+ trace: collect_build_prerequisites: end libbar/0.1.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/0.1.0 with some other version
+ trace: try_replace_dependency: replace unsatisfactory dependency version libbar/0.1.0 with 1.2.0 by adding constraint 'libbar' -> 'libbar == 1.2.0' on command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build: add libbar/1.2.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: pick libbar/1.2.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: pick libbar/1.2.0 over libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: collect_build_prerequisites: resume libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: execute_plan: simulate: yes
+ %.*
+ new libbar/1.2.0
+ new libbaz/2.0.0
+ new libfox/1.1.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -ar >>EOO;
+ !libbar configured 1.2.0 available 2.1.0
+ !libbaz configured 2.0.0
+ !libbar configured 1.2.0 available 2.1.0
+ !libfox configured !1.1.0 available 2.0.0
+ !libbar configured 1.2.0 available 2.1.0
+ EOO
+
+ $pkg_drop libfox libbaz libbar
+ }
+
+ : to-hold-constr
+ :
+ : Similar to the above, but also specify the version constraint.
+ :
+ {
+ $clone_cfg;
+
+ $* libbaz libfox/1.1.0 'libbar < 3.0.0' 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build: add libbar/2.1.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: pick libbar/0.1.0 over libbar/2.1.0
+ trace: collect_build: libbar/2.1.0 package version needs to be replaced with libbar/0.1.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build: apply version replacement for libbar/2.1.0
+ trace: collect_build: replacement: libbar/0.1.0
+ trace: collect_build: add libbar/0.1.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/0.1.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libbar/0.1.0
+ trace: collect_build_prerequisites: end libbar/0.1.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: postpone failure for dependent libfox unsatisfied with dependency libbar/0.1.0 (>= 1.0.0)
+ trace: collect_build: pick libbar/0.1.0 over libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/0.1.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: collect_build_prerequisites: resume libbar/0.1.0
+ trace: collect_build_prerequisites: end libbar/0.1.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/0.1.0 with some other version
+ trace: try_replace_dependency: replace unsatisfactory dependency version libbar/0.1.0 with 1.2.0 by overwriting constraint 'libbar < 3.0.0' -> 'libbar == 1.2.0' on command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build: add libbar/1.2.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: pick libbar/1.2.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: pick libbar/1.2.0 over libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: collect_build_prerequisites: resume libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -ar >>EOO;
+ !libbar configured !1.2.0 available 2.1.0
+ !libbaz configured 2.0.0
+ !libbar configured !1.2.0 available 2.1.0
+ !libfox configured !1.1.0 available 2.0.0
+ !libbar configured !1.2.0 available 2.1.0
+ EOO
+
+ $pkg_drop libfox libbaz libbar
+ }
+
+ : configured
+ :
+ : Similar to replace-dependency but the dependency is already configured
+ : as built-to-hold.
+ :
+ {
+ $clone_cfg;
+
+ $* libbar 2>!;
+
+ $* libfox/1.1.0 libbaz 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: add libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.1.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: skip configured libbar/2.1.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: postpone failure for dependent libbaz unsatisfied with dependency libbar/2.1.0 (< 2.1.0)
+ trace: collect_build: pick libbar/2.1.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/2.1.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/2.1.0 with some other version
+ warning: package libbaz/2.0.0 dependency on (libbar < 2.1.0) is forcing downgrade of libbar/2.1.0 to 1.2.0
+ trace: try_replace_dependency: replace unsatisfactory dependency version libbar/2.1.0 with 1.2.0 by adding package spec 'libbar == 1.2.0' to command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfox/1.1.0
+ trace: collect_build: add libbaz/2.0.0
+ trace: collect_build: add libbar/1.2.0
+ trace: collect_build_prerequisites: begin libfox/1.1.0
+ trace: collect_build: pick libbar/1.2.0 over libbar/2.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: collect_build_prerequisites: end libfox/1.1.0
+ trace: collect_build_prerequisites: begin libbaz/2.0.0
+ trace: collect_build: pick libbar/1.2.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.2.0 of dependent libbaz/2.0.0
+ trace: collect_build_prerequisites: end libbaz/2.0.0
+ trace: collect_build_prerequisites: resume libbar/1.2.0
+ trace: collect_build_prerequisites: end libbar/1.2.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: libbox/2.0.0: unused
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_drop: add libbox
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: libbax/1.0.0: unused
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_drop: overwrite libbox
+ trace: collect_drop: add libbax
+ trace: execute_plan: simulate: yes
+ %.*
+ drop libbax/1.0.0 (unused)
+ drop libbox/2.0.0 (unused)
+ downgrade libbar/1.2.0
+ new libfox/1.1.0
+ new libbaz/2.0.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -ar >>EOO;
+ !libbar configured 1.2.0 available 2.1.0
+ !libfox configured !1.1.0 available 2.0.0
+ !libbar configured 1.2.0 available 2.1.0
+ !libbaz configured 2.0.0
+ !libbar configured 1.2.0 available 2.1.0
+ EOO
+
+ $pkg_drop libfox libbaz libbar
+ }
+
+ : unsatisfied-dependent
+ :
+ : Test that not being able to upgrade a dependency to a later version
+ : which doesn't satisfy an existing dependent, we don't upgrade the
+ : dependency.
+ :
+ {
+ $clone_cfg;
+
+ $* libfoo 2>!;
+
+ $pkg_status -ar >>EOO;
+ libbar configured 1.2.0 available 2.1.0
+ !libfoo configured 2.0.0
+ libbar configured 1.2.0 available 2.1.0
+ EOO
+
+ $* libbar 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbar/2.1.0
+ trace: collect_build_prerequisites: skip unsatisfied existing dependent libfoo of dependency libbar/2.1.0 due to constraint (libbar == 1.2.0)
+ trace: collect_build_prerequisites: begin libbar/2.1.0
+ trace: collect_build: add libbox/2.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbox/2.0.0 of dependent libbar/2.1.0
+ trace: collect_build_prerequisites: begin libbox/2.0.0
+ trace: collect_build: add libbax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbax/1.0.0 of dependent libbox/2.0.0
+ trace: collect_build_prerequisites: begin libbax/1.0.0
+ trace: collect_build_prerequisites: end libbax/1.0.0
+ trace: collect_build_prerequisites: end libbox/2.0.0
+ trace: collect_build_prerequisites: end libbar/2.1.0
+ trace: collect_dependents: postpone failure for existing dependent libfoo unsatisfied with dependency libbar/2.1.0 (== 1.2.0)
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency libbar/2.1.0 with some other version
+ trace: try_replace_dependency: replace unsatisfactory dependency version libbar/2.1.0 with 1.2.0 by adding constraint 'libbar' -> 'libbar == 1.2.0' on command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbar/1.2.0
+ trace: collect_build_prerequisites: skip configured libbar/1.2.0
+ trace: execute_plan: simulate: yes
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_drop libfoo libbar
+ }
+ }
+ }
}
: upgrade
@@ -3441,6 +6126,19 @@ test.options += --no-progress
configured libbar/0.0.2
EOE
+ +$pkg_status -ar >>EOO
+ libfix configured 0.0.1 available 0.0.3
+ !libfoo configured !0.0.1 available 1.0.0
+ libfix configured 0.0.1 available 0.0.3
+ !libbaz configured !0.0.2 available 0.1.0 0.0.4 0.0.3
+ !libfoo configured !0.0.1 available 1.0.0
+ libfix configured 0.0.1 available 0.0.3
+ !libbar configured !0.0.2 available 1.0.0 0.0.3
+ !libbaz configured !0.0.2 available 0.1.0 0.0.4 0.0.3
+ !libfoo configured !0.0.1 available 1.0.0
+ libfix configured 0.0.1 available 0.0.3
+ EOO
+
clone_cfg = [cmdline] cp --no-cleanup -r ../cfg ./ &cfg/***
: immediate
@@ -3606,6 +6304,17 @@ test.options += --no-progress
$* libbar --recursive --yes
}
+ : unavailable-masked
+ :
+ : As above but using --mask-repository* instead of rep-remove.
+ :
+ {
+ $clone_cfg;
+
+ $* libbar --mask-repository $rep/t0a --mask-repository $rep/t0b \
+ --mask-repository-uuid "$cfg_uuid=($rep/t0c)" --recursive --yes
+ }
+
-$pkg_drop libbar libbaz libfoo
}
@@ -3636,7 +6345,7 @@ test.options += --no-progress
$pkg_drop foo
}
- : multiple-alternatives
+ : multiple-alts
:
{
+$clone_cfg
@@ -3893,7 +6602,7 @@ test.options += --no-progress
{
+$clone_cfg
- : reevaluate-alternatives
+ : reevaluate-alts
:
{
+$clone_cfg
@@ -3945,6 +6654,7 @@ test.options += --no-progress
cat cfg/box-1.0.0/build/config.build >>~%EOO%;
%.*
config.box.backend = libbox
+ %.*
EOO
$pkg_drop box;
@@ -3952,7 +6662,7 @@ test.options += --no-progress
$pkg_drop libbiz
}
- : change-downgraded-depenency
+ : change-downgraded-dependency
:
: Test that libbiz is selected as a dependency since the existing
: dependency decision cannot be preserved (libbox is downgraded to
@@ -3965,16 +6675,16 @@ test.options += --no-progress
$* box +{ config.box.extras=true } ?libbox/0.1.0 2>>~%EOE%;
build plan:
- new libbiz/1.0.0 (required by box)
drop libbox/1.0.0 (unused)
+ new libbiz/1.0.0 (required by box)
reconfigure/update box/1.0.0
config.box.extras=true (user configuration)
config.box.backend=libbiz (set by box)
disfigured box/1.0.0
disfigured libbox/1.0.0
+ purged libbox/1.0.0
fetched libbiz/1.0.0
unpacked libbiz/1.0.0
- purged libbox/1.0.0
configured libbiz/1.0.0
configured box/1.0.0
%info: .+box-1.0.0.+ is up to date%
@@ -3990,6 +6700,7 @@ test.options += --no-progress
cat cfg/box-1.0.0/build/config.build >>~%EOO%;
%.*
config.box.backend = libbiz
+ %.*
EOO
$pkg_drop box
@@ -4005,19 +6716,17 @@ test.options += --no-progress
$* box libbox 2>!;
# While at it, test the reused-only alternative selection mode.
+ # Also test the postponement of the 'unable to satisfy constraints
+ # on package' failure.
#
$* box +{ config.box.extras=true } libbox/0.1.0 2>>EOE != 0;
- error: unable to select dependency alternative for package box/1.0.0
- info: explicitly specify dependency packages to manually select the alternative
- info: alternative: libbiz
- info: unsatisfactory alternative: libbox
- error: unable to satisfy constraints on package libbox
+ error: unable to satisfy constraints on package libbox
info: command line depends on (libbox == 0.1.0)
- info: box depends on (libbox >= 0.1.1)
+ info: box/1.0.0 depends on (libbox >= 0.1.1)
info: available libbox/0.1.0
info: available libbox/1.0.0
+ info: while satisfying box/1.0.0
info: explicitly specify libbox version to manually satisfy both constraints
- info: while satisfying box/1.0.0
EOE
$* box +{ config.box.extras=true } libbox/0.1.0 ?libbiz 2>>~%EOE%;
@@ -4051,11 +6760,99 @@ test.options += --no-progress
cat cfg/box-1.0.0/build/config.build >>~%EOO%;
%.*
config.box.backend = libbiz
+ %.*
EOO
$pkg_drop box;
$pkg_drop libbox
}
+
+ : postpone-unable-satisfy
+ :
+ : Similar to the above, but this time the postponement of the
+ : 'unable to satisfy constraints on package' failure ends up with
+ : downgrading of the unsatisfied dependent (bax).
+ :
+ {
+ $clone_cfg;
+
+ $* bax libbox 2>!;
+
+ $* bax +{ config.bax.extras=true } libbox/0.1.0 bix 2>>~%EOE%;
+ build plan:
+ downgrade libbox/0.1.0
+ downgrade bax/0.1.0
+ config.bax.extras=true (user configuration)
+ config.bax.backend=libbox (set by bax)
+ new bix/1.0.0
+ disfigured bax/1.0.0
+ disfigured libbox/1.0.0
+ fetched libbox/0.1.0
+ unpacked libbox/0.1.0
+ fetched bax/0.1.0
+ unpacked bax/0.1.0
+ fetched bix/1.0.0
+ unpacked bix/1.0.0
+ configured libbox/0.1.0
+ configured bax/0.1.0
+ configured bix/1.0.0
+ %info: .+libbox-0.1.0.+ is up to date%
+ %info: .+bax-0.1.0.+ is up to date%
+ %info: .+bix-1.0.0.+ is up to date%
+ updated libbox/0.1.0
+ updated bax/0.1.0
+ updated bix/1.0.0
+ EOE
+
+ $pkg_drop bix;
+ $pkg_drop bax;
+ $pkg_drop libbox
+ }
+
+ : postpone-unable-satisfy-dep
+ :
+ : Similar to the above, but the failure postponement ends up with
+ : downgrading on the next dependency refinement iteration.
+ :
+ {
+ $clone_cfg;
+
+ $* bax libbox bux ?bix/0.1.0 2>!;
+
+ $* bax +{ config.bax.extras=true } libbox/0.1.0 ?bix 2>>~%EOE%;
+ build plan:
+ downgrade libbox/0.1.0
+ downgrade bax/0.1.0
+ config.bax.extras=true (user configuration)
+ config.bax.backend=libbox (set by bax)
+ upgrade bix/1.0.0
+ reconfigure bux (dependent of bix)
+ disfigured bux/1.0.0
+ disfigured bix/0.1.0
+ disfigured bax/1.0.0
+ disfigured libbox/1.0.0
+ fetched libbox/0.1.0
+ unpacked libbox/0.1.0
+ fetched bax/0.1.0
+ unpacked bax/0.1.0
+ fetched bix/1.0.0
+ unpacked bix/1.0.0
+ configured libbox/0.1.0
+ configured bax/0.1.0
+ configured bix/1.0.0
+ configured bux/1.0.0
+ %info: .+libbox-0.1.0.+ is up to date%
+ %info: .+bax-0.1.0.+ is up to date%
+ %info: .+bux-1.0.0.+ is up to date%
+ updated libbox/0.1.0
+ updated bax/0.1.0
+ updated bux/1.0.0
+ EOE
+
+ $pkg_drop bux;
+ $pkg_drop bax;
+ $pkg_drop libbox
+ }
}
: reconfigure
@@ -4091,6 +6888,7 @@ test.options += --no-progress
cat cfg/box-1.0.0/build/config.build >>~%EOO%;
%.*
config.box.backend = libbox
+ %.*
EOO
# Downgrade libbaz to reconfigure box and make sure we still keep
@@ -4126,6 +6924,7 @@ test.options += --no-progress
cat cfg/box-1.0.0/build/config.build >>~%EOO%;
%.*
config.box.backend = libbox
+ %.*
EOO
# Make sure the decision is hold for downgraded dependency either.
@@ -4154,6 +6953,7 @@ test.options += --no-progress
cat cfg/box-1.0.0/build/config.build >>~%EOO%;
%.*
config.box.backend = libbox
+ %.*
EOO
$pkg_drop box;
@@ -4240,6 +7040,147 @@ test.options += --no-progress
$pkg_drop fax
}
+ : enable-indirect-dependency
+ :
+ {
+ $clone_cfg;
+
+ test.arguments += --plan "";
+
+ $* dax 2>>~%EOE%;
+ new libbaz/1.1.0 (required by dax)
+ new dax/1.0.0
+ fetched libbaz/1.1.0
+ unpacked libbaz/1.1.0
+ fetched dax/1.0.0
+ unpacked dax/1.0.0
+ configured libbaz/1.1.0
+ configured dax/1.0.0
+ %info: .+dax-1.0.0.+ is up to date%
+ updated dax/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !dax configured 1.0.0
+ libbaz configured 1.1.0
+ EOO
+
+ $* dix 2>>~%EOE%;
+ new libbar/1.0.0 (required by dax)
+ reconfigure/update dax/1.0.0 (required by dix)
+ config.dax.extras=true (set by dix)
+ new dix/1.0.0
+ disfigured dax/1.0.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ fetched dix/1.0.0
+ unpacked dix/1.0.0
+ configured libbar/1.0.0
+ configured dax/1.0.0
+ configured dix/1.0.0
+ %info: .+dix-1.0.0.+ is up to date%
+ updated dix/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !dax configured 1.0.0
+ libbar configured 1.0.0
+ libbaz configured 1.1.0
+ !dix configured 1.0.0
+ !dax configured 1.0.0
+ libbar configured 1.0.0
+ libbaz configured 1.1.0
+ EOO
+
+ $pkg_drop dax dix
+ }
+
+ : repoint-enable-indirect-dependency
+ :
+ {
+ $clone_cfg;
+
+ test.arguments += --plan "";
+
+ $* dax dux ?dix/0.1.0 2>>~%EOE%;
+ new libbaz/1.1.0 (required by dax)
+ new dax/1.0.0
+ new dix/0.1.0 (required by dux)
+ new dux/1.0.0
+ fetched libbaz/1.1.0
+ unpacked libbaz/1.1.0
+ fetched dax/1.0.0
+ unpacked dax/1.0.0
+ fetched dix/0.1.0
+ unpacked dix/0.1.0
+ fetched dux/1.0.0
+ unpacked dux/1.0.0
+ configured libbaz/1.1.0
+ configured dax/1.0.0
+ configured dix/0.1.0
+ configured dux/1.0.0
+ %info: .+dax-1.0.0.+ is up to date%
+ %info: .+dux-1.0.0.+ is up to date%
+ updated dax/1.0.0
+ updated dux/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !dax configured 1.0.0
+ libbaz configured 1.1.0
+ !dux configured 1.0.0
+ dix configured !0.1.0 available 1.0.0
+ EOO
+
+ $cfg_create -d cfg2 --name cfg2 &cfg2/***;
+ $cfg_link -d cfg cfg2;
+ $rep_add -d cfg2 $rep/t8a && $rep_fetch -d cfg2;
+
+ $* libbaz +{ --config-name cfg2 } ?dix 2>>~%EOE%;
+ % new libbaz/1.1.0 \[cfg2.\]%
+ drop libbaz/1.1.0 (unused)
+ new libbar/1.0.0 (required by dax)
+ reconfigure/update dax/1.0.0 (required by dix)
+ config.dax.extras=true (set by dix)
+ upgrade dix/1.0.0
+ reconfigure dux (dependent of dix)
+ disfigured dux/1.0.0
+ disfigured dix/0.1.0
+ disfigured dax/1.0.0
+ disfigured libbaz/1.1.0
+ %fetched libbaz/1.1.0 \[cfg2.\]%
+ %unpacked libbaz/1.1.0 \[cfg2.\]%
+ purged libbaz/1.1.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ fetched dix/1.0.0
+ unpacked dix/1.0.0
+ %configured libbaz/1.1.0 \[cfg2.\]%
+ configured libbar/1.0.0
+ configured dax/1.0.0
+ configured dix/1.0.0
+ configured dux/1.0.0
+ %info: .+libbaz-1.1.0.+ is up to date%
+ %info: .+dux-1.0.0.+ is up to date%
+ %updated libbaz/1.1.0 \[cfg2.\]%
+ updated dux/1.0.0
+ EOE
+
+ $pkg_status -r >>/EOO;
+ !dax configured 1.0.0
+ libbar configured 1.0.0
+ !libbaz [cfg2/] configured 1.1.0
+ !dux configured 1.0.0
+ dix configured 1.0.0
+ !dax configured 1.0.0
+ libbar configured 1.0.0
+ !libbaz [cfg2/] configured 1.1.0
+ EOO
+
+ $pkg_drop dux;
+ $pkg_drop dax
+ }
+
: reevaluate-alternatives
:
{
@@ -4363,7 +7304,7 @@ test.options += --no-progress
{
+$clone_cfg
- +tar (!$posix ? --force-local : ) -xzf $src/t8a/fax-1.0.0.tar.gz &fax-1.0.0/***
+ +$tar -xzf $src/t8a/fax-1.0.0.tar.gz &fax-1.0.0/***
+mv fax-1.0.0 fax
: change-manifest
@@ -4499,45 +7440,51 @@ test.options += --no-progress
$backend_configured
EOO
- # No upgrade after turning a package from the archive-based repo
- # into an external package.
+ # Iteration increment and upgrade after turning a package from the
+ # archive-based repo into an external package.
#
$* fax/ 2>>~%EOE%;
- %info: .+fax-1.0.0.+ is up to date%
- updated fax/1.0.0
+ disfigured fax/1.0.0
+ using fax/1.0.0#1 (external)
+ configured fax/1.0.0#1
+ %info: .+dir.fax.+ is up to date%
+ updated fax/1.0.0#1
EOE
$pkg_status -r >>"EOO";
- !fax configured !1.0.0
+ !fax configured !1.0.0#1
$backend_configured
EOO
- # Upgrade after the package' buildfile is edited.
+ # Further upgrade after the package' buildfile is edited.
#
echo '' >+fax/build/root.build;
$* fax/ 2>>~%EOE%;
- disfigured fax/1.0.0
- using fax/1.0.0#1 (external)
- configured fax/1.0.0#1
+ disfigured fax/1.0.0#1
+ using fax/1.0.0#2 (external)
+ configured fax/1.0.0#2
%info: .+fax.+ is up to date%
- updated fax/1.0.0#1
+ updated fax/1.0.0#2
EOE
$pkg_status -r >>"EOO";
- !fax configured !1.0.0#1
+ !fax configured !1.0.0#2
$backend_configured
EOO
# No upgrade if the buildfile is not edited.
#
$* fax/ 2>>~%EOE%;
+ disfigured fax/1.0.0#2
+ using fax/1.0.0#2 (external)
+ configured fax/1.0.0#2
%info: .+fax.+ is up to date%
- updated fax/1.0.0#1
+ updated fax/1.0.0#2
EOE
$pkg_status -r >>"EOO";
- !fax configured !1.0.0#1
+ !fax configured !1.0.0#2
$backend_configured
EOO
@@ -4566,37 +7513,40 @@ test.options += --no-progress
$backend_configured
EOO
- # No upgrade after turning a package from the archive-based repo
- # into an external package.
+ # Iteration increment and upgrade after turning a package from the
+ # archive-based repo into an external package.
#
$rep_add --type dir fax/ && $rep_fetch;
$* fax 2>>~%EOE%;
- %info: .+fax-1.0.0.+ is up to date%
- updated fax/1.0.0
+ disfigured fax/1.0.0
+ using fax/1.0.0#1 (external)
+ configured fax/1.0.0#1
+ %info: .+dir.fax.+ is up to date%
+ updated fax/1.0.0#1
EOE
$pkg_status -r >>"EOO";
- !fax configured 1.0.0
+ !fax configured 1.0.0#1
$backend_configured
EOO
- # Upgrade after the package' buildfile is edited.
+ # Further upgrade after the package' buildfile is edited.
#
echo '' >+fax/build/root.build;
$rep_fetch;
$* fax 2>>~%EOE%;
- disfigured fax/1.0.0
- using fax/1.0.0#1 (external)
- configured fax/1.0.0#1
+ disfigured fax/1.0.0#1
+ using fax/1.0.0#2 (external)
+ configured fax/1.0.0#2
%info: .+fax.+ is up to date%
- updated fax/1.0.0#1
+ updated fax/1.0.0#2
EOE
$pkg_status -r >>"EOO";
- !fax configured 1.0.0#1
+ !fax configured 1.0.0#2
$backend_configured
EOO
@@ -4606,11 +7556,11 @@ test.options += --no-progress
$* fax 2>>~%EOE%;
%info: .+fax.+ is up to date%
- updated fax/1.0.0#1
+ updated fax/1.0.0#2
EOE
$pkg_status -r >>"EOO";
- !fax configured 1.0.0#1
+ !fax configured 1.0.0#2
$backend_configured
EOO
@@ -4659,6 +7609,7 @@ test.options += --no-progress
disfigured fax/1.0.0
%disfigured $backend/.+%
%purged $backend/.+%
+ using fax/1.0.0 \(external\)
configured sys:$backend/*
configured fax/1.0.0
%info: .+fax.+ is up to date%
@@ -4686,6 +7637,7 @@ test.options += --no-progress
disfigured fax/1.0.0
disfigured libbiz/1.0.0
purged libbiz/1.0.0
+ using fax/1.0.0 \(external\)
configured fax/1.0.0
%info: .+fax.+ is up to date%
updated fax/1.0.0
@@ -4733,6 +7685,436 @@ test.options += --no-progress
$pkg_drop fax
}
}
+
+ : reconfigure-dependent
+ :
+ : Test some cases when a dependent needs to be reconfigured due to an
+ : upgraded dependency.
+ :
+ {
+ +$clone_cfg
+
+ test.arguments += --yes
+
+ : keep-alternative
+ :
+ {
+ $clone_cfg;
+
+ $* tax ?libfoo/1.0.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !tax configured 1.0.0
+ libfoo configured !1.0.0 available 2.0.0
+ EOO
+
+ $* --upgrade --recursive 2>!; # Noop.
+
+ $pkg_status -r >>EOO;
+ !tax configured 1.0.0
+ libfoo configured !1.0.0 available 2.0.0
+ EOO
+
+ $* ?libfoo 2>!; # Noop.
+
+ $pkg_status -r >>EOO;
+ !tax configured 1.0.0
+ libfoo configured !1.0.0 available 2.0.0
+ EOO
+
+ $* ?libfoo/2.0.0 2>>EOE != 0;
+ error: package libfoo doesn't satisfy its dependents
+ info: libfoo/2.0.0 doesn't satisfy tax/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tax configured 1.0.0
+ libfoo configured !1.0.0 available 2.0.0
+ EOO
+
+ $pkg_drop tax
+ }
+
+ : re-evaluate-dependent
+ :
+ {
+ $clone_cfg;
+
+ $* tex ?libfoo/1.0.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !tex configured 1.0.0
+ libfoo configured !1.0.0 available 2.0.0
+ EOO
+
+ cat cfg/tex-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.tex.libfoo_protocol = 1
+ %.*
+ EOO
+
+ # @@ Strangely, if upgrade with -ur instead of ?libfoo, then status
+ # prints 'libfoo configured !2.0.0' instead of
+ # 'libfoo configured 2.0.0'.
+ #
+ $* ?libfoo 2>>~%EOE%;
+ disfigured tex/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/2.0.0
+ unpacked libfoo/2.0.0
+ configured libfoo/2.0.0
+ configured tex/1.0.0
+ %info: .+tex-1.0.0.+ is up to date%
+ updated tex/1.0.0
+ EOE
+
+ cat cfg/tex-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.tex.libfoo_protocol = 2
+ %.*
+ EOO
+
+ $pkg_status -r >>EOO;
+ !tex configured 1.0.0
+ libfoo configured 2.0.0
+ EOO
+
+ $pkg_drop tex
+ }
+
+ : re-evaluate-reflect
+ :
+ {
+ $clone_cfg;
+
+ # @@ The fact that `$* tix` fails as follows but `$* tix ?libfoo`
+ # doesn't looks confusing:
+ #
+ # error: unable to select dependency alternative for package tix/1.0.0
+ # info: explicitly specify dependency packages to manually select the alternative
+ # info: alternative: libfoo
+ # info: alternative: libfoo
+ # info: while satisfying tix/1.0.0
+ #
+ # Note:
+ #
+ # tix -> libfoo>=2.0.0 reflect{...} | libfoo>=1.0.0 reflect{...}
+ #
+ $* tix ?libfoo/1.0.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !tix configured 1.0.0
+ libfoo configured !1.0.0 available 2.0.0
+ EOO
+
+ cat cfg/tix-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.tix.reflect = 1
+ %.*
+ EOO
+
+ $* ?libfoo 2>>~%EOE%;
+ disfigured tix/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/2.0.0
+ unpacked libfoo/2.0.0
+ configured libfoo/2.0.0
+ configured tix/1.0.0
+ %info: .+tix-1.0.0.+ is up to date%
+ updated tix/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tix configured 1.0.0
+ libfoo configured 2.0.0
+ EOO
+
+ cat cfg/tix-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.tix.reflect = 2
+ %.*
+ EOO
+
+ $pkg_drop tix
+ }
+
+ : select-alt-with-reflect
+ :
+ {
+ $clone_cfg;
+
+ $* tox ?libfoo/1.0.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !tox configured 1.0.0
+ libfoo configured !1.0.0 available 2.0.0
+ EOO
+
+ cat cfg/tox-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.tox.libfoo_protocol = '1 or 2'
+ %.*
+ EOO
+
+ $* ?libfoo 2>>~%EOE%;
+ disfigured tox/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/2.0.0
+ unpacked libfoo/2.0.0
+ configured libfoo/2.0.0
+ configured tox/1.0.0
+ %info: .+tox-1.0.0.+ is up to date%
+ updated tox/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tox configured 1.0.0
+ libfoo configured 2.0.0
+ EOO
+
+ cat cfg/tox-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.tox.libfoo_protocol = 2
+ %.*
+ EOO
+
+ $pkg_drop tox
+ }
+
+ : re-evaluate-from
+ :
+ {
+ +$clone_cfg
+
+ : earlier-depends
+ :
+ {
+ $clone_cfg;
+
+ $* tux ?libbox/0.1.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !tux configured 1.0.0
+ libbox configured !0.1.0 available 1.0.0 0.1.1
+ libfoo configured 2.0.0
+ EOO
+
+ cat cfg/libfoo-2.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.libfoo.protocol = 1
+ %.*
+ EOO
+
+ $* ?libbox 2>>~%EOE%;
+ disfigured tux/1.0.0
+ disfigured libbox/0.1.0
+ fetched libbox/1.0.0
+ unpacked libbox/1.0.0
+ configured libbox/1.0.0
+ configured tux/1.0.0
+ %info: .+tux-1.0.0.+ is up to date%
+ updated tux/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tux configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 2.0.0
+ EOO
+
+ cat cfg/libfoo-2.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.libfoo.protocol = 1
+ %.*
+ EOO
+
+ $pkg_drop tux
+ }
+
+ : later-depends
+ :
+ {
+ $clone_cfg;
+
+ $* twx ?libbiz/0.1.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !twx configured 1.0.0
+ libbiz configured !0.1.0 available 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 2.0.0
+ EOO
+
+ cat cfg/libfoo-2.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.libfoo.protocol = 1
+ %.*
+ EOO
+
+ $* ?libbiz 2>>~%EOE%;
+ disfigured twx/1.0.0
+ disfigured libbiz/0.1.0
+ fetched libbiz/1.0.0
+ unpacked libbiz/1.0.0
+ configured libbiz/1.0.0
+ configured twx/1.0.0
+ %info: .+twx-1.0.0.+ is up to date%
+ updated twx/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !twx configured 1.0.0
+ libbiz configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 2.0.0
+ EOO
+
+ cat cfg/libfoo-2.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.libfoo.protocol = 1
+ %.*
+ EOO
+
+ $pkg_drop twx
+ }
+
+ : same-depends
+ :
+ {
+ $clone_cfg;
+
+ $* tvx ?libfoo/1.0.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !tvx configured 1.0.0
+ libfoo configured !1.0.0 available 2.0.0
+ libfox configured 1.0.0
+ EOO
+
+ cat cfg/libfox-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.libfox.level = 1
+ %.*
+ EOO
+
+ $* ?libfoo 2>>~%EOE%;
+ disfigured tvx/1.0.0
+ disfigured libfoo/1.0.0
+ disfigured libfox/1.0.0
+ fetched libfoo/2.0.0
+ unpacked libfoo/2.0.0
+ configured libfox/1.0.0
+ configured libfoo/2.0.0
+ configured tvx/1.0.0
+ %info: .+tvx-1.0.0.+ is up to date%
+ updated tvx/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tvx configured 1.0.0
+ libfoo configured 2.0.0
+ libfox configured 1.0.0
+ EOO
+
+ cat cfg/libfox-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.libfox.level = 2
+ %.*
+ EOO
+
+ $pkg_drop tvx
+ }
+ }
+
+ : change-alternative
+ :
+ {
+ $clone_cfg;
+
+ $* tpx ?libfoo/1.0.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !tpx configured 1.0.0
+ libfoo configured !1.0.0 available 2.0.0
+ EOO
+
+ cat cfg/tpx-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.tpx.libfoo_protocol = 1
+ %.*
+ EOO
+
+ $* ?libfoo 2>>~%EOE%;
+ disfigured tpx/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/2.0.0
+ unpacked libfoo/2.0.0
+ configured libfoo/2.0.0
+ configured tpx/1.0.0
+ %info: .+tpx-1.0.0.+ is up to date%
+ updated tpx/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tpx configured 1.0.0
+ libfoo configured 2.0.0
+ EOO
+
+ cat cfg/tpx-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.tpx.libfoo_protocol = 2
+ %.*
+ EOO
+
+ $pkg_drop tpx
+ }
+
+ : fail-change-unsatisfactory-alternative
+ :
+ {
+ $clone_cfg;
+
+ $* tpx ?libfoo 2>!;
+
+ $pkg_status -r >>EOO;
+ !tpx configured 1.0.0
+ libfoo configured 2.0.0
+ EOO
+
+ cat cfg/tpx-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.tpx.libfoo_protocol = 2
+ %.*
+ EOO
+
+ $* tax 2>>EOE != 0;
+ error: unable to downgrade package libfoo/2.0.0 to 1.0.0
+ info: because configured package tpx/1.0.0 depends on (libfoo >= 2.0.0)
+ info: package libfoo/1.0.0 required by
+ tax/1.0.0 (libfoo == 1.0.0)
+ info: re-run with -v for additional dependency information
+ info: consider re-trying with --upgrade|-u potentially combined with --recursive|-r
+ info: or explicitly request up/downgrade of package tpx
+ info: or explicitly specify package libfoo version to manually satisfy these constraints
+ EOE
+
+ # @@ Note that the above advises doesn't really work here since the
+ # tpx package is not re-collected recursively. We should probably
+ # invent the package-specific --rebuild option to re-collect a
+ # configured package.
+ #
+ $* tax tpx ?libfoo/1.0.0 2>>EOE != 0;
+ error: unable to downgrade package libfoo/2.0.0 to 1.0.0
+ info: because configured package tpx/1.0.0 depends on (libfoo >= 2.0.0)
+ info: re-run with -v for additional dependency information
+ info: consider re-trying with --upgrade|-u potentially combined with --recursive|-r
+ info: or explicitly request up/downgrade of package tpx
+ info: or explicitly specify package libfoo version to manually satisfy these constraints
+ EOE
+
+ $pkg_drop tpx
+ }
+ }
}
: version-replacement
@@ -4840,10 +8222,14 @@ test.options += --no-progress
: replaced with 0.1.0 but without re-collection from scratch since it
: does not have any dependencies.
:
+ : Note that the inplace replacement has been disabled for now (see
+ : build_packages::collect_build() for details).
+ :
{
$clone_cfg && $rep_add $rep/t12a && $rep_fetch;
- $* libbaz libbar --verbose 5 2>>~%EOE%;
+#\
+ $* libbaz libbar --verbose 5 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
%.*
@@ -4863,6 +8249,38 @@ test.options += --no-progress
trace: execute_plan: simulate: yes
%.*
EOE
+#\
+
+ $* libbaz libbar --verbose 5 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ %.*
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ %.*
+ trace: collect_build: pick libbaz/0.1.0 over libbaz/1.0.0
+ trace: collect_build: libbaz/1.0.0 package version needs to be replaced with libbaz/0.1.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: apply version replacement for libbaz/1.0.0
+ trace: collect_build: replacement: libbaz/0.1.0
+ trace: collect_build: add libbaz/0.1.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: begin libbaz/0.1.0
+ trace: collect_build_prerequisites: end libbaz/0.1.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ %.*
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/0.1.0 of dependent libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
$pkg_status -r >>EOO;
!libbaz configured 0.1.0 available 1.0.0
@@ -4913,21 +8331,6 @@ test.options += --no-progress
: dropped, which will happen some later execution plan refinement
: iteration.
:
- : @@ This scenario is not supported yet and fails with:
- :
- : error: unable to upgrade package libbaz/0.1.0 to 1.0.0
- : info: because package libbar depends on (libbaz == 0.1.0)
- : info: package libbaz/1.0.0 required by baz
- : info: explicitly request up/downgrade of package libbar
- : info: or explicitly specify package libbaz version to manually satisfy these constraints
- :
- : We could probably fix this postponing the constraints check in
- : collect_order_dependents() until the final execution plan is produced
- : (after all that refinement iterations). We could have an additional
- : iteration after all the refinements which would enable the constraint
- : check in collect_order_dependents().
- :
- if false
{
$clone_cfg;
@@ -4939,12 +8342,15 @@ test.options += --no-progress
libbaz configured 0.1.0 available [1.0.0]
EOO
- $* baz foo/0.1.0 2>|;
+ $* baz foo/0.1.0 2>!;
$pkg_status -r >>EOO;
+ !foo configured !0.1.0 available 1.0.0
+ !baz configured 1.0.0
+ libbaz configured 1.0.0
EOO
- $pkg_drop foo
+ $pkg_drop baz foo
}
}
@@ -4953,7 +8359,16 @@ test.options += --no-progress
{
+$clone_root_cfg && $rep_add $rep/t11a && $rep_fetch
- test.arguments += --yes --plan 'build plan:' --verbose 5 --build-option --quiet
+ test.arguments += --yes --plan='build plan:' --verbose 5 --build-option --quiet
+
+ # Note that on some platforms matching bpkg's stderr using a regular
+ # expression which contains too may '%.*' lines ends up with the
+ # regex_error exception with the error_complexity code. To fix that we
+ # pipe bpkg's stderr through the sed-based pipeline filtering the stream
+ # content and simplify the stderr-matching regular expressions.
+ #
+ filter = [cmdline] sed -e "'"'s/^mkdir -p .*//'"'" | \
+ sed -n -e "'"'s/(.+)/\1/p'"'" >&2
: initial-collection
:
@@ -4965,33 +8380,35 @@ test.options += --no-progress
{
$clone_cfg;
- $* foo fox fux 2>>~%EOE%;
+ # Dependencies:
+ #
+ # foo: depends: libfoo(c)
+ #
+ # fox: depends: libfoo(c)
+ #
+ # fux: depends: libfoo
+ #
+ $* foo fox fux 2>&1 | $filter 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add foo/1.0.0
trace: collect_build: add fox/1.0.0
trace: collect_build: add fux/1.0.0
trace: collect_build_prerequisites: begin foo/1.0.0
- %.*
trace: collect_build: add libfoo/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
trace: collect_build_prerequisites: postpone foo/1.0.0
trace: collect_build_prerequisites: begin fox/1.0.0
- %.*
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent fox/1.0.0
trace: postponed_configurations::add: add {fox 1,1: libfoo} to {foo | libfoo->{foo/1,1}}
trace: collect_build_prerequisites: postpone fox/1.0.0
trace: collect_build_prerequisites: begin fux/1.0.0
- %.*
- trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0 since already in cluster {foo fox | libfoo->{foo/1,1 fox/1,1}}
trace: collect_build_prerequisites: end fux/1.0.0
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {foo fox | libfoo->{foo/1,1 fox/1,1}}
- %.*
trace: collect_build_postponed (1): cfg-negotiate begin {foo fox | libfoo->{foo/1,1 fox/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libfoo/1.0.0
trace: collect_build_prerequisites: end libfoo/1.0.0
@@ -5011,7 +8428,9 @@ test.options += --no-progress
new libfoo/1.0.0 (required by foo, fox, fux)
config.libfoo.extras=true (set by foo)
new foo/1.0.0
+ config.foo.libfoo_extras=true (set by foo)
new fox/1.0.0
+ config.fox.libfoo_extras=true (set by fox)
new fux/1.0.0
%.*
EOE
@@ -5033,28 +8452,22 @@ test.options += --no-progress
{
$clone_cfg;
- $* foo fox '?sys:libfoo/*' 2>>~%EOE%;
+ $* foo fox '?sys:libfoo/*' 2>&1 | $filter 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add foo/1.0.0
trace: collect_build: add fox/1.0.0
trace: collect_build_prerequisites: begin foo/1.0.0
- %.*
trace: collect_build_prerequisites: cfg-postpone dependency sys:libfoo/* of dependent foo/1.0.0
trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
trace: collect_build_prerequisites: postpone foo/1.0.0
trace: collect_build_prerequisites: begin fox/1.0.0
- %.*
trace: collect_build_prerequisites: cfg-postpone dependency sys:libfoo/* of dependent fox/1.0.0
trace: postponed_configurations::add: add {fox 1,1: libfoo} to {foo | libfoo->{foo/1,1}}
trace: collect_build_prerequisites: postpone fox/1.0.0
- %.*
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {foo fox | libfoo->{foo/1,1 fox/1,1}}
- %.*
trace: collect_build_postponed (1): cfg-negotiate begin {foo fox | libfoo->{foo/1,1 fox/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: skip system sys:libfoo/*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
@@ -5067,14 +8480,15 @@ test.options += --no-progress
trace: collect_build_postponed (1): cfg-negotiate end {foo fox | libfoo->{foo/1,1 fox/1,1}}!
trace: collect_build_postponed (1): end {foo fox | libfoo->{foo/1,1 fox/1,1}}
trace: collect_build_postponed (0): end
- %.*
trace: execute_plan: simulate: yes
%.*
build plan:
configure sys:libfoo/* (required by foo, fox)
config.libfoo.extras=true (expected by foo)
new foo/1.0.0
+ config.foo.libfoo_extras=true (set by foo)
new fox/1.0.0
+ config.fox.libfoo_extras=true (set by fox)
%.*
EOE
@@ -5093,27 +8507,23 @@ test.options += --no-progress
{
$clone_cfg;
- $* foo bar baz 2>>~%EOE%;
+ $* foo bar baz 2>&1 | $filter 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add foo/1.0.0
trace: collect_build: add bar/1.0.0
trace: collect_build: add baz/1.0.0
trace: collect_build_prerequisites: begin foo/1.0.0
- %.*
trace: collect_build: add libfoo/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
trace: collect_build_prerequisites: postpone foo/1.0.0
trace: collect_build_prerequisites: begin bar/1.0.0
- %.*
trace: collect_build: add libbar/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
trace: postponed_configurations::add: create {bar | libbar->{bar/1,1}}
trace: collect_build_prerequisites: postpone bar/1.0.0
trace: collect_build_prerequisites: begin baz/1.0.0
- %.*
trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent baz/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent baz/1.0.0
trace: postponed_configurations::add: add {baz 1,1: libbar libfoo} to {foo | libfoo->{foo/1,1}}
@@ -5121,9 +8531,7 @@ test.options += --no-progress
trace: collect_build_prerequisites: postpone baz/1.0.0
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {bar baz foo | libfoo->{baz/1,1 foo/1,1} libbar->{bar/1,1 baz/1,1}}
- %.*
trace: collect_build_postponed (1): cfg-negotiate begin {bar baz foo | libfoo->{baz/1,1 foo/1,1} libbar->{bar/1,1 baz/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libfoo/1.0.0
trace: collect_build_prerequisites: end libfoo/1.0.0
@@ -5148,6 +8556,7 @@ test.options += --no-progress
new libfoo/1.0.0 (required by baz, foo)
config.libfoo.extras=true (set by baz)
new foo/1.0.0
+ config.foo.libfoo_extras=true (set by foo)
new libbar/1.0.0 (required by bar, baz)
config.libbar.extras=true (set by bar)
new bar/1.0.0
@@ -5224,6 +8633,573 @@ test.options += --no-progress
$pkg_drop fex
}
+ : reconf-existing-dept
+ :
+ {
+ +$clone_cfg
+
+ : no-build-clause
+ :
+ {
+ +$clone_cfg
+
+ : no-config
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # fex: depends: fux(c)
+ #
+ # fux: depends: libfoo
+ #
+ $* fex/0.1.0 fux libfoo 2>!;
+
+ $pkg_status -r >>EOO;
+ !libfoo configured 1.0.0
+ !fux configured 1.0.0
+ !libfoo configured 1.0.0
+ !fex configured !0.1.0 available 1.0.0
+ !fux configured 1.0.0
+ !libfoo configured 1.0.0
+ EOO
+
+ cat cfg/fux-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.fux.extras = true
+ config.fux.network = false
+ %.*
+ EOO
+
+ $* libfoo/0.1.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !libfoo configured !0.1.0 available 1.0.0
+ !fux configured 1.0.0
+ !libfoo configured !0.1.0 available 1.0.0
+ !fex configured !0.1.0 available 1.0.0
+ !fux configured 1.0.0
+ !libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ cat cfg/fux-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.fux.extras = true
+ config.fux.network = false
+ %.*
+ EOO
+
+ $pkg_drop fex fux libfoo
+ }
+
+ : dept-upgrade
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # fux: depends: libfoo ?
+ #
+ $* fux/0.1.0 +{ config.fux.extras=true } 2>!;
+
+ $pkg_status -r >>EOO;
+ !fux configured !0.1.0 available 1.0.0 0.2.0 0.1.1
+ libfoo configured 1.0.0
+ EOO
+
+ cat cfg/fux-0.1.0/build/config.build >>~%EOO%;
+ %.*
+ config.fux.extras = true
+ config.fux.network = false
+ %.*
+ EOO
+
+ $* fux/0.1.1 2>!;
+
+ $pkg_status -r >>EOO;
+ !fux configured !0.1.1 available 1.0.0 0.2.0
+ libfoo configured 1.0.0
+ EOO
+
+ cat cfg/fux-0.1.1/build/config.build >>~%EOO%;
+ %.*
+ config.fux.extras = true
+ config.fux.network = false
+ %.*
+ EOO
+
+ $pkg_drop fux
+ }
+
+ : dept-depc
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # fux: depends: libfoo
+ #
+ $* fux +{ config.fux.extras=true } ?libfoo +{ config.libfoo.extras=true } 2>!;
+
+ $pkg_status -r >>EOO;
+ !fux configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ cat cfg/fux-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.fux.extras = true
+ config.fux.network = false
+ %.*
+ EOO
+
+ cat cfg/libfoo-1.0.0/build2/config.build2 >>~%EOO%;
+ %.*
+ config.libfoo.extras = true
+ config.libfoo.network = false
+ %.*
+ EOO
+
+ $* ?libfoo/0.1.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !fux configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ cat cfg/fux-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.fux.extras = true
+ config.fux.network = false
+ %.*
+ EOO
+
+ cat cfg/libfoo-0.1.0/build/config.build >>~%EOO%;
+ %.*
+ config.libfoo.extras = true
+ EOO
+
+ $pkg_drop fux
+ }
+
+ : dept-depc-no-plan
+ :
+ : As above but the configuration is not printed (as a part of the
+ : plan) before the plan execution.
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # fux: depends: libfoo
+ #
+ $* fux +{ config.fux.extras=true } ?libfoo +{ config.libfoo.extras=true } 2>!;
+
+ $pkg_status -r >>EOO;
+ !fux configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ cat cfg/fux-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.fux.extras = true
+ config.fux.network = false
+ %.*
+ EOO
+
+ cat cfg/libfoo-1.0.0/build2/config.build2 >>~%EOO%;
+ %.*
+ config.libfoo.extras = true
+ config.libfoo.network = false
+ EOO
+
+ test.arguments = $regex.filter_out_match($test.arguments, '--plan=.*');
+
+ $* ?libfoo/0.1.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !fux configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ cat cfg/fux-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.fux.extras = true
+ config.fux.network = false
+ %.*
+ EOO
+
+ cat cfg/libfoo-0.1.0/build/config.build >>~%EOO%;
+ %.*
+ config.libfoo.extras = true
+ EOO
+
+ $pkg_drop fux
+ }
+ }
+
+ : enabled-clause
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # fex: depends: fux(c)
+ #
+ # fux: depends: libfoo ?
+ #
+ $* fex/0.1.0 fux/0.1.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !fux configured !0.1.0 available 1.0.0 0.2.0 0.1.1
+ libfoo configured 1.0.0
+ !fex configured !0.1.0 available 1.0.0
+ !fux configured !0.1.0 available 1.0.0 0.2.0 0.1.1
+ libfoo configured 1.0.0
+ EOO
+
+ cat cfg/fux-0.1.0/build/config.build >>~%EOO%;
+ %.*
+ config.fux.extras = true
+ config.fux.network = false
+ %.*
+ EOO
+
+ $* ?libfoo/0.1.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !fux configured !0.1.0 available 1.0.0 0.2.0 0.1.1
+ libfoo configured !0.1.0 available 1.0.0
+ !fex configured !0.1.0 available 1.0.0
+ !fux configured !0.1.0 available 1.0.0 0.2.0 0.1.1
+ libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ cat cfg/fux-0.1.0/build/config.build >>~%EOO%;
+ %.*
+ config.fux.extras = true
+ config.fux.network = false
+ %.*
+ EOO
+
+ $pkg_drop fex fux
+ }
+
+ : require-clause
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # fex: depends: fux(c)
+ #
+ # fux: depends: libfoo(c) ?
+ #
+ $* fex/0.1.0 fux/0.2.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !fux configured !0.2.0 available 1.0.0
+ libfoo configured 1.0.0
+ !fex configured !0.1.0 available 1.0.0
+ !fux configured !0.2.0 available 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ cat cfg/fux-0.2.0/build/config.build >>~%EOO%;
+ %.*
+ config.fux.extras = true
+ config.fux.network = false
+ %.*
+ EOO
+
+ cat cfg/libfoo-1.0.0/build2/config.build2 >>~%EOO%;
+ %.*
+ config.libfoo.extras = true
+ config.libfoo.network = false
+ %.*
+ EOO
+
+ $* ?libfoo/0.1.0 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: execute_plan: simulate: yes
+ trace: evaluate_dependency: libfoo/1.0.0: update to libfoo/0.1.0
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_build_prerequisites: pre-reeval fux/0.2.0
+ trace: collect_build_prerequisites: pre-reevaluated fux/0.2.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent fux/0.2.0 due to dependency libfoo/0.1.0
+ trace: collect_build: add fux/0.2.0
+ trace: postponed_configurations::add: create {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_prerequisites: pre-reeval fux/0.2.0
+ trace: collect_build_prerequisites: pre-reevaluated fux/0.2.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_prerequisites: reeval fux/0.2.0
+ trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0
+ trace: postponed_configurations::add: add {fux^ 1,1: libfoo} to {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent fux/0.2.0 results in {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_prerequisites: re-evaluated fux/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/0.1.0
+ trace: collect_build_prerequisites: end libfoo/0.1.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent fux/0.2.0
+ trace: collect_build_prerequisites: resume fux/0.2.0
+ trace: collect_build_prerequisites: end fux/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {fux^ | libfoo->{fux/1,1}}!
+ trace: collect_build_postponed (1): end {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ downgrade libfoo/0.1.0
+ config.libfoo.extras=true (set by fux)
+ reconfigure fux/0.2.0 (dependent of libfoo)
+ config.fux.extras=true (dependent configuration)
+ reconfigure fex (dependent of fux)
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !fux configured !0.2.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !fex configured !0.1.0 available 1.0.0
+ !fux configured !0.2.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ cat cfg/fux-0.2.0/build/config.build >>~%EOO%;
+ %.*
+ config.fux.extras = true
+ config.fux.network = false
+ %.*
+ EOO
+
+ cat cfg/libfoo-0.1.0/build/config.build >>~%EOO%;
+ %.*
+ config.libfoo.extras = true
+ EOO
+
+ $* ?fex ?fux libfoo/0.1.0 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfoo/0.1.0
+ trace: collect_build_prerequisites: skip configured libfoo/0.1.0
+ trace: execute_plan: simulate: yes
+ trace: evaluate_dependency: fux/0.2.0: update to fux/1.0.0
+ trace: evaluate_dependency: fex/0.1.0: unused
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_build_prerequisites: pre-reeval fex/0.1.0
+ trace: collect_build_prerequisites: pre-reevaluated fex/0.1.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency fux/1.0.0 of existing dependent fex/0.1.0 due to dependency fux/1.0.0
+ trace: postponed_configurations::add: create {fex^ | fux->{fex/1,1}}
+ trace: collect_drop: fex/0.1.0 package version needs to be replaced with drop
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfoo/0.1.0
+ trace: collect_build_prerequisites: skip configured libfoo/0.1.0
+ trace: collect_build_prerequisites: skip expected to be dropped existing dependent fex of dependency fux
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/0.1.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: collect_drop: overwrite fex
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: fux/1.0.0: unused
+ trace: pkg_build: one of dependency evaluation decisions has changed, re-collecting from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfoo/0.1.0
+ trace: collect_build_prerequisites: skip configured libfoo/0.1.0
+ trace: collect_drop: overwrite fex
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: fux/0.2.0: unused
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_drop: overwrite fex
+ trace: collect_drop: overwrite fux
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ drop fux/0.2.0 (unused)
+ drop fex/0.1.0 (unused)
+ update libfoo/0.1.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ cat cfg/libfoo-0.1.0/build/config.build >>~%EOO%;
+ %.*
+ config.libfoo.extras = true
+ EOO
+
+ $pkg_drop libfoo
+ }
+
+ : require-clause-user-config
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # fex: depends: fux(c)
+ #
+ # fux: depends: libfoo(c) ?
+ #
+ $* fex/0.1.0 fux/0.2.0 +{ config.fux.network=true } 2>!;
+
+ $pkg_status -r >>EOO;
+ !fux configured !0.2.0 available 1.0.0
+ libfoo configured 1.0.0
+ !fex configured !0.1.0 available 1.0.0
+ !fux configured !0.2.0 available 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ cat cfg/fux-0.2.0/build/config.build >>~%EOO%;
+ %.*
+ config.fux.extras = true
+ config.fux.network = true
+ %.*
+ EOO
+
+ cat cfg/libfoo-1.0.0/build2/config.build2 >>~%EOO%;
+ %.*
+ config.libfoo.extras = true
+ config.libfoo.network = false
+ %.*
+ EOO
+
+ $* ?libfoo/0.1.0 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: execute_plan: simulate: yes
+ trace: evaluate_dependency: libfoo/1.0.0: update to libfoo/0.1.0
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_build_prerequisites: pre-reeval fux/0.2.0
+ trace: collect_build_prerequisites: pre-reevaluated fux/0.2.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent fux/0.2.0 due to dependency libfoo/0.1.0
+ trace: collect_build: add fux/0.2.0
+ trace: postponed_configurations::add: create {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_prerequisites: pre-reeval fux/0.2.0
+ trace: collect_build_prerequisites: pre-reevaluated fux/0.2.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_prerequisites: reeval fux/0.2.0
+ trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0
+ trace: postponed_configurations::add: add {fux^ 1,1: libfoo} to {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent fux/0.2.0 results in {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_prerequisites: re-evaluated fux/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/0.1.0
+ trace: collect_build_prerequisites: end libfoo/0.1.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent fux/0.2.0
+ trace: collect_build_prerequisites: resume fux/0.2.0
+ trace: collect_build_prerequisites: end fux/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {fux^ | libfoo->{fux/1,1}}!
+ trace: collect_build_postponed (1): end {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ downgrade libfoo/0.1.0
+ config.libfoo.extras=true (set by fux)
+ reconfigure fux/0.2.0 (dependent of libfoo)
+ config.fux.network=true (user configuration)
+ config.fux.extras=true (dependent configuration)
+ reconfigure fex (dependent of fux)
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !fux configured !0.2.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !fex configured !0.1.0 available 1.0.0
+ !fux configured !0.2.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ cat cfg/fux-0.2.0/build/config.build >>~%EOO%;
+ %.*
+ config.fux.extras = true
+ config.fux.network = true
+ %.*
+ EOO
+
+ cat cfg/libfoo-0.1.0/build/config.build >>~%EOO%;
+ %.*
+ config.libfoo.extras = true
+ %.*
+ EOO
+
+ $* ?fex ?libfoo 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: execute_plan: simulate: yes
+ trace: evaluate_dependency: libfoo/0.1.0: update to libfoo/1.0.0
+ trace: evaluate_dependency: fex/0.1.0: unused
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_build_prerequisites: pre-reeval fux/0.2.0
+ trace: collect_build_prerequisites: pre-reevaluated fux/0.2.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent fux/0.2.0 due to dependency libfoo/1.0.0
+ trace: collect_build: add fux/0.2.0
+ trace: postponed_configurations::add: create {fux^ | libfoo->{fux/1,1}}
+ trace: collect_drop: overwrite fex
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_prerequisites: pre-reeval fux/0.2.0
+ trace: collect_build_prerequisites: pre-reevaluated fux/0.2.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_prerequisites: reeval fux/0.2.0
+ trace: collect_build: pick libfoo/1.0.0 over libfoo/0.1.0
+ trace: postponed_configurations::add: add {fux^ 1,1: libfoo} to {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent fux/0.2.0 results in {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_prerequisites: re-evaluated fux/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent fux/0.2.0
+ trace: collect_build_prerequisites: resume fux/0.2.0
+ trace: collect_build_prerequisites: end fux/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {fux^ | libfoo->{fux/1,1}}!
+ trace: collect_build_postponed (1): end {fux^ | libfoo->{fux/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ upgrade libfoo/1.0.0
+ config.libfoo.extras=true (set by fux)
+ reconfigure fux/0.2.0 (dependent of libfoo)
+ config.fux.network=true (user configuration)
+ config.fux.extras=true (user configuration)
+ drop fex/0.1.0 (unused)
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_drop fux
+ }
+ }
+
: premature
:
{
@@ -5302,143 +9278,67 @@ test.options += --no-progress
$pkg_drop fux foo fox
}
- : bogus-postponment
+ : bogus-postponement
:
{
$clone_cfg;
- $* fux foo fix 2>>~%EOE%;
- %.*
- trace: pkg_build: refine package collection/plan execution from scratch
- %.*
- trace: collect_build: add fux/1.0.0
- trace: collect_build: add foo/1.0.0
- trace: collect_build: add fix/1.0.0
- trace: collect_build_prerequisites: begin fux/1.0.0
- %.*
- trace: collect_build: add libfoo/1.0.0
- trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent fux/1.0.0
- trace: collect_build_prerequisites: begin libfoo/1.0.0
- trace: collect_build_prerequisites: end libfoo/1.0.0
- trace: collect_build_prerequisites: end fux/1.0.0
- trace: collect_build_prerequisites: begin foo/1.0.0
- %.*
- trace: collect_build_prerequisites: cannot cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0 (collected prematurely), throwing postpone_dependency
- trace: pkg_build: collection failed due to prematurely collected dependency (libfoo), retry from scratch
- %.*
- trace: pkg_build: refine package collection/plan execution from scratch
- %.*
- trace: collect_build: add fux/1.0.0
- trace: collect_build: add foo/1.0.0
- trace: collect_build: add fix/1.0.0
- trace: collect_build_prerequisites: begin fux/1.0.0
- %.*
- trace: collect_build: add libfoo/1.0.0
- trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0
- trace: collect_build_prerequisites: end fux/1.0.0
- trace: collect_build_prerequisites: begin foo/1.0.0
- %.*
- trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
- trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
- trace: collect_build_prerequisites: postpone foo/1.0.0
- trace: collect_build_prerequisites: begin fix/1.0.0
- %.*
- trace: collect_build_prerequisites: cannot cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0 (collected prematurely), throwing postpone_dependency
- trace: pkg_build: collection failed due to prematurely collected dependency (foo), retry from scratch
- %.*
- trace: pkg_build: refine package collection/plan execution from scratch
- %.*
- trace: collect_build: add fux/1.0.0
- trace: collect_build: add foo/1.0.0
- trace: collect_build: add fix/1.0.0
- trace: collect_build_prerequisites: begin fux/1.0.0
- %.*
- trace: collect_build: add libfoo/1.0.0
- trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0
- trace: collect_build_prerequisites: end fux/1.0.0
- trace: pkg_build: dep-postpone user-specified foo
- trace: collect_build_prerequisites: begin fix/1.0.0
- %.*
- trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0
- trace: postponed_configurations::add: create {fix | foo->{fix/1,1}}
- trace: collect_build_prerequisites: postpone fix/1.0.0
- trace: pkg_build: erase bogus postponement libfoo
- trace: pkg_build: bogus postponements erased, throwing
- trace: pkg_build: collection failed due to bogus dependency collection postponement cancellation, retry from scratch
+ # Dependencies:
+ #
+ # fux: depends: libfoo
+ #
+ # foo: depends: libfoo(c)
+ #
+ # fix: depends: foo(c)
+ #
+ $* fux foo fix 2>&1 | $filter 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add fux/1.0.0
trace: collect_build: add foo/1.0.0
trace: collect_build: add fix/1.0.0
trace: collect_build_prerequisites: begin fux/1.0.0
- %.*
trace: collect_build: add libfoo/1.0.0
trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent fux/1.0.0
trace: collect_build_prerequisites: begin libfoo/1.0.0
trace: collect_build_prerequisites: end libfoo/1.0.0
trace: collect_build_prerequisites: end fux/1.0.0
- trace: pkg_build: dep-postpone user-specified foo
- trace: collect_build_prerequisites: begin fix/1.0.0
- %.*
- trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0
- trace: postponed_configurations::add: create {fix | foo->{fix/1,1}}
- trace: collect_build_prerequisites: postpone fix/1.0.0
- trace: collect_build_postponed (0): begin
- trace: collect_build_postponed (1): begin {fix | foo->{fix/1,1}}
- %.*
- trace: collect_build_postponed (1): cfg-negotiate begin {fix | foo->{fix/1,1}}
- %.*
- trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin foo/1.0.0
- %.*
trace: collect_build_prerequisites: cannot cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0 (collected prematurely), throwing postpone_dependency
trace: pkg_build: collection failed due to prematurely collected dependency (libfoo), retry from scratch
- %.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add fux/1.0.0
trace: collect_build: add foo/1.0.0
trace: collect_build: add fix/1.0.0
trace: collect_build_prerequisites: begin fux/1.0.0
- %.*
trace: collect_build: add libfoo/1.0.0
trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0
trace: collect_build_prerequisites: end fux/1.0.0
trace: collect_build_prerequisites: begin foo/1.0.0
- %.*
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
trace: collect_build_prerequisites: postpone foo/1.0.0
trace: collect_build_prerequisites: begin fix/1.0.0
- %.*
trace: collect_build_prerequisites: cannot cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0 (collected prematurely), throwing postpone_dependency
trace: pkg_build: collection failed due to prematurely collected dependency (foo), retry from scratch
- %.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add fux/1.0.0
trace: collect_build: add foo/1.0.0
trace: collect_build: add fix/1.0.0
trace: collect_build_prerequisites: begin fux/1.0.0
- %.*
trace: collect_build: add libfoo/1.0.0
trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0
trace: collect_build_prerequisites: end fux/1.0.0
trace: pkg_build: dep-postpone user-specified foo
trace: collect_build_prerequisites: begin fix/1.0.0
- %.*
trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0
trace: postponed_configurations::add: create {fix | foo->{fix/1,1}}
trace: collect_build_prerequisites: postpone fix/1.0.0
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {fix | foo->{fix/1,1}}
- %.*
trace: collect_build_postponed (1): cfg-negotiate begin {fix | foo->{fix/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin foo/1.0.0
- %.*
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
trace: collect_build_prerequisites: postpone foo/1.0.0
@@ -5448,9 +9348,7 @@ test.options += --no-progress
trace: collect_build_prerequisites: end fix/1.0.0
trace: collect_build_postponed (1): cfg-negotiate end {fix | foo->{fix/1,1}}!
trace: collect_build_postponed (2): begin {foo | libfoo->{foo/1,1}}
- %.*
trace: collect_build_postponed (2): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
- %.*
trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libfoo/1.0.0
trace: collect_build_prerequisites: end libfoo/1.0.0
@@ -5464,6 +9362,16 @@ test.options += --no-progress
trace: collect_build_postponed (0): end
trace: execute_plan: simulate: yes
%.*
+ build plan:
+ new libfoo/1.0.0 (required by foo, fux)
+ config.libfoo.extras=true (set by foo)
+ new fux/1.0.0
+ new foo/1.0.0
+ config.foo.extras=true (set by fix)
+ config.foo.libfoo_extras=true (set by foo)
+ new fix/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
EOE
$pkg_status -r >>EOO;
@@ -5490,7 +9398,7 @@ test.options += --no-progress
{
$clone_cfg;
- $* libfoo 2>!;
+ $* libfoo --verbose 1 2>!;
$* foo 2>>~%EOE%;
%.*
@@ -5546,7 +9454,11 @@ test.options += --no-progress
{
$clone_cfg;
- $* foo 2>>~%EOE%;
+ # Dependencies:
+ #
+ # foo/1.0.0: depends: libfoo(c)
+ #
+ $* foo +{ config.foo.extras=true } 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
%.*
@@ -5574,8 +9486,34 @@ test.options += --no-progress
trace: collect_build_postponed (0): end
trace: execute_plan: simulate: yes
%.*
+ build plan:
+ new libfoo/1.0.0 (required by foo)
+ config.libfoo.extras=true (set by foo)
+ new foo/1.0.0
+ config.foo.extras=true (user configuration)
+ config.foo.libfoo_extras=true (set by foo)
+ trace: execute_plan: simulate: no
+ %.*
EOE
+ $pkg_status -r >>EOO;
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ cat cfg/foo-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.foo.extras = true
+ config.foo.libfoo_extras = true
+ %.*
+ EOO
+
+ cat cfg/libfoo-1.0.0/build2/config.build2 >>~%EOO%;
+ %.*
+ config.libfoo.extras = true
+ %.*
+ EOO
+
# Downgrade the dependency.
#
$* ?libfoo/0.1.0 2>>~%EOE%;
@@ -5588,13 +9526,19 @@ test.options += --no-progress
%.*
trace: pkg_build: refine package collection/plan execution
%.*
- trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent foo/1.0.0
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent foo/1.0.0 due to dependency libfoo/0.1.0
+ trace: collect_build: add foo/1.0.0
trace: postponed_configurations::add: create {foo^ | libfoo->{foo/1,1}}
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {foo^ | libfoo->{foo/1,1}}
%.*
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1
trace: collect_build_postponed (1): re-evaluate existing dependents for {foo^ | libfoo->{foo/1,1}}
- trace: collect_build: add foo/1.0.0
trace: collect_build_prerequisites: reeval foo/1.0.0
%.*
trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0
@@ -5642,6 +9586,19 @@ test.options += --no-progress
libfoo configured !0.1.0 available 1.0.0
EOO
+ cat cfg/foo-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.foo.extras = true
+ config.foo.libfoo_extras = true
+ %.*
+ EOO
+
+ cat cfg/libfoo-0.1.0/build/config.build >>~%EOO%;
+ %.*
+ config.libfoo.extras = true
+ %.*
+ EOO
+
# Reconfigure the dependency and hold.
#
$* libfoo/0.1.0 +{ config.libfoo.extras=true } 2>>~%EOE%;
@@ -5650,14 +9607,19 @@ test.options += --no-progress
%.*
trace: collect_build: add libfoo/0.1.0
%.*
- trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent foo/1.0.0
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent foo/1.0.0 due to dependency libfoo/0.1.0
+ trace: collect_build: add foo/1.0.0
trace: postponed_configurations::add: create {foo^ | libfoo->{foo/1,1}}
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {foo^ | libfoo->{foo/1,1}}
%.*
- trace: collect_build_postponed (1): re-evaluate existing dependents for {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
%.*
- trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {foo^ | libfoo->{foo/1,1}}
trace: collect_build_prerequisites: reeval foo/1.0.0
%.*
trace: postponed_configurations::add: add {foo^ 1,1: libfoo} to {foo^ | libfoo->{foo/1,1}}
@@ -5702,6 +9664,19 @@ test.options += --no-progress
!libfoo configured !0.1.0 available 1.0.0
EOO
+ cat cfg/foo-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.foo.extras = true
+ config.foo.libfoo_extras = true
+ %.*
+ EOO
+
+ cat cfg/libfoo-0.1.0/build/config.build >>~%EOO%;
+ %.*
+ config.libfoo.extras = true
+ %.*
+ EOO
+
# Upgrade the dependency and unhold existing dependent.
#
$* libfoo ?foo 2>>~%EOE%;
@@ -5710,11 +9685,17 @@ test.options += --no-progress
%.*
trace: collect_build: add libfoo/1.0.0
%.*
- trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent foo/1.0.0
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent foo/1.0.0 due to dependency libfoo/1.0.0
trace: postponed_configurations::add: create {foo^ | libfoo->{foo/1,1}}
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {foo^ | libfoo->{foo/1,1}}
%.*
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1
trace: collect_build_postponed (1): re-evaluate existing dependents for {foo^ | libfoo->{foo/1,1}}
trace: collect_build_prerequisites: reeval foo/1.0.0
%.*
@@ -5739,8 +9720,15 @@ test.options += --no-progress
%.*
trace: evaluate_dependency: foo/1.0.0: unused
%.*
- trace: pkg_build: refine package collection/plan execution
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
%.*
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent foo/1.0.0 due to dependency libfoo/1.0.0
+ trace: postponed_configurations::add: create {foo^ | libfoo->{foo/1,1}}
trace: collect_drop: foo/1.0.0 package version needs to be replaced with drop
trace: pkg_build: collection failed due to package version replacement, retry from scratch
%.*
@@ -5757,6 +9745,7 @@ test.options += --no-progress
%.*
build plan:
upgrade libfoo/1.0.0
+ config.libfoo.extras=true (user configuration)
drop foo/1.0.0 (unused)
%.*
disfigured foo/1.0.0
@@ -5779,9 +9768,240 @@ test.options += --no-progress
!libfoo configured 1.0.0
EOO
+ cat cfg/libfoo-1.0.0/build2/config.build2 >>~%EOO%;
+ %.*
+ config.libfoo.extras = true
+ %.*
+ EOO
+
$pkg_drop libfoo
}
+ : multiple-dependents
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # foo/1.0.0: depends: libfoo(c)
+ # fox/1.0.0: depends: libfoo(c)
+ #
+ $* libfoo/0.1.0 foo/1.0.0 fox/1.0.0 --verbose 1 2>!;
+
+ $pkg_status -r >>EOO;
+ !libfoo configured !0.1.0 available 1.0.0
+ !foo configured !1.0.0
+ !libfoo configured !0.1.0 available 1.0.0
+ !fox configured !1.0.0
+ !libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ $* libfoo 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval fox/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated fox/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent foo/1.0.0 due to dependency libfoo/1.0.0
+ trace: collect_build: add foo/1.0.0
+ trace: postponed_configurations::add: create {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent fox/1.0.0 due to dependency libfoo/1.0.0
+ trace: collect_build: add fox/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval fox/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated fox/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: reeval foo/1.0.0
+ trace: collect_build: pick libfoo/1.0.0 over libfoo/0.1.0
+ trace: postponed_configurations::add: add {foo^ 1,1: libfoo} to {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent foo/1.0.0 results in {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: re-evaluated foo/1.0.0
+ trace: collect_build_prerequisites: reeval fox/1.0.0
+ trace: collect_build: pick libfoo/1.0.0 over libfoo/0.1.0
+ trace: postponed_configurations::add: add {fox^ 1,1: libfoo} to {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent fox/1.0.0 results in {foo^ fox^ | libfoo->{foo/1,1 fox/1,1}}
+ trace: collect_build_prerequisites: re-evaluated fox/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {foo^ fox^ | libfoo->{foo/1,1 fox/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent fox/1.0.0
+ trace: collect_build_prerequisites: resume fox/1.0.0
+ trace: collect_build_prerequisites: end fox/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {foo^ fox^ | libfoo->{foo/1,1 fox/1,1}}!
+ trace: collect_build_postponed (1): end {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ upgrade libfoo/1.0.0
+ config.libfoo.extras=true (set by foo)
+ reconfigure fox/1.0.0 (dependent of libfoo)
+ config.fox.libfoo_extras=true (set by fox)
+ reconfigure foo/1.0.0 (dependent of libfoo)
+ config.foo.libfoo_extras=true (set by foo)
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !libfoo configured 1.0.0
+ !foo configured !1.0.0
+ !libfoo configured 1.0.0
+ !fox configured !1.0.0
+ !libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop libfoo foo fox
+ }
+
+ : postpone-existing-dependency
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # bus: depends: foo(c)
+ #
+ # fix: depends: foo == 0.1.0
+ #
+ # biz/0.1.0: depends: libbiz == 0.1.0
+ #
+ # libbiz/1.0.0: depends: libbar
+ # libbiz/0.1.0:
+ #
+ # foo: depends: libfoo(c)
+ #
+ $* bus/0.1.0 --verbose 1 2>!;
+
+ $pkg_status -r >>EOO;
+ !bus configured !0.1.0 available 1.0.0
+ foo configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $* fix/0.1.0 libbiz biz/0.1.0 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add fix/0.1.0
+ trace: collect_build: add libbiz/1.0.0
+ trace: collect_build: add biz/0.1.0
+ trace: collect_build_prerequisites: begin fix/0.1.0
+ trace: collect_build: add foo/0.1.0
+ info: package fix dependency on (foo == 0.1.0) is forcing downgrade of foo/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency foo/0.1.0 of dependent fix/0.1.0
+ trace: collect_build_prerequisites: pre-reeval bus/0.1.0
+ trace: collect_build_prerequisites: pre-reevaluated bus/0.1.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/0.1.0 of existing dependent bus/0.1.0 due to dependency foo/0.1.0
+ trace: collect_build: add bus/0.1.0
+ trace: postponed_configurations::add: create {bus^ | foo->{bus/1,1}}
+ trace: collect_build_prerequisites: end fix/0.1.0
+ trace: collect_build_prerequisites: begin libbiz/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent libbiz/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: end libbiz/1.0.0
+ trace: collect_build_prerequisites: begin biz/0.1.0
+ trace: collect_build: pick libbiz/0.1.0 over libbiz/1.0.0
+ trace: collect_build: libbiz/1.0.0 package version needs to be replaced with libbiz/0.1.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add fix/0.1.0
+ trace: collect_build: apply version replacement for libbiz/1.0.0
+ trace: collect_build: replacement: libbiz/0.1.0
+ trace: collect_build: add libbiz/0.1.0
+ trace: collect_build: add biz/0.1.0
+ trace: collect_build_prerequisites: begin fix/0.1.0
+ trace: collect_build: add foo/0.1.0
+ info: package fix dependency on (foo == 0.1.0) is forcing downgrade of foo/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency foo/0.1.0 of dependent fix/0.1.0
+ trace: collect_build_prerequisites: pre-reeval bus/0.1.0
+ trace: collect_build_prerequisites: pre-reevaluated bus/0.1.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/0.1.0 of existing dependent bus/0.1.0 due to dependency foo/0.1.0
+ trace: collect_build: add bus/0.1.0
+ trace: postponed_configurations::add: create {bus^ | foo->{bus/1,1}}
+ trace: collect_build_prerequisites: end fix/0.1.0
+ trace: collect_build_prerequisites: begin libbiz/0.1.0
+ trace: collect_build_prerequisites: end libbiz/0.1.0
+ trace: collect_build_prerequisites: begin biz/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbiz/0.1.0 of dependent biz/0.1.0
+ trace: collect_build_prerequisites: end biz/0.1.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bus^ | foo->{bus/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bus/0.1.0
+ trace: collect_build_prerequisites: pre-reevaluated bus/0.1.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bus^ | foo->{bus/1,1}}
+ trace: collect_build_prerequisites: reeval bus/0.1.0
+ trace: collect_build: pick foo/0.1.0 over foo/1.0.0
+ trace: postponed_configurations::add: add {bus^ 1,1: foo} to {bus^ | foo->{bus/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bus/0.1.0 results in {bus^ | foo->{bus/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bus/0.1.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bus^ | foo->{bus/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin foo/0.1.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/0.1.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/0.1.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bus/0.1.0
+ trace: collect_build_prerequisites: resume bus/0.1.0
+ trace: collect_build_prerequisites: end bus/0.1.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bus^ | foo->{bus/1,1}}!
+ trace: collect_build_postponed (2): begin {foo | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent foo of dependency libfoo
+ trace: collect_build_postponed (2): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent foo/0.1.0
+ trace: collect_build_prerequisites: resume foo/0.1.0
+ trace: collect_build_prerequisites: end foo/0.1.0
+ trace: collect_build_postponed (2): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
+ trace: collect_build_postponed (2): end {foo | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (1): end {bus^ | foo->{bus/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ downgrade foo/0.1.0 (required by bus, fix)
+ config.foo.extras=true (set by bus)
+ reconfigure bus/0.1.0 (dependent of foo)
+ config.bus.foo_extras=true (set by bus)
+ new fix/0.1.0
+ new libbiz/0.1.0
+ new biz/0.1.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bus configured !0.1.0 available 1.0.0
+ foo configured 0.1.0 available 1.0.0 0.2.0
+ libfoo configured 1.0.0
+ !fix configured !0.1.0 available 1.0.0
+ foo configured 0.1.0 available 1.0.0 0.2.0
+ libfoo configured 1.0.0
+ !libbiz configured 0.1.0 available 1.0.0
+ !biz configured !0.1.0 available 1.0.0
+ !libbiz configured 0.1.0 available 1.0.0
+ EOO
+
+ $pkg_drop bus fix libbiz biz
+ }
+
: postpone-existing
:
{
@@ -5795,61 +10015,57 @@ test.options += --no-progress
# fix/0.1.0: depends: foo == 0.1.0
# foo/0.1.0: depends: libfoo(c)
#
- $* fix 2>!;
+ $* fix --verbose 1 2>!;
+
+ $pkg_status -r >>EOO;
+ !fix configured 1.0.0
+ foo configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
- $* libfoo/0.1.0 fix/0.1.0 2>>~%EOE%;
+ $* libfoo/0.1.0 fix/0.1.0 2>&1 | $filter 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add libfoo/0.1.0
trace: collect_build: add fix/0.1.0
- %.*
- trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent foo/1.0.0
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent foo/1.0.0 due to dependency libfoo/0.1.0
+ trace: collect_build: add foo/1.0.0
trace: postponed_configurations::add: create {foo^ | libfoo->{foo/1,1}}
- %.*
trace: collect_build_prerequisites: begin fix/0.1.0
- %.*
+ trace: collect_build: pick foo/0.1.0 over foo/1.0.0
+ trace: collect_build: foo/1.0.0 package version needs to be replaced with foo/0.1.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add libfoo/0.1.0
trace: collect_build: add fix/0.1.0
- %.*
trace: collect_build_prerequisites: skip expected to be built existing dependent foo of dependency libfoo
trace: collect_build_prerequisites: begin libfoo/0.1.0
trace: collect_build_prerequisites: end libfoo/0.1.0
- %.*
trace: collect_build_prerequisites: begin fix/0.1.0
- %.*
trace: collect_build: apply version replacement for foo/0.1.0
trace: collect_build: replacement: foo/0.1.0
trace: collect_build: add foo/0.1.0
info: package fix dependency on (foo == 0.1.0) is forcing downgrade of foo/1.0.0 to 0.1.0
trace: collect_build_prerequisites: no cfg-clause for dependency foo/0.1.0 of dependent fix/0.1.0
- %.*
trace: collect_build_prerequisites: skip being built existing dependent fix of dependency foo
trace: collect_build_prerequisites: begin foo/0.1.0
- %.*
trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0
trace: collect_build_prerequisites: cannot cfg-postpone dependency libfoo/0.1.0 of dependent foo/0.1.0 (collected prematurely), throwing postpone_dependency
trace: pkg_build: collection failed due to prematurely collected dependency (libfoo), retry from scratch
- %.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add libfoo/0.1.0
trace: collect_build: add fix/0.1.0
trace: pkg_build: dep-postpone user-specified libfoo
- %.*
trace: collect_build_prerequisites: begin fix/0.1.0
- %.*
trace: collect_build: apply version replacement for foo/0.1.0
trace: collect_build: replacement: foo/0.1.0
trace: collect_build: add foo/0.1.0
info: package fix dependency on (foo == 0.1.0) is forcing downgrade of foo/1.0.0 to 0.1.0
trace: collect_build_prerequisites: no cfg-clause for dependency foo/0.1.0 of dependent fix/0.1.0
- %.*
trace: collect_build_prerequisites: skip being built existing dependent fix of dependency foo
trace: collect_build_prerequisites: begin foo/0.1.0
- %.*
trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of dependent foo/0.1.0
trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
@@ -5857,10 +10073,8 @@ test.options += --no-progress
trace: collect_build_prerequisites: end fix/0.1.0
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {foo | libfoo->{foo/1,1}}
- %.*
trace: collect_build_postponed (1): skip being built existing dependent foo of dependency libfoo
trace: collect_build_postponed (1): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libfoo/0.1.0
trace: collect_build_prerequisites: end libfoo/0.1.0
@@ -5871,9 +10085,16 @@ test.options += --no-progress
trace: collect_build_postponed (1): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
trace: collect_build_postponed (1): end {foo | libfoo->{foo/1,1}}
trace: collect_build_postponed (0): end
- %.*
trace: execute_plan: simulate: yes
%.*
+ build plan:
+ downgrade libfoo/0.1.0
+ config.libfoo.extras=true (set by foo)
+ downgrade foo/0.1.0 (required by fix)
+ config.foo.extras=true (dependent configuration)
+ downgrade fix/0.1.0
+ trace: execute_plan: simulate: no
+ %.*
EOE
$pkg_status -r >>EOO;
@@ -5902,56 +10123,51 @@ test.options += --no-progress
# tex: depends: libbar(c)
# depends: libfoo(c)
#
- $* tex 2>!;
+ $* tex --verbose 1 2>!;
+
+ $pkg_status -r >>EOO;
+ !tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
- $* libfoo/0.1.0 libbar/0.1.0 2>>~%EOE%;
+ $* libfoo/0.1.0 libbar/0.1.0 2>&1 | $filter 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add libfoo/0.1.0
trace: collect_build: add libbar/0.1.0
- %.*
- trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent tex/1.0.0
- trace: postponed_configurations::add: create {tex^ | libfoo->{tex/2,1}}
- %.*
- trace: collect_build_prerequisites: cfg-postpone dependency libbar/0.1.0 of existing dependent tex/1.0.0
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build: pick libbar/0.1.0 over libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/0.1.0 of existing dependent tex/1.0.0 due to dependency libfoo/0.1.0
+ trace: collect_build: add tex/1.0.0
trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}}
+ trace: pkg_build: dep-postpone user-specified libbar since already in cluster {tex^ | libbar->{tex/1,1}}
trace: collect_build_postponed (0): begin
- trace: collect_build_postponed (1): begin {tex^ | libfoo->{tex/2,1}}
- %.*
- trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libfoo->{tex/2,1}}
- trace: collect_build_postponed (1): cannot re-evaluate dependent tex to dependency index 2 due to earlier dependency index 1 in {tex^ | libbar->{tex/1,1}}, skipping {tex^ | libfoo->{tex/2,1}}
- trace: collect_build_postponed (0): postpone cfg-negotiation of {tex^ | libfoo->{tex/2,1}}
trace: collect_build_postponed (1): begin {tex^ | libbar->{tex/1,1}}
- %.*
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libbar->{tex/1,1}}
- %.*
- trace: collect_build: add tex/1.0.0
trace: collect_build_prerequisites: reeval tex/1.0.0
- %.*
trace: collect_build: pick libbar/0.1.0 over libbar/1.0.0
trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {tex^ | libbar->{tex/1,1}}
trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ | libbar->{tex/1,1}}
trace: collect_build_prerequisites: re-evaluated tex/1.0.0
trace: collect_build_postponed (1): cfg-negotiate begin {tex^ | libbar->{tex/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libbar/0.1.0
trace: collect_build_prerequisites: end libbar/0.1.0
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tex/1.0.0
trace: collect_build_prerequisites: resume tex/1.0.0
- %.*
trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of dependent tex/1.0.0
- trace: postponed_configurations::add: add {tex 2,1: libfoo} to {tex^ | libfoo->{tex/2,1}}
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
trace: collect_build_prerequisites: postpone tex/1.0.0
trace: collect_build_postponed (1): cfg-negotiate end {tex^ | libbar->{tex/1,1}}!
- trace: collect_build_postponed (2): begin {tex^ | libfoo->{tex/2,1}}
- %.*
+ trace: collect_build_postponed (2): begin {tex | libfoo->{tex/2,1}}
trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
- trace: collect_build_postponed (2): cfg-negotiate begin {tex^ | libfoo->{tex/2,1}}
- %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libfoo/0.1.0
trace: collect_build_prerequisites: end libfoo/0.1.0
@@ -5959,11 +10175,10 @@ test.options += --no-progress
trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/1.0.0
trace: collect_build_prerequisites: resume tex/1.0.0
trace: collect_build_prerequisites: end tex/1.0.0
- trace: collect_build_postponed (2): cfg-negotiate end {tex^ | libfoo->{tex/2,1}}!
- trace: collect_build_postponed (2): end {tex^ | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (2): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (2): end {tex | libfoo->{tex/2,1}}
trace: collect_build_postponed (1): end {tex^ | libbar->{tex/1,1}}
trace: collect_build_postponed (0): end
- %.*
trace: execute_plan: simulate: yes
%.*
build plan:
@@ -5971,33 +10186,9 @@ test.options += --no-progress
config.libfoo.extras=true (set by tex)
downgrade libbar/0.1.0
config.libbar.extras=true (set by tex)
- reconfigure tex/1.0.0 (dependent of libbar)
- %.*
- disfigured tex/1.0.0
- %.*
- disfigured libbar/1.0.0
- %.*
- disfigured libfoo/1.0.0
- %.*
- fetched libfoo/0.1.0
- %.*
- unpacked libfoo/0.1.0
- %.*
- fetched libbar/0.1.0
- %.*
- unpacked libbar/0.1.0
- %.*
- configured libfoo/0.1.0
- %.*
- configured libbar/0.1.0
- %.*
- configured tex/1.0.0
- %.*
- updated libfoo/0.1.0
- %.*
- updated libbar/0.1.0
- %.*
- updated tex/1.0.0
+ reconfigure tex/1.0.0 (dependent of libbar, libfoo)
+ config.tex.libfoo_extras=true (set by tex)
+ trace: execute_plan: simulate: no
%.*
EOE
@@ -6024,86 +10215,55 @@ test.options += --no-progress
#
# bar: depends: libbar == 0.1.0 (c)
#
- $* tex 2>!;
+ $* tex --verbose 1 2>!;
- $* libfoo/0.1.0 bar/0.1.0 2>>~%EOE%;
+ $pkg_status -r >>EOO;
+ !tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $* libfoo/0.1.0 bar/0.1.0 2>&1 | $filter 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add libfoo/0.1.0
trace: collect_build: add bar/0.1.0
- %.*
- trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent tex/1.0.0
- trace: postponed_configurations::add: create {tex^ | libfoo->{tex/2,1}}
- trace: collect_build_prerequisites: begin bar/0.1.0
- %.*
- trace: collect_build: add libbar/0.1.0
- info: package bar dependency on (libbar == 0.1.0) is forcing downgrade of libbar/1.0.0 to 0.1.0
- trace: collect_build_prerequisites: cfg-postpone dependency libbar/0.1.0 of dependent bar/0.1.0
- trace: postponed_configurations::add: create {bar | libbar->{bar/1,1}}
- trace: collect_build_prerequisites: postpone bar/0.1.0
- trace: collect_build_postponed (0): begin
- trace: collect_build_postponed (1): begin {tex^ | libfoo->{tex/2,1}}
- %.*
- trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libfoo->{tex/2,1}}
- %.*
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent tex/1.0.0 due to dependency libfoo/0.1.0
trace: collect_build: add tex/1.0.0
- trace: collect_build_prerequisites: reeval tex/1.0.0
- %.*
+ trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: begin bar/0.1.0
trace: collect_build: pick libbar/0.1.0 over libbar/1.0.0
- %.*
- trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0
- trace: postponed_configurations::add: add {tex^ 2,1: libfoo} to {tex^ | libfoo->{tex/2,1}}
- trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ | libfoo->{tex/2,1}}
- trace: collect_build_prerequisites: re-evaluated tex/1.0.0
- trace: collect_build_postponed (1): cfg-negotiate begin {tex^ | libfoo->{tex/2,1}}
- %.*
- trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
- trace: collect_build_prerequisites: begin libfoo/0.1.0
- trace: collect_build_prerequisites: end libfoo/0.1.0
- trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
- trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tex/1.0.0
- trace: collect_build_prerequisites: resume tex/1.0.0
- trace: collect_build_prerequisites: end tex/1.0.0
- trace: collect_build_postponed (1): cfg-negotiate end {tex^ | libfoo->{tex/2,1}}!
- trace: collect_build_postponed (2): begin {bar | libbar->{bar/1,1}}
- %.*
- trace: collect_build_postponed (2): re-evaluate existing dependents for {bar | libbar->{bar/1,1}}
- trace: collect_build_postponed (2): cannot re-evaluate dependent tex to dependency index 1 due to greater dependency index 2 in {tex^ | libfoo->{tex/2,1}}!, throwing postpone_position
- trace: pkg_build: collection failed due to earlier dependency position, retry from scratch
- %.*
+ trace: collect_build: libbar/1.0.0 package version needs to be replaced with libbar/0.1.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add libfoo/0.1.0
trace: collect_build: add bar/0.1.0
- %.*
- trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent tex/1.0.0
- trace: postponed_configurations::add: create {tex^ | libfoo->{tex/2,1}}
- trace: collect_build_prerequisites: begin bar/0.1.0
- %.*
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build: apply version replacement for libbar/1.0.0
+ trace: collect_build: replacement: libbar/0.1.0
trace: collect_build: add libbar/0.1.0
- info: package bar dependency on (libbar == 0.1.0) is forcing downgrade of libbar/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/0.1.0 of existing dependent tex/1.0.0 due to dependency libfoo/0.1.0
+ trace: collect_build: add tex/1.0.0
+ trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: begin bar/0.1.0
trace: collect_build_prerequisites: cfg-postpone dependency libbar/0.1.0 of dependent bar/0.1.0
- trace: postponed_configurations::add: create {bar | libbar->{bar/1,1}}
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {tex^ | libbar->{tex/1,1}}
trace: collect_build_prerequisites: postpone bar/0.1.0
trace: collect_build_postponed (0): begin
- trace: collect_build_postponed (1): begin {tex^ | libfoo->{tex/2,1}}
- %.*
- trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libfoo->{tex/2,1}}
- trace: collect_build_postponed (1): pos-postpone existing dependent tex re-evaluation to dependency index 2 due to recorded index 1, skipping {tex^ | libfoo->{tex/2,1}}
- trace: collect_build_postponed (0): postpone cfg-negotiation of {tex^ | libfoo->{tex/2,1}}
- trace: collect_build_postponed (1): begin {bar | libbar->{bar/1,1}}
- %.*
- trace: collect_build_postponed (1): re-evaluate existing dependents for {bar | libbar->{bar/1,1}}
- trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (1): begin {bar tex^ | libbar->{bar/1,1 tex/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bar tex^ | libbar->{bar/1,1 tex/1,1}}
trace: collect_build_prerequisites: reeval tex/1.0.0
- %.*
trace: collect_build: pick libbar/0.1.0 over libbar/1.0.0
- trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {bar | libbar->{bar/1,1}}
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {bar tex^ | libbar->{bar/1,1 tex/1,1}}
trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {bar tex^ | libbar->{bar/1,1 tex/1,1}}
trace: collect_build_prerequisites: re-evaluated tex/1.0.0
trace: collect_build_postponed (1): cfg-negotiate begin {bar tex^ | libbar->{bar/1,1 tex/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libbar/0.1.0
trace: collect_build_prerequisites: end libbar/0.1.0
@@ -6113,17 +10273,14 @@ test.options += --no-progress
trace: collect_build_prerequisites: end bar/0.1.0
trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tex/1.0.0
trace: collect_build_prerequisites: resume tex/1.0.0
- %.*
trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of dependent tex/1.0.0
- trace: postponed_configurations::add: add {tex 2,1: libfoo} to {tex^ | libfoo->{tex/2,1}}
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
trace: collect_build_prerequisites: postpone tex/1.0.0
trace: collect_build_postponed (1): cfg-negotiate end {bar tex^ | libbar->{bar/1,1 tex/1,1}}!
- trace: collect_build_postponed (2): begin {tex^ | libfoo->{tex/2,1}}
- %.*
+ trace: collect_build_postponed (2): begin {tex | libfoo->{tex/2,1}}
trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
- trace: collect_build_postponed (2): cfg-negotiate begin {tex^ | libfoo->{tex/2,1}}
- %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libfoo/0.1.0
trace: collect_build_prerequisites: end libfoo/0.1.0
@@ -6131,13 +10288,22 @@ test.options += --no-progress
trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/1.0.0
trace: collect_build_prerequisites: resume tex/1.0.0
trace: collect_build_prerequisites: end tex/1.0.0
- trace: collect_build_postponed (2): cfg-negotiate end {tex^ | libfoo->{tex/2,1}}!
- trace: collect_build_postponed (2): end {tex^ | libfoo->{tex/2,1}}
- trace: collect_build_postponed (1): end {bar | libbar->{bar/1,1}}
+ trace: collect_build_postponed (2): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (2): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (1): end {bar tex^ | libbar->{bar/1,1 tex/1,1}}
trace: collect_build_postponed (0): end
- %.*
trace: execute_plan: simulate: yes
%.*
+ build plan:
+ downgrade libfoo/0.1.0
+ config.libfoo.extras=true (set by tex)
+ downgrade libbar/0.1.0 (required by bar, tex)
+ config.libbar.extras=true (set by bar)
+ reconfigure tex/1.0.0 (dependent of libbar, libfoo)
+ config.tex.libfoo_extras=true (set by tex)
+ new bar/0.1.0
+ trace: execute_plan: simulate: no
+ %.*
EOE
$pkg_status -r >>EOO;
@@ -6164,7 +10330,7 @@ test.options += --no-progress
#
# baz: depends: {libbar libfoo} == 0.1.0 (c)
#
- $* tex 2>!;
+ $* tex --verbose 1 2>!;
$* baz/0.1.0 2>>~%EOE%;
%.*
@@ -6250,122 +10416,81 @@ test.options += --no-progress
#
# baz: depends: {libbar libfoo} (c)
#
- $* bax baz 2>!;
+ $* bax baz --verbose 1 2>!;
- $* libbox/0.1.0 2>>~%EOE%;
+ $* libbox/0.1.0 2>&1 | $filter 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add libbox/0.1.0
- %.*
- trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of existing dependent bax/1.0.0
- trace: postponed_configurations::add: create {bax^ | libbox->{bax/2,1}}
- trace: collect_build_postponed (0): begin
- trace: collect_build_postponed (1): begin {bax^ | libbox->{bax/2,1}}
- %.*
- trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libbox->{bax/2,1}}
- %.*
- trace: collect_build: add bax/1.0.0
- trace: collect_build_prerequisites: reeval bax/1.0.0
- %.*
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
trace: collect_build: add libfoo/1.0.0
- %.*
- trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
- trace: collect_build: add libbar/1.0.0
- trace: postponed_configurations::add: add {bax^ 2,1: libbox libbar} to {bax^ | libbox->{bax/2,1}}
- trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}}
- trace: collect_build_prerequisites: re-evaluated bax/1.0.0
- %.*
- trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
- trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}}
- %.*
- trace: collect_build: add baz/1.0.0
- trace: collect_build_prerequisites: reeval baz/1.0.0
- %.*
- trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}}
- trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libbox->{bax/2,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}}
- trace: collect_build_prerequisites: re-evaluated baz/1.0.0
- %.*
- trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libfoo
- trace: collect_build_postponed (1): cannot re-evaluate dependent bax to dependency index 1 since it is already re-evaluated to greater index 2 in {bax^ baz^ | libbox->{bax/2,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}}, throwing postpone_position
- trace: pkg_build: collection failed due to earlier dependency position, retry from scratch
- %.*
- trace: pkg_build: refine package collection/plan execution from scratch
- %.*
- trace: collect_build: add libbox/0.1.0
- %.*
- trace: collect_build_prerequisites: replace dependency at index 2 of existing dependent bax/1.0.0 with dependency libfoo/1.0.0 at index 1
- trace: collect_build: add libfoo/1.0.0
- trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent bax/1.0.0 due to dependency libbox/0.1.0
+ trace: collect_build: add bax/1.0.0
trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}}
- %.*
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval baz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated baz/1.0.0: 1,1
trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
- trace: collect_build: add bax/1.0.0
trace: collect_build_prerequisites: reeval bax/1.0.0
- %.*
trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluated bax/1.0.0
trace: collect_build: add baz/1.0.0
trace: collect_build_prerequisites: reeval baz/1.0.0
- %.*
trace: collect_build: add libbar/1.0.0
trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
trace: collect_build_prerequisites: re-evaluated baz/1.0.0
- %.*
trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libbar
trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: skip configured libfoo/1.0.0
trace: collect_build_prerequisites: skip configured libbar/1.0.0
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
trace: collect_build_prerequisites: resume bax/1.0.0
- %.*
trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent bax/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}?
- %.*
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbox
trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 involves (being) negotiated configurations and results in {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1}}?, throwing retry_configuration
trace: collect_build_postponed (0): cfg-negotiation of {bax^ | libfoo->{bax/1,1}} failed due to dependent bax, refining configuration
trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}}
- %.*
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval baz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated baz/1.0.0: 1,1
trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
- trace: collect_build: add bax/1.0.0
trace: collect_build_prerequisites: reeval bax/1.0.0
- %.*
trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluated bax/1.0.0
trace: collect_build: add baz/1.0.0
trace: collect_build_prerequisites: reeval baz/1.0.0
- %.*
trace: collect_build: add libbar/1.0.0
trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
trace: collect_build_prerequisites: re-evaluated baz/1.0.0
- %.*
trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libbar
trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: skip configured libfoo/1.0.0
trace: collect_build_prerequisites: skip configured libbar/1.0.0
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
trace: collect_build_prerequisites: resume bax/1.0.0
- %.*
trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent bax/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}?
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbox
trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is negotiated
trace: collect_build_prerequisites: collecting cfg-postponed dependency libbox/0.1.0 of dependent bax/1.0.0
trace: collect_build_prerequisites: begin libbox/0.1.0
@@ -6378,9 +10503,15 @@ test.options += --no-progress
trace: collect_build_postponed (1): cfg-negotiate end {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1}}!
trace: collect_build_postponed (1): end {bax^ | libfoo->{bax/1,1}}
trace: collect_build_postponed (0): end
- %.*
trace: execute_plan: simulate: yes
%.*
+ build plan:
+ downgrade libbox/0.1.0
+ config.libbox.extras=true (set by bax)
+ reconfigure bax/1.0.0 (dependent of libbox, libfoo)
+ config.bax.libfoo_extras=true (set by bax)
+ trace: execute_plan: simulate: no
+ %.*
EOE
$pkg_status -r >>EOO;
@@ -6411,15 +10542,13 @@ test.options += --no-progress
#
# box: depends: libbox == 0.1.0 (c)
#
- $* bax baz 2>!;
+ $* bax baz --verbose 1 2>!;
- $* box/0.1.0 2>>~%EOE%;
+ $* box/0.1.0 2>&1 | $filter 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add box/0.1.0
trace: collect_build_prerequisites: begin box/0.1.0
- %.*
trace: collect_build: add libbox/0.1.0
info: package box dependency on (libbox == 0.1.0) is forcing downgrade of libbox/1.0.0 to 0.1.0
trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent box/0.1.0
@@ -6427,123 +10556,86 @@ test.options += --no-progress
trace: collect_build_prerequisites: postpone box/0.1.0
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
- %.*
- trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
- %.*
- trace: collect_build: add bax/1.0.0
- trace: collect_build_prerequisites: reeval bax/1.0.0
- %.*
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
trace: collect_build: add libfoo/1.0.0
- %.*
- trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
- trace: collect_build: add libbar/1.0.0
- trace: postponed_configurations::add: add {bax^ 2,1: libbox libbar} to {box | libbox->{box/1,1}}
- trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}}
- trace: collect_build_prerequisites: re-evaluated bax/1.0.0
- %.*
- trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
- trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}}
- %.*
- trace: collect_build: add baz/1.0.0
- trace: collect_build_prerequisites: reeval baz/1.0.0
- %.*
- trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}}
- trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}}
- trace: collect_build_prerequisites: re-evaluated baz/1.0.0
- %.*
- trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libfoo
- trace: collect_build_postponed (1): cannot re-evaluate dependent bax to dependency index 1 since it is already re-evaluated to greater index 2 in {bax^ baz^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}}, throwing postpone_position
- trace: pkg_build: collection failed due to earlier dependency position, retry from scratch
- %.*
- trace: pkg_build: refine package collection/plan execution from scratch
- %.*
- trace: collect_build: add box/0.1.0
- trace: collect_build_prerequisites: begin box/0.1.0
- %.*
- trace: collect_build: add libbox/0.1.0
- info: package box dependency on (libbox == 0.1.0) is forcing downgrade of libbox/1.0.0 to 0.1.0
- trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent box/0.1.0
- trace: postponed_configurations::add: create {box | libbox->{box/1,1}}
- trace: collect_build_prerequisites: postpone box/0.1.0
- trace: collect_build_postponed (0): begin
- trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
- %.*
trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
- trace: collect_build_postponed (1): pos-postpone existing dependent bax re-evaluation to dependency index 2 due to recorded index 1, skipping {box | libbox->{box/1,1}}
- trace: collect_build_postponed (0): replace dependency at index 2 of existing dependent bax/1.0.0 with dependency libfoo/1.0.0 at index 1
- trace: collect_build: add libfoo/1.0.0
- trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
- trace: collect_build_postponed (0): postpone cfg-negotiation of {box | libbox->{box/1,1}}
- trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}}
- %.*
- trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
trace: collect_build: add bax/1.0.0
trace: collect_build_prerequisites: reeval bax/1.0.0
- %.*
- trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/0.1.0
+ trace: collect_build_prerequisites: end libbox/0.1.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.1.0
+ trace: collect_build_prerequisites: resume box/0.1.0
+ trace: collect_build_prerequisites: end box/0.1.0
+ trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}!
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_prerequisites: pre-reeval baz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated baz/1.0.0: 1,1
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
trace: collect_build: add baz/1.0.0
trace: collect_build_prerequisites: reeval baz/1.0.0
- %.*
trace: collect_build: add libbar/1.0.0
trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
trace: collect_build_prerequisites: re-evaluated baz/1.0.0
- %.*
- trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
- trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libbar
- trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
- %.*
- trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (2): skip being built existing dependent baz of dependency libbar
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: skip configured libfoo/1.0.0
trace: collect_build_prerequisites: skip configured libbar/1.0.0
- trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
- trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
trace: collect_build_prerequisites: resume bax/1.0.0
- %.*
trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent bax/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
- trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}?
- trace: postponed_configurations::add: merge {box | libbox->{box/1,1}} into {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1}}?
- trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1 box/1,1}}?, throwing merge_configuration
- trace: collect_build_postponed (0): cfg-negotiation of {bax^ | libfoo->{bax/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1 box/1,1}}?
- trace: collect_build_postponed (0): force-merge {box | libbox->{box/1,1}} into {bax^ | libfoo->{bax/1,1}}
- trace: collect_build_postponed (1): begin {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}}
- %.*
- trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}}
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {box | libbox->{box/1,1}}!
+ trace: postponed_configurations::add: merge {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}? into {bax box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax baz^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 baz/1,1} libfoo->{bax/1,1 baz/1,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {box | libbox->{box/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax baz^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 baz/1,1} libfoo->{bax/1,1 baz/1,1}}!
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
trace: collect_build: add bax/1.0.0
trace: collect_build_prerequisites: reeval bax/1.0.0
- %.*
- trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}} (shadow cluster-based)
- trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}}
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {box | libbox->{box/1,1}} (shadow cluster-based)
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ box | libbox->{box/1,1} libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_prerequisites: pre-reeval baz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated baz/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ box | libbox->{box/1,1} libfoo->{bax/1,1}}
trace: collect_build: add baz/1.0.0
trace: collect_build_prerequisites: reeval baz/1.0.0
- %.*
trace: collect_build: add libbar/1.0.0
- trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}} (shadow cluster-based)
- trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbox->{box/1,1} libbar->{baz/1,1}}
+ trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ box | libbox->{box/1,1} libfoo->{bax/1,1}} (shadow cluster-based)
+ trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ box | libbox->{box/1,1} libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
trace: collect_build_prerequisites: re-evaluated baz/1.0.0
- %.*
trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libbar
- trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbox->{box/1,1} libbar->{baz/1,1}}
- %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ box | libbox->{box/1,1} libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
- trace: collect_build_prerequisites: skip configured libfoo/1.0.0
trace: collect_build_prerequisites: begin libbox/0.1.0
trace: collect_build_prerequisites: end libbox/0.1.0
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
trace: collect_build_prerequisites: skip configured libbar/1.0.0
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
trace: collect_build_prerequisites: resume bax/1.0.0
- %.*
trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent bax/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
- trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbox->{box/1,1} libbar->{baz/1,1}}? (shadow cluster-based)
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ baz^ box | libbox->{box/1,1} libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}? (shadow cluster-based)
trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is shadow-negotiated
trace: collect_build_prerequisites: dependency libbox/0.1.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
@@ -6554,12 +10646,19 @@ test.options += --no-progress
trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.1.0
trace: collect_build_prerequisites: resume box/0.1.0
trace: collect_build_prerequisites: end box/0.1.0
- trace: collect_build_postponed (1): cfg-negotiate end {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 baz/1,1}}!
- trace: collect_build_postponed (1): end {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}}
+ trace: collect_build_postponed (1): cfg-negotiate end {bax^ baz^ box | libbox->{bax/2,1 box/1,1} libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1}}!
+ trace: collect_build_postponed (1): end {box | libbox->{box/1,1}}
trace: collect_build_postponed (0): end
- %.*
trace: execute_plan: simulate: yes
%.*
+ build plan:
+ downgrade libbox/0.1.0 (required by bax, box)
+ config.libbox.extras=true (set by box)
+ reconfigure bax/1.0.0 (dependent of libbox)
+ config.bax.libfoo_extras=true (set by bax)
+ new box/0.1.0
+ trace: execute_plan: simulate: no
+ %.*
EOE
$pkg_status -r >>EOO;
@@ -6570,7 +10669,7 @@ test.options += --no-progress
!baz configured 1.0.0
libbar configured 1.0.0
libfoo configured 1.0.0
- !box configured !0.1.0 available 1.0.0
+ !box configured !0.1.0 available 1.0.0 0.2.0
libbox configured 0.1.0 available 1.0.0
EOO
@@ -6589,118 +10688,89 @@ test.options += --no-progress
#
# baz: depends: {libbar libfoo} (c)
#
- $* bax baz 2>!;
+ $* bax baz --verbose 1 2>!;
- $* libbox/0.1.0 ?baz 2>>~%EOE%;
- %.*
- trace: pkg_build: refine package collection/plan execution from scratch
- %.*
- trace: collect_build: add libbox/0.1.0
- %.*
- trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of existing dependent bax/1.0.0
- trace: postponed_configurations::add: create {bax^ | libbox->{bax/2,1}}
- trace: collect_build_postponed (0): begin
- trace: collect_build_postponed (1): begin {bax^ | libbox->{bax/2,1}}
- %.*
- trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libbox->{bax/2,1}}
- %.*
- trace: collect_build: add bax/1.0.0
- trace: collect_build_prerequisites: reeval bax/1.0.0
- %.*
- trace: collect_build: add libfoo/1.0.0
- %.*
- trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
- trace: collect_build: add libbar/1.0.0
- trace: postponed_configurations::add: add {bax^ 2,1: libbox libbar} to {bax^ | libbox->{bax/2,1}}
- trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}}
- trace: collect_build_prerequisites: re-evaluated bax/1.0.0
- %.*
- trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
- trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}}
- trace: collect_build_prerequisites: reeval baz/1.0.0
- %.*
- trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}}
- trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libbox->{bax/2,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}}
- trace: collect_build_prerequisites: re-evaluated baz/1.0.0
- %.*
- trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libfoo
- trace: collect_build_postponed (1): cannot re-evaluate dependent bax to dependency index 1 since it is already re-evaluated to greater index 2 in {bax^ baz^ | libbox->{bax/2,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}}, throwing postpone_position
- trace: pkg_build: collection failed due to earlier dependency position, retry from scratch
+ $pkg_status -r >>EOO;
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 1.0.0
+ !baz configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $* libbox/0.1.0 ?baz 2>&1 | $filter 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add libbox/0.1.0
- %.*
- trace: collect_build_prerequisites: replace dependency at index 2 of existing dependent bax/1.0.0 with dependency libfoo/1.0.0 at index 1
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
trace: collect_build: add libfoo/1.0.0
- trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent bax/1.0.0 due to dependency libbox/0.1.0
+ trace: collect_build: add bax/1.0.0
trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}}
- %.*
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval baz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated baz/1.0.0: 1,1
trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
- trace: collect_build: add bax/1.0.0
trace: collect_build_prerequisites: reeval bax/1.0.0
- %.*
trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluated bax/1.0.0
trace: collect_build_prerequisites: reeval baz/1.0.0
- %.*
trace: collect_build: add libbar/1.0.0
trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
trace: collect_build_prerequisites: re-evaluated baz/1.0.0
- %.*
trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libbar
trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: skip configured libfoo/1.0.0
trace: collect_build_prerequisites: skip configured libbar/1.0.0
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
trace: collect_build_prerequisites: resume bax/1.0.0
- %.*
trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent bax/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}?
- %.*
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbox
trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 involves (being) negotiated configurations and results in {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1}}?, throwing retry_configuration
trace: collect_build_postponed (0): cfg-negotiation of {bax^ | libfoo->{bax/1,1}} failed due to dependent bax, refining configuration
trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}}
- %.*
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval baz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated baz/1.0.0: 1,1
trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
- trace: collect_build: add bax/1.0.0
trace: collect_build_prerequisites: reeval bax/1.0.0
- %.*
trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluated bax/1.0.0
trace: collect_build_prerequisites: reeval baz/1.0.0
- %.*
trace: collect_build: add libbar/1.0.0
trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
trace: collect_build_prerequisites: re-evaluated baz/1.0.0
- %.*
trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libbar
trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: skip configured libfoo/1.0.0
trace: collect_build_prerequisites: skip configured libbar/1.0.0
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
trace: collect_build_prerequisites: resume bax/1.0.0
- %.*
trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent bax/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}?
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbox
trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is negotiated
trace: collect_build_prerequisites: collecting cfg-postponed dependency libbox/0.1.0 of dependent bax/1.0.0
trace: collect_build_prerequisites: begin libbox/0.1.0
@@ -6713,54 +10783,34 @@ test.options += --no-progress
trace: collect_build_postponed (1): cfg-negotiate end {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1}}!
trace: collect_build_postponed (1): end {bax^ | libfoo->{bax/1,1}}
trace: collect_build_postponed (0): end
- %.*
trace: execute_plan: simulate: yes
%.*
trace: evaluate_dependency: baz/1.0.0: unused
- %.*
- trace: pkg_build: refine package collection/plan execution
- %.*
- trace: collect_drop: baz/1.0.0 package version needs to be replaced with drop
- trace: pkg_build: collection failed due to package version replacement, retry from scratch
- %.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add libbox/0.1.0
- trace: pkg_build: dep-postpone user-specified libbox
- trace: collect_drop: overwrite baz
- trace: collect_build_postponed (0): begin
- trace: collect_build_postponed (0): erase bogus postponement libbox
- trace: collect_build_postponed (0): bogus postponements erased, throwing
- trace: pkg_build: collection failed due to bogus dependency collection postponement cancellation, retry from scratch
- %.*
- trace: pkg_build: refine package collection/plan execution from scratch
- %.*
- trace: collect_build: add libbox/0.1.0
- %.*
- trace: collect_build_prerequisites: replace dependency at index 2 of existing dependent bax/1.0.0 with dependency libfoo/1.0.0 at index 1
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
trace: collect_build: add libfoo/1.0.0
- trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent bax/1.0.0 due to dependency libbox/0.1.0
+ trace: collect_build: add bax/1.0.0
trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
trace: collect_drop: overwrite baz
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}}
- %.*
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
trace: collect_build_postponed (1): skip being dropped existing dependent baz of dependency libfoo
trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
- trace: collect_build: add bax/1.0.0
trace: collect_build_prerequisites: reeval bax/1.0.0
- %.*
trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
trace: collect_build_prerequisites: re-evaluated bax/1.0.0
trace: collect_build_postponed (1): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: skip configured libfoo/1.0.0
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
trace: collect_build_prerequisites: resume bax/1.0.0
- %.*
trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent bax/1.0.0
trace: collect_build: add libbar/1.0.0
@@ -6769,13 +10819,10 @@ test.options += --no-progress
trace: collect_build_prerequisites: postpone bax/1.0.0
trace: collect_build_postponed (1): cfg-negotiate end {bax^ | libfoo->{bax/1,1}}!
trace: collect_build_postponed (2): begin {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
- %.*
trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libbox
- %.*
trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libbar
trace: collect_build_postponed (2): skip being dropped existing dependent baz of dependency libbar
trace: collect_build_postponed (2): cfg-negotiate begin {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
- %.*
trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libbox/0.1.0
trace: collect_build_prerequisites: end libbox/0.1.0
@@ -6788,9 +10835,16 @@ test.options += --no-progress
trace: collect_build_postponed (2): end {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
trace: collect_build_postponed (1): end {bax^ | libfoo->{bax/1,1}}
trace: collect_build_postponed (0): end
- %.*
trace: execute_plan: simulate: yes
%.*
+ build plan:
+ drop baz/1.0.0 (unused)
+ downgrade libbox/0.1.0
+ config.libbox.extras=true (set by bax)
+ reconfigure bax/1.0.0 (dependent of libbox, libfoo)
+ config.bax.libfoo_extras=true (set by bax)
+ trace: execute_plan: simulate: no
+ %.*
EOE
$pkg_status -r >>EOO;
@@ -7250,6 +11304,280 @@ test.options += --no-progress
$pkg_drop fux bex fix buz
}
+ : premature-in-cluster
+ :
+ : Test recollecting from scratch if the prematurely collected dependency
+ : belongs (as a dependency) to a non-negotiated cluster.
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # bas: depends: libbar(c)
+ # depends: bus(c)
+ #
+ # bax: depends: libfoo(c)
+ # depends: {libbox libbar} (c)
+ #
+ # bix: depends: {libbar bar} (c)
+ # depends: bux
+ #
+ # buz: depends: bux(c)
+ #
+ # buc: depends: libfoo(c)
+ # depends: bux(c)
+ #
+ # bus: depends: libbaz(c)
+ # depends: foo(c)
+ #
+ # bux: depends: libbar(c)
+ #
+ # bar: depends: libbar(c)
+ #
+ # foo: depends: libfoo(c)
+ #
+ $* bas bax bix buz buc 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add bas/1.0.0
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build: add bix/1.0.0
+ trace: collect_build: add buz/1.0.0
+ trace: collect_build: add buc/1.0.0
+ trace: collect_build_prerequisites: begin bas/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bas/1.0.0
+ trace: postponed_configurations::add: create {bas | libbar->{bas/1,1}}
+ trace: collect_build_prerequisites: postpone bas/1.0.0
+ trace: collect_build_prerequisites: begin bax/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: create {bax | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: postpone bax/1.0.0
+ trace: collect_build_prerequisites: begin bix/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bix/1.0.0
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent bix/1.0.0
+ trace: postponed_configurations::add: add {bix 1,1: libbar bar} to {bas | libbar->{bas/1,1}}
+ trace: collect_build_prerequisites: postpone bix/1.0.0
+ trace: collect_build_prerequisites: begin buz/1.0.0
+ trace: collect_build: add bux/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bux/1.0.0 of dependent buz/1.0.0
+ trace: postponed_configurations::add: create {buz | bux->{buz/1,1}}
+ trace: collect_build_prerequisites: postpone buz/1.0.0
+ trace: collect_build_prerequisites: begin buc/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent buc/1.0.0
+ trace: postponed_configurations::add: add {buc 1,1: libfoo} to {bax | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: postpone buc/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bas bix | libbar->{bas/1,1 bix/1,1} bar->{bix/1,1}}
+ trace: collect_build_postponed (1): cfg-negotiate begin {bas bix | libbar->{bas/1,1 bix/1,1} bar->{bix/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {bas bix | libbar->{bas/1,1 bix/1,1} bar->{bix/1,1}}?
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bar/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bar/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bas/1.0.0
+ trace: collect_build_prerequisites: resume bas/1.0.0
+ trace: collect_build: add bus/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bus/1.0.0 of dependent bas/1.0.0
+ trace: postponed_configurations::add: create {bas | bus->{bas/2,1}}
+ trace: collect_build_prerequisites: postpone bas/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bix/1.0.0
+ trace: collect_build_prerequisites: resume bix/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency bux/1.0.0 of dependent bix/1.0.0 since already in cluster {buz | bux->{buz/1,1}}
+ trace: collect_build_prerequisites: end bix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bar bas bix | libbar->{bar/1,1 bas/1,1 bix/1,1} bar->{bix/1,1}}!
+ trace: collect_build_postponed (2): begin {bax buc | libfoo->{bax/1,1 buc/1,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax buc | libfoo->{bax/1,1 buc/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bar bas bix | libbar->{bar/1,1 bas/1,1 bix/1,1} bar->{bix/1,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 involves (being) negotiated configurations and results in {bar bas bax bix | libbar->{bar/1,1 bas/1,1 bax/2,1 bix/1,1} bar->{bix/1,1} libbox->{bax/2,1}}!, throwing retry_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {bas bix | libbar->{bas/1,1 bix/1,1} bar->{bix/1,1}} failed due to dependent bax, refining configuration
+ trace: collect_build_postponed (1): begin {bas bix | libbar->{bas/1,1 bix/1,1} bar->{bix/1,1}}
+ trace: collect_build_postponed (1): cfg-negotiate begin {bas bix | libbar->{bas/1,1 bix/1,1} bar->{bix/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {bas bix | libbar->{bas/1,1 bix/1,1} bar->{bix/1,1}}?
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bar/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bar/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bas/1.0.0
+ trace: collect_build_prerequisites: resume bas/1.0.0
+ trace: collect_build: add bus/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bus/1.0.0 of dependent bas/1.0.0
+ trace: postponed_configurations::add: create {bas | bus->{bas/2,1}}
+ trace: collect_build_prerequisites: postpone bas/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bix/1.0.0
+ trace: collect_build_prerequisites: resume bix/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency bux/1.0.0 of dependent bix/1.0.0 since already in cluster {buz | bux->{buz/1,1}}
+ trace: collect_build_prerequisites: end bix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bar bas bix | libbar->{bar/1,1 bas/1,1 bix/1,1} bar->{bix/1,1}}!
+ trace: collect_build_postponed (2): begin {bax buc | libfoo->{bax/1,1 buc/1,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax buc | libfoo->{bax/1,1 buc/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bar bas bix | libbar->{bar/1,1 bas/1,1 bix/1,1} bar->{bix/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is negotiated
+ trace: collect_build_prerequisites: collecting cfg-postponed dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent buc/1.0.0
+ trace: collect_build_prerequisites: resume buc/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bux/1.0.0 of dependent buc/1.0.0
+ trace: postponed_configurations::add: add {buc 2,1: bux} to {buz | bux->{buz/1,1}}
+ trace: collect_build_prerequisites: postpone buc/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bax buc | libfoo->{bax/1,1 buc/1,1}}!
+ trace: collect_build_postponed (3): begin {buc buz | bux->{buc/2,1 buz/1,1}}
+ trace: collect_build_postponed (3): cfg-negotiate begin {buc buz | bux->{buc/2,1 buz/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bux/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bux/1.0.0
+ trace: postponed_configurations::add: add {bux 1,1: libbar} to {bar bas bax bix | libbar->{bar/1,1 bas/1,1 bax/2,1 bix/1,1} bar->{bix/1,1} libbox->{bax/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bux/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bux/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bux/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent buc/1.0.0
+ trace: collect_build_prerequisites: resume buc/1.0.0
+ trace: collect_build_prerequisites: end buc/1.0.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent buz/1.0.0
+ trace: collect_build_prerequisites: resume buz/1.0.0
+ trace: collect_build_prerequisites: end buz/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {buc buz | bux->{buc/2,1 buz/1,1}}!
+ trace: collect_build_postponed (4): begin {bas | bus->{bas/2,1}}
+ trace: collect_build_postponed (4): cfg-negotiate begin {bas | bus->{bas/2,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bus/1.0.0
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bus/1.0.0
+ trace: postponed_configurations::add: create {bus | libbaz->{bus/1,1}}
+ trace: collect_build_prerequisites: postpone bus/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent bas/1.0.0
+ trace: collect_build_prerequisites: resume bas/1.0.0
+ trace: collect_build_prerequisites: end bas/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {bas | bus->{bas/2,1}}!
+ trace: collect_build_postponed (5): begin {bus | libbaz->{bus/1,1}}
+ trace: collect_build_postponed (5): cfg-negotiate begin {bus | libbaz->{bus/1,1}}
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (5): select cfg-negotiated dependency alternative for dependent bus/1.0.0
+ trace: collect_build_prerequisites: resume bus/1.0.0
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent bus/1.0.0
+ trace: postponed_configurations::add: create {bus | foo->{bus/2,1}}
+ trace: collect_build_prerequisites: postpone bus/1.0.0
+ trace: collect_build_postponed (5): cfg-negotiate end {bus | libbaz->{bus/1,1}}!
+ trace: collect_build_postponed (6): begin {bus | foo->{bus/2,1}}
+ trace: collect_build_postponed (6): cfg-negotiate begin {bus | foo->{bus/2,1}}
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: add {foo 1,1: libfoo} to {bax buc | libfoo->{bax/1,1 buc/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent foo/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libfoo/1.0.0 of dependent foo/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (6): select cfg-negotiated dependency alternative for dependent bus/1.0.0
+ trace: collect_build_prerequisites: resume bus/1.0.0
+ trace: collect_build_prerequisites: end bus/1.0.0
+ trace: collect_build_postponed (6): cfg-negotiate end {bus | foo->{bus/2,1}}!
+ trace: collect_build_postponed (6): end {bus | foo->{bus/2,1}}
+ trace: collect_build_postponed (5): end {bus | libbaz->{bus/1,1}}
+ trace: collect_build_postponed (4): end {bas | bus->{bas/2,1}}
+ trace: collect_build_postponed (3): end {buc buz | bux->{buc/2,1 buz/1,1}}
+ trace: collect_build_postponed (2): end {bax buc | libfoo->{bax/1,1 buc/1,1}}
+ trace: collect_build_postponed (1): end {bas bix | libbar->{bas/1,1 bix/1,1} bar->{bix/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ new libbaz/1.0.0 (required by bus)
+ config.libbaz.extras=true (set by bus)
+ new libbox/1.0.0 (required by bax)
+ config.libbox.extras=true (set by bax)
+ new libfoo/1.0.0 (required by bax, buc, foo)
+ config.libfoo.extras=true (set by bax)
+ new foo/1.0.0 (required by bus)
+ config.foo.extras=true (set by bus)
+ config.foo.libfoo_extras=true (set by foo)
+ new bus/1.0.0 (required by bas)
+ config.bus.extras=true (set by bas)
+ new libbar/1.0.0 (required by bar, bas, bax, bix, bux)
+ config.libbar.extras=true (set by bas)
+ new bas/1.0.0
+ new bax/1.0.0
+ config.bax.libfoo_extras=true (set by bax)
+ new bar/1.0.0 (required by bix)
+ config.bar.extras=true (set by bix)
+ new bux/1.0.0 (required by bix, buc, buz)
+ config.bux.extras=true (set by buc)
+ new bix/1.0.0
+ new buz/1.0.0
+ new buc/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bas configured 1.0.0
+ bus configured 1.0.0
+ foo configured 1.0.0
+ libfoo configured 1.0.0
+ libbaz configured 1.0.0
+ libbar configured 1.0.0
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 1.0.0
+ !bix configured 1.0.0
+ bar configured 1.0.0
+ libbar configured 1.0.0
+ bux configured 1.0.0
+ libbar configured 1.0.0
+ libbar configured 1.0.0
+ !buz configured 1.0.0
+ bux configured 1.0.0
+ libbar configured 1.0.0
+ !buc configured 1.0.0
+ bux configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop bas bax bix buz buc
+ }
+
: up-negotiate-dependency
:
{
@@ -7752,7 +12080,7 @@ test.options += --no-progress
}
}
- : bogus-postponment
+ : bogus-postponement
:
{
$clone_cfg;
@@ -8017,6 +12345,7 @@ test.options += --no-progress
trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
trace: collect_build_prerequisites: end tez/1.0.0
trace: collect_build_postponed (3): cfg-negotiate end {tez | toz->{tez/2,1}}!
+ %.*
trace: collect_build_postponed (3): erase bogus postponement libfoo
trace: collect_build_postponed (3): bogus postponements erased, throwing
trace: pkg_build: collection failed due to bogus dependency collection postponement cancellation, retry from scratch
@@ -8112,6 +12441,1220 @@ test.options += --no-progress
$pkg_drop tax toz tez
}
+
+ : unconstrain-deps
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tvz: depends: toz == 0.2.0 (c)
+ #
+ # toz/0.2.0: depends: libfoo(c)
+ # depends: libbar(c)
+ #
+ # tez: depends: libbox(c)
+ # depends: toz == 0.1.0 (c)
+ # depends: libbar(c)
+ #
+ $* tvz 2>!;
+
+ $pkg_status -r >>EOO;
+ !tvz configured 1.0.0
+ toz configured 0.2.0 available 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $* tvz +{ config.tvz.extras=true } tez 2>&1 != 0 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tvz/1.0.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tvz/1.0.0
+ trace: collect_build: add toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tvz/1.0.0
+ trace: postponed_configurations::add: create {tvz | toz->{tvz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/1.0.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): skip being built existing dependent tvz of dependency toz
+ trace: collect_build_postponed (1): cfg-negotiate begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tvz/1.0.0
+ trace: collect_build_prerequisites: resume tvz/1.0.0
+ trace: collect_build_prerequisites: end tvz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (3): begin {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: add {toz 2,1: libbar} to {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (3): cfg-negotiate end {toz | libfoo->{toz/1,1}}!
+ trace: collect_build_postponed (4): begin {tez toz | libbar->{tez/3,1 toz/2,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent toz of dependency libbar
+ trace: collect_build_postponed (4): cfg-negotiate begin {tez toz | libbar->{tez/3,1 toz/2,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build_prerequisites: end tez/1.0.0
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: end toz/0.2.0
+ trace: collect_build_postponed (4): cfg-negotiate end {tez toz | libbar->{tez/3,1 toz/2,1}}!
+ trace: collect_build_postponed (4): end {tez toz | libbar->{tez/3,1 toz/2,1}}
+ trace: collect_build_postponed (3): end {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (2): end {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): end {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: execute_plan: while configuring dependent tez in simulation mode unconstrain (toz == 0.1.0)
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency toz/0.2.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent tez/1.0.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replace unsatisfied dependent version tez/1.0.0 with 0.1.0 by adding constraint 'tez' -> 'tez == 0.1.0' on command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tvz/1.0.0
+ trace: collect_build: add tez/0.1.0
+ trace: collect_build_prerequisites: begin tvz/1.0.0
+ trace: collect_build: add toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tvz/1.0.0
+ trace: postponed_configurations::add: create {tvz | toz->{tvz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/1.0.0
+ trace: collect_build_prerequisites: begin tez/0.1.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/0.1.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/0.1.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): skip being built existing dependent tvz of dependency toz
+ trace: collect_build_postponed (1): cfg-negotiate begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tvz/1.0.0
+ trace: collect_build_prerequisites: resume tvz/1.0.0
+ trace: collect_build_prerequisites: end tvz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/0.1.0
+ trace: collect_build_prerequisites: resume tez/0.1.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/0.1.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/0.1.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/0.1.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tez/0.1.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (3): begin {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libbar->{toz/2,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (3): cfg-negotiate end {toz | libfoo->{toz/1,1}}!
+ trace: collect_build_postponed (4): begin {toz | libbar->{toz/2,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent toz of dependency libbar
+ trace: collect_build_postponed (4): cfg-negotiate begin {toz | libbar->{toz/2,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: end toz/0.2.0
+ trace: collect_build_postponed (4): cfg-negotiate end {toz | libbar->{toz/2,1}}!
+ trace: collect_build_postponed (4): end {toz | libbar->{toz/2,1}}
+ trace: collect_build_postponed (3): end {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (2): end {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): end {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: execute_plan: while configuring dependent tez in simulation mode unconstrain (toz == 0.1.0)
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency toz/0.2.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent tez/0.1.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replacement of unsatisfied dependent version tez/0.1.0 is denied since it is specified on command line as 'tez == 0.1.0'
+ trace: try_replace_dependent: try to replace conflicting dependent tvz/1.0.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replace conflicting dependent version tvz/1.0.0 with 0.1.0 by adding constraint 'tvz' -> 'tvz == 0.1.0' on command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tvz/0.1.0
+ trace: collect_build: add tez/0.1.0
+ trace: collect_build_prerequisites: begin tvz/0.1.0
+ trace: collect_build: add toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tvz/0.1.0
+ trace: postponed_configurations::add: create {tvz | toz->{tvz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/0.1.0
+ trace: collect_build_prerequisites: begin tez/0.1.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/0.1.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/0.1.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): skip being built existing dependent tvz of dependency toz
+ trace: collect_build_postponed (1): cfg-negotiate begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tvz/0.1.0
+ trace: collect_build_prerequisites: resume tvz/0.1.0
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency bax/1.0.0 of dependent tvz/0.1.0
+ trace: collect_build_prerequisites: begin bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 1,1: libfoo} to {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tvz/0.1.0
+ trace: postponed_configurations::add: add {tvz 3,1: libfoo} to {bax toz | libfoo->{bax/1,1 toz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/0.1.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/0.1.0
+ trace: collect_build_prerequisites: resume tez/0.1.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/0.1.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/0.1.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/0.1.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tez/0.1.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (3): begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1}}!
+ trace: collect_build_prerequisites: skip being built existing dependent toz of dependency libbar
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 involves (being) negotiated configurations and results in {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1}}!, throwing retry_configuration
+ trace: collect_build_postponed (1): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to dependent bax, refining configuration
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/0.1.0
+ trace: collect_build_prerequisites: resume tez/0.1.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/0.1.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/0.1.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/0.1.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tez/0.1.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (3): begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1}}!
+ trace: collect_build_prerequisites: skip being built existing dependent toz of dependency libbar
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbox/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: collecting cfg-postponed dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: add {toz 2,1: libbar} to {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent toz/0.2.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent toz/0.2.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end toz/0.2.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tvz/0.1.0
+ trace: collect_build_prerequisites: resume tvz/0.1.0
+ trace: collect_build_prerequisites: end tvz/0.1.0
+ trace: collect_build_postponed (3): cfg-negotiate end {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}!
+ trace: collect_build_postponed (3): end {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (2): end {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): end {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: execute_plan: while configuring dependent tez in simulation mode unconstrain (toz == 0.1.0)
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency toz/0.2.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent tez/0.1.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replacement of unsatisfied dependent version tez/0.1.0 is denied since it is specified on command line as 'tez == 0.1.0'
+ trace: try_replace_dependent: try to replace conflicting dependent tvz/0.1.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replacement of conflicting dependent version tvz/0.1.0 is denied since it is specified on command line as 'tvz == 0.1.0'
+ trace: pkg_build: cannot replace any package, rolling back latest command line adjustment ('tvz' -> 'tvz == 0.1.0')
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tvz/1.0.0
+ trace: collect_build: add tez/0.1.0
+ trace: collect_build_prerequisites: begin tvz/1.0.0
+ trace: collect_build: add toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tvz/1.0.0
+ trace: postponed_configurations::add: create {tvz | toz->{tvz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/1.0.0
+ trace: collect_build_prerequisites: begin tez/0.1.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/0.1.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/0.1.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): skip being built existing dependent tvz of dependency toz
+ trace: collect_build_postponed (1): cfg-negotiate begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tvz/1.0.0
+ trace: collect_build_prerequisites: resume tvz/1.0.0
+ trace: collect_build_prerequisites: end tvz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/0.1.0
+ trace: collect_build_prerequisites: resume tez/0.1.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/0.1.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/0.1.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/0.1.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tez/0.1.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (3): begin {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libbar->{toz/2,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (3): cfg-negotiate end {toz | libfoo->{toz/1,1}}!
+ trace: collect_build_postponed (4): begin {toz | libbar->{toz/2,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent toz of dependency libbar
+ trace: collect_build_postponed (4): cfg-negotiate begin {toz | libbar->{toz/2,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: end toz/0.2.0
+ trace: collect_build_postponed (4): cfg-negotiate end {toz | libbar->{toz/2,1}}!
+ trace: collect_build_postponed (4): end {toz | libbar->{toz/2,1}}
+ trace: collect_build_postponed (3): end {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (2): end {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): end {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: execute_plan: while configuring dependent tez in simulation mode unconstrain (toz == 0.1.0)
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency toz/0.2.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent tez/0.1.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replacement of unsatisfied dependent version tez/0.1.0 is denied since it is specified on command line as 'tez == 0.1.0'
+ trace: try_replace_dependent: try to replace conflicting dependent tvz/1.0.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replacement tvz/0.1.0 tried earlier for same command line, skipping
+ trace: pkg_build: cannot replace any package, rolling back latest command line adjustment ('tez' -> 'tez == 0.1.0')
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tvz/1.0.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tvz/1.0.0
+ trace: collect_build: add toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tvz/1.0.0
+ trace: postponed_configurations::add: create {tvz | toz->{tvz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/1.0.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): skip being built existing dependent tvz of dependency toz
+ trace: collect_build_postponed (1): cfg-negotiate begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tvz/1.0.0
+ trace: collect_build_prerequisites: resume tvz/1.0.0
+ trace: collect_build_prerequisites: end tvz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (3): begin {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: add {toz 2,1: libbar} to {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (3): cfg-negotiate end {toz | libfoo->{toz/1,1}}!
+ trace: collect_build_postponed (4): begin {tez toz | libbar->{tez/3,1 toz/2,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent toz of dependency libbar
+ trace: collect_build_postponed (4): cfg-negotiate begin {tez toz | libbar->{tez/3,1 toz/2,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build_prerequisites: end tez/1.0.0
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: end toz/0.2.0
+ trace: collect_build_postponed (4): cfg-negotiate end {tez toz | libbar->{tez/3,1 toz/2,1}}!
+ trace: collect_build_postponed (4): end {tez toz | libbar->{tez/3,1 toz/2,1}}
+ trace: collect_build_postponed (3): end {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (2): end {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): end {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: execute_plan: while configuring dependent tez in simulation mode unconstrain (toz == 0.1.0)
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency toz/0.2.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent tez/1.0.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replacement tez/0.1.0 tried earlier for same command line, skipping
+ trace: try_replace_dependent: try to replace conflicting dependent tvz/1.0.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replace conflicting dependent version tvz/1.0.0 with 0.1.0 by adding constraint 'tvz' -> 'tvz == 0.1.0' on command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tvz/0.1.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tvz/0.1.0
+ trace: collect_build: add toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tvz/0.1.0
+ trace: postponed_configurations::add: create {tvz | toz->{tvz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/0.1.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): skip being built existing dependent tvz of dependency toz
+ trace: collect_build_postponed (1): cfg-negotiate begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tvz/0.1.0
+ trace: collect_build_prerequisites: resume tvz/0.1.0
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency bax/1.0.0 of dependent tvz/0.1.0
+ trace: collect_build_prerequisites: begin bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 1,1: libfoo} to {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tvz/0.1.0
+ trace: postponed_configurations::add: add {tvz 3,1: libfoo} to {bax toz | libfoo->{bax/1,1 toz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/0.1.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (3): begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1}}!
+ trace: postponed_configurations::add: merge {tez | libbar->{tez/3,1}} into {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tez/3,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (1): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tez/3,1}}!
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 3,1: libbar} to {tez | libbox->{tez/1,1}}? (shadow cluster-based)
+ trace: collect_build_prerequisites: skip being built existing dependent toz of dependency libbar
+ trace: collect_build_prerequisites: cfg-postponing dependent tez/1.0.0 involves (being) negotiated configurations and results in {tez | libbox->{tez/1,1} libbar->{tez/3,1}}?, throwing retry_configuration
+ trace: collect_build_postponed (1): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to dependent tez, refining configuration
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 3,1: libbar} to {tez | libbox->{tez/1,1}}? (shadow cluster-based)
+ trace: collect_build_prerequisites: skip being built existing dependent toz of dependency libbar
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is shadow-negotiated
+ trace: collect_build_prerequisites: collecting cfg-postponed dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_prerequisites: end tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1} libbar->{tez/3,1}}!
+ trace: collect_build_postponed (3): begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1} libbar->{tez/3,1}}! (shadow cluster-based)
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is shadow-negotiated
+ trace: collect_build_prerequisites: dependency libbox/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: add {toz 2,1: libbar} to {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tez/3,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent toz/0.2.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent toz/0.2.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end toz/0.2.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tvz/0.1.0
+ trace: collect_build_prerequisites: resume tvz/0.1.0
+ trace: collect_build_prerequisites: end tvz/0.1.0
+ trace: collect_build_postponed (3): cfg-negotiate end {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}!
+ trace: collect_build_postponed (3): end {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (2): end {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): end {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: execute_plan: while configuring dependent tez in simulation mode unconstrain (toz == 0.1.0)
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency toz/0.2.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent tez/1.0.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replacement tez/0.1.0 tried earlier for same command line, skipping
+ trace: try_replace_dependent: try to replace conflicting dependent tvz/0.1.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replacement of conflicting dependent version tvz/0.1.0 is denied since it is specified on command line as 'tvz == 0.1.0'
+ trace: pkg_build: cannot replace any package, rolling back latest command line adjustment ('tvz' -> 'tvz == 0.1.0')
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tvz/1.0.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tvz/1.0.0
+ trace: collect_build: add toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tvz/1.0.0
+ trace: postponed_configurations::add: create {tvz | toz->{tvz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/1.0.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): skip being built existing dependent tvz of dependency toz
+ trace: collect_build_postponed (1): cfg-negotiate begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tvz/1.0.0
+ trace: collect_build_prerequisites: resume tvz/1.0.0
+ trace: collect_build_prerequisites: end tvz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (3): begin {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: add {toz 2,1: libbar} to {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (3): cfg-negotiate end {toz | libfoo->{toz/1,1}}!
+ trace: collect_build_postponed (4): begin {tez toz | libbar->{tez/3,1 toz/2,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent toz of dependency libbar
+ trace: collect_build_postponed (4): cfg-negotiate begin {tez toz | libbar->{tez/3,1 toz/2,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build_prerequisites: end tez/1.0.0
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: end toz/0.2.0
+ trace: collect_build_postponed (4): cfg-negotiate end {tez toz | libbar->{tez/3,1 toz/2,1}}!
+ trace: collect_build_postponed (4): end {tez toz | libbar->{tez/3,1 toz/2,1}}
+ trace: collect_build_postponed (3): end {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (2): end {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): end {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: execute_plan: while configuring dependent tez in simulation mode unconstrain (toz == 0.1.0)
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency toz/0.2.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent tez/1.0.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replacement tez/0.1.0 tried earlier for same command line, skipping
+ trace: try_replace_dependent: try to replace conflicting dependent tvz/1.0.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replacement tvz/0.1.0 tried earlier for same command line, skipping
+ error: unable to satisfy constraints on package toz
+ info: tvz/1.0.0 depends on (toz == 0.2.0)
+ info: tez/1.0.0 depends on (toz == 0.1.0)
+ info: available toz/0.2.0
+ info: available toz/0.1.0
+ info: while satisfying tez/1.0.0
+ info: explicitly specify toz version to manually satisfy both constraints
+ %.*
+ EOE
+
+ $pkg_drop tvz
+ }
+
+ : restore-unsatisfied-depts
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tez: depends: libbox(c)
+ # depends: toz == 0.1.0 (c)
+ # depends: libbar(c)
+ #
+ # toz/0.1.0:
+ #
+ # toz/0.2.0: depends: libfoo(c)
+ # depends: libbar(c)
+ #
+ # tvz: depends: toz == 0.2.0 (c)
+ # depends: bax
+ # depends: libfoo(c)
+ #
+ # bax: depends: libfoo(c)
+ # depends: {libbox libbar} (c)
+ #
+ $* tez 2>!;
+
+ $pkg_status -r >>EOO;
+ !tez configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ toz configured 0.1.0 available 1.0.0 0.2.0
+ EOO
+
+ $* tvz/0.1.0 tez +{ config.tvz.extras=true } 2>&1 != 0 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tvz/0.1.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tvz/0.1.0
+ trace: collect_build: add toz/0.2.0
+ info: package tvz dependency on (toz == 0.2.0) is forcing upgrade of toz/0.1.0 to 0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tvz/0.1.0
+ trace: postponed_configurations::add: create {tvz | toz->{tvz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/0.1.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): skip being built existing dependent tez of dependency toz
+ trace: collect_build_postponed (1): cfg-negotiate begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tvz/0.1.0
+ trace: collect_build_prerequisites: resume tvz/0.1.0
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency bax/1.0.0 of dependent tvz/0.1.0
+ trace: collect_build_prerequisites: begin bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 1,1: libfoo} to {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tvz/0.1.0
+ trace: postponed_configurations::add: add {tvz 3,1: libfoo} to {bax toz | libfoo->{bax/1,1 toz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/0.1.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tez of dependency libbox
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (3): begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1}}!
+ trace: postponed_configurations::add: merge {tez | libbar->{tez/3,1}} into {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tez/3,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (1): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tez/3,1}}!
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tez of dependency libbox
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 3,1: libbar} to {tez | libbox->{tez/1,1}}? (shadow cluster-based)
+ trace: collect_build_prerequisites: skip being built existing dependent tez of dependency libbar
+ trace: collect_build_prerequisites: cfg-postponing dependent tez/1.0.0 involves (being) negotiated configurations and results in {tez | libbox->{tez/1,1} libbar->{tez/3,1}}?, throwing retry_configuration
+ trace: collect_build_postponed (1): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to dependent tez, refining configuration
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tez of dependency libbox
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 3,1: libbar} to {tez | libbox->{tez/1,1}}? (shadow cluster-based)
+ trace: collect_build_prerequisites: skip being built existing dependent tez of dependency libbar
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is shadow-negotiated
+ trace: collect_build_prerequisites: collecting cfg-postponed dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_prerequisites: end tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1} libbar->{tez/3,1}}!
+ trace: collect_build_postponed (3): begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1} libbar->{tez/3,1}}! (shadow cluster-based)
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is shadow-negotiated
+ trace: collect_build_prerequisites: dependency libbox/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: add {toz 2,1: libbar} to {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tez/3,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent toz/0.2.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent toz/0.2.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end toz/0.2.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tvz/0.1.0
+ trace: collect_build_prerequisites: resume tvz/0.1.0
+ trace: collect_build_prerequisites: end tvz/0.1.0
+ trace: collect_build_postponed (3): cfg-negotiate end {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}!
+ trace: collect_build_postponed (3): end {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (2): end {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): end {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: execute_plan: while configuring dependent tez in simulation mode unconstrain (toz == 0.1.0)
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency toz/0.2.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent tez/1.0.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replace unsatisfied dependent version tez/1.0.0 with 0.1.0 by adding constraint 'tez' -> 'tez == 0.1.0' on command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tvz/0.1.0
+ trace: collect_build: add tez/0.1.0
+ trace: collect_build_prerequisites: begin tvz/0.1.0
+ trace: collect_build: add toz/0.2.0
+ info: package tvz dependency on (toz == 0.2.0) is forcing upgrade of toz/0.1.0 to 0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tvz/0.1.0
+ trace: postponed_configurations::add: create {tvz | toz->{tvz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/0.1.0
+ trace: collect_build_prerequisites: begin tez/0.1.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/0.1.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/0.1.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): skip being built existing dependent tez of dependency toz
+ trace: collect_build_postponed (1): cfg-negotiate begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tvz/0.1.0
+ trace: collect_build_prerequisites: resume tvz/0.1.0
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency bax/1.0.0 of dependent tvz/0.1.0
+ trace: collect_build_prerequisites: begin bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 1,1: libfoo} to {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tvz/0.1.0
+ trace: postponed_configurations::add: add {tvz 3,1: libfoo} to {bax toz | libfoo->{bax/1,1 toz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/0.1.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tez of dependency libbox
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/0.1.0
+ trace: collect_build_prerequisites: resume tez/0.1.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/0.1.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/0.1.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/0.1.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tez/0.1.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (3): begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1}}!
+ trace: collect_build_prerequisites: skip being built existing dependent tez of dependency libbar
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 involves (being) negotiated configurations and results in {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1}}!, throwing retry_configuration
+ trace: collect_build_postponed (1): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to dependent bax, refining configuration
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tez of dependency libbox
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/0.1.0
+ trace: collect_build_prerequisites: resume tez/0.1.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/0.1.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/0.1.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/0.1.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tez/0.1.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (3): begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1}}!
+ trace: collect_build_prerequisites: skip being built existing dependent tez of dependency libbar
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbox/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: collecting cfg-postponed dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: add {toz 2,1: libbar} to {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent toz/0.2.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent toz/0.2.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end toz/0.2.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tvz/0.1.0
+ trace: collect_build_prerequisites: resume tvz/0.1.0
+ trace: collect_build_prerequisites: end tvz/0.1.0
+ trace: collect_build_postponed (3): cfg-negotiate end {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}!
+ trace: collect_build_postponed (3): end {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (2): end {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): end {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: execute_plan: while configuring dependent tez in simulation mode unconstrain (toz == 0.1.0)
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency toz/0.2.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent tez/0.1.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replacement of unsatisfied dependent version tez/0.1.0 is denied since it is specified on command line as 'tez == 0.1.0'
+ trace: try_replace_dependent: try to replace conflicting dependent tvz/0.1.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replacement of conflicting dependent version tvz/0.1.0 is denied since it is specified on command line as 'tvz == 0.1.0'
+ trace: pkg_build: cannot replace any package, rolling back latest command line adjustment ('tez' -> 'tez == 0.1.0')
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tvz/0.1.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tvz/0.1.0
+ trace: collect_build: add toz/0.2.0
+ info: package tvz dependency on (toz == 0.2.0) is forcing upgrade of toz/0.1.0 to 0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tvz/0.1.0
+ trace: postponed_configurations::add: create {tvz | toz->{tvz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/0.1.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): skip being built existing dependent tez of dependency toz
+ trace: collect_build_postponed (1): cfg-negotiate begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tvz/0.1.0
+ trace: collect_build_prerequisites: resume tvz/0.1.0
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency bax/1.0.0 of dependent tvz/0.1.0
+ trace: collect_build_prerequisites: begin bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 1,1: libfoo} to {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tvz/0.1.0
+ trace: postponed_configurations::add: add {tvz 3,1: libfoo} to {bax toz | libfoo->{bax/1,1 toz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/0.1.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tez of dependency libbox
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (3): begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1}}!
+ trace: postponed_configurations::add: merge {tez | libbar->{tez/3,1}} into {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tez/3,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (1): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tez/3,1}}!
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tez of dependency libbox
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 3,1: libbar} to {tez | libbox->{tez/1,1}}? (shadow cluster-based)
+ trace: collect_build_prerequisites: skip being built existing dependent tez of dependency libbar
+ trace: collect_build_prerequisites: cfg-postponing dependent tez/1.0.0 involves (being) negotiated configurations and results in {tez | libbox->{tez/1,1} libbar->{tez/3,1}}?, throwing retry_configuration
+ trace: collect_build_postponed (1): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to dependent tez, refining configuration
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tez of dependency libbox
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 3,1: libbar} to {tez | libbox->{tez/1,1}}? (shadow cluster-based)
+ trace: collect_build_prerequisites: skip being built existing dependent tez of dependency libbar
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is shadow-negotiated
+ trace: collect_build_prerequisites: collecting cfg-postponed dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_prerequisites: end tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1} libbar->{tez/3,1}}!
+ trace: collect_build_postponed (3): begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1} libbar->{tez/3,1}}! (shadow cluster-based)
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is shadow-negotiated
+ trace: collect_build_prerequisites: dependency libbox/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: add {toz 2,1: libbar} to {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tez/3,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent toz/0.2.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent toz/0.2.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end toz/0.2.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tvz/0.1.0
+ trace: collect_build_prerequisites: resume tvz/0.1.0
+ trace: collect_build_prerequisites: end tvz/0.1.0
+ trace: collect_build_postponed (3): cfg-negotiate end {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}!
+ trace: collect_build_postponed (3): end {bax toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (2): end {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): end {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: execute_plan: while configuring dependent tez in simulation mode unconstrain (toz == 0.1.0)
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency toz/0.2.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent tez/1.0.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replacement tez/0.1.0 tried earlier for same command line, skipping
+ trace: try_replace_dependent: try to replace conflicting dependent tvz/0.1.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replacement of conflicting dependent version tvz/0.1.0 is denied since it is specified on command line as 'tvz == 0.1.0'
+ error: unable to satisfy constraints on package toz
+ info: tvz/0.1.0 depends on (toz == 0.2.0)
+ command line requires (tvz == 0.1.0)
+ info: tez/1.0.0 depends on (toz == 0.1.0)
+ info: available toz/0.2.0
+ info: available toz/0.1.0
+ info: while satisfying tez/1.0.0
+ info: explicitly specify toz version to manually satisfy both constraints
+ %.*
+ EOE
+
+ $pkg_drop tez
+ }
}
: cycle
@@ -8487,6 +14030,7 @@ test.options += --no-progress
trace: collect_build_prerequisites: no cfg-clause for dependency tix/0.1.0 of dependent tux/1.0.0
trace: collect_build_prerequisites: end tux/1.0.0
trace: collect_build_postponed (1): cfg-negotiate end {tux | libbox->{tux/1,1}}!
+ %.*
trace: collect_build_postponed (1): erase bogus postponement tex
trace: collect_build_postponed (1): bogus postponements erased, throwing
trace: pkg_build: collection failed due to bogus dependency collection postponement cancellation, retry from scratch
@@ -8997,88 +14541,74 @@ test.options += --no-progress
# tix: depends: libbar(c)
# depends: tex(c)
#
- $* tex 2>!;
+ $* tex --verbose 1 2>!;
# Build new dependency of an existing dependent.
#
- $* tix 2>>~%EOE%;
+ $* tix 2>&1 | $filter 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add tix/1.0.0
trace: collect_build_prerequisites: begin tix/1.0.0
- %.*
trace: collect_build: add libbar/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tix/1.0.0
trace: postponed_configurations::add: create {tix | libbar->{tix/1,1}}
trace: collect_build_prerequisites: postpone tix/1.0.0
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {tix | libbar->{tix/1,1}}
- %.*
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
trace: collect_build_postponed (1): re-evaluate existing dependents for {tix | libbar->{tix/1,1}}
- %.*
trace: collect_build: add tex/1.0.0
trace: collect_build_prerequisites: reeval tex/1.0.0
- %.*
trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {tix | libbar->{tix/1,1}}
trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ tix | libbar->{tex/1,1 tix/1,1}}
trace: collect_build_prerequisites: re-evaluated tex/1.0.0
trace: collect_build_postponed (1): cfg-negotiate begin {tex^ tix | libbar->{tex/1,1 tix/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: skip configured libbar/1.0.0
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tex/1.0.0
trace: collect_build_prerequisites: resume tex/1.0.0
- %.*
trace: collect_build: add libfoo/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
trace: collect_build_prerequisites: postpone tex/1.0.0
trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
trace: collect_build_prerequisites: resume tix/1.0.0
- %.*
trace: collect_build_prerequisites: cannot cfg-postpone dependency tex/1.0.0 of dependent tix/1.0.0 (collected prematurely), throwing postpone_dependency
trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
- %.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add tix/1.0.0
trace: collect_build_prerequisites: begin tix/1.0.0
- %.*
trace: collect_build: add libbar/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tix/1.0.0
trace: postponed_configurations::add: create {tix | libbar->{tix/1,1}}
trace: collect_build_prerequisites: postpone tix/1.0.0
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {tix | libbar->{tix/1,1}}
- %.*
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
trace: collect_build_postponed (1): skip dep-postponed existing dependent tex of dependency libbar
+ trace: collect_build: add tex/1.0.0
trace: collect_build_postponed (1): cfg-negotiate begin {tix | libbar->{tix/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: skip configured libbar/1.0.0
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
trace: collect_build_prerequisites: resume tix/1.0.0
- %.*
- trace: collect_build: add tex/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency tex/1.0.0 of dependent tix/1.0.0
trace: postponed_configurations::add: create {tix | tex->{tix/2,1}}
trace: collect_build_prerequisites: postpone tix/1.0.0
trace: collect_build_postponed (1): cfg-negotiate end {tix | libbar->{tix/1,1}}!
trace: collect_build_postponed (2): begin {tix | tex->{tix/2,1}}
- %.*
trace: collect_build_postponed (2): cfg-negotiate begin {tix | tex->{tix/2,1}}
- %.*
trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin tex/1.0.0
- %.*
trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
trace: postponed_configurations::add: add {tex 1,1: libbar} to {tix | libbar->{tix/1,1}}!
trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
- %.*
trace: collect_build: add libfoo/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
@@ -9089,10 +14619,8 @@ test.options += --no-progress
trace: collect_build_prerequisites: end tix/1.0.0
trace: collect_build_postponed (2): cfg-negotiate end {tix | tex->{tix/2,1}}!
trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}}
- %.*
trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libfoo
trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
- %.*
trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: skip configured libfoo/1.0.0
trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
@@ -9104,9 +14632,12 @@ test.options += --no-progress
trace: collect_build_postponed (2): end {tix | tex->{tix/2,1}}
trace: collect_build_postponed (1): end {tix | libbar->{tix/1,1}}
trace: collect_build_postponed (0): end
- %.*
trace: execute_plan: simulate: yes
%.*
+ build plan:
+ new tix/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
EOE
$pkg_status -r >>EOO;
@@ -9128,68 +14659,21 @@ test.options += --no-progress
%.*
trace: collect_build: add tex/0.3.0
%.*
- trace: collect_build_prerequisites: cfg-postpone dependency tex/0.3.0 of existing dependent tix/1.0.0
- trace: postponed_configurations::add: create {tix^ | tex->{tix/2,1}}
- trace: collect_build_postponed (0): begin
- trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}}
- %.*
- trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}}
- %.*
- trace: collect_build: add tix/1.0.0
- trace: collect_build_prerequisites: reeval tix/1.0.0
- %.*
- trace: collect_build: add libbar/1.0.0
- %.*
- trace: collect_build: pick tex/0.3.0 over tex/1.0.0
- trace: postponed_configurations::add: add {tix^ 2,1: tex} to {tix^ | tex->{tix/2,1}}
- trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | tex->{tix/2,1}}
- trace: collect_build_prerequisites: re-evaluated tix/1.0.0
- trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | tex->{tix/2,1}}
- %.*
- trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
- trace: collect_build_prerequisites: begin tex/0.3.0
- %.*
- trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/0.3.0
- trace: postponed_configurations::add: create {tex | libbar->{tex/1,1}}
- trace: collect_build_prerequisites: postpone tex/0.3.0
- trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
- trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
- trace: collect_build_prerequisites: resume tix/1.0.0
- trace: collect_build_prerequisites: end tix/1.0.0
- trace: collect_build_postponed (1): cfg-negotiate end {tix^ | tex->{tix/2,1}}!
- trace: collect_build_postponed (2): begin {tex | libbar->{tex/1,1}}
- %.*
- trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libbar
- trace: collect_build_postponed (2): re-evaluate existing dependents for {tex | libbar->{tex/1,1}}
- trace: collect_build_postponed (2): cannot re-evaluate dependent tix to dependency index 1 due to greater dependency index 2 in {tix^ | tex->{tix/2,1}}!, throwing postpone_position
- trace: pkg_build: collection failed due to earlier dependency position, retry from scratch
- %.*
- trace: pkg_build: refine package collection/plan execution from scratch
- %.*
- trace: collect_build: add tex/0.3.0
- %.*
- trace: collect_build_prerequisites: cfg-postpone dependency tex/0.3.0 of existing dependent tix/1.0.0
- trace: postponed_configurations::add: create {tix^ | tex->{tix/2,1}}
- trace: collect_build_postponed (0): begin
- trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}}
- %.*
- trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}}
- trace: collect_build_postponed (1): pos-postpone existing dependent tix re-evaluation to dependency index 2 due to recorded index 1, skipping {tix^ | tex->{tix/2,1}}
- trace: collect_build_postponed (0): postpone cfg-negotiation of {tix^ | tex->{tix/2,1}}
- trace: collect_build_postponed (0): non-negotiated clusters left and non-replace postponed positions are present, overriding first encountered non-replace position to replace
- trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: pre-reeval tix/1.0.0
%.*
- trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}}
- trace: collect_build_postponed (1): pos-postpone existing dependent tix re-evaluation to dependency index 2 due to recorded index 1, skipping {tix^ | tex->{tix/2,1}}
- trace: collect_build_postponed (0): replace dependency at index 2 of existing dependent tix/1.0.0 with dependency libbar/1.0.0 at index 1
+ trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1
trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent tix/1.0.0 due to dependency tex/0.3.0
+ trace: collect_build: add tix/1.0.0
trace: postponed_configurations::add: create {tix^ | libbar->{tix/1,1}}
- trace: collect_build_postponed (0): postpone cfg-negotiation of {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {tix^ | libbar->{tix/1,1}}
%.*
trace: collect_build_postponed (1): skip being built existing dependent tex of dependency libbar
+ trace: collect_build_prerequisites: pre-reeval tix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1
trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | libbar->{tix/1,1}}
- trace: collect_build: add tix/1.0.0
trace: collect_build_prerequisites: reeval tix/1.0.0
%.*
trace: postponed_configurations::add: add {tix^ 1,1: libbar} to {tix^ | libbar->{tix/1,1}}
@@ -9205,13 +14689,13 @@ test.options += --no-progress
%.*
trace: collect_build: pick tex/0.3.0 over tex/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency tex/0.3.0 of dependent tix/1.0.0
- trace: postponed_configurations::add: add {tix 2,1: tex} to {tix^ | tex->{tix/2,1}}
+ trace: postponed_configurations::add: create {tix | tex->{tix/2,1}}
trace: collect_build_prerequisites: postpone tix/1.0.0
trace: collect_build_postponed (1): cfg-negotiate end {tix^ | libbar->{tix/1,1}}!
- trace: collect_build_postponed (2): begin {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (2): begin {tix | tex->{tix/2,1}}
%.*
trace: collect_build_postponed (2): skip being built existing dependent tix of dependency tex
- trace: collect_build_postponed (2): cfg-negotiate begin {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tix | tex->{tix/2,1}}
%.*
trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin tex/0.3.0
@@ -9229,7 +14713,7 @@ test.options += --no-progress
trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tix/1.0.0
trace: collect_build_prerequisites: resume tix/1.0.0
trace: collect_build_prerequisites: end tix/1.0.0
- trace: collect_build_postponed (2): cfg-negotiate end {tix^ | tex->{tix/2,1}}!
+ trace: collect_build_postponed (2): cfg-negotiate end {tix | tex->{tix/2,1}}!
trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}}
%.*
trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libfoo
@@ -9243,12 +14727,18 @@ test.options += --no-progress
trace: collect_build_prerequisites: end tex/0.3.0
trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
trace: collect_build_postponed (3): end {tex | libfoo->{tex/2,1}}
- trace: collect_build_postponed (2): end {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (2): end {tix | tex->{tix/2,1}}
trace: collect_build_postponed (1): end {tix^ | libbar->{tix/1,1}}
trace: collect_build_postponed (0): end
%.*
trace: execute_plan: simulate: yes
%.*
+ build plan:
+ downgrade tex/0.3.0
+ config.tex.extras=true (set by tix)
+ reconfigure tix/1.0.0 (dependent of libbar, tex)
+ trace: execute_plan: simulate: no
+ %.*
EOE
$pkg_drop tex tix
@@ -9272,7 +14762,7 @@ test.options += --no-progress
# tix: depends: libbar(c)
# depends: tex(c)
#
- $* tex tix 2>!;
+ $* tex tix --verbose 1 2>!;
$* tix tex/0.1.0 2>>~%EOE%;
%.*
@@ -9282,52 +14772,80 @@ test.options += --no-progress
trace: collect_build: add tex/0.1.0
trace: collect_build_prerequisites: skip configured tix/1.0.0
%.*
- trace: collect_build_prerequisites: cfg-postpone dependency tex/0.1.0 of existing dependent tix/1.0.0
- trace: postponed_configurations::add: create {tix^ | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: pre-reeval tix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent tix/1.0.0 due to dependency tex/0.1.0
+ trace: postponed_configurations::add: create {tix^ | libbar->{tix/1,1}}
trace: collect_build_postponed (0): begin
- trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): begin {tix^ | libbar->{tix/1,1}}
%.*
- trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}}
- trace: collect_build_prerequisites: reeval tix/1.0.0
+ trace: collect_build_postponed (1): skip being built existing dependent tex of dependency libbar
+ trace: collect_build_prerequisites: pre-reeval tix/1.0.0
%.*
- trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: reeval tix/1.0.0
%.*
- trace: collect_build: pick tex/0.1.0 over tex/1.0.0
- trace: postponed_configurations::add: add {tix^ 2,1: tex} to {tix^ | tex->{tix/2,1}}
- trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | tex->{tix/2,1}}
+ trace: postponed_configurations::add: add {tix^ 1,1: libbar} to {tix^ | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | libbar->{tix/1,1}}
trace: collect_build_prerequisites: re-evaluated tix/1.0.0
- trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | libbar->{tix/1,1}}
%.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ %.*
+ trace: collect_build: pick tex/0.1.0 over tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/0.1.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tix^ | libbar->{tix/1,1}}!
+ trace: collect_build_postponed (2): begin {tix | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent tix of dependency tex
+ trace: collect_build_postponed (2): cfg-negotiate begin {tix | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin tex/0.1.0
%.*
trace: collect_build: add libfoo/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/0.1.0
trace: postponed_configurations::add: create {tex | libfoo->{tex/1,1}}
trace: collect_build_prerequisites: postpone tex/0.1.0
- trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
- trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tix/1.0.0
trace: collect_build_prerequisites: resume tix/1.0.0
trace: collect_build_prerequisites: end tix/1.0.0
- trace: collect_build_postponed (1): cfg-negotiate end {tix^ | tex->{tix/2,1}}!
- trace: collect_build_postponed (2): begin {tex | libfoo->{tex/1,1}}
+ trace: collect_build_postponed (2): cfg-negotiate end {tix | tex->{tix/2,1}}!
+ trace: collect_build_postponed (3): begin {tex | libfoo->{tex/1,1}}
%.*
- trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
- trace: collect_build_postponed (2): cfg-negotiate begin {tex | libfoo->{tex/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/1,1}}
%.*
- trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: skip configured libfoo/1.0.0
- trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
- trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/0.1.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/0.1.0
trace: collect_build_prerequisites: resume tex/0.1.0
trace: collect_build_prerequisites: end tex/0.1.0
- trace: collect_build_postponed (2): cfg-negotiate end {tex | libfoo->{tex/1,1}}!
- trace: collect_build_postponed (2): end {tex | libfoo->{tex/1,1}}
- trace: collect_build_postponed (1): end {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/1,1}}!
+ trace: collect_build_postponed (3): end {tex | libfoo->{tex/1,1}}
+ trace: collect_build_postponed (2): end {tix | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): end {tix^ | libbar->{tix/1,1}}
trace: collect_build_postponed (0): end
%.*
trace: execute_plan: simulate: yes
%.*
+ build plan:
+ downgrade tex/0.1.0
+ config.tex.extras=true (set by tix)
+ reconfigure/update tix/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
EOE
$pkg_drop tex tix
@@ -9348,7 +14866,7 @@ test.options += --no-progress
# tix: depends: libbar(c)
# depends: tex(c)
#
- $* tex tix 2>!;
+ $* tex tix --verbose 1 2>!;
$* tix ?tex/0.1.0 2>>~%EOE%;
%.*
@@ -9362,52 +14880,80 @@ test.options += --no-progress
%.*
trace: pkg_build: refine package collection/plan execution
%.*
- trace: collect_build_prerequisites: cfg-postpone dependency tex/0.1.0 of existing dependent tix/1.0.0
- trace: postponed_configurations::add: create {tix^ | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: pre-reeval tix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent tix/1.0.0 due to dependency tex/0.1.0
+ trace: postponed_configurations::add: create {tix^ | libbar->{tix/1,1}}
trace: collect_build_postponed (0): begin
- trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): begin {tix^ | libbar->{tix/1,1}}
%.*
- trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}}
- trace: collect_build_prerequisites: reeval tix/1.0.0
+ trace: collect_build_postponed (1): skip being built existing dependent tex of dependency libbar
+ trace: collect_build_prerequisites: pre-reeval tix/1.0.0
%.*
- trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: reeval tix/1.0.0
%.*
- trace: collect_build: pick tex/0.1.0 over tex/1.0.0
- trace: postponed_configurations::add: add {tix^ 2,1: tex} to {tix^ | tex->{tix/2,1}}
- trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | tex->{tix/2,1}}
+ trace: postponed_configurations::add: add {tix^ 1,1: libbar} to {tix^ | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | libbar->{tix/1,1}}
trace: collect_build_prerequisites: re-evaluated tix/1.0.0
- trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | libbar->{tix/1,1}}
%.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ %.*
+ trace: collect_build: pick tex/0.1.0 over tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/0.1.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tix^ | libbar->{tix/1,1}}!
+ trace: collect_build_postponed (2): begin {tix | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent tix of dependency tex
+ trace: collect_build_postponed (2): cfg-negotiate begin {tix | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin tex/0.1.0
%.*
trace: collect_build: add libfoo/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/0.1.0
trace: postponed_configurations::add: create {tex | libfoo->{tex/1,1}}
trace: collect_build_prerequisites: postpone tex/0.1.0
- trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
- trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tix/1.0.0
trace: collect_build_prerequisites: resume tix/1.0.0
trace: collect_build_prerequisites: end tix/1.0.0
- trace: collect_build_postponed (1): cfg-negotiate end {tix^ | tex->{tix/2,1}}!
- trace: collect_build_postponed (2): begin {tex | libfoo->{tex/1,1}}
+ trace: collect_build_postponed (2): cfg-negotiate end {tix | tex->{tix/2,1}}!
+ trace: collect_build_postponed (3): begin {tex | libfoo->{tex/1,1}}
%.*
- trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
- trace: collect_build_postponed (2): cfg-negotiate begin {tex | libfoo->{tex/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/1,1}}
%.*
- trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: skip configured libfoo/1.0.0
- trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
- trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/0.1.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/0.1.0
trace: collect_build_prerequisites: resume tex/0.1.0
trace: collect_build_prerequisites: end tex/0.1.0
- trace: collect_build_postponed (2): cfg-negotiate end {tex | libfoo->{tex/1,1}}!
- trace: collect_build_postponed (2): end {tex | libfoo->{tex/1,1}}
- trace: collect_build_postponed (1): end {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/1,1}}!
+ trace: collect_build_postponed (3): end {tex | libfoo->{tex/1,1}}
+ trace: collect_build_postponed (2): end {tix | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): end {tix^ | libbar->{tix/1,1}}
trace: collect_build_postponed (0): end
%.*
trace: execute_plan: simulate: yes
%.*
+ build plan:
+ downgrade/unhold tex/0.1.0
+ config.tex.extras=true (set by tix)
+ reconfigure/update tix/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
EOE
$pkg_drop tix
@@ -9415,7 +14961,7 @@ test.options += --no-progress
: dependency-downgrade-unhold-premature
:
- : As above but the dependency (tex) depends on libbar without
+ : As above but the dependency (tex/0.2.0) depends on libbar without
: configuration clause.
:
{
@@ -9429,7 +14975,7 @@ test.options += --no-progress
# tix: depends: libbar(c)
# depends: tex(c)
#
- $* tex tix 2>!;
+ $* tex tix --verbose 1 2>!;
$* tix ?tex/0.2.0 2>>~%EOE%;
%.*
@@ -9443,54 +14989,82 @@ test.options += --no-progress
%.*
trace: pkg_build: refine package collection/plan execution
%.*
- trace: collect_build_prerequisites: cfg-postpone dependency tex/0.2.0 of existing dependent tix/1.0.0
- trace: postponed_configurations::add: create {tix^ | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: pre-reeval tix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent tix/1.0.0 due to dependency tex/0.2.0
+ trace: postponed_configurations::add: create {tix^ | libbar->{tix/1,1}}
trace: collect_build_postponed (0): begin
- trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): begin {tix^ | libbar->{tix/1,1}}
%.*
- trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}}
- trace: collect_build_prerequisites: reeval tix/1.0.0
+ trace: collect_build_postponed (1): skip being built existing dependent tex of dependency libbar
+ trace: collect_build_prerequisites: pre-reeval tix/1.0.0
%.*
- trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: reeval tix/1.0.0
%.*
- trace: collect_build: pick tex/0.2.0 over tex/1.0.0
- trace: postponed_configurations::add: add {tix^ 2,1: tex} to {tix^ | tex->{tix/2,1}}
- trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | tex->{tix/2,1}}
+ trace: postponed_configurations::add: add {tix^ 1,1: libbar} to {tix^ | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | libbar->{tix/1,1}}
trace: collect_build_prerequisites: re-evaluated tix/1.0.0
- trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | libbar->{tix/1,1}}
%.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ %.*
+ trace: collect_build: pick tex/0.2.0 over tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/0.2.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tix^ | libbar->{tix/1,1}}!
+ trace: collect_build_postponed (2): begin {tix | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent tix of dependency tex
+ trace: collect_build_postponed (2): cfg-negotiate begin {tix | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin tex/0.2.0
%.*
- trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent tex/0.2.0
+ trace: collect_build_prerequisites: dep-postpone dependency libbar/1.0.0 of dependent tex/0.2.0 since already in cluster {tix^ | libbar->{tix/1,1}}!
%.*
trace: collect_build: add libfoo/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/0.2.0
trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
trace: collect_build_prerequisites: postpone tex/0.2.0
- trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
- trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tix/1.0.0
trace: collect_build_prerequisites: resume tix/1.0.0
trace: collect_build_prerequisites: end tix/1.0.0
- trace: collect_build_postponed (1): cfg-negotiate end {tix^ | tex->{tix/2,1}}!
- trace: collect_build_postponed (2): begin {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (2): cfg-negotiate end {tix | tex->{tix/2,1}}!
+ trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}}
%.*
- trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
- trace: collect_build_postponed (2): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
%.*
- trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: skip configured libfoo/1.0.0
- trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
- trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/0.2.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/0.2.0
trace: collect_build_prerequisites: resume tex/0.2.0
trace: collect_build_prerequisites: end tex/0.2.0
- trace: collect_build_postponed (2): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
- trace: collect_build_postponed (2): end {tex | libfoo->{tex/2,1}}
- trace: collect_build_postponed (1): end {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (3): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (2): end {tix | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): end {tix^ | libbar->{tix/1,1}}
trace: collect_build_postponed (0): end
%.*
trace: execute_plan: simulate: yes
%.*
+ build plan:
+ downgrade/unhold tex/0.2.0
+ config.tex.extras=true (set by tix)
+ reconfigure/update tix/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
EOE
$pkg_drop tix
@@ -9521,7 +15095,7 @@ test.options += --no-progress
# dox: dex(c)
#
# dix: depends: libbar(c)
- # depends: libbox(c) # causes postponment and initial cluster finished negotiating
+ # depends: libbox(c) # causes postponement and initial cluster finished negotiating
# depends: dox(c)
#
$* tax dex dix 2>>~%EOE%;
@@ -9863,7 +15437,7 @@ test.options += --no-progress
# dox: dex(c)
#
# dix: depends: libbar(c)
- # depends: libbox(c) # causes postponment and initial cluster finished negotiating
+ # depends: libbox(c) # causes postponement and initial cluster finished negotiating
# depends: dox(c)
#
$* dix 2>>~%EOE%;
@@ -10473,11 +16047,11 @@ test.options += --no-progress
# dex: depends: bar(c)
# depends: libfoo(c)
#
- # bux: depends: libbar(c)
- #
# buc: depends: libfoo(c)
# depends: bux(c)
#
+ # bux: depends: libbar(c)
+ #
$* bar dex buc bux 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
@@ -10560,23 +16134,6 @@ test.options += --no-progress
trace: collect_build: add dex/1.0.0
trace: collect_build: add buc/1.0.0
trace: collect_build: add bux/1.0.0
- trace: collect_build_prerequisites: begin bar/1.0.0
- %.*
- trace: collect_build: add libbar/1.0.0
- trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
- trace: postponed_configurations::add: create {bar | libbar->{bar/1,1}}
- trace: collect_build_prerequisites: postpone bar/1.0.0
- trace: collect_build_prerequisites: begin dex/1.0.0
- %.*
- trace: collect_build_prerequisites: cannot cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0 (collected prematurely), throwing postpone_dependency
- trace: pkg_build: collection failed due to prematurely collected dependency (bar), retry from scratch
- %.*
- trace: pkg_build: refine package collection/plan execution from scratch
- %.*
- trace: collect_build: add bar/1.0.0
- trace: collect_build: add dex/1.0.0
- trace: collect_build: add buc/1.0.0
- trace: collect_build: add bux/1.0.0
trace: pkg_build: dep-postpone user-specified bar
trace: collect_build_prerequisites: begin dex/1.0.0
%.*
@@ -10594,7 +16151,6 @@ test.options += --no-progress
trace: collect_build_postponed (1): begin {dex | bar->{dex/1,1}}
%.*
trace: collect_build_postponed (1): cfg-negotiate begin {dex | bar->{dex/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin bar/1.0.0
%.*
@@ -10613,7 +16169,6 @@ test.options += --no-progress
trace: collect_build_postponed (2): begin {buc dex | libfoo->{buc/1,1 dex/2,1}}
%.*
trace: collect_build_postponed (2): cfg-negotiate begin {buc dex | libfoo->{buc/1,1 dex/2,1}}
- %.*
trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libfoo/1.0.0
trace: collect_build_prerequisites: end libfoo/1.0.0
@@ -10664,6 +16219,19 @@ test.options += --no-progress
trace: collect_build_postponed (0): end
trace: execute_plan: simulate: yes
%.*
+ build plan:
+ new libfoo/1.0.0 (required by buc, dex)
+ config.libfoo.extras=true (set by buc)
+ new libbar/1.0.0 (required by bar, bux)
+ config.libbar.extras=true (set by bar)
+ new bar/1.0.0
+ config.bar.extras=true (set by dex)
+ new dex/1.0.0
+ new bux/1.0.0
+ config.bux.extras=true (set by buc)
+ new buc/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
EOE
$pkg_status -r >>EOO;
@@ -10991,35 +16559,31 @@ test.options += --no-progress
# dox: dex(c)
#
# dix: depends: libbar(c)
- # depends: libbox(c) # causes postponment and initial cluster finished negotiating
+ # depends: libbox(c) # causes postponement and initial cluster finished negotiating
# depends: dox(c)
#
- $* dex 2>!;
+ $* dex --verbose 1 2>!;
- $* dix 2>>~%EOE%;
+ $* dix 2>&1 | $filter 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add dix/1.0.0
trace: collect_build_prerequisites: begin dix/1.0.0
- %.*
trace: collect_build: add libbar/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent dix/1.0.0
trace: postponed_configurations::add: create {dix | libbar->{dix/1,1}}
trace: collect_build_prerequisites: postpone dix/1.0.0
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {dix | libbar->{dix/1,1}}
- %.*
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
trace: collect_build_postponed (1): re-evaluate existing dependents for {dix | libbar->{dix/1,1}}
- %.*
trace: collect_build: add bar/1.0.0
trace: collect_build_prerequisites: reeval bar/1.0.0
- %.*
trace: postponed_configurations::add: add {bar^ 1,1: libbar} to {dix | libbar->{dix/1,1}}
trace: collect_build_prerequisites: re-evaluating dependent bar/1.0.0 results in {bar^ dix | libbar->{bar/1,1 dix/1,1}}
trace: collect_build_prerequisites: re-evaluated bar/1.0.0
trace: collect_build_postponed (1): cfg-negotiate begin {bar^ dix | libbar->{bar/1,1 dix/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: skip configured libbar/1.0.0
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
@@ -11028,35 +16592,28 @@ test.options += --no-progress
trace: collect_build_prerequisites: end bar/1.0.0
trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent dix/1.0.0
trace: collect_build_prerequisites: resume dix/1.0.0
- %.*
trace: collect_build: add libbox/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent dix/1.0.0
trace: postponed_configurations::add: create {dix | libbox->{dix/2,1}}
trace: collect_build_prerequisites: postpone dix/1.0.0
trace: collect_build_postponed (1): cfg-negotiate end {bar^ dix | libbar->{bar/1,1 dix/1,1}}!
trace: collect_build_postponed (2): begin {dix | libbox->{dix/2,1}}
- %.*
trace: collect_build_postponed (2): cfg-negotiate begin {dix | libbox->{dix/2,1}}
- %.*
trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libbox/1.0.0
trace: collect_build_prerequisites: end libbox/1.0.0
trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent dix/1.0.0
trace: collect_build_prerequisites: resume dix/1.0.0
- %.*
trace: collect_build: add dox/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of dependent dix/1.0.0
trace: postponed_configurations::add: create {dix | dox->{dix/3,1}}
trace: collect_build_prerequisites: postpone dix/1.0.0
trace: collect_build_postponed (2): cfg-negotiate end {dix | libbox->{dix/2,1}}!
trace: collect_build_postponed (3): begin {dix | dox->{dix/3,1}}
- %.*
trace: collect_build_postponed (3): cfg-negotiate begin {dix | dox->{dix/3,1}}
- %.*
trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin dox/1.0.0
- %.*
trace: collect_build: add dex/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
@@ -11067,64 +16624,52 @@ test.options += --no-progress
trace: collect_build_prerequisites: end dix/1.0.0
trace: collect_build_postponed (3): cfg-negotiate end {dix | dox->{dix/3,1}}!
trace: collect_build_postponed (4): begin {dox | dex->{dox/1,1}}
- %.*
trace: collect_build_postponed (4): cfg-negotiate begin {dox | dex->{dox/1,1}}
- %.*
trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin dex/1.0.0
- %.*
trace: collect_build_prerequisites: cannot cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0 (collected prematurely), throwing postpone_dependency
trace: pkg_build: collection failed due to prematurely collected dependency (bar), retry from scratch
- %.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add dix/1.0.0
trace: collect_build_prerequisites: begin dix/1.0.0
- %.*
trace: collect_build: add libbar/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent dix/1.0.0
trace: postponed_configurations::add: create {dix | libbar->{dix/1,1}}
trace: collect_build_prerequisites: postpone dix/1.0.0
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {dix | libbar->{dix/1,1}}
- %.*
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
trace: collect_build_postponed (1): skip dep-postponed existing dependent bar of dependency libbar
+ trace: collect_build: add bar/1.0.0
trace: collect_build_postponed (1): cfg-negotiate begin {dix | libbar->{dix/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: skip configured libbar/1.0.0
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent dix/1.0.0
trace: collect_build_prerequisites: resume dix/1.0.0
- %.*
trace: collect_build: add libbox/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent dix/1.0.0
trace: postponed_configurations::add: create {dix | libbox->{dix/2,1}}
trace: collect_build_prerequisites: postpone dix/1.0.0
trace: collect_build_postponed (1): cfg-negotiate end {dix | libbar->{dix/1,1}}!
trace: collect_build_postponed (2): begin {dix | libbox->{dix/2,1}}
- %.*
trace: collect_build_postponed (2): cfg-negotiate begin {dix | libbox->{dix/2,1}}
- %.*
trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libbox/1.0.0
trace: collect_build_prerequisites: end libbox/1.0.0
trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent dix/1.0.0
trace: collect_build_prerequisites: resume dix/1.0.0
- %.*
trace: collect_build: add dox/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of dependent dix/1.0.0
trace: postponed_configurations::add: create {dix | dox->{dix/3,1}}
trace: collect_build_prerequisites: postpone dix/1.0.0
trace: collect_build_postponed (2): cfg-negotiate end {dix | libbox->{dix/2,1}}!
trace: collect_build_postponed (3): begin {dix | dox->{dix/3,1}}
- %.*
trace: collect_build_postponed (3): cfg-negotiate begin {dix | dox->{dix/3,1}}
- %.*
trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin dox/1.0.0
- %.*
trace: collect_build: add dex/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
@@ -11135,13 +16680,9 @@ test.options += --no-progress
trace: collect_build_prerequisites: end dix/1.0.0
trace: collect_build_postponed (3): cfg-negotiate end {dix | dox->{dix/3,1}}!
trace: collect_build_postponed (4): begin {dox | dex->{dox/1,1}}
- %.*
trace: collect_build_postponed (4): cfg-negotiate begin {dox | dex->{dox/1,1}}
- %.*
trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin dex/1.0.0
- %.*
- trace: collect_build: add bar/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
trace: collect_build_prerequisites: postpone dex/1.0.0
@@ -11151,13 +16692,10 @@ test.options += --no-progress
trace: collect_build_prerequisites: end dox/1.0.0
trace: collect_build_postponed (4): cfg-negotiate end {dox | dex->{dox/1,1}}!
trace: collect_build_postponed (5): begin {dex | bar->{dex/1,1}}
- %.*
trace: collect_build_postponed (5): skip being built existing dependent dex of dependency bar
trace: collect_build_postponed (5): cfg-negotiate begin {dex | bar->{dex/1,1}}
- %.*
trace: collect_build_postponed (5): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin bar/1.0.0
- %.*
trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
trace: postponed_configurations::add: add {bar 1,1: libbar} to {dix | libbar->{dix/1,1}}!
trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bar/1.0.0 is negotiated
@@ -11166,17 +16704,14 @@ test.options += --no-progress
trace: collect_build_postponed (5): recursively collect cfg-negotiated dependents
trace: collect_build_postponed (5): select cfg-negotiated dependency alternative for dependent dex/1.0.0
trace: collect_build_prerequisites: resume dex/1.0.0
- %.*
trace: collect_build: add libfoo/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent dex/1.0.0
trace: postponed_configurations::add: create {dex | libfoo->{dex/2,1}}
trace: collect_build_prerequisites: postpone dex/1.0.0
trace: collect_build_postponed (5): cfg-negotiate end {dex | bar->{dex/1,1}}!
trace: collect_build_postponed (6): begin {dex | libfoo->{dex/2,1}}
- %.*
trace: collect_build_postponed (6): skip being built existing dependent dex of dependency libfoo
trace: collect_build_postponed (6): cfg-negotiate begin {dex | libfoo->{dex/2,1}}
- %.*
trace: collect_build_postponed (6): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: skip configured libfoo/1.0.0
trace: collect_build_postponed (6): recursively collect cfg-negotiated dependents
@@ -11191,9 +16726,16 @@ test.options += --no-progress
trace: collect_build_postponed (2): end {dix | libbox->{dix/2,1}}
trace: collect_build_postponed (1): end {dix | libbar->{dix/1,1}}
trace: collect_build_postponed (0): end
- %.*
trace: execute_plan: simulate: yes
%.*
+ build plan:
+ new libbox/1.0.0 (required by dix)
+ config.libbox.extras=true (set by dix)
+ new dox/1.0.0 (required by dix)
+ config.dox.extras=true (set by dix)
+ new dix/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
EOE
$pkg_status -r >>EOO;
@@ -11237,20 +16779,17 @@ test.options += --no-progress
{
$clone_cfg;
- $* foo fox/0.1.0 ?libbar 2>>~%EOE%;
+ $* foo fox/0.1.0 ?libbar 2>&1 | $filter 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add foo/1.0.0
trace: collect_build: add fox/0.1.0
trace: collect_build_prerequisites: begin foo/1.0.0
- %.*
trace: collect_build: add libfoo/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
trace: collect_build_prerequisites: postpone foo/1.0.0
trace: collect_build_prerequisites: begin fox/0.1.0
- %.*
trace: collect_build_prerequisites: alt-postpone dependent fox/0.1.0 since max index is reached: 0
info: dependency alternative: libfoo
{
@@ -11258,15 +16797,12 @@ test.options += --no-progress
{
config.libfoo.extras = true
}
-
accept (false)
}
trace: collect_build_prerequisites: postpone fox/0.1.0
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {foo | libfoo->{foo/1,1}}
- %.*
trace: collect_build_postponed (1): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libfoo/1.0.0
trace: collect_build_prerequisites: end libfoo/1.0.0
@@ -11277,34 +16813,26 @@ test.options += --no-progress
trace: collect_build_postponed (1): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
trace: collect_build_postponed (1): index 1 collect alt-postponed fox/0.1.0
trace: collect_build_prerequisites: resume fox/0.1.0
- %.*
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent fox/0.1.0
- %.*
trace: postponed_configurations::add: add {fox 1,1: libfoo} to {foo | libfoo->{foo/1,1}}!
- %.*
trace: collect_build_prerequisites: unable to cfg-negotiate dependency alternative 1,1 for dependent fox/0.1.0, throwing unaccept_alternative
trace: pkg_build: collection failed due to unacceptable alternative, retry from scratch
- %.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add foo/1.0.0
trace: collect_build: add fox/0.1.0
trace: collect_build_prerequisites: begin foo/1.0.0
- %.*
trace: collect_build: add libfoo/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
trace: collect_build_prerequisites: postpone foo/1.0.0
trace: collect_build_prerequisites: begin fox/0.1.0
trace: collect_build_prerequisites: dependency alternative 1,1 for dependent fox/0.1.0 is unacceptable, skipping
- %.*
trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent fox/0.1.0
trace: collect_build_prerequisites: begin libbar/1.0.0
trace: collect_build_prerequisites: end libbar/1.0.0
trace: collect_build_prerequisites: end fox/0.1.0
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {foo | libfoo->{foo/1,1}}
- %.*
trace: collect_build_postponed (1): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libfoo/1.0.0
@@ -11326,6 +16854,7 @@ test.options += --no-progress
new libfoo/1.0.0 (required by foo)
config.libfoo.extras=true (set by foo)
new foo/1.0.0
+ config.foo.libfoo_extras=true (set by foo)
new libbar/1.0.0 (required by fox)
new fox/0.1.0
trace: execute_plan: simulate: no
@@ -11347,20 +16876,17 @@ test.options += --no-progress
{
$clone_cfg;
- $* foo fox/0.2.0 2>>~%EOE%;
+ $* foo fox/0.2.0 2>&1 | $filter 2>>~%EOE%;
%.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add foo/1.0.0
trace: collect_build: add fox/0.2.0
trace: collect_build_prerequisites: begin foo/1.0.0
- %.*
trace: collect_build: add libfoo/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
trace: collect_build_prerequisites: postpone foo/1.0.0
trace: collect_build_prerequisites: begin fox/0.2.0
- %.*
trace: collect_build_prerequisites: alt-postpone dependent fox/0.2.0 since max index is reached: 0
info: dependency alternative: libfoo
{
@@ -11368,15 +16894,12 @@ test.options += --no-progress
{
config.libfoo.extras = false
}
-
accept (!$config.libfoo.extras)
}
trace: collect_build_prerequisites: postpone fox/0.2.0
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {foo | libfoo->{foo/1,1}}
- %.*
trace: collect_build_postponed (1): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
- %.*
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libfoo/1.0.0
trace: collect_build_prerequisites: end libfoo/1.0.0
@@ -11387,15 +16910,11 @@ test.options += --no-progress
trace: collect_build_postponed (1): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
trace: collect_build_postponed (1): index 1 collect alt-postponed fox/0.2.0
trace: collect_build_prerequisites: resume fox/0.2.0
- %.*
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent fox/0.2.0
- %.*
trace: postponed_configurations::add: add {fox 1,1: libfoo} to {foo | libfoo->{foo/1,1}}!
- %.*
trace: collect_build_prerequisites: cfg-postponing dependent fox/0.2.0 involves (being) negotiated configurations and results in {foo fox | libfoo->{foo/1,1 fox/1,1}}!, throwing retry_configuration
trace: collect_build_postponed (0): cfg-negotiation of {foo | libfoo->{foo/1,1}} failed due to dependent fox, refining configuration
trace: collect_build_postponed (1): begin {foo | libfoo->{foo/1,1}}
- %.*
trace: collect_build_postponed (1): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libfoo/1.0.0
@@ -11407,14 +16926,11 @@ test.options += --no-progress
trace: collect_build_postponed (1): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
trace: collect_build_postponed (1): index 1 collect alt-postponed fox/0.2.0
trace: collect_build_prerequisites: resume fox/0.2.0
- %.*
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent fox/0.2.0
- %.*
trace: postponed_configurations::add: add {fox 1,1: libfoo} to {foo | libfoo->{foo/1,1}}!
trace: collect_build_prerequisites: cfg-postponing dependent fox/0.2.0 involves (being) negotiated configurations and results in {foo fox | libfoo->{foo/1,1 fox/1,1}}!, throwing retry_configuration
trace: collect_build_postponed (0): cfg-negotiation of {foo | libfoo->{foo/1,1}} failed due to dependent fox, refining configuration
trace: collect_build_postponed (1): begin {foo | libfoo->{foo/1,1}}
- %.*
trace: collect_build_postponed (1): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libfoo/1.0.0
@@ -11426,26 +16942,20 @@ test.options += --no-progress
trace: collect_build_postponed (1): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
trace: collect_build_postponed (1): index 1 collect alt-postponed fox/0.2.0
trace: collect_build_prerequisites: resume fox/0.2.0
- %.*
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent fox/0.2.0
- %.*
trace: postponed_configurations::add: add {fox 1,1: libfoo} to {foo | libfoo->{foo/1,1}}!
trace: collect_build_prerequisites: unable to cfg-negotiate dependency alternative 1,1 for dependent fox/0.2.0, throwing unaccept_alternative
trace: pkg_build: collection failed due to unacceptable alternative, retry from scratch
- %.*
trace: pkg_build: refine package collection/plan execution from scratch
- %.*
trace: collect_build: add foo/1.0.0
trace: collect_build: add fox/0.2.0
trace: collect_build_prerequisites: begin foo/1.0.0
- %.*
trace: collect_build: add libfoo/1.0.0
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
trace: collect_build_prerequisites: postpone foo/1.0.0
trace: collect_build_prerequisites: begin fox/0.2.0
trace: collect_build_prerequisites: dependency alternative 1,1 for dependent fox/0.2.0 is unacceptable, skipping
- %.*
trace: collect_build_prerequisites: alt-postpone dependent fox/0.2.0 since max index is reached: 1
info: dependency alternative: libfoo
{
@@ -11453,13 +16963,11 @@ test.options += --no-progress
{
config.libfoo.extras = true
}
-
accept (true)
}
trace: collect_build_prerequisites: postpone fox/0.2.0
trace: collect_build_postponed (0): begin
trace: collect_build_postponed (1): begin {foo | libfoo->{foo/1,1}}
- %.*
trace: collect_build_postponed (1): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
trace: collect_build_prerequisites: begin libfoo/1.0.0
@@ -11472,7 +16980,6 @@ test.options += --no-progress
trace: collect_build_postponed (1): index 1 collect alt-postponed fox/0.2.0
trace: collect_build_prerequisites: resume fox/0.2.0
trace: collect_build_prerequisites: dependency alternative 1,1 for dependent fox/0.2.0 is unacceptable, skipping
- %.*
trace: collect_build_prerequisites: alt-postpone dependent fox/0.2.0 since max index is reached: 1
info: dependency alternative: libfoo
{
@@ -11480,27 +16987,26 @@ test.options += --no-progress
{
config.libfoo.extras = true
}
-
accept (true)
}
trace: collect_build_prerequisites: postpone fox/0.2.0
trace: collect_build_postponed (1): index 2 collect alt-postponed fox/0.2.0
trace: collect_build_prerequisites: resume fox/0.2.0
trace: collect_build_prerequisites: dependency alternative 1,1 for dependent fox/0.2.0 is unacceptable, skipping
- %.*
trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent fox/0.2.0
- %.*
trace: postponed_configurations::add: add {fox 1,2: libfoo} to {foo | libfoo->{foo/1,1}}!
trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent fox/0.2.0 is negotiated
trace: collect_build_prerequisites: dependency libfoo/1.0.0 of dependent fox/0.2.0 is already (being) recursively collected, skipping
trace: collect_build_prerequisites: end fox/0.2.0
trace: collect_build_postponed (1): end {foo | libfoo->{foo/1,1}}
trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
%.*
build plan:
new libfoo/1.0.0 (required by foo, fox)
config.libfoo.extras=true (set by foo)
new foo/1.0.0
+ config.foo.libfoo_extras=true (set by foo)
new fox/0.2.0
trace: execute_plan: simulate: no
%.*
@@ -11590,136 +17096,7325 @@ test.options += --no-progress
}
}
- : all-repo-packages
+ : skip-existing-dependent
:
- : Don't match the tracing but just make sure that pkg-build doesn't crash
- : or hang and ends up with an expected packages setup.
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tix: depends: libbar(c)
+ # depends: tex(c)
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ $* tix ?libfoo/0.1.0 --verbose 1 2>!;
+
+ $pkg_status -r >>EOO;
+ !tix configured 1.0.0
+ libbar configured 1.0.0
+ tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ $* --upgrade --recursive 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build_prerequisites: skip configured tix/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: libfoo/0.1.0: update to libfoo/1.0.0
+ %.*
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent tex/1.0.0 due to dependency libfoo/1.0.0
+ trace: collect_build: add tex/1.0.0
+ trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tix/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build_prerequisites: reeval tix/1.0.0
+ trace: postponed_configurations::add: add {tix^ 1,1: libbar} to {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tex^ tix^ | libbar->{tex/1,1 tix/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tex^ tix^ | libbar->{tex/1,1 tix/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build: pick libfoo/1.0.0 over libfoo/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency tex/1.0.0 of dependent tix/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build_prerequisites: skip configured tix/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent tex/1.0.0 due to dependency libfoo/1.0.0
+ trace: collect_build: add tex/1.0.0
+ trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tix/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tix/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex of dependency libbar
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: reeval tix/1.0.0
+ trace: postponed_configurations::add: add {tix^ 1,1: libbar} to {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tex^ tix^ | libbar->{tex/1,1 tix/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tex^ tix^ | libbar->{tex/1,1 tix/1,1}}
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tex^ tix^ | libbar->{tex/1,1 tix/1,1}}!
+ trace: collect_build_postponed (2): begin {tix | tex->{tix/2,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tix of dependency tex
+ trace: collect_build_postponed (2): cfg-negotiate begin {tix | tex->{tix/2,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {tex^ tix^ | libbar->{tex/1,1 tix/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: pick libfoo/1.0.0 over libfoo/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: end tix/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tix | tex->{tix/2,1}}!
+ trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (3): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (2): end {tix | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): end {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ upgrade libfoo/1.0.0
+ config.libfoo.extras=true (set by tex)
+ reconfigure/update tex/1.0.0 (required by tix)
+ config.tex.extras=true (set by tix)
+ config.tex.libfoo_extras=true (set by tex)
+ reconfigure/update tix/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tix configured 1.0.0
+ libbar configured 1.0.0
+ tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop tix
+ }
+
+ : skip-existing-dependent-last
+ :
+ : Similar to the above but the skipped existing dependent is the last/only
+ : dependent in the cluster.
:
{
$clone_cfg;
- $* libfoo libbar ?libbaz/0.1.0 ?libbox/0.1.0 \
- foo fox fux fix fex bar baz bac bat bas bus \
- box bax bux bix bex boo biz buz buc tax tex \
- tix tiz toz tez tux dex dix diz dox 2>!;
+ # Dependencies:
+ #
+ # tiz: depends: tex(c)
+ # depends: libbar(c)
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ $* tiz ?libfoo/0.1.0 --verbose 1 2>!;
$pkg_status -r >>EOO;
- !libfoo configured 1.0.0
- !libbar configured 1.0.0
- !bat configured 1.0.0
- libbaz configured !0.1.0 available 1.0.0
- !tix configured 0.1.0 available 1.0.0
- !toz configured 0.1.0 available 1.0.0 0.2.0
- !tux configured 1.0.0
+ !tiz configured 1.0.0
+ libbar configured 1.0.0
+ tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ $* --upgrade --recursive 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: skip configured tiz/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: libfoo/0.1.0: update to libfoo/1.0.0
+ %.*
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent tex/1.0.0 due to dependency libfoo/1.0.0
+ trace: collect_build: add tex/1.0.0
+ trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: collect_build_prerequisites: cannot re-evaluate existing dependent tiz/1.0.0 due to dependency tex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: skip configured tiz/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent tex/1.0.0 due to dependency libfoo/1.0.0
+ trace: collect_build: add tex/1.0.0
+ trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex of dependency libbar
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: postponed_configurations::add: create {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tiz/1.0.0 results in {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tiz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex
+ trace: collect_build_postponed (1): cfg-negotiate end {tex^ | libbar->{tex/1,1}}!
+ trace: collect_build_postponed (2): begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tiz of dependency tex
+ trace: collect_build_postponed (2): cfg-negotiate begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {tex^ | libbar->{tex/1,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent tex/1.0.0 involves (being) negotiated configurations and results in {tex^ | libbar->{tex/1,1}}!, throwing retry_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {tex^ | libbar->{tex/1,1}} failed due to dependent tex, refining configuration
+ trace: collect_build_postponed (1): begin {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex of dependency libbar
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: postponed_configurations::add: create {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tiz/1.0.0 results in {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tiz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex
+ trace: collect_build_postponed (1): cfg-negotiate end {tex^ | libbar->{tex/1,1}}!
+ trace: collect_build_postponed (2): begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tiz of dependency tex
+ trace: collect_build_postponed (2): cfg-negotiate begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {tex^ | libbar->{tex/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: pick libfoo/1.0.0 over libfoo/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tiz/1.0.0
+ trace: collect_build_prerequisites: resume tiz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: add {tiz 2,1: libbar} to {tex^ | libbar->{tex/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tiz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tiz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tiz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tiz^ | tex->{tiz/1,1}}!
+ trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (3): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (2): end {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (1): end {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ upgrade libfoo/1.0.0
+ config.libfoo.extras=true (set by tex)
+ reconfigure/update tex/1.0.0 (required by tiz)
+ config.tex.extras=true (set by tiz)
+ config.tex.libfoo_extras=true (set by tex)
+ reconfigure/update tiz/1.0.0
+ config.tiz.tex_extras=true (set by tiz)
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tiz configured 1.0.0
+ libbar configured 1.0.0
+ tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop tiz
+ }
+
+ : skip-existing-dependent-cluster
+ :
+ : Similar to skip-existing-dependent but skip the existing dependent
+ : because it is already in a cluster as a dependency.
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # bac: depends: libbar(c)
+ # depends: libbaz(c)
+ # depends: libfoo(c)
+ #
+ # bas: depends: libbar(c)
+ # depends: bus(c)
+ #
+ # bus: depends: libbaz(c)
+ # depends: foo(c)
+ #
+ # foo: depends: libfoo(c)
+ #
+ # box: depends: {libbar libfoo} (c) | libbox
+ #
+ $* bac bas 2>!;
+
+ $pkg_status -r >>EOO;
+ !bac configured 1.0.0
+ libbar configured 1.0.0
+ libbaz configured 1.0.0
+ libfoo configured 1.0.0
+ !bas configured 1.0.0
+ bus configured 1.0.0
+ foo configured 1.0.0
+ libfoo configured 1.0.0
+ libbaz configured 1.0.0
+ libbar configured 1.0.0
+ EOO
+
+ $* box 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add box/1.0.0
+ trace: collect_build_prerequisites: begin box/1.0.0
+ trace: collect_build_prerequisites: alt-postpone dependent box/1.0.0 since max index is reached: 0
+ info: dependency alternative: {libbar libfoo}
+ {
+ require
+ {
+ config.libbar.extras = true
+ config.libfoo.extras = true
+ }
+ }
+ trace: collect_build_prerequisites: postpone box/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (0): index 1 collect alt-postponed box/1.0.0
+ trace: collect_build_prerequisites: resume box/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent box/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent box/1.0.0
+ trace: postponed_configurations::add: create {box | libbar->{box/1,1} libfoo->{box/1,1}}
+ trace: collect_build_prerequisites: postpone box/1.0.0
+ trace: collect_build_postponed (1): begin {box | libbar->{box/1,1} libfoo->{box/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bac/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bac/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval bas/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bas/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval bac/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bac/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbar->{box/1,1} libfoo->{box/1,1}}
+ trace: collect_build: add bac/1.0.0
+ trace: collect_build_prerequisites: reeval bac/1.0.0
+ trace: postponed_configurations::add: add {bac^ 1,1: libbar} to {box | libbar->{box/1,1} libfoo->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bac/1.0.0 results in {bac^ box | libbar->{bac/1,1 box/1,1} libfoo->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bac/1.0.0
+ trace: collect_build: add bas/1.0.0
+ trace: collect_build_prerequisites: reeval bas/1.0.0
+ trace: postponed_configurations::add: add {bas^ 1,1: libbar} to {bac^ box | libbar->{bac/1,1 box/1,1} libfoo->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bas/1.0.0 results in {bac^ bas^ box | libbar->{bac/1,1 bas/1,1 box/1,1} libfoo->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bas/1.0.0
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: reeval foo/1.0.0
+ trace: postponed_configurations::add: add {foo^ 1,1: libfoo} to {bac^ bas^ box | libbar->{bac/1,1 bas/1,1 box/1,1} libfoo->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent foo/1.0.0 results in {bac^ bas^ box foo^ | libbar->{bac/1,1 bas/1,1 box/1,1} libfoo->{box/1,1 foo/1,1}}
+ trace: collect_build_prerequisites: re-evaluated foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bac^ bas^ box foo^ | libbar->{bac/1,1 bas/1,1 box/1,1} libfoo->{box/1,1 foo/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bac/1.0.0
+ trace: collect_build_prerequisites: resume bac/1.0.0
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bac/1.0.0
+ trace: postponed_configurations::add: create {bac | libbaz->{bac/2,1}}
+ trace: collect_build_prerequisites: postpone bac/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bas/1.0.0
+ trace: collect_build_prerequisites: resume bas/1.0.0
+ trace: collect_build: add bus/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bus/1.0.0 of dependent bas/1.0.0
+ trace: postponed_configurations::add: create {bas | bus->{bas/2,1}}
+ trace: collect_build_prerequisites: postpone bas/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/1.0.0
+ trace: collect_build_prerequisites: resume box/1.0.0
+ trace: collect_build_prerequisites: end box/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bac^ bas^ box foo^ | libbar->{bac/1,1 bas/1,1 box/1,1} libfoo->{box/1,1 foo/1,1}}!
+ trace: collect_build_postponed (2): begin {bac | libbaz->{bac/2,1}}
+ trace: collect_build_prerequisites: pre-reeval bus/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bus/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bac of dependency libbaz
+ trace: collect_build_postponed (2): skip existing dependent bus of dependency libbaz since dependent already in cluster {bas | bus->{bas/2,1}} (as a dependency)
+ trace: collect_build_postponed (2): cfg-negotiate begin {bac | libbaz->{bac/2,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbaz/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bac/1.0.0
+ trace: collect_build_prerequisites: resume bac/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent bac/1.0.0
+ trace: postponed_configurations::add: add {bac 3,1: libfoo} to {bac^ bas^ box foo^ | libbar->{bac/1,1 bas/1,1 box/1,1} libfoo->{box/1,1 foo/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bac/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libfoo/1.0.0 of dependent bac/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bac/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bac | libbaz->{bac/2,1}}!
+ trace: collect_build_postponed (3): begin {bas | bus->{bas/2,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent bas of dependency bus
+ trace: collect_build_postponed (3): cfg-negotiate begin {bas | bus->{bas/2,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bus/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bus/1.0.0
+ trace: postponed_configurations::add: add {bus 1,1: libbaz} to {bac | libbaz->{bac/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bus/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbaz/1.0.0 of dependent bus/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency foo/1.0.0 of dependent bus/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (foo), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add box/1.0.0
+ trace: collect_build_prerequisites: begin box/1.0.0
+ trace: collect_build_prerequisites: alt-postpone dependent box/1.0.0 since max index is reached: 0
+ info: dependency alternative: {libbar libfoo}
+ {
+ require
+ {
+ config.libbar.extras = true
+ config.libfoo.extras = true
+ }
+ }
+ trace: collect_build_prerequisites: postpone box/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (0): index 1 collect alt-postponed box/1.0.0
+ trace: collect_build_prerequisites: resume box/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent box/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent box/1.0.0
+ trace: postponed_configurations::add: create {box | libbar->{box/1,1} libfoo->{box/1,1}}
+ trace: collect_build_prerequisites: postpone box/1.0.0
+ trace: collect_build_postponed (1): begin {box | libbar->{box/1,1} libfoo->{box/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bac/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bac/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval bas/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bas/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval bac/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bac/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent foo of dependency libfoo
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbar->{box/1,1} libfoo->{box/1,1}}
+ trace: collect_build: add bac/1.0.0
+ trace: collect_build_prerequisites: reeval bac/1.0.0
+ trace: postponed_configurations::add: add {bac^ 1,1: libbar} to {box | libbar->{box/1,1} libfoo->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bac/1.0.0 results in {bac^ box | libbar->{bac/1,1 box/1,1} libfoo->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bac/1.0.0
+ trace: collect_build: add bas/1.0.0
+ trace: collect_build_prerequisites: reeval bas/1.0.0
+ trace: postponed_configurations::add: add {bas^ 1,1: libbar} to {bac^ box | libbar->{bac/1,1 box/1,1} libfoo->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bas/1.0.0 results in {bac^ bas^ box | libbar->{bac/1,1 bas/1,1 box/1,1} libfoo->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bas/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bac^ bas^ box | libbar->{bac/1,1 bas/1,1 box/1,1} libfoo->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bac/1.0.0
+ trace: collect_build_prerequisites: resume bac/1.0.0
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bac/1.0.0
+ trace: postponed_configurations::add: create {bac | libbaz->{bac/2,1}}
+ trace: collect_build_prerequisites: postpone bac/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bas/1.0.0
+ trace: collect_build_prerequisites: resume bas/1.0.0
+ trace: collect_build: add bus/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bus/1.0.0 of dependent bas/1.0.0
+ trace: postponed_configurations::add: create {bas | bus->{bas/2,1}}
+ trace: collect_build_prerequisites: postpone bas/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/1.0.0
+ trace: collect_build_prerequisites: resume box/1.0.0
+ trace: collect_build_prerequisites: end box/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bac^ bas^ box | libbar->{bac/1,1 bas/1,1 box/1,1} libfoo->{box/1,1}}!
+ trace: collect_build_postponed (2): begin {bac | libbaz->{bac/2,1}}
+ trace: collect_build_prerequisites: pre-reeval bus/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bus/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bac of dependency libbaz
+ trace: collect_build_postponed (2): skip existing dependent bus of dependency libbaz since dependent already in cluster {bas | bus->{bas/2,1}} (as a dependency)
+ trace: collect_build_postponed (2): cfg-negotiate begin {bac | libbaz->{bac/2,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbaz/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bac/1.0.0
+ trace: collect_build_prerequisites: resume bac/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent bac/1.0.0
+ trace: postponed_configurations::add: add {bac 3,1: libfoo} to {bac^ bas^ box | libbar->{bac/1,1 bas/1,1 box/1,1} libfoo->{box/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bac/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libfoo/1.0.0 of dependent bac/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bac/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bac | libbaz->{bac/2,1}}!
+ trace: collect_build_postponed (3): begin {bas | bus->{bas/2,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent bas of dependency bus
+ trace: collect_build_postponed (3): cfg-negotiate begin {bas | bus->{bas/2,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bus/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bus/1.0.0
+ trace: postponed_configurations::add: add {bus 1,1: libbaz} to {bac | libbaz->{bac/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bus/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbaz/1.0.0 of dependent bus/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent bus/1.0.0
+ trace: postponed_configurations::add: create {bus | foo->{bus/2,1}}
+ trace: collect_build_prerequisites: postpone bus/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bas/1.0.0
+ trace: collect_build_prerequisites: resume bas/1.0.0
+ trace: collect_build_prerequisites: end bas/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {bas | bus->{bas/2,1}}!
+ trace: collect_build_postponed (4): begin {bus | foo->{bus/2,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent bus of dependency foo
+ trace: collect_build_postponed (4): cfg-negotiate begin {bus | foo->{bus/2,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: add {foo 1,1: libfoo} to {bac^ bas^ box | libbar->{bac/1,1 bas/1,1 box/1,1} libfoo->{bac/3,1 box/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent foo/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libfoo/1.0.0 of dependent foo/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent bus/1.0.0
+ trace: collect_build_prerequisites: resume bus/1.0.0
+ trace: collect_build_prerequisites: end bus/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {bus | foo->{bus/2,1}}!
+ trace: collect_build_postponed (4): end {bus | foo->{bus/2,1}}
+ trace: collect_build_postponed (3): end {bas | bus->{bas/2,1}}
+ trace: collect_build_postponed (2): end {bac | libbaz->{bac/2,1}}
+ trace: collect_build_postponed (1): end {box | libbar->{box/1,1} libfoo->{box/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ new box/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_drop bac bas box
+ }
+
+ : replace-configured-dependency
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # diz: depends: dox(c)
+ # depends: libbox(c)
+ # depends: libbar(c)
+ #
+ # dox: depends: dex(c)
+ #
+ # dex: depends: bar(c)
+ # depends: libfoo(c)
+ #
+ # bar: depends: libbar(c)
+ #
+ $* diz libbar/0.1.0 ?libbox/0.1.0 --verbose 1 2>!;
+
+ $pkg_status -r >>EOO;
+ !libbar configured !0.1.0 available 1.0.0
+ !diz configured 1.0.0
+ dox configured 1.0.0
+ dex configured 1.0.0
+ bar configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
libbox configured !0.1.0 available 1.0.0
- !tix configured 0.1.0 available 1.0.0
- !bar configured 1.0.0
- !libbar configured 1.0.0
- !bux configured 1.0.0
+ EOO
+
+ cat cfg/libbox-0.1.0/build/config.build >>~%EOO%;
+ %.*
+ config.libbox.extras = true
+ EOO
+
+ $* --upgrade --recursive 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build: add diz/1.0.0
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent bar/1.0.0 due to dependency libbar/1.0.0
+ trace: collect_build: add bar/1.0.0
+ trace: postponed_configurations::add: create {bar^ | libbar->{bar/1,1}}
+ trace: collect_build: add dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of existing dependent diz/1.0.0 due to dependency libbar/1.0.0
+ trace: postponed_configurations::add: create {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: skip configured diz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: reeval bar/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: postponed_configurations::add: add {bar^ 1,1: libbar} to {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bar/1.0.0 results in {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bar/1.0.0
+ trace: collect_build_prerequisites: reeval diz/1.0.0
+ trace: postponed_configurations::add: add {diz^ 1,1: dox} to {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent diz/1.0.0 results in {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated diz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bar/1.0.0
+ trace: collect_build_prerequisites: resume bar/1.0.0
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bar^ | libbar->{bar/1,1}}!
+ trace: collect_build_postponed (2): begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent diz of dependency dox
+ trace: collect_build_postponed (2): cfg-negotiate begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
+ trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
+ trace: collect_build_prerequisites: postpone dox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ trace: collect_build: add libbox/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: create {diz | libbox->{diz/2,1}}
+ trace: collect_build_prerequisites: postpone diz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {diz^ | dox->{diz/1,1}}!
+ trace: collect_build_postponed (3): begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent dox of dependency dex
+ trace: collect_build_postponed (3): cfg-negotiate begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (bar), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build: add diz/1.0.0
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent bar/1.0.0 due to dependency libbar/1.0.0
+ trace: collect_build: add bar/1.0.0
+ trace: postponed_configurations::add: create {bar^ | libbar->{bar/1,1}}
+ trace: collect_build: add dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of existing dependent diz/1.0.0 due to dependency libbar/1.0.0
+ trace: postponed_configurations::add: create {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: skip configured diz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar of dependency libbar
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: reeval diz/1.0.0
+ trace: postponed_configurations::add: add {diz^ 1,1: dox} to {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent diz/1.0.0 results in {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated diz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar
+ trace: collect_build_postponed (1): cfg-negotiate end {bar^ | libbar->{bar/1,1}}!
+ trace: collect_build_postponed (2): begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent diz of dependency dox
+ trace: collect_build_postponed (2): cfg-negotiate begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
+ trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
+ trace: collect_build_prerequisites: postpone dox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ trace: collect_build: add libbox/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: create {diz | libbox->{diz/2,1}}
+ trace: collect_build_prerequisites: postpone diz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {diz^ | dox->{diz/1,1}}!
+ trace: collect_build_postponed (3): begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent dox of dependency dex
+ trace: collect_build_postponed (3): cfg-negotiate begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent dox/1.0.0
+ trace: collect_build_prerequisites: resume dox/1.0.0
+ trace: collect_build_prerequisites: end dox/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {dox | dex->{dox/1,1}}!
+ trace: collect_build_postponed (4): begin {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent diz of dependency libbox
+ trace: collect_build_postponed (4): cfg-negotiate begin {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/0.1.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: add {diz 3,1: libbar} to {bar^ | libbar->{bar/1,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent diz/1.0.0 involves (being) negotiated configurations and results in {bar^ diz | libbar->{bar/1,1 diz/3,1}}!, throwing retry_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {bar^ | libbar->{bar/1,1}} failed due to dependent diz, refining configuration
+ trace: collect_build_postponed (1): begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar of dependency libbar
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: reeval diz/1.0.0
+ trace: postponed_configurations::add: add {diz^ 1,1: dox} to {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent diz/1.0.0 results in {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated diz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar
+ trace: collect_build_postponed (1): cfg-negotiate end {bar^ | libbar->{bar/1,1}}!
+ trace: collect_build_postponed (2): begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent diz of dependency dox
+ trace: collect_build_postponed (2): cfg-negotiate begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
+ trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
+ trace: collect_build_prerequisites: postpone dox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ trace: collect_build: add libbox/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: create {diz | libbox->{diz/2,1}}
+ trace: collect_build_prerequisites: postpone diz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {diz^ | dox->{diz/1,1}}!
+ trace: collect_build_postponed (3): begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent dox of dependency dex
+ trace: collect_build_postponed (3): cfg-negotiate begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent dox/1.0.0
+ trace: collect_build_prerequisites: resume dox/1.0.0
+ trace: collect_build_prerequisites: end dox/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {dox | dex->{dox/1,1}}!
+ trace: collect_build_postponed (4): begin {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent diz of dependency libbox
+ trace: collect_build_postponed (4): cfg-negotiate begin {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/0.1.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: add {diz 3,1: libbar} to {bar^ | libbar->{bar/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent diz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent diz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end diz/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {diz | libbox->{diz/2,1}}!
+ trace: collect_build_postponed (5): begin {dex | bar->{dex/1,1}}
+ trace: collect_build_postponed (5): skip being built existing dependent dex of dependency bar
+ trace: collect_build_postponed (5): cfg-negotiate begin {dex | bar->{dex/1,1}}
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {bar^ diz | libbar->{bar/1,1 diz/3,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bar/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bar/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (5): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | libfoo->{dex/2,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (5): cfg-negotiate end {dex | bar->{dex/1,1}}!
+ trace: collect_build_postponed (6): begin {dex | libfoo->{dex/2,1}}
+ trace: collect_build_postponed (6): skip being built existing dependent dex of dependency libfoo
+ trace: collect_build_postponed (6): cfg-negotiate begin {dex | libfoo->{dex/2,1}}
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (6): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ trace: collect_build_prerequisites: end dex/1.0.0
+ trace: collect_build_postponed (6): cfg-negotiate end {dex | libfoo->{dex/2,1}}!
+ trace: collect_build_postponed (6): end {dex | libfoo->{dex/2,1}}
+ trace: collect_build_postponed (5): end {dex | bar->{dex/1,1}}
+ trace: collect_build_postponed (4): end {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (3): end {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (2): end {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (1): end {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: libbox/0.1.0: update to libbox/1.0.0
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build: add diz/1.0.0
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent bar/1.0.0 due to dependency libbar/1.0.0
+ trace: collect_build: add bar/1.0.0
+ trace: postponed_configurations::add: create {bar^ | libbar->{bar/1,1}}
+ trace: collect_build: add dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of existing dependent diz/1.0.0 due to dependency libbar/1.0.0
+ trace: postponed_configurations::add: create {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: skip configured diz/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of existing dependent diz/1.0.0 due to dependency libbox/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: reeval bar/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: postponed_configurations::add: add {bar^ 1,1: libbar} to {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bar/1.0.0 results in {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bar/1.0.0
+ trace: collect_build_prerequisites: reeval diz/1.0.0
+ trace: postponed_configurations::add: add {diz^ 1,1: dox} to {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent diz/1.0.0 results in {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated diz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bar/1.0.0
+ trace: collect_build_prerequisites: resume bar/1.0.0
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bar^ | libbar->{bar/1,1}}!
+ trace: collect_build_postponed (2): begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent diz of dependency dox
+ trace: collect_build_postponed (2): cfg-negotiate begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
+ trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
+ trace: collect_build_prerequisites: postpone dox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ trace: collect_build: pick libbox/1.0.0 over libbox/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: create {diz | libbox->{diz/2,1}}
+ trace: collect_build_prerequisites: postpone diz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {diz^ | dox->{diz/1,1}}!
+ trace: collect_build_postponed (3): begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent dox of dependency dex
+ trace: collect_build_postponed (3): cfg-negotiate begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (bar), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build: add diz/1.0.0
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent bar/1.0.0 due to dependency libbar/1.0.0
+ trace: collect_build: add bar/1.0.0
+ trace: postponed_configurations::add: create {bar^ | libbar->{bar/1,1}}
+ trace: collect_build: add dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of existing dependent diz/1.0.0 due to dependency libbar/1.0.0
+ trace: postponed_configurations::add: create {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: skip configured diz/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of existing dependent diz/1.0.0 due to dependency libbox/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar of dependency libbar
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: reeval diz/1.0.0
+ trace: postponed_configurations::add: add {diz^ 1,1: dox} to {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent diz/1.0.0 results in {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated diz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar
+ trace: collect_build_postponed (1): cfg-negotiate end {bar^ | libbar->{bar/1,1}}!
+ trace: collect_build_postponed (2): begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent diz of dependency dox
+ trace: collect_build_postponed (2): cfg-negotiate begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
+ trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
+ trace: collect_build_prerequisites: postpone dox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ trace: collect_build: pick libbox/1.0.0 over libbox/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: create {diz | libbox->{diz/2,1}}
+ trace: collect_build_prerequisites: postpone diz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {diz^ | dox->{diz/1,1}}!
+ trace: collect_build_postponed (3): begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent dox of dependency dex
+ trace: collect_build_postponed (3): cfg-negotiate begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent dox/1.0.0
+ trace: collect_build_prerequisites: resume dox/1.0.0
+ trace: collect_build_prerequisites: end dox/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {dox | dex->{dox/1,1}}!
+ trace: collect_build_postponed (4): begin {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent diz of dependency libbox
+ trace: collect_build_postponed (4): cfg-negotiate begin {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: add {diz 3,1: libbar} to {bar^ | libbar->{bar/1,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent diz/1.0.0 involves (being) negotiated configurations and results in {bar^ diz | libbar->{bar/1,1 diz/3,1}}!, throwing retry_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {bar^ | libbar->{bar/1,1}} failed due to dependent diz, refining configuration
+ trace: collect_build_postponed (1): begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar of dependency libbar
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: reeval diz/1.0.0
+ trace: postponed_configurations::add: add {diz^ 1,1: dox} to {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent diz/1.0.0 results in {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated diz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar
+ trace: collect_build_postponed (1): cfg-negotiate end {bar^ | libbar->{bar/1,1}}!
+ trace: collect_build_postponed (2): begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent diz of dependency dox
+ trace: collect_build_postponed (2): cfg-negotiate begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
+ trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
+ trace: collect_build_prerequisites: postpone dox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ trace: collect_build: pick libbox/1.0.0 over libbox/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: create {diz | libbox->{diz/2,1}}
+ trace: collect_build_prerequisites: postpone diz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {diz^ | dox->{diz/1,1}}!
+ trace: collect_build_postponed (3): begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent dox of dependency dex
+ trace: collect_build_postponed (3): cfg-negotiate begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent dox/1.0.0
+ trace: collect_build_prerequisites: resume dox/1.0.0
+ trace: collect_build_prerequisites: end dox/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {dox | dex->{dox/1,1}}!
+ trace: collect_build_postponed (4): begin {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent diz of dependency libbox
+ trace: collect_build_postponed (4): cfg-negotiate begin {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: add {diz 3,1: libbar} to {bar^ | libbar->{bar/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent diz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent diz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end diz/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {diz | libbox->{diz/2,1}}!
+ trace: collect_build_postponed (5): begin {dex | bar->{dex/1,1}}
+ trace: collect_build_postponed (5): skip being built existing dependent dex of dependency bar
+ trace: collect_build_postponed (5): cfg-negotiate begin {dex | bar->{dex/1,1}}
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {bar^ diz | libbar->{bar/1,1 diz/3,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bar/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bar/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (5): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | libfoo->{dex/2,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (5): cfg-negotiate end {dex | bar->{dex/1,1}}!
+ trace: collect_build_postponed (6): begin {dex | libfoo->{dex/2,1}}
+ trace: collect_build_postponed (6): skip being built existing dependent dex of dependency libfoo
+ trace: collect_build_postponed (6): cfg-negotiate begin {dex | libfoo->{dex/2,1}}
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (6): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ trace: collect_build_prerequisites: end dex/1.0.0
+ trace: collect_build_postponed (6): cfg-negotiate end {dex | libfoo->{dex/2,1}}!
+ trace: collect_build_postponed (6): end {dex | libfoo->{dex/2,1}}
+ trace: collect_build_postponed (5): end {dex | bar->{dex/1,1}}
+ trace: collect_build_postponed (4): end {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (3): end {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (2): end {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (1): end {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ upgrade libbar/1.0.0
+ config.libbar.extras=true (set by diz)
+ reconfigure/update bar/1.0.0 (required by dex)
+ config.bar.extras=true (set by dex)
+ reconfigure/update dex/1.0.0 (required by dox)
+ config.dex.extras=true (set by dox)
+ reconfigure/update dox/1.0.0 (required by diz)
+ config.dox.extras=true (set by diz)
+ upgrade libbox/1.0.0
+ config.libbox.extras=true (set by diz)
+ reconfigure/update diz/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ cat cfg/libbox-1.0.0/build2/config.build2 >>~%EOO%;
+ %.*
+ config.libbox.extras = true
+ EOO
+
+ $pkg_status -r >>EOO;
+ !libbar configured 1.0.0
+ !diz configured 1.0.0
+ dox configured 1.0.0
+ dex configured 1.0.0
+ bar configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured 1.0.0
!libbar configured 1.0.0
- !bex configured 1.0.0
+ libbox configured !1.0.0
+ EOO
+
+ $pkg_drop diz libbar --drop-dependent
+ }
+
+ : multiple-dependency-postpones
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # diz: depends: dox(c)
+ # depends: libbox(c)
+ # depends: libbar(c)
+ #
+ # dox: depends: dex(c)
+ #
+ # dex: depends: bar(c)
+ # depends: libfoo(c)
+ #
+ # bar: depends: libbar(c)
+ #
+ $* diz dex libbar/0.1.0 --verbose 1 2>!;
+
+ $pkg_status -r >>EOO;
+ !libbar configured !0.1.0 available 1.0.0
+ !dex configured 1.0.0
+ bar configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured 1.0.0
+ !diz configured 1.0.0
+ dox configured 1.0.0
+ !dex configured 1.0.0
+ bar configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libbox configured 1.0.0
+ EOO
+
+ $* --upgrade --recursive 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build: add diz/1.0.0
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent bar/1.0.0 due to dependency libbar/1.0.0
+ trace: collect_build: add bar/1.0.0
+ trace: postponed_configurations::add: create {bar^ | libbar->{bar/1,1}}
+ trace: collect_build: add dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of existing dependent diz/1.0.0 due to dependency libbar/1.0.0
+ trace: postponed_configurations::add: create {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: skip configured dex/1.0.0
+ trace: collect_build_prerequisites: skip configured diz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: reeval bar/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: postponed_configurations::add: add {bar^ 1,1: libbar} to {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bar/1.0.0 results in {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bar/1.0.0
+ trace: collect_build_prerequisites: reeval diz/1.0.0
+ trace: postponed_configurations::add: add {diz^ 1,1: dox} to {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent diz/1.0.0 results in {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated diz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bar/1.0.0
+ trace: collect_build_prerequisites: resume bar/1.0.0
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bar^ | libbar->{bar/1,1}}!
+ trace: collect_build_postponed (2): begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent diz of dependency dox
+ trace: collect_build_postponed (2): cfg-negotiate begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (dex), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build: add diz/1.0.0
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent bar/1.0.0 due to dependency libbar/1.0.0
+ trace: collect_build: add bar/1.0.0
+ trace: postponed_configurations::add: create {bar^ | libbar->{bar/1,1}}
+ trace: collect_build: add dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of existing dependent diz/1.0.0 due to dependency libbar/1.0.0
+ trace: postponed_configurations::add: create {diz^ | dox->{diz/1,1}}
+ trace: pkg_build: dep-postpone user-specified dex
+ trace: collect_build_prerequisites: skip configured diz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: reeval bar/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: postponed_configurations::add: add {bar^ 1,1: libbar} to {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bar/1.0.0 results in {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bar/1.0.0
+ trace: collect_build_prerequisites: reeval diz/1.0.0
+ trace: postponed_configurations::add: add {diz^ 1,1: dox} to {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent diz/1.0.0 results in {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated diz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bar/1.0.0
+ trace: collect_build_prerequisites: resume bar/1.0.0
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bar^ | libbar->{bar/1,1}}!
+ trace: collect_build_postponed (2): begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent diz of dependency dox
+ trace: collect_build_postponed (2): cfg-negotiate begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
+ trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
+ trace: collect_build_prerequisites: postpone dox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: create {diz | libbox->{diz/2,1}}
+ trace: collect_build_prerequisites: postpone diz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {diz^ | dox->{diz/1,1}}!
+ trace: collect_build_postponed (3): begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent dox of dependency dex
+ trace: collect_build_postponed (3): cfg-negotiate begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (bar), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build: add diz/1.0.0
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent bar/1.0.0 due to dependency libbar/1.0.0
+ trace: collect_build: add bar/1.0.0
+ trace: postponed_configurations::add: create {bar^ | libbar->{bar/1,1}}
+ trace: collect_build: add dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of existing dependent diz/1.0.0 due to dependency libbar/1.0.0
+ trace: postponed_configurations::add: create {diz^ | dox->{diz/1,1}}
+ trace: pkg_build: dep-postpone user-specified dex
+ trace: collect_build_prerequisites: skip configured diz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar of dependency libbar
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: reeval diz/1.0.0
+ trace: postponed_configurations::add: add {diz^ 1,1: dox} to {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent diz/1.0.0 results in {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated diz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar
+ trace: collect_build_postponed (1): cfg-negotiate end {bar^ | libbar->{bar/1,1}}!
+ trace: collect_build_postponed (2): begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent diz of dependency dox
+ trace: collect_build_postponed (2): cfg-negotiate begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
+ trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
+ trace: collect_build_prerequisites: postpone dox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: create {diz | libbox->{diz/2,1}}
+ trace: collect_build_prerequisites: postpone diz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {diz^ | dox->{diz/1,1}}!
+ trace: collect_build_postponed (3): begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent dox of dependency dex
+ trace: collect_build_postponed (3): cfg-negotiate begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent dox/1.0.0
+ trace: collect_build_prerequisites: resume dox/1.0.0
+ trace: collect_build_prerequisites: end dox/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {dox | dex->{dox/1,1}}!
+ trace: collect_build_postponed (4): begin {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent diz of dependency libbox
+ trace: collect_build_postponed (4): cfg-negotiate begin {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: add {diz 3,1: libbar} to {bar^ | libbar->{bar/1,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent diz/1.0.0 involves (being) negotiated configurations and results in {bar^ diz | libbar->{bar/1,1 diz/3,1}}!, throwing retry_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {bar^ | libbar->{bar/1,1}} failed due to dependent diz, refining configuration
+ trace: collect_build_postponed (1): begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bar/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bar/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval diz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated diz/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar of dependency libbar
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: reeval diz/1.0.0
+ trace: postponed_configurations::add: add {diz^ 1,1: dox} to {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent diz/1.0.0 results in {diz^ | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated diz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar
+ trace: collect_build_postponed (1): cfg-negotiate end {bar^ | libbar->{bar/1,1}}!
+ trace: collect_build_postponed (2): begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent diz of dependency dox
+ trace: collect_build_postponed (2): cfg-negotiate begin {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
+ trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
+ trace: collect_build_prerequisites: postpone dox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: create {diz | libbox->{diz/2,1}}
+ trace: collect_build_prerequisites: postpone diz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {diz^ | dox->{diz/1,1}}!
+ trace: collect_build_postponed (3): begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent dox of dependency dex
+ trace: collect_build_postponed (3): cfg-negotiate begin {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent dox/1.0.0
+ trace: collect_build_prerequisites: resume dox/1.0.0
+ trace: collect_build_prerequisites: end dox/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {dox | dex->{dox/1,1}}!
+ trace: collect_build_postponed (4): begin {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent diz of dependency libbox
+ trace: collect_build_postponed (4): cfg-negotiate begin {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: add {diz 3,1: libbar} to {bar^ | libbar->{bar/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent diz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent diz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end diz/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {diz | libbox->{diz/2,1}}!
+ trace: collect_build_postponed (5): begin {dex | bar->{dex/1,1}}
+ trace: collect_build_postponed (5): skip being built existing dependent dex of dependency bar
+ trace: collect_build_postponed (5): cfg-negotiate begin {dex | bar->{dex/1,1}}
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {bar^ diz | libbar->{bar/1,1 diz/3,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bar/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bar/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (5): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | libfoo->{dex/2,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (5): cfg-negotiate end {dex | bar->{dex/1,1}}!
+ trace: collect_build_postponed (6): begin {dex | libfoo->{dex/2,1}}
+ trace: collect_build_postponed (6): skip being built existing dependent dex of dependency libfoo
+ trace: collect_build_postponed (6): cfg-negotiate begin {dex | libfoo->{dex/2,1}}
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (6): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ trace: collect_build_prerequisites: end dex/1.0.0
+ trace: collect_build_postponed (6): cfg-negotiate end {dex | libfoo->{dex/2,1}}!
+ trace: collect_build_postponed (6): end {dex | libfoo->{dex/2,1}}
+ trace: collect_build_postponed (5): end {dex | bar->{dex/1,1}}
+ trace: collect_build_postponed (4): end {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (3): end {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (2): end {diz^ | dox->{diz/1,1}}
+ trace: collect_build_postponed (1): end {bar^ | libbar->{bar/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ upgrade libbar/1.0.0
+ config.libbar.extras=true (set by diz)
+ reconfigure/update bar/1.0.0 (required by dex)
+ config.bar.extras=true (set by dex)
+ reconfigure/update dex/1.0.0
+ config.dex.extras=true (set by dox)
+ reconfigure/update dox/1.0.0 (required by diz)
+ config.dox.extras=true (set by diz)
+ reconfigure/update diz/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !libbar configured 1.0.0
+ !dex configured 1.0.0
+ bar configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !diz configured 1.0.0
+ dox configured 1.0.0
+ !dex configured 1.0.0
+ bar configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured 1.0.0
!libbar configured 1.0.0
- !boo configured 1.0.0
+ libbox configured 1.0.0
+ EOO
+
+ $pkg_drop diz dex libbar --drop-dependent
+ }
+
+ : collected-dependency-non-negotiated-cluster
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tiz: depends: tex(c)
+ # depends: libbar(c)
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ $* tiz libbar/0.1.0 --verbose 1 2>!;
+
+ $pkg_status -r >>EOO;
+ !libbar configured !0.1.0 available 1.0.0
+ !tiz configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ tex configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $* --upgrade --recursive 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of existing dependent tex/1.0.0 due to dependency libbar/1.0.0
+ trace: collect_build: add tex/1.0.0
+ trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/1.0.0 of existing dependent tiz/1.0.0 due to dependency libbar/1.0.0
+ trace: postponed_configurations::add: create {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: skip configured tiz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip existing dependent tex of dependency libbar since dependent already in cluster {tiz^ | tex->{tiz/1,1}} (as a dependency)
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: postponed_configurations::add: add {tiz^ 1,1: tex} to {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tiz/1.0.0 results in {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tiz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex
+ trace: collect_build_postponed (1): cfg-negotiate end {tex^ | libbar->{tex/1,1}}!
+ trace: collect_build_postponed (2): begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tiz of dependency tex
+ trace: collect_build_postponed (2): cfg-negotiate begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {tex^ | libbar->{tex/1,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent tex/1.0.0 involves (being) negotiated configurations and results in {tex^ | libbar->{tex/1,1}}!, throwing retry_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {tex^ | libbar->{tex/1,1}} failed due to dependent tex, refining configuration
+ trace: collect_build_postponed (1): begin {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip existing dependent tex of dependency libbar since dependent already in cluster {tiz^ | tex->{tiz/1,1}} (as a dependency)
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: postponed_configurations::add: add {tiz^ 1,1: tex} to {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tiz/1.0.0 results in {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tiz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex
+ trace: collect_build_postponed (1): cfg-negotiate end {tex^ | libbar->{tex/1,1}}!
+ trace: collect_build_postponed (2): begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tiz of dependency tex
+ trace: collect_build_postponed (2): cfg-negotiate begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {tex^ | libbar->{tex/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tiz/1.0.0
+ trace: collect_build_prerequisites: resume tiz/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: add {tiz 2,1: libbar} to {tex^ | libbar->{tex/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tiz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tiz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tiz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tiz^ | tex->{tiz/1,1}}!
+ trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (3): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (2): end {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (1): end {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ upgrade libbar/1.0.0
+ config.libbar.extras=true (set by tex)
+ reconfigure/update tex/1.0.0 (required by tiz)
+ config.tex.extras=true (set by tiz)
+ config.tex.libfoo_extras=true (set by tex)
+ reconfigure/update tiz/1.0.0
+ config.tiz.tex_extras=true (set by tiz)
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !libbar configured 1.0.0
+ !tiz configured 1.0.0
!libbar configured 1.0.0
- !biz configured 1.0.0
- !boo configured 1.0.0
- !libbar configured 1.0.0
- !buz configured 1.0.0
- !bux configured 1.0.0
+ tex configured 1.0.0
!libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop tiz libbar --drop-dependent
+ }
+
+ : from-scratch-refinement-drop
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tiz: depends: tex(c)
+ # depends: libbar(c)
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ # toz: depends: libbaz(c)
+ # depends: libfoo(c)
+ # depends: libbar(c)
+ #
+ # tez: depends: libbox(c)
+ # depends: toz == 0.1.0 (c)
+ # depends: libbar (c)
+ #
+ # toz/0.1.0:
+ #
+ $* tiz toz --verbose 1 2>!;
+
+ $pkg_status -r >>EOO;
+ !tiz configured 1.0.0
+ libbar configured 1.0.0
+ tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !toz configured 1.0.0
+ libbar configured 1.0.0
+ libbaz configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $* tez 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add toz/0.1.0
+ warning: package tez dependency on (toz == 0.1.0) is forcing downgrade of toz/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.1.0
+ trace: collect_build_prerequisites: end toz/0.1.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | toz->{tez/2,1}}!
+ trace: collect_build_postponed (3): begin {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_postponed (3): skip being built existing dependent toz of dependency libbar
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (3): re-evaluate existing dependents for {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ tez | libbar->{tex/1,1 tez/3,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: collect_build_prerequisites: cannot re-evaluate existing dependent tiz/1.0.0 due to dependency tex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add toz/0.1.0
+ warning: package tez dependency on (toz == 0.1.0) is forcing downgrade of toz/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.1.0
+ trace: collect_build_prerequisites: end toz/0.1.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | toz->{tez/2,1}}!
+ trace: collect_build_postponed (3): begin {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_postponed (3): skip being built existing dependent toz of dependency libbar
+ trace: collect_build_postponed (3): skip dep-postponed existing dependent tex of dependency libbar
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (3): re-evaluate existing dependents for {tez | libbar->{tez/3,1}}
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: postponed_configurations::add: create {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tiz/1.0.0 results in {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tiz/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate begin {tez | libbar->{tez/3,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build_prerequisites: end tez/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tez | libbar->{tez/3,1}}!
+ trace: collect_build_postponed (4): begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent tiz of dependency tex
+ trace: collect_build_postponed (4): cfg-negotiate begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {tez | libbar->{tez/3,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent tiz/1.0.0
+ trace: collect_build_prerequisites: resume tiz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: add {tiz 2,1: libbar} to {tex tez | libbar->{tex/1,1 tez/3,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tiz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tiz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tiz/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {tiz^ | tex->{tiz/1,1}}!
+ trace: collect_build_postponed (5): begin {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (5): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (5): skip being built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (5): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (5): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (5): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (5): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (4): end {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (3): end {tez | libbar->{tez/3,1}}
+ trace: collect_build_postponed (2): end {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (1): end {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: libbaz/1.0.0: unused
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_drop: add libbaz
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add toz/0.1.0
+ warning: package tez dependency on (toz == 0.1.0) is forcing downgrade of toz/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.1.0
+ trace: collect_build_prerequisites: end toz/0.1.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | toz->{tez/2,1}}!
+ trace: collect_build_postponed (3): begin {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_postponed (3): skip being built existing dependent toz of dependency libbar
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (3): re-evaluate existing dependents for {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ tez | libbar->{tex/1,1 tez/3,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: collect_build_prerequisites: cannot re-evaluate existing dependent tiz/1.0.0 due to dependency tex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_drop: add libbaz
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add toz/0.1.0
+ warning: package tez dependency on (toz == 0.1.0) is forcing downgrade of toz/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.1.0
+ trace: collect_build_prerequisites: end toz/0.1.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | toz->{tez/2,1}}!
+ trace: collect_build_postponed (3): begin {tez | libbar->{tez/3,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_postponed (3): skip being built existing dependent toz of dependency libbar
+ trace: collect_build_postponed (3): skip dep-postponed existing dependent tex of dependency libbar
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (3): re-evaluate existing dependents for {tez | libbar->{tez/3,1}}
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: postponed_configurations::add: create {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tiz/1.0.0 results in {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tiz/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate begin {tez | libbar->{tez/3,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build_prerequisites: end tez/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tez | libbar->{tez/3,1}}!
+ trace: collect_build_postponed (4): begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent tiz of dependency tex
+ trace: collect_build_postponed (4): cfg-negotiate begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {tez | libbar->{tez/3,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent tiz/1.0.0
+ trace: collect_build_prerequisites: resume tiz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: add {tiz 2,1: libbar} to {tex tez | libbar->{tex/1,1 tez/3,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tiz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tiz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tiz/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {tiz^ | tex->{tiz/1,1}}!
+ trace: collect_build_postponed (5): begin {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (5): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (5): skip being built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (5): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (5): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (5): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (5): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (4): end {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (3): end {tez | libbar->{tez/3,1}}
+ trace: collect_build_postponed (2): end {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (1): end {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ new libbox/1.0.0 (required by tez)
+ config.libbox.extras=true (set by tez)
+ drop libbaz/1.0.0 (unused)
+ downgrade toz/0.1.0 (required by tez)
+ config.toz.extras=true (set by tez)
+ new tez/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tiz configured 1.0.0
+ libbar configured 1.0.0
+ tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
!tez configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ EOO
+
+ $pkg_drop tiz toz tez
+ }
+
+ : from-scratch-refinement-upgrade
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tiz: depends: tex(c)
+ # depends: libbar(c)
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ # tez: depends: libbox(c)
+ # depends: toz == 0.1.0 (c)
+ #
+ # toz/0.1.0:
+ #
+ # tuz: depends: toz (c)
+ #
+ # tix: depends: libbar(c)
+ # depends: tex(c)
+ #
+ # toz/1.0.0: depends: libbaz(c)
+ # depends: libfoo(c)
+ # depends: libbar(c)
+ #
+ $* tiz tez/0.1.0 tuz --verbose 1 2>!;
+
+ $pkg_status -r >>EOO;
+ !tiz configured 1.0.0
+ libbar configured 1.0.0
+ tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !tez configured !0.1.0 available 1.0.0
+ libbox configured 1.0.0
+ toz configured 0.1.0 available 1.0.0 0.2.0
+ !tuz configured 1.0.0
+ toz configured 0.1.0 available 1.0.0 0.2.0
+ EOO
+
+ $* tix ?tez ?toz 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build_prerequisites: begin tix/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ tix | libbar->{tex/1,1 tix/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: collect_build_prerequisites: cannot re-evaluate existing dependent tiz/1.0.0 due to dependency tex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build_prerequisites: begin tix/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex of dependency libbar
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix | libbar->{tix/1,1}}
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: postponed_configurations::add: create {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tiz/1.0.0 results in {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tiz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tix | libbar->{tix/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: add {tix 2,1: tex} to {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tix | libbar->{tix/1,1}}!
+ trace: collect_build_postponed (2): begin {tix tiz^ | tex->{tix/2,1 tiz/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tiz of dependency tex
+ trace: collect_build_postponed (2): cfg-negotiate begin {tix tiz^ | tex->{tix/2,1 tiz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {tix | libbar->{tix/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: end tix/1.0.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tiz/1.0.0
+ trace: collect_build_prerequisites: resume tiz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: add {tiz 2,1: libbar} to {tex tix | libbar->{tex/1,1 tix/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tiz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tiz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tiz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tix tiz^ | tex->{tix/2,1 tiz/1,1}}!
+ trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (3): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (2): end {tix tiz^ | tex->{tix/2,1 tiz/1,1}}
+ trace: collect_build_postponed (1): end {tix | libbar->{tix/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: tez/0.1.0: unused
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build_prerequisites: begin tix/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_drop: overwrite tez
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ tix | libbar->{tex/1,1 tix/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: collect_build_prerequisites: cannot re-evaluate existing dependent tiz/1.0.0 due to dependency tex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build_prerequisites: begin tix/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_drop: overwrite tez
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex of dependency libbar
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix | libbar->{tix/1,1}}
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: postponed_configurations::add: create {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tiz/1.0.0 results in {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tiz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tix | libbar->{tix/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: add {tix 2,1: tex} to {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tix | libbar->{tix/1,1}}!
+ trace: collect_build_postponed (2): begin {tix tiz^ | tex->{tix/2,1 tiz/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tiz of dependency tex
+ trace: collect_build_postponed (2): cfg-negotiate begin {tix tiz^ | tex->{tix/2,1 tiz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {tix | libbar->{tix/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: end tix/1.0.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tiz/1.0.0
+ trace: collect_build_prerequisites: resume tiz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: add {tiz 2,1: libbar} to {tex tix | libbar->{tex/1,1 tix/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tiz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tiz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tiz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tix tiz^ | tex->{tix/2,1 tiz/1,1}}!
+ trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (3): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (2): end {tix tiz^ | tex->{tix/2,1 tiz/1,1}}
+ trace: collect_build_postponed (1): end {tix | libbar->{tix/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: libbox/1.0.0: unused
+ %.*
+ trace: evaluate_dependency: toz/0.1.0: update to toz/1.0.0
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build_prerequisites: begin tix/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_drop: overwrite tez
+ trace: collect_drop: add libbox
+ trace: collect_build_prerequisites: skip being dropped existing dependent tez of dependency toz
+ trace: collect_build_prerequisites: pre-reeval tuz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tuz/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/1.0.0 of existing dependent tuz/1.0.0 due to dependency toz/1.0.0
+ trace: collect_build: add tuz/1.0.0
+ trace: postponed_configurations::add: create {tuz^ | toz->{tuz/1,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ tix | libbar->{tex/1,1 tix/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: collect_build_prerequisites: cannot re-evaluate existing dependent tiz/1.0.0 due to dependency tex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build_prerequisites: begin tix/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_drop: overwrite tez
+ trace: collect_drop: add libbox
+ trace: collect_build_prerequisites: skip being dropped existing dependent tez of dependency toz
+ trace: collect_build_prerequisites: pre-reeval tuz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tuz/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/1.0.0 of existing dependent tuz/1.0.0 due to dependency toz/1.0.0
+ trace: collect_build: add tuz/1.0.0
+ trace: postponed_configurations::add: create {tuz^ | toz->{tuz/1,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex of dependency libbar
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix | libbar->{tix/1,1}}
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: postponed_configurations::add: create {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tiz/1.0.0 results in {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tiz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tix | libbar->{tix/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: add {tix 2,1: tex} to {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tix | libbar->{tix/1,1}}!
+ trace: collect_build_postponed (2): begin {tuz^ | toz->{tuz/1,1}}
+ trace: collect_build_postponed (2): skip being dropped existing dependent tez of dependency toz
+ trace: collect_build_prerequisites: pre-reeval tuz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tuz/1.0.0: 1,1
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {tuz^ | toz->{tuz/1,1}}
+ trace: collect_build_prerequisites: reeval tuz/1.0.0
+ trace: collect_build: pick toz/1.0.0 over toz/0.1.0
+ trace: postponed_configurations::add: add {tuz^ 1,1: toz} to {tuz^ | toz->{tuz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tuz/1.0.0 results in {tuz^ | toz->{tuz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tuz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate begin {tuz^ | toz->{tuz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/1.0.0
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent toz/1.0.0
+ trace: postponed_configurations::add: create {toz | libbaz->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tuz/1.0.0
+ trace: collect_build_prerequisites: resume tuz/1.0.0
+ trace: collect_build_prerequisites: end tuz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tuz^ | toz->{tuz/1,1}}!
+ trace: collect_build_postponed (3): begin {tix tiz^ | tex->{tix/2,1 tiz/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent tiz of dependency tex
+ trace: collect_build_postponed (3): cfg-negotiate begin {tix tiz^ | tex->{tix/2,1 tiz/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {tix | libbar->{tix/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: end tix/1.0.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tiz/1.0.0
+ trace: collect_build_prerequisites: resume tiz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: add {tiz 2,1: libbar} to {tex tix | libbar->{tex/1,1 tix/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tiz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tiz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tiz/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tix tiz^ | tex->{tix/2,1 tiz/1,1}}!
+ trace: collect_build_postponed (4): begin {toz | libbaz->{toz/1,1}}
+ trace: collect_build_postponed (4): cfg-negotiate begin {toz | libbaz->{toz/1,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent toz/1.0.0
+ trace: collect_build_prerequisites: resume toz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/1.0.0
+ trace: postponed_configurations::add: add {toz 2,1: libfoo} to {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone toz/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {toz | libbaz->{toz/1,1}}!
+ trace: collect_build_postponed (5): begin {tex toz | libfoo->{tex/2,1 toz/2,1}}
+ trace: collect_build_postponed (5): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (5): cfg-negotiate begin {tex toz | libfoo->{tex/2,1 toz/2,1}}
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (5): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (5): select cfg-negotiated dependency alternative for dependent toz/1.0.0
+ trace: collect_build_prerequisites: resume toz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/1.0.0
+ trace: postponed_configurations::add: add {toz 3,1: libbar} to {tex tix tiz | libbar->{tex/1,1 tix/1,1 tiz/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent toz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent toz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end toz/1.0.0
+ trace: collect_build_postponed (5): cfg-negotiate end {tex toz | libfoo->{tex/2,1 toz/2,1}}!
+ trace: collect_build_postponed (5): end {tex toz | libfoo->{tex/2,1 toz/2,1}}
+ trace: collect_build_postponed (4): end {toz | libbaz->{toz/1,1}}
+ trace: collect_build_postponed (3): end {tix tiz^ | tex->{tix/2,1 tiz/1,1}}
+ trace: collect_build_postponed (2): end {tuz^ | toz->{tuz/1,1}}
+ trace: collect_build_postponed (1): end {tix | libbar->{tix/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ drop libbox/1.0.0 (unused)
+ new libbaz/1.0.0 (required by toz)
+ config.libbaz.extras=true (set by toz)
+ new tix/1.0.0
+ upgrade toz/1.0.0
+ config.toz.extras=true (set by tuz)
+ drop tez/0.1.0 (unused)
+ reconfigure tuz/1.0.0 (dependent of toz)
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tiz configured 1.0.0
+ libbar configured 1.0.0
+ tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !tuz configured 1.0.0
+ toz configured 1.0.0
+ libbar configured 1.0.0
+ libbaz configured 1.0.0
+ libfoo configured 1.0.0
+ !tix configured 1.0.0
+ libbar configured 1.0.0
+ tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop tiz tuz tix
+ }
+
+ : reeval-cycle-resolution
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # bax: depends: libfoo(c)
+ # depends: {libbox libbar} (c)
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ # box/0.1.0: depends: libbox(c)
+ #
+ $* bax tex --verbose 1 2>!;
+
+ $pkg_status -r >>EOO;
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 1.0.0
+ !tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $* box/0.2.0 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add box/0.2.0
+ trace: collect_build_prerequisites: begin box/0.2.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent box/0.2.0
+ trace: postponed_configurations::add: create {box | libbox->{box/1,1}}
+ trace: collect_build_prerequisites: postpone box/0.2.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ %.*
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ %.*
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.2.0
+ trace: collect_build_prerequisites: resume box/0.2.0
+ trace: collect_build_prerequisites: end box/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}!
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ %.*
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ %.*
+ trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {box | libbox->{box/1,1}}!
+ trace: postponed_configurations::add: merge {tex^ | libbar->{tex/1,1}} into {bax box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax box tex^ | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 tex/1,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {box | libbox->{box/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax box tex^ | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 tex/1,1}}!
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ %.*
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ %.*
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.2.0
+ trace: collect_build_prerequisites: resume box/0.2.0
+ trace: collect_build_prerequisites: end box/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}!
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ %.*
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {box | libbox->{box/1,1}}! (shadow cluster-based)
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 involves negotiated configurations and results in {box tex^ | libbox->{box/1,1} libbar->{tex/1,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {box | libbox->{box/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {box tex^ | libbox->{box/1,1} libbar->{tex/1,1}}!
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ %.*
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ %.*
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.2.0
+ trace: collect_build_prerequisites: resume box/0.2.0
+ trace: collect_build_prerequisites: end box/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}!
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ %.*
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {box | libbox->{box/1,1}}! (shadow cluster-based)
+ trace: collect_build_prerequisites: merge configuration cycle detected for being re-evaluated dependent tex/1.0.0 since {box tex^ | libbox->{box/1,1} libbar->{tex/1,1}}! is a shadow of itself, throwing merge_configuration_cycle
+ trace: collect_build_postponed (2): re-evaluation of existing dependent tex/1.0.0 failed due to merge configuration cycle for {bax^ | libfoo->{bax/1,1}}, throwing recollect_existing_dependents
+ trace: collect_build_postponed (0): cfg-negotiation of {box | libbox->{box/1,1}} failed due to some existing dependents related problem, scheduling their re-collection
+ trace: collect_build_postponed (0): schedule re-collection of existing dependent tex/1.0.0
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ %.*
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ %.*
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.2.0
+ trace: collect_build_prerequisites: resume box/0.2.0
+ trace: collect_build_prerequisites: end box/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}!
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {box | libbox->{box/1,1}}!
+ trace: postponed_configurations::add: merge {tex | libbar->{tex/1,1}} into {bax box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax box tex | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 tex/1,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {box | libbox->{box/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax box tex | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 tex/1,1}}!
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ %.*
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ %.*
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.2.0
+ trace: collect_build_prerequisites: resume box/0.2.0
+ trace: collect_build_prerequisites: end box/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}!
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {box | libbox->{box/1,1}}! (shadow cluster-based)
+ %.*
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: skip being built existing dependent tex of dependency libbar
+ %.*
+ trace: collect_build_prerequisites: cfg-postponing dependent tex/1.0.0 involves (being) negotiated configurations and results in {box tex | libbox->{box/1,1} libbar->{tex/1,1}}!, throwing retry_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {box | libbox->{box/1,1}} failed due to dependent tex, refining configuration
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ %.*
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ %.*
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ %.*
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.2.0
+ trace: collect_build_prerequisites: resume box/0.2.0
+ trace: collect_build_prerequisites: end box/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}!
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {box | libbox->{box/1,1}}! (shadow cluster-based)
+ %.*
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: skip being built existing dependent tex of dependency libbar
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is shadow-negotiated
+ trace: collect_build_prerequisites: collecting cfg-postponed dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 2,1: libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (2): begin {bax^ tex | libfoo->{bax/1,1 tex/2,1}}
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ tex | libfoo->{bax/1,1 tex/2,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {box tex | libbox->{box/1,1} libbar->{tex/1,1}}! (shadow cluster-based)
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is shadow-negotiated
+ trace: collect_build_prerequisites: dependency libbox/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bax^ tex | libfoo->{bax/1,1 tex/2,1}}!
+ trace: collect_build_postponed (2): end {bax^ tex | libfoo->{bax/1,1 tex/2,1}}
+ trace: collect_build_postponed (1): end {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ new box/0.2.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 1.0.0
+ !tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !box configured !0.2.0 available 1.0.0
+ libbox configured 1.0.0
+ EOO
+
+ $pkg_drop bax tex box
+ }
+
+ : up-negotiate-not-collected-existing-dependents
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # bax: depends: libfoo(c)
+ # depends: {libbox libbar} (c)
+ #
+ # tiz: depends: tex(c)
+ # depends: libbar(c)
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ # box/0.1.0: depends: libbox(c)
+ #
+ $* bax tiz --verbose 1 2>!;
+
+ $pkg_status -r >>EOO;
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 1.0.0
+ !tiz configured 1.0.0
+ libbar configured 1.0.0
+ tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $* box/0.2.0 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add box/0.2.0
+ trace: collect_build_prerequisites: begin box/0.2.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent box/0.2.0
+ trace: postponed_configurations::add: create {box | libbox->{box/1,1}}
+ trace: collect_build_prerequisites: postpone box/0.2.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.2.0
+ trace: collect_build_prerequisites: resume box/0.2.0
+ trace: collect_build_prerequisites: end box/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}!
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {box | libbox->{box/1,1}}!
+ trace: postponed_configurations::add: merge {tex^ | libbar->{tex/1,1}} into {bax box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax box tex^ | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 tex/1,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {box | libbox->{box/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax box tex^ | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 tex/1,1}}!
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.2.0
+ trace: collect_build_prerequisites: resume box/0.2.0
+ trace: collect_build_prerequisites: end box/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}!
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {box | libbox->{box/1,1}}! (shadow cluster-based)
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 involves negotiated configurations and results in {box tex^ | libbox->{box/1,1} libbar->{tex/1,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {box | libbox->{box/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {box tex^ | libbox->{box/1,1} libbar->{tex/1,1}}!
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.2.0
+ trace: collect_build_prerequisites: resume box/0.2.0
+ trace: collect_build_prerequisites: end box/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}!
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {box | libbox->{box/1,1}}! (shadow cluster-based)
+ trace: collect_build_prerequisites: merge configuration cycle detected for being re-evaluated dependent tex/1.0.0 since {box tex^ | libbox->{box/1,1} libbar->{tex/1,1}}! is a shadow of itself, throwing merge_configuration_cycle
+ trace: collect_build_postponed (2): re-evaluation of existing dependent tex/1.0.0 failed due to merge configuration cycle for {bax^ | libfoo->{bax/1,1}}, throwing recollect_existing_dependents
+ trace: collect_build_postponed (0): cfg-negotiation of {box | libbox->{box/1,1}} failed due to some existing dependents related problem, scheduling their re-collection
+ trace: collect_build_postponed (0): schedule re-collection of existing dependent tex/1.0.0
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.2.0
+ trace: collect_build_prerequisites: resume box/0.2.0
+ trace: collect_build_prerequisites: end box/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}!
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {box | libbox->{box/1,1}}!
+ trace: postponed_configurations::add: merge {tex | libbar->{tex/1,1}} into {bax box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax box tex | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 tex/1,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {box | libbox->{box/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax box tex | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 tex/1,1}}!
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.2.0
+ trace: collect_build_prerequisites: resume box/0.2.0
+ trace: collect_build_prerequisites: end box/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}!
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {box | libbox->{box/1,1}}! (shadow cluster-based)
+ trace: collect_build_prerequisites: skip being built existing dependent tex of dependency libbar
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postponing dependent tex/1.0.0 adds not (being) collected dependencies libbar/1.0.0 with not (being) collected existing dependents to (being) negotiated cluster and results in {box tex | libbox->{box/1,1} libbar->{tex/1,1}}!, throwing recollect_existing_dependents
+ trace: collect_build_postponed (0): cfg-negotiation of {box | libbox->{box/1,1}} failed due to some existing dependents related problem, scheduling their re-collection
+ trace: collect_build_postponed (0): schedule re-collection of existing dependent tiz/1.0.0
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.2.0
+ trace: collect_build_prerequisites: resume box/0.2.0
+ trace: collect_build_prerequisites: end box/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}!
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_prerequisites: begin tiz/1.0.0
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency tex/1.0.0 of dependent tiz/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add box/0.2.0
+ trace: collect_build_prerequisites: begin box/0.2.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent box/0.2.0
+ trace: postponed_configurations::add: create {box | libbox->{box/1,1}}
+ trace: collect_build_prerequisites: postpone box/0.2.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.2.0
+ trace: collect_build_prerequisites: resume box/0.2.0
+ trace: collect_build_prerequisites: end box/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}!
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (2): skip dep-postponed existing dependent tex of dependency libfoo
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {box | libbox->{box/1,1}}!
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 adds not (being) collected dependencies libbar/1.0.0 with not (being) collected existing dependents to (being) negotiated cluster and results in {bax box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}}!, throwing recollect_existing_dependents
+ trace: collect_build_postponed (0): cfg-negotiation of {box | libbox->{box/1,1}} failed due to some existing dependents related problem, scheduling their re-collection
+ trace: collect_build_postponed (0): schedule re-collection of existing dependent tex/1.0.0
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (0): schedule re-collection of existing dependent tiz/1.0.0
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.2.0
+ trace: collect_build_prerequisites: resume box/0.2.0
+ trace: collect_build_prerequisites: end box/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}!
+ trace: collect_build_postponed (1): skip re-collection of dep-postponed package tex
+ trace: collect_build_prerequisites: begin tiz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: create {tiz | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: postpone tiz/1.0.0
+ trace: collect_build_postponed (1): skip re-collection of dep-postponed package tex
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {box | libbox->{box/1,1}}!
+ trace: collect_build_prerequisites: skip being built existing dependent tex of dependency libbar
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: skip being built existing dependent tiz of dependency libbar
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 involves (being) negotiated configurations and results in {bax box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}}!, throwing retry_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {box | libbox->{box/1,1}} failed due to dependent bax, refining configuration
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.2.0
+ trace: collect_build_prerequisites: resume box/0.2.0
+ trace: collect_build_prerequisites: end box/0.2.0
+ trace: collect_build_postponed (1): cfg-negotiate end {box | libbox->{box/1,1}}!
+ trace: collect_build_postponed (1): skip re-collection of dep-postponed package tex
+ trace: collect_build_prerequisites: begin tiz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: create {tiz | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: postpone tiz/1.0.0
+ trace: collect_build_postponed (1): skip re-collection of dep-postponed package tex
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {box | libbox->{box/1,1}}!
+ trace: collect_build_prerequisites: skip being built existing dependent tex of dependency libbar
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: skip being built existing dependent tiz of dependency libbar
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbox/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: collecting cfg-postponed dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bax^ | libfoo->{bax/1,1}}!
+ trace: collect_build_postponed (2): skip re-collection of dep-postponed package tex
+ trace: collect_build_postponed (3): begin {tiz | tex->{tiz/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent tiz of dependency tex
+ trace: collect_build_postponed (3): cfg-negotiate begin {tiz | tex->{tiz/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {bax box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 2,1: libfoo} to {bax^ | libfoo->{bax/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libfoo/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tiz/1.0.0
+ trace: collect_build_prerequisites: resume tiz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: add {tiz 2,1: libbar} to {bax box tex | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 tex/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tiz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tiz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tiz/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tiz | tex->{tiz/1,1}}!
+ trace: collect_build_postponed (3): end {tiz | tex->{tiz/1,1}}
+ trace: collect_build_postponed (2): end {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (1): end {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ new box/0.2.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 1.0.0
+ !tiz configured 1.0.0
+ libbar configured 1.0.0
+ tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !box configured !0.2.0 available 1.0.0
+ libbox configured 1.0.0
+ EOO
+
+ $pkg_drop bax tiz box
+ }
+
+ : up-negotiate-not-collected-existing-dependents2
+ :
+ : Similar to the above but more complicated.
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # bax: depends: libfoo(c)
+ # depends: {libbox libbar} (c)
+ #
+ # tiz: depends: tex(c)
+ # depends: libbar(c)
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ # tez: depends: libbox(c)
+ # depends: toz == 0.1.0 (c)
+ # depends: libbar(c)
+ #
+ # tvz: depends: toz == 0.2.0 (c)
+ #
+ # toz/0.1.0:
+ #
+ $* bax tiz --verbose 1 2>!;
+
+ $pkg_status -r >>EOO;
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 1.0.0
+ !tiz configured 1.0.0
+ libbar configured 1.0.0
+ tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $* tez 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1}}!
+ trace: postponed_configurations::add: merge {tex^ | libbar->{tex/1,1}} into {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax tex^ tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tex/1,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax tex^ tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tex/1,1}}!
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {tez | libbox->{tez/1,1}}! (shadow cluster-based)
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 involves negotiated configurations and results in {tex^ tez | libbox->{tez/1,1} libbar->{tex/1,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {tex^ tez | libbox->{tez/1,1} libbar->{tex/1,1}}!
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {tez | libbox->{tez/1,1}}! (shadow cluster-based)
+ trace: collect_build_prerequisites: merge configuration cycle detected for being re-evaluated dependent tex/1.0.0 since {tex^ tez | libbox->{tez/1,1} libbar->{tex/1,1}}! is a shadow of itself, throwing merge_configuration_cycle
+ trace: collect_build_postponed (2): re-evaluation of existing dependent tex/1.0.0 failed due to merge configuration cycle for {bax^ | libfoo->{bax/1,1}}, throwing recollect_existing_dependents
+ trace: collect_build_postponed (0): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to some existing dependents related problem, scheduling their re-collection
+ trace: collect_build_postponed (0): schedule re-collection of existing dependent tex/1.0.0
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1}}!
+ trace: postponed_configurations::add: merge {tex | libbar->{tex/1,1}} into {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax tex tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tex/1,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax tex tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tex/1,1}}!
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {tez | libbox->{tez/1,1}}! (shadow cluster-based)
+ trace: collect_build_prerequisites: skip being built existing dependent tex of dependency libbar
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postponing dependent tex/1.0.0 adds not (being) collected dependencies libbar/1.0.0 with not (being) collected existing dependents to (being) negotiated cluster and results in {tex tez | libbox->{tez/1,1} libbar->{tex/1,1}}!, throwing recollect_existing_dependents
+ trace: collect_build_postponed (0): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to some existing dependents related problem, scheduling their re-collection
+ trace: collect_build_postponed (0): schedule re-collection of existing dependent tiz/1.0.0
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_prerequisites: begin tiz/1.0.0
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency tex/1.0.0 of dependent tiz/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (2): skip dep-postponed existing dependent tex of dependency libfoo
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1}}!
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 adds not (being) collected dependencies libbar/1.0.0 with not (being) collected existing dependents to (being) negotiated cluster and results in {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1}}!, throwing recollect_existing_dependents
+ trace: collect_build_postponed (0): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to some existing dependents related problem, scheduling their re-collection
+ trace: collect_build_postponed (0): schedule re-collection of existing dependent tex/1.0.0
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (0): schedule re-collection of existing dependent tiz/1.0.0
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (1): skip re-collection of dep-postponed package tex
+ trace: collect_build_prerequisites: begin tiz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: create {tiz | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: postpone tiz/1.0.0
+ trace: collect_build_postponed (1): skip re-collection of dep-postponed package tex
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1}}!
+ trace: collect_build_prerequisites: skip being built existing dependent tex of dependency libbar
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: skip being built existing dependent tiz of dependency libbar
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 involves (being) negotiated configurations and results in {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1}}!, throwing retry_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to dependent bax, refining configuration
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (1): skip re-collection of dep-postponed package tex
+ trace: collect_build_prerequisites: begin tiz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: create {tiz | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: postpone tiz/1.0.0
+ trace: collect_build_postponed (1): skip re-collection of dep-postponed package tex
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1}}!
+ trace: collect_build_prerequisites: skip being built existing dependent tex of dependency libbar
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: skip being built existing dependent tiz of dependency libbar
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbox/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: collecting cfg-postponed dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bax^ | libfoo->{bax/1,1}}!
+ trace: collect_build_postponed (2): skip re-collection of dep-postponed package tex
+ trace: collect_build_postponed (3): begin {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (3): cfg-negotiate begin {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.1.0
+ trace: collect_build_prerequisites: end toz/0.1.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 3,1: libbar} to {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tez/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tez | toz->{tez/2,1}}!
+ trace: collect_build_postponed (3): skip re-collection of dep-postponed package tex
+ trace: collect_build_postponed (4): begin {tiz | tex->{tiz/1,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent tiz of dependency tex
+ trace: collect_build_postponed (4): cfg-negotiate begin {tiz | tex->{tiz/1,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tez/3,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 2,1: libfoo} to {bax^ | libfoo->{bax/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libfoo/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent tiz/1.0.0
+ trace: collect_build_prerequisites: resume tiz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: add {tiz 2,1: libbar} to {bax tex tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tex/1,1 tez/3,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tiz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tiz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tiz/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {tiz | tex->{tiz/1,1}}!
+ trace: collect_build_postponed (4): end {tiz | tex->{tiz/1,1}}
+ trace: collect_build_postponed (3): end {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (2): end {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (1): end {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ new toz/0.1.0 (required by tez)
+ config.toz.extras=true (set by tez)
+ new tez/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 1.0.0
+ !tiz configured 1.0.0
+ libbar configured 1.0.0
+ tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !tez configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ toz configured 0.1.0 available 1.0.0 0.2.0
+ EOO
+
+ # While at it make sure that we won't be able to build tvz since it
+ # requires toz of the 0.2.0 version, which initially can't be
+ # satisfied. But this get automatically resolved by the unsatisfied
+ # constraints resolution machinery.
+ #
+ $* tvz 2>&1 != 0 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tvz/1.0.0
+ trace: collect_build_prerequisites: begin tvz/1.0.0
+ trace: collect_build: add toz/0.2.0
+ info: package tvz dependency on (toz == 0.2.0) is forcing upgrade of toz/0.1.0 to 0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tvz/1.0.0
+ trace: postponed_configurations::add: create {tvz | toz->{tvz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): skip unsatisfied existing dependent tez of dependency toz/0.2.0 due to constraint (toz == 0.1.0)
+ trace: collect_build_postponed (1): cfg-negotiate begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tvz/1.0.0
+ trace: collect_build_prerequisites: resume tvz/1.0.0
+ trace: collect_build_prerequisites: end tvz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_postponed (2): begin {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {toz | libfoo->{toz/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ toz | libfoo->{bax/1,1 toz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ toz | libfoo->{bax/1,1 toz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone bax/1.0.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: add {toz 2,1: libbar} to {bax tex^ | libbar->{bax/2,1 tex/1,1} libbox->{bax/2,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bax^ toz | libfoo->{bax/1,1 toz/1,1}}!
+ trace: collect_build_postponed (3): begin {bax tex^ toz | libbar->{bax/2,1 tex/1,1 toz/2,1} libbox->{bax/2,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libbar
+ trace: collect_build_postponed (3): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tez/1.0.0
+ trace: collect_build_prerequisites: re-evaluation of dependent tez/1.0.0 deviated for depends clause 2: now cannot select alternative, previously 1 was selected
+ trace: collect_build_postponed (3): schedule re-collection of deviated existing dependent tez/1.0.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_postponed (3): skip being built existing dependent bax of dependency libbox
+ trace: collect_build_postponed (3): skip being built existing dependent tez of dependency libbox
+ trace: collect_build_postponed (3): re-evaluate existing dependents for {bax tex^ toz | libbar->{bax/2,1 tex/1,1 toz/2,1} libbox->{bax/2,1}}
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: collect_build_prerequisites: cannot re-evaluate existing dependent tiz/1.0.0 due to dependency tex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tvz/1.0.0
+ trace: collect_build_prerequisites: begin tvz/1.0.0
+ trace: collect_build: add toz/0.2.0
+ info: package tvz dependency on (toz == 0.2.0) is forcing upgrade of toz/0.1.0 to 0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tvz/1.0.0
+ trace: postponed_configurations::add: create {tvz | toz->{tvz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): skip unsatisfied existing dependent tez of dependency toz/0.2.0 due to constraint (toz == 0.1.0)
+ trace: collect_build_postponed (1): cfg-negotiate begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tvz/1.0.0
+ trace: collect_build_prerequisites: resume tvz/1.0.0
+ trace: collect_build_prerequisites: end tvz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_postponed (2): begin {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip dep-postponed existing dependent tex of dependency libfoo
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {toz | libfoo->{toz/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ toz | libfoo->{bax/1,1 toz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ toz | libfoo->{bax/1,1 toz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: create {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: postpone bax/1.0.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: add {toz 2,1: libbar} to {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bax^ toz | libfoo->{bax/1,1 toz/1,1}}!
+ trace: collect_build_postponed (3): begin {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent bax of dependency libbox
+ trace: collect_build_prerequisites: pre-reeval tez/1.0.0
+ trace: collect_build_prerequisites: re-evaluation of dependent tez/1.0.0 deviated for depends clause 2: now cannot select alternative, previously 1 was selected
+ trace: collect_build_postponed (3): schedule re-collection of deviated existing dependent tez/1.0.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_postponed (3): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_postponed (3): skip being built existing dependent tez of dependency libbar
+ trace: collect_build_postponed (3): skip dep-postponed existing dependent tex of dependency libbar
+ trace: collect_build_postponed (3): re-evaluate existing dependents for {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: postponed_configurations::add: create {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tiz/1.0.0 results in {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tiz/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: end toz/0.2.0
+ trace: collect_build_postponed (3): cfg-negotiate end {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}!
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 1,1: libbox} to {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbox/1.0.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 3,1: libbar} to {bax tez toz | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 toz/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tez/1.0.0
+ trace: collect_build_postponed (4): begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent tiz of dependency tex
+ trace: collect_build_postponed (4): cfg-negotiate begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {bax tez toz | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tez/3,1 toz/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 2,1: libfoo} to {bax^ toz | libfoo->{bax/1,1 toz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libfoo/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent tiz/1.0.0
+ trace: collect_build_prerequisites: resume tiz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: add {tiz 2,1: libbar} to {bax tex tez toz | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tex/1,1 tez/3,1 toz/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tiz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tiz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tiz/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {tiz^ | tex->{tiz/1,1}}!
+ trace: collect_build_postponed (4): end {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (3): end {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}
+ trace: collect_build_postponed (2): end {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (1): end {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency toz/0.2.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent tez/1.0.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependent: try to replace conflicting dependent tvz/1.0.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replace conflicting dependent version tvz/1.0.0 with 0.1.0 by adding constraint 'tvz' -> 'tvz == 0.1.0' on command line
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tvz/0.1.0
+ trace: collect_build_prerequisites: begin tvz/0.1.0
+ trace: collect_build: add toz/0.2.0
+ info: package tvz dependency on (toz == 0.2.0) is forcing upgrade of toz/0.1.0 to 0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tvz/0.1.0
+ trace: postponed_configurations::add: create {tvz | toz->{tvz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/0.1.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): skip unsatisfied existing dependent tez of dependency toz/0.2.0 due to constraint (toz == 0.1.0)
+ trace: collect_build_postponed (1): cfg-negotiate begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tvz/0.1.0
+ trace: collect_build_prerequisites: resume tvz/0.1.0
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency bax/1.0.0 of dependent tvz/0.1.0
+ trace: collect_build_prerequisites: skip configured bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tvz/0.1.0
+ trace: postponed_configurations::add: add {tvz 3,1: libfoo} to {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/0.1.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_postponed (2): begin {toz tvz | libfoo->{toz/1,1 tvz/3,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {toz tvz | libfoo->{toz/1,1 tvz/3,1}}
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {toz tvz | libfoo->{toz/1,1 tvz/3,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone bax/1.0.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: add {toz 2,1: libbar} to {bax tex^ | libbar->{bax/2,1 tex/1,1} libbox->{bax/2,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tvz/0.1.0
+ trace: collect_build_prerequisites: resume tvz/0.1.0
+ trace: collect_build_prerequisites: end tvz/0.1.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bax^ toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}!
+ trace: collect_build_postponed (3): begin {bax tex^ toz | libbar->{bax/2,1 tex/1,1 toz/2,1} libbox->{bax/2,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libbar
+ trace: collect_build_postponed (3): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tez/1.0.0
+ trace: collect_build_prerequisites: re-evaluation of dependent tez/1.0.0 deviated for depends clause 2: now cannot select alternative, previously 1 was selected
+ trace: collect_build_postponed (3): schedule re-collection of deviated existing dependent tez/1.0.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_postponed (3): skip being built existing dependent bax of dependency libbox
+ trace: collect_build_postponed (3): skip being built existing dependent tez of dependency libbox
+ trace: collect_build_postponed (3): re-evaluate existing dependents for {bax tex^ toz | libbar->{bax/2,1 tex/1,1 toz/2,1} libbox->{bax/2,1}}
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: collect_build_prerequisites: cannot re-evaluate existing dependent tiz/1.0.0 due to dependency tex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tvz/0.1.0
+ trace: collect_build_prerequisites: begin tvz/0.1.0
+ trace: collect_build: add toz/0.2.0
+ info: package tvz dependency on (toz == 0.2.0) is forcing upgrade of toz/0.1.0 to 0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tvz/0.1.0
+ trace: postponed_configurations::add: create {tvz | toz->{tvz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/0.1.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): skip unsatisfied existing dependent tez of dependency toz/0.2.0 due to constraint (toz == 0.1.0)
+ trace: collect_build_postponed (1): cfg-negotiate begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tvz/0.1.0
+ trace: collect_build_prerequisites: resume tvz/0.1.0
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency bax/1.0.0 of dependent tvz/0.1.0
+ trace: collect_build_prerequisites: skip configured bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tvz/0.1.0
+ trace: postponed_configurations::add: add {tvz 3,1: libfoo} to {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/0.1.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_postponed (2): begin {toz tvz | libfoo->{toz/1,1 tvz/3,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip dep-postponed existing dependent tex of dependency libfoo
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {toz tvz | libfoo->{toz/1,1 tvz/3,1}}
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {toz tvz | libfoo->{toz/1,1 tvz/3,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: create {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: postpone bax/1.0.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: add {toz 2,1: libbar} to {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tvz/0.1.0
+ trace: collect_build_prerequisites: resume tvz/0.1.0
+ trace: collect_build_prerequisites: end tvz/0.1.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bax^ toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}!
+ trace: collect_build_postponed (3): begin {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent bax of dependency libbox
+ trace: collect_build_prerequisites: pre-reeval tez/1.0.0
+ trace: collect_build_prerequisites: re-evaluation of dependent tez/1.0.0 deviated for depends clause 2: now cannot select alternative, previously 1 was selected
+ trace: collect_build_postponed (3): schedule re-collection of deviated existing dependent tez/1.0.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_postponed (3): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_postponed (3): skip being built existing dependent tez of dependency libbar
+ trace: collect_build_postponed (3): skip dep-postponed existing dependent tex of dependency libbar
+ trace: collect_build_postponed (3): re-evaluate existing dependents for {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: postponed_configurations::add: create {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tiz/1.0.0 results in {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tiz/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: end toz/0.2.0
+ trace: collect_build_postponed (3): cfg-negotiate end {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}!
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 1,1: libbox} to {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbox/1.0.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 3,1: libbar} to {bax tez toz | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 toz/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tez/1.0.0
+ trace: collect_build_postponed (4): begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent tiz of dependency tex
+ trace: collect_build_postponed (4): cfg-negotiate begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {bax tez toz | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tez/3,1 toz/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 2,1: libfoo} to {bax^ toz tvz | libfoo->{bax/1,1 toz/1,1 tvz/3,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libfoo/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent tiz/1.0.0
+ trace: collect_build_prerequisites: resume tiz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: add {tiz 2,1: libbar} to {bax tex tez toz | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tex/1,1 tez/3,1 toz/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tiz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tiz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tiz/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {tiz^ | tex->{tiz/1,1}}!
+ trace: collect_build_postponed (4): end {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (3): end {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}
+ trace: collect_build_postponed (2): end {toz tvz | libfoo->{toz/1,1 tvz/3,1}}
+ trace: collect_build_postponed (1): end {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency toz/0.2.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent tez/1.0.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependent: try to replace conflicting dependent tvz/0.1.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replacement of conflicting dependent version tvz/0.1.0 is denied since it is specified on command line as 'tvz == 0.1.0'
+ trace: pkg_build: cannot replace any package, rolling back latest command line adjustment ('tvz' -> 'tvz == 0.1.0')
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tvz/1.0.0
+ trace: collect_build_prerequisites: begin tvz/1.0.0
+ trace: collect_build: add toz/0.2.0
+ info: package tvz dependency on (toz == 0.2.0) is forcing upgrade of toz/0.1.0 to 0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tvz/1.0.0
+ trace: postponed_configurations::add: create {tvz | toz->{tvz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): skip unsatisfied existing dependent tez of dependency toz/0.2.0 due to constraint (toz == 0.1.0)
+ trace: collect_build_postponed (1): cfg-negotiate begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tvz/1.0.0
+ trace: collect_build_prerequisites: resume tvz/1.0.0
+ trace: collect_build_prerequisites: end tvz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_postponed (2): begin {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {toz | libfoo->{toz/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ toz | libfoo->{bax/1,1 toz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ toz | libfoo->{bax/1,1 toz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone bax/1.0.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: add {toz 2,1: libbar} to {bax tex^ | libbar->{bax/2,1 tex/1,1} libbox->{bax/2,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bax^ toz | libfoo->{bax/1,1 toz/1,1}}!
+ trace: collect_build_postponed (3): begin {bax tex^ toz | libbar->{bax/2,1 tex/1,1 toz/2,1} libbox->{bax/2,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libbar
+ trace: collect_build_postponed (3): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval tez/1.0.0
+ trace: collect_build_prerequisites: re-evaluation of dependent tez/1.0.0 deviated for depends clause 2: now cannot select alternative, previously 1 was selected
+ trace: collect_build_postponed (3): schedule re-collection of deviated existing dependent tez/1.0.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_postponed (3): skip being built existing dependent bax of dependency libbox
+ trace: collect_build_postponed (3): skip being built existing dependent tez of dependency libbox
+ trace: collect_build_postponed (3): re-evaluate existing dependents for {bax tex^ toz | libbar->{bax/2,1 tex/1,1 toz/2,1} libbox->{bax/2,1}}
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: collect_build_prerequisites: cannot re-evaluate existing dependent tiz/1.0.0 due to dependency tex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tvz/1.0.0
+ trace: collect_build_prerequisites: begin tvz/1.0.0
+ trace: collect_build: add toz/0.2.0
+ info: package tvz dependency on (toz == 0.2.0) is forcing upgrade of toz/0.1.0 to 0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tvz/1.0.0
+ trace: postponed_configurations::add: create {tvz | toz->{tvz/1,1}}
+ trace: collect_build_prerequisites: postpone tvz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): skip unsatisfied existing dependent tez of dependency toz/0.2.0 due to constraint (toz == 0.1.0)
+ trace: collect_build_postponed (1): cfg-negotiate begin {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tvz/1.0.0
+ trace: collect_build_prerequisites: resume tvz/1.0.0
+ trace: collect_build_prerequisites: end tvz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_postponed (2): begin {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip dep-postponed existing dependent tex of dependency libfoo
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {toz | libfoo->{toz/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ toz | libfoo->{bax/1,1 toz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ toz | libfoo->{bax/1,1 toz/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: create {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: postpone bax/1.0.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: add {toz 2,1: libbar} to {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bax^ toz | libfoo->{bax/1,1 toz/1,1}}!
+ trace: collect_build_postponed (3): begin {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent bax of dependency libbox
+ trace: collect_build_prerequisites: pre-reeval tez/1.0.0
+ trace: collect_build_prerequisites: re-evaluation of dependent tez/1.0.0 deviated for depends clause 2: now cannot select alternative, previously 1 was selected
+ trace: collect_build_postponed (3): schedule re-collection of deviated existing dependent tez/1.0.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: pre-reeval tex/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/1.0.0: 1,1
+ trace: collect_build_postponed (3): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: pre-reeval tiz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tiz/1.0.0: 1,1
+ trace: collect_build_postponed (3): skip being built existing dependent tez of dependency libbar
+ trace: collect_build_postponed (3): skip dep-postponed existing dependent tex of dependency libbar
+ trace: collect_build_postponed (3): re-evaluate existing dependents for {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: reeval tiz/1.0.0
+ trace: postponed_configurations::add: create {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tiz/1.0.0 results in {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tiz/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ trace: collect_build_prerequisites: end toz/0.2.0
+ trace: collect_build_postponed (3): cfg-negotiate end {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}!
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 1,1: libbox} to {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbox/1.0.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build: postpone failure for dependent tez unsatisfied with dependency toz/0.2.0 (== 0.1.0)
+ trace: collect_build: pick toz/0.2.0 over toz/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.2.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 2,1: toz} to {tvz | toz->{tvz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency toz/0.2.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 3,1: libbar} to {bax tez toz | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 toz/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tez/1.0.0
+ trace: collect_build_postponed (4): begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent tiz of dependency tex
+ trace: collect_build_postponed (4): cfg-negotiate begin {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {bax tez toz | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tez/3,1 toz/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 2,1: libfoo} to {bax^ toz | libfoo->{bax/1,1 toz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libfoo/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent tiz/1.0.0
+ trace: collect_build_prerequisites: resume tiz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: add {tiz 2,1: libbar} to {bax tex tez toz | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 tex/1,1 tez/3,1 toz/2,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tiz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tiz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tiz/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {tiz^ | tex->{tiz/1,1}}!
+ trace: collect_build_postponed (4): end {tiz^ | tex->{tiz/1,1}}
+ trace: collect_build_postponed (3): end {bax toz | libbox->{bax/2,1} libbar->{bax/2,1 toz/2,1}}
+ trace: collect_build_postponed (2): end {toz | libfoo->{toz/1,1}}
+ trace: collect_build_postponed (1): end {tvz | toz->{tvz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: pkg_build: try to replace unsatisfactory dependency toz/0.2.0 with some other version
+ trace: try_replace_dependent: try to replace unsatisfied dependent tez/1.0.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependent: try to replace conflicting dependent tvz/1.0.0 of dependency toz/0.2.0 with some other version
+ trace: try_replace_dependency: replacement tvz/0.1.0 tried earlier for same command line, skipping
+ error: unable to satisfy constraints on package toz
+ info: tvz/1.0.0 depends on (toz == 0.2.0)
+ info: tez/1.0.0 depends on (toz == 0.1.0)
+ info: available toz/0.2.0
+ info: available toz/0.1.0
+ info: while satisfying tez/1.0.0
+ info: explicitly specify toz version to manually satisfy both constraints
+ %.*
+ EOE
+
+ $pkg_drop bax tiz tez
+ }
+
+ : merge-config-version-replacement
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # box: depends: {libbar libfoo} (c) | libbox
+ #
+ # bax: depends: libfoo(c)
+ # depends: {libbox libbar} (c)
+ #
+ # toz: depends: libbaz(c)
+ # depends: libfoo(c)
+ # depends: libbar(c)
+ #
+ # tez: depends: libbox(c)
+ # depends: toz == 0.1.0 (c)
+ # depends: libbar(c)
+ #
+ # toz/0.1.0:
+ #
+ $* box bax toz --verbose 1 2>!;
+
+ $pkg_status -r >>EOO;
+ !box configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 1.0.0
+ !toz configured 1.0.0
+ libbar configured 1.0.0
+ libbaz configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $* tez 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add toz/0.1.0
+ warning: package tez dependency on (toz == 0.1.0) is forcing downgrade of toz/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval box/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated box/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (2): skip being built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add box/1.0.0
+ trace: collect_build_prerequisites: reeval box/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {box^ 1,1: libbar libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent box/1.0.0 results in {bax^ box^ | libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluated box/1.0.0
+ trace: collect_build_postponed (2): skip being built existing dependent box of dependency libbar
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (2): skip being built existing dependent toz of dependency libbar
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ box^ | libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1}}!
+ trace: postponed_configurations::add: merge {bax^ box^ | libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}? into {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax box^ tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 box/1,1} libfoo->{bax/1,1 box/1,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax box^ tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 box/1,1} libfoo->{bax/1,1 box/1,1}}!
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {tez | libbox->{tez/1,1}} (shadow cluster-based)
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ tez | libbox->{tez/1,1} libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_prerequisites: pre-reeval box/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated box/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_prerequisites: pre-reeval toz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated toz/1.0.0: 1,1
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ tez | libbox->{tez/1,1} libfoo->{bax/1,1}}
+ trace: collect_build: add box/1.0.0
+ trace: collect_build_prerequisites: reeval box/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {box^ 1,1: libbar libfoo} to {bax^ tez | libbox->{tez/1,1} libfoo->{bax/1,1}} (shadow cluster-based)
+ trace: collect_build_prerequisites: re-evaluating dependent box/1.0.0 results in {bax^ box^ tez | libbox->{tez/1,1} libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluated box/1.0.0
+ trace: collect_build: add toz/1.0.0
+ trace: collect_build_prerequisites: reeval toz/1.0.0
+ trace: postponed_configurations::add: create {toz^ | libbaz->{toz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent toz/1.0.0 results in {toz^ | libbaz->{toz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated toz/1.0.0
+ trace: collect_build_postponed (1): skip being built existing dependent box of dependency libbar
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (1): skip being built existing dependent toz of dependency libbar
+ trace: collect_build_postponed (1): cfg-negotiate begin {bax^ box^ tez | libbox->{tez/1,1} libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ box^ tez | libbox->{tez/1,1} libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}? (shadow cluster-based)
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is shadow-negotiated
+ trace: collect_build_prerequisites: dependency libbox/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/1.0.0
+ trace: collect_build_prerequisites: resume box/1.0.0
+ trace: collect_build_prerequisites: end box/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: pick toz/0.1.0 over toz/1.0.0
+ trace: collect_build: toz/1.0.0 package version needs to be replaced with toz/0.1.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: apply version replacement for toz/0.1.0
+ trace: collect_build: replacement: toz/0.1.0
+ trace: collect_build: add toz/0.1.0
+ warning: package tez dependency on (toz == 0.1.0) is forcing downgrade of toz/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval box/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated box/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (2): skip being built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add box/1.0.0
+ trace: collect_build_prerequisites: reeval box/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {box^ 1,1: libbar libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent box/1.0.0 results in {bax^ box^ | libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluated box/1.0.0
+ trace: collect_build_postponed (2): skip being built existing dependent box of dependency libbar
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (2): skip being built existing dependent toz of dependency libbar
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ box^ | libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1}}!
+ trace: postponed_configurations::add: merge {bax^ box^ | libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}? into {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax box^ tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 box/1,1} libfoo->{bax/1,1 box/1,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax box^ tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 box/1,1} libfoo->{bax/1,1 box/1,1}}!
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {tez | libbox->{tez/1,1}} (shadow cluster-based)
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ tez | libbox->{tez/1,1} libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_prerequisites: pre-reeval box/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated box/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (1): skip expected to be built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ tez | libbox->{tez/1,1} libfoo->{bax/1,1}}
+ trace: collect_build: add box/1.0.0
+ trace: collect_build_prerequisites: reeval box/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {box^ 1,1: libbar libfoo} to {bax^ tez | libbox->{tez/1,1} libfoo->{bax/1,1}} (shadow cluster-based)
+ trace: collect_build_prerequisites: re-evaluating dependent box/1.0.0 results in {bax^ box^ tez | libbox->{tez/1,1} libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluated box/1.0.0
+ trace: collect_build_postponed (1): skip being built existing dependent box of dependency libbar
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (1): skip expected to be built existing dependent toz of dependency libbar
+ trace: collect_build_postponed (1): cfg-negotiate begin {bax^ box^ tez | libbox->{tez/1,1} libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ box^ tez | libbox->{tez/1,1} libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}? (shadow cluster-based)
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is shadow-negotiated
+ trace: collect_build_prerequisites: dependency libbox/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/1.0.0
+ trace: collect_build_prerequisites: resume box/1.0.0
+ trace: collect_build_prerequisites: end box/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: apply version replacement for toz/0.1.0
+ trace: collect_build: replacement: toz/0.1.0
+ trace: collect_build: add toz/0.1.0
+ warning: package tez dependency on (toz == 0.1.0) is forcing downgrade of toz/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bax^ box^ tez | libbox->{bax/2,1 tez/1,1} libfoo->{bax/1,1 box/1,1} libbar->{bax/2,1 box/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.1.0
+ trace: collect_build_prerequisites: end toz/0.1.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 3,1: libbar} to {bax^ box^ tez | libbox->{bax/2,1 tez/1,1} libfoo->{bax/1,1 box/1,1} libbar->{bax/2,1 box/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | toz->{tez/2,1}}!
+ trace: collect_build_postponed (2): end {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (1): end {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: libbaz/1.0.0: unused
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_drop: add libbaz
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: add toz/0.1.0
+ warning: package tez dependency on (toz == 0.1.0) is forcing downgrade of toz/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval box/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated box/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (2): skip being built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add box/1.0.0
+ trace: collect_build_prerequisites: reeval box/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {box^ 1,1: libbar libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent box/1.0.0 results in {bax^ box^ | libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluated box/1.0.0
+ trace: collect_build_postponed (2): skip being built existing dependent box of dependency libbar
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (2): skip being built existing dependent toz of dependency libbar
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ box^ | libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1}}!
+ trace: postponed_configurations::add: merge {bax^ box^ | libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}? into {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax box^ tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 box/1,1} libfoo->{bax/1,1 box/1,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax box^ tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 box/1,1} libfoo->{bax/1,1 box/1,1}}!
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {tez | libbox->{tez/1,1}} (shadow cluster-based)
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ tez | libbox->{tez/1,1} libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_prerequisites: pre-reeval box/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated box/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_prerequisites: pre-reeval toz/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated toz/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ tez | libbox->{tez/1,1} libfoo->{bax/1,1}}
+ trace: collect_build: add box/1.0.0
+ trace: collect_build_prerequisites: reeval box/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {box^ 1,1: libbar libfoo} to {bax^ tez | libbox->{tez/1,1} libfoo->{bax/1,1}} (shadow cluster-based)
+ trace: collect_build_prerequisites: re-evaluating dependent box/1.0.0 results in {bax^ box^ tez | libbox->{tez/1,1} libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluated box/1.0.0
+ trace: collect_build: add toz/1.0.0
+ trace: collect_build_prerequisites: reeval toz/1.0.0
+ trace: postponed_configurations::add: create {toz^ | libbaz->{toz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent toz/1.0.0 results in {toz^ | libbaz->{toz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated toz/1.0.0
+ trace: collect_build_postponed (1): skip being built existing dependent box of dependency libbar
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (1): skip being built existing dependent toz of dependency libbar
+ trace: collect_build_postponed (1): cfg-negotiate begin {bax^ box^ tez | libbox->{tez/1,1} libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ box^ tez | libbox->{tez/1,1} libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}? (shadow cluster-based)
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is shadow-negotiated
+ trace: collect_build_prerequisites: dependency libbox/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/1.0.0
+ trace: collect_build_prerequisites: resume box/1.0.0
+ trace: collect_build_prerequisites: end box/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: pick toz/0.1.0 over toz/1.0.0
+ trace: collect_build: toz/1.0.0 package version needs to be replaced with toz/0.1.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_drop: add libbaz
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: apply version replacement for toz/0.1.0
+ trace: collect_build: replacement: toz/0.1.0
+ trace: collect_build: add toz/0.1.0
+ warning: package tez dependency on (toz == 0.1.0) is forcing downgrade of toz/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (2): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval box/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated box/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (2): skip being built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add box/1.0.0
+ trace: collect_build_prerequisites: reeval box/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {box^ 1,1: libbar libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent box/1.0.0 results in {bax^ box^ | libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluated box/1.0.0
+ trace: collect_build_postponed (2): skip being built existing dependent box of dependency libbar
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (2): skip being built existing dependent toz of dependency libbar
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax^ box^ | libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {tez | libbox->{tez/1,1}}!
+ trace: postponed_configurations::add: merge {bax^ box^ | libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}? into {bax tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1}}!
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax box^ tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 box/1,1} libfoo->{bax/1,1 box/1,1}}!, throwing merge_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {tez | libbox->{tez/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax box^ tez | libbox->{bax/2,1 tez/1,1} libbar->{bax/2,1 box/1,1} libfoo->{bax/1,1 box/1,1}}!
+ trace: collect_build_postponed (1): begin {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tez | libbox->{tez/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {tez | libbox->{tez/1,1}} (shadow cluster-based)
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ tez | libbox->{tez/1,1} libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_prerequisites: pre-reeval box/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated box/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (1): skip expected to be built existing dependent toz of dependency libfoo
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ tez | libbox->{tez/1,1} libfoo->{bax/1,1}}
+ trace: collect_build: add box/1.0.0
+ trace: collect_build_prerequisites: reeval box/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {box^ 1,1: libbar libfoo} to {bax^ tez | libbox->{tez/1,1} libfoo->{bax/1,1}} (shadow cluster-based)
+ trace: collect_build_prerequisites: re-evaluating dependent box/1.0.0 results in {bax^ box^ tez | libbox->{tez/1,1} libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluated box/1.0.0
+ trace: collect_build_postponed (1): skip being built existing dependent box of dependency libbar
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (1): skip expected to be built existing dependent toz of dependency libbar
+ trace: collect_build_postponed (1): cfg-negotiate begin {bax^ box^ tez | libbox->{tez/1,1} libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ box^ tez | libbox->{tez/1,1} libfoo->{bax/1,1 box/1,1} libbar->{box/1,1}}? (shadow cluster-based)
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is shadow-negotiated
+ trace: collect_build_prerequisites: dependency libbox/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/1.0.0
+ trace: collect_build_prerequisites: resume box/1.0.0
+ trace: collect_build_prerequisites: end box/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build: apply version replacement for toz/0.1.0
+ trace: collect_build: replacement: toz/0.1.0
+ trace: collect_build: add toz/0.1.0
+ warning: package tez dependency on (toz == 0.1.0) is forcing downgrade of toz/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bax^ box^ tez | libbox->{bax/2,1 tez/1,1} libfoo->{bax/1,1 box/1,1} libbar->{bax/2,1 box/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.1.0
+ trace: collect_build_prerequisites: end toz/0.1.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 3,1: libbar} to {bax^ box^ tez | libbox->{bax/2,1 tez/1,1} libfoo->{bax/1,1 box/1,1} libbar->{bax/2,1 box/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | toz->{tez/2,1}}!
+ trace: collect_build_postponed (2): end {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (1): end {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ drop libbaz/1.0.0 (unused)
+ downgrade toz/0.1.0 (required by tez)
+ config.toz.extras=true (set by tez)
+ new tez/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !box configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tez configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ EOO
+
+ $pkg_drop box bax toz tez
+ }
+
+ : recollect-dependent-bogus-dependency-postponement
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # bax: depends: libfoo(c)
+ # depends: {libbox libbar} (c)
+ #
+ # bas: depends: libbar(c)
+ # depends: bus(c)
+ #
+ # bus: depends: libbaz(c)
+ # depends: foo(c)
+ #
+ # foo: depends: libfoo(c)
+ #
+ # bat: depends: libbaz(c)
+ #
+ $* bax bas --verbose 1 2>!;
+
+ $pkg_status -r >>EOO;
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 1.0.0
+ !bas configured 1.0.0
+ bus configured 1.0.0
+ foo configured 1.0.0
+ libfoo configured 1.0.0
+ libbaz configured 1.0.0
+ libbar configured 1.0.0
+ EOO
+
+ $* bat 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add bat/1.0.0
+ trace: collect_build_prerequisites: begin bat/1.0.0
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bat/1.0.0
+ trace: postponed_configurations::add: create {bat | libbaz->{bat/1,1}}
+ trace: collect_build_prerequisites: postpone bat/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bat | libbaz->{bat/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bus/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bus/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bat | libbaz->{bat/1,1}}
+ trace: collect_build: add bus/1.0.0
+ trace: collect_build_prerequisites: reeval bus/1.0.0
+ trace: postponed_configurations::add: add {bus^ 1,1: libbaz} to {bat | libbaz->{bat/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bus/1.0.0 results in {bat bus^ | libbaz->{bat/1,1 bus/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bus/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bat bus^ | libbaz->{bat/1,1 bus/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbaz/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bat/1.0.0
+ trace: collect_build_prerequisites: resume bat/1.0.0
+ trace: collect_build_prerequisites: end bat/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bus/1.0.0
+ trace: collect_build_prerequisites: resume bus/1.0.0
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent bus/1.0.0
+ trace: postponed_configurations::add: create {bus | foo->{bus/2,1}}
+ trace: collect_build_prerequisites: postpone bus/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bat bus^ | libbaz->{bat/1,1 bus/1,1}}!
+ trace: collect_build_postponed (2): begin {bus | foo->{bus/2,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent bus of dependency foo
+ trace: collect_build_postponed (2): cfg-negotiate begin {bus | foo->{bus/2,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bus/1.0.0
+ trace: collect_build_prerequisites: resume bus/1.0.0
+ trace: collect_build_prerequisites: end bus/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bus | foo->{bus/2,1}}!
+ trace: collect_build_postponed (3): begin {foo | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (3): skip being built existing dependent foo of dependency libfoo
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build_postponed (3): re-evaluate existing dependents for {foo | libfoo->{foo/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ foo | libfoo->{bax/1,1 foo/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax^ foo | libfoo->{bax/1,1 foo/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: create {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: postpone bax/1.0.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {bax^ foo | libfoo->{bax/1,1 foo/1,1}}!
+ trace: collect_build_postponed (4): begin {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent bax of dependency libbox
+ trace: collect_build_postponed (4): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_prerequisites: pre-reeval bas/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bas/1.0.0: 1,1
+ trace: collect_build_postponed (4): re-evaluate existing dependents for {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build: add bas/1.0.0
+ trace: collect_build_prerequisites: reeval bas/1.0.0
+ trace: postponed_configurations::add: add {bas^ 1,1: libbar} to {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bas/1.0.0 results in {bas^ bax | libbox->{bax/2,1} libbar->{bas/1,1 bax/2,1}}
+ trace: collect_build_prerequisites: re-evaluated bas/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate begin {bas^ bax | libbox->{bax/2,1} libbar->{bas/1,1 bax/2,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent bas/1.0.0
+ trace: collect_build_prerequisites: resume bas/1.0.0
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency bus/1.0.0 of dependent bas/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (bus), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add bat/1.0.0
+ trace: collect_build_prerequisites: begin bat/1.0.0
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bat/1.0.0
+ trace: postponed_configurations::add: create {bat | libbaz->{bat/1,1}}
+ trace: collect_build_prerequisites: postpone bat/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bat | libbaz->{bat/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bus/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bus/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bus of dependency libbaz
+ trace: collect_build: add bus/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bat | libbaz->{bat/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbaz/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bat/1.0.0
+ trace: collect_build_prerequisites: resume bat/1.0.0
+ trace: collect_build_prerequisites: end bat/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bat | libbaz->{bat/1,1}}!
+ trace: collect_build_prerequisites: pre-reeval bas/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bas/1.0.0: 1,1
+ trace: collect_build_postponed (1): schedule re-collection of existing dependent bas/1.0.0 due to bogus postponement of dependency bus
+ trace: collect_build: add bas/1.0.0
+ trace: collect_build_prerequisites: begin bas/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bas/1.0.0
+ trace: postponed_configurations::add: create {bas | libbar->{bas/1,1}}
+ trace: collect_build_prerequisites: postpone bas/1.0.0
+ trace: collect_build_postponed (2): begin {bas | libbar->{bas/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bas of dependency libbar
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bas | libbar->{bas/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate begin {bas | libbar->{bas/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bas/1.0.0
+ trace: collect_build_prerequisites: resume bas/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bus/1.0.0 of dependent bas/1.0.0
+ trace: postponed_configurations::add: create {bas | bus->{bas/2,1}}
+ trace: collect_build_prerequisites: postpone bas/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bas | libbar->{bas/1,1}}!
+ trace: collect_build_postponed (3): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1
+ trace: collect_build_postponed (3): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (3): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: reeval foo/1.0.0
+ trace: postponed_configurations::add: add {foo^ 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent foo/1.0.0 results in {bax^ foo^ | libfoo->{bax/1,1 foo/1,1}}
+ trace: collect_build_prerequisites: re-evaluated foo/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax^ foo^ | libfoo->{bax/1,1 foo/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bas | libbar->{bas/1,1}}!
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbox
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 involves (being) negotiated configurations and results in {bas bax | libbar->{bas/1,1 bax/2,1} libbox->{bax/2,1}}!, throwing retry_configuration
+ trace: collect_build_postponed (1): cfg-negotiation of {bas | libbar->{bas/1,1}} failed due to dependent bax, refining configuration
+ trace: collect_build_postponed (2): begin {bas | libbar->{bas/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bas of dependency libbar
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bas | libbar->{bas/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate begin {bas | libbar->{bas/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bas/1.0.0
+ trace: collect_build_prerequisites: resume bas/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bus/1.0.0 of dependent bas/1.0.0
+ trace: postponed_configurations::add: create {bas | bus->{bas/2,1}}
+ trace: collect_build_prerequisites: postpone bas/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bas | libbar->{bas/1,1}}!
+ trace: collect_build_postponed (3): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1
+ trace: collect_build_postponed (3): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (3): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: reeval foo/1.0.0
+ trace: postponed_configurations::add: add {foo^ 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent foo/1.0.0 results in {bax^ foo^ | libfoo->{bax/1,1 foo/1,1}}
+ trace: collect_build_prerequisites: re-evaluated foo/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax^ foo^ | libfoo->{bax/1,1 foo/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bas | libbar->{bas/1,1}}!
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbox
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is negotiated
+ trace: collect_build_prerequisites: collecting cfg-postponed dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {bax^ foo^ | libfoo->{bax/1,1 foo/1,1}}!
+ trace: collect_build_postponed (4): begin {bas | bus->{bas/2,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent bas of dependency bus
+ trace: collect_build_postponed (4): cfg-negotiate begin {bas | bus->{bas/2,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bus/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bus/1.0.0
+ trace: postponed_configurations::add: add {bus 1,1: libbaz} to {bat | libbaz->{bat/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bus/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbaz/1.0.0 of dependent bus/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency foo/1.0.0 of dependent bus/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (foo), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add bat/1.0.0
+ trace: collect_build_prerequisites: begin bat/1.0.0
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bat/1.0.0
+ trace: postponed_configurations::add: create {bat | libbaz->{bat/1,1}}
+ trace: collect_build_prerequisites: postpone bat/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bat | libbaz->{bat/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bus/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bus/1.0.0: 1,1
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bus of dependency libbaz
+ trace: collect_build: add bus/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bat | libbaz->{bat/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbaz/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bat/1.0.0
+ trace: collect_build_prerequisites: resume bat/1.0.0
+ trace: collect_build_prerequisites: end bat/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bat | libbaz->{bat/1,1}}!
+ trace: collect_build_prerequisites: pre-reeval bas/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bas/1.0.0: 1,1
+ trace: collect_build_postponed (1): schedule re-collection of existing dependent bas/1.0.0 due to bogus postponement of dependency bus
+ trace: collect_build: add bas/1.0.0
+ trace: collect_build_prerequisites: begin bas/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bas/1.0.0
+ trace: postponed_configurations::add: create {bas | libbar->{bas/1,1}}
+ trace: collect_build_prerequisites: postpone bas/1.0.0
+ trace: collect_build_postponed (2): begin {bas | libbar->{bas/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bas of dependency libbar
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bas | libbar->{bas/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate begin {bas | libbar->{bas/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bas/1.0.0
+ trace: collect_build_prerequisites: resume bas/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bus/1.0.0 of dependent bas/1.0.0
+ trace: postponed_configurations::add: create {bas | bus->{bas/2,1}}
+ trace: collect_build_prerequisites: postpone bas/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bas | libbar->{bas/1,1}}!
+ trace: collect_build_postponed (3): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1
+ trace: collect_build_postponed (3): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (3): skip dep-postponed existing dependent foo of dependency libfoo
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bas | libbar->{bas/1,1}}!
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbox
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 involves (being) negotiated configurations and results in {bas bax | libbar->{bas/1,1 bax/2,1} libbox->{bax/2,1}}!, throwing retry_configuration
+ trace: collect_build_postponed (1): cfg-negotiation of {bas | libbar->{bas/1,1}} failed due to dependent bax, refining configuration
+ trace: collect_build_postponed (2): begin {bas | libbar->{bas/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build_postponed (2): skip being built existing dependent bas of dependency libbar
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bas | libbar->{bas/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate begin {bas | libbar->{bas/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bas/1.0.0
+ trace: collect_build_prerequisites: resume bas/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bus/1.0.0 of dependent bas/1.0.0
+ trace: postponed_configurations::add: create {bas | bus->{bas/2,1}}
+ trace: collect_build_prerequisites: postpone bas/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bas | libbar->{bas/1,1}}!
+ trace: collect_build_postponed (3): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval foo/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated foo/1.0.0: 1,1
+ trace: collect_build_postponed (3): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (3): skip dep-postponed existing dependent foo of dependency libfoo
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bas | libbar->{bas/1,1}}!
+ trace: collect_build_prerequisites: skip being built existing dependent bax of dependency libbox
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is negotiated
+ trace: collect_build_prerequisites: collecting cfg-postponed dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {bax^ | libfoo->{bax/1,1}}!
+ trace: collect_build_postponed (4): begin {bas | bus->{bas/2,1}}
+ trace: collect_build_postponed (4): skip being built existing dependent bas of dependency bus
+ trace: collect_build_postponed (4): cfg-negotiate begin {bas | bus->{bas/2,1}}
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bus/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bus/1.0.0
+ trace: postponed_configurations::add: add {bus 1,1: libbaz} to {bat | libbaz->{bat/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bus/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbaz/1.0.0 of dependent bus/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent bus/1.0.0
+ trace: postponed_configurations::add: create {bus | foo->{bus/2,1}}
+ trace: collect_build_prerequisites: postpone bus/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent bas/1.0.0
+ trace: collect_build_prerequisites: resume bas/1.0.0
+ trace: collect_build_prerequisites: end bas/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {bas | bus->{bas/2,1}}!
+ trace: collect_build_postponed (5): begin {bus | foo->{bus/2,1}}
+ trace: collect_build_postponed (5): skip being built existing dependent bus of dependency foo
+ trace: collect_build_postponed (5): cfg-negotiate begin {bus | foo->{bus/2,1}}
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: add {foo 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent foo/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libfoo/1.0.0 of dependent foo/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (5): select cfg-negotiated dependency alternative for dependent bus/1.0.0
+ trace: collect_build_prerequisites: resume bus/1.0.0
+ trace: collect_build_prerequisites: end bus/1.0.0
+ trace: collect_build_postponed (5): cfg-negotiate end {bus | foo->{bus/2,1}}!
+ trace: collect_build_postponed (5): end {bus | foo->{bus/2,1}}
+ trace: collect_build_postponed (4): end {bas | bus->{bas/2,1}}
+ trace: collect_build_postponed (3): end {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (2): end {bas | libbar->{bas/1,1}}
+ trace: collect_build_postponed (1): end {bat | libbaz->{bat/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ new bat/1.0.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 1.0.0
+ !bas configured 1.0.0
+ bus configured 1.0.0
+ foo configured 1.0.0
+ libfoo configured 1.0.0
+ libbaz configured 1.0.0
+ libbar configured 1.0.0
+ !bat configured 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $pkg_drop bax bas bat
+ }
+
+ : recollect-pruned-collection
+ :
+ {
+ $clone_cfg;
+
+ $* libbar/0.1.0 libbiz/0.1.0 bax 2>!;
+
+ $pkg_status -r >>EOO;
+ !libbar configured !0.1.0 available 1.0.0
+ !libbiz configured !0.1.0 available 1.0.0
+ !bax configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $* --upgrade --immediate 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build: add libbiz/1.0.0
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent bax/1.0.0 due to dependency libbar/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: begin libbiz/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent libbiz/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: end libbiz/1.0.0
+ trace: collect_build_prerequisites: skip configured bax/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (libbar), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build: add libbiz/1.0.0
+ trace: collect_build: add bax/1.0.0
+ trace: pkg_build: dep-postpone user-specified libbar
+ trace: collect_build_prerequisites: begin libbiz/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: dep-postpone dependency libbar/1.0.0 of dependent libbiz/1.0.0
+ trace: collect_build_prerequisites: end libbiz/1.0.0
+ trace: collect_build_prerequisites: skip configured bax/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_prerequisites: pre-reeval bax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated bax/1.0.0: 1,1
+ trace: collect_build_postponed (0): schedule re-collection of existing dependent bax/1.0.0 due to bogus postponement of dependency libbar
+ trace: collect_build_prerequisites: begin bax/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: create {bax | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: postpone bax/1.0.0
+ trace: collect_build_postponed (1): begin {bax | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libfoo
+ trace: collect_build_postponed (1): cfg-negotiate begin {bax | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent bax/1.0.0
+ trace: collect_build: pick libbar/1.0.0 over libbar/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: create {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: postpone bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bax | libfoo->{bax/1,1}}!
+ trace: collect_build_postponed (2): begin {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libbox
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbox/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bax | libbox->{bax/2,1} libbar->{bax/2,1}}!
+ trace: collect_build_postponed (2): end {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_postponed (1): end {bax | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ upgrade libbar/1.0.0
+ config.libbar.extras=true (set by bax)
+ upgrade libbiz/1.0.0
+ reconfigure/update bax/1.0.0
+ config.bax.libfoo_extras=true (set by bax)
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !libbar configured 1.0.0
+ !libbiz configured 1.0.0
!libbar configured 1.0.0
- libbox configured !0.1.0 available 1.0.0
+ !bax configured 1.0.0
+ !libbar configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop libbar libbiz bax
+ }
+
+ : optimization
+ :
+ {
+ +$clone_cfg
+
+ : dependency-after-config-clause
+ :
+ {
+ $clone_cfg;
+
+ $* tax ?libfoo/0.1.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !tax configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ $* ?libfoo 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: execute_plan: simulate: yes
+ trace: evaluate_dependency: libfoo/0.1.0: update to libfoo/1.0.0
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_build_prerequisites: pre-reeval tax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tax/1.0.0: 1,1 re-evaluation is optional
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ upgrade libfoo/1.0.0
+ reconfigure tax (dependent of libfoo)
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tax configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop tax
+ }
+
+ : dependency-before-config-clause
+ :
+ {
+ $clone_cfg;
+
+ $* tex/0.2.0 ?libbar/0.1.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !tex configured !0.2.0 available 1.0.0 0.3.0
+ libbar configured !0.1.0 available 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $* ?libbar 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: execute_plan: simulate: yes
+ trace: evaluate_dependency: libbar/0.1.0: update to libbar/1.0.0
+ trace: pkg_build: refine package collection/plan execution
+ trace: collect_build_prerequisites: pre-reeval tex/0.2.0
+ trace: collect_build_prerequisites: pre-reevaluated tex/0.2.0: 2,1 re-evaluation is optional
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ upgrade libbar/1.0.0
+ reconfigure tex (dependent of libbar)
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tex configured !0.2.0 available 1.0.0 0.3.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop tex
+ }
+
+ : other-config-clause
+ :
+ {
+ $clone_cfg;
+
+ $* tax ?libfoo/0.1.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !tax configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ $* libfoo foo/0.1.0 2>&1 | $filter 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build: add foo/0.1.0
+ trace: collect_build_prerequisites: pre-reeval tax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tax/1.0.0: 1,1 re-evaluation is optional
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: begin foo/0.1.0
+ trace: collect_build: pick libfoo/1.0.0 over libfoo/0.1.0
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency libfoo/1.0.0 of dependent foo/0.1.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (libfoo), retry from scratch
+ trace: pkg_build: refine package collection/plan execution from scratch
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build: add foo/0.1.0
+ trace: pkg_build: dep-postpone user-specified libfoo
+ trace: collect_build_prerequisites: begin foo/0.1.0
+ trace: collect_build: pick libfoo/1.0.0 over libfoo/0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/0.1.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/0.1.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: pre-reeval tax/1.0.0
+ trace: collect_build_prerequisites: pre-reevaluated tax/1.0.0: 1,1 re-evaluation is optional
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {foo | libfoo->{foo/1,1}}
+ trace: collect_build: add tax/1.0.0
+ trace: collect_build_prerequisites: reeval tax/1.0.0
+ trace: postponed_configurations::add: create {tax^ | libbar->{tax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tax/1.0.0 results in {tax^ | libbar->{tax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/0.1.0
+ trace: collect_build_prerequisites: resume foo/0.1.0
+ trace: collect_build_prerequisites: end foo/0.1.0
+ trace: collect_build_postponed (1): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
+ trace: collect_build_postponed (2): begin {tax^ | libbar->{tax/1,1}}
+ trace: collect_build_postponed (2): skip being built existing dependent tax of dependency libbar
+ trace: collect_build_postponed (2): cfg-negotiate begin {tax^ | libbar->{tax/1,1}}
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tax/1.0.0
+ trace: collect_build_prerequisites: resume tax/1.0.0
+ trace: collect_build: pick libfoo/1.0.0 over libfoo/0.1.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent tax/1.0.0
+ trace: collect_build_prerequisites: end tax/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tax^ | libbar->{tax/1,1}}!
+ trace: collect_build_postponed (2): end {tax^ | libbar->{tax/1,1}}
+ trace: collect_build_postponed (1): end {foo | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ upgrade libfoo/1.0.0
+ config.libfoo.extras=true (set by foo)
+ reconfigure tax/1.0.0 (dependent of libfoo)
+ new foo/0.1.0
+ trace: execute_plan: simulate: no
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !libfoo configured 1.0.0
+ !tax configured 1.0.0
+ libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !foo configured !0.1.0 available 1.0.0 0.2.0
+ !libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop tax foo libfoo
+ }
+ }
+
+ : repo-packages
+ :
+ : Don't match the tracing but just make sure that pkg-build doesn't crash
+ : or hang and ends up with an expected packages setup.
+ :
+ {
+ +$clone_cfg
+
+ # Note that we don't mach the configuration negotiation flows in the
+ # tests of this scope.
+ #
+ test.arguments += --verbose 1
+
+ # Convert specific warnings to infos since we expect them to
+ # appear. This, in particular, prevents bbot workers to set task result
+ # status to warning.
+ #
+ warn_to_info = [cmdline] sed -e 's/warning: (package .* is forcing .*)/info: \1/' >&2
+
+ : new-all
+ :
+ {
+ $clone_cfg;
+
+ $* libfoo libbar ?libbaz/0.1.0 ?libbox/0.1.0 libbiz \
+ foo fox fux fix fex bar baz bac bat bas bus \
+ box bax bux bix bex boo biz buz buc tax tex \
+ tix tiz toz tez tuz tux dex dix diz dox 2>!;
+
+ $pkg_status -r >>EOO;
+ !libfoo configured 1.0.0
+ !libbar configured 1.0.0
+ !bat configured 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ !tix configured 0.1.0 available 1.0.0
!toz configured 0.1.0 available 1.0.0 0.2.0
- !bix configured 1.0.0
+ !tuz configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tux configured 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !libbiz configured 1.0.0
+ !libbar configured 1.0.0
!bar configured 1.0.0
!libbar configured 1.0.0
!bux configured 1.0.0
!libbar configured 1.0.0
- !libbar configured 1.0.0
- !foo configured 1.0.0
- !libfoo configured 1.0.0
- !fox configured 1.0.0
- !libfoo configured 1.0.0
- !fux configured 1.0.0
- !libfoo configured 1.0.0
- !baz configured 1.0.0
- !libbar configured 1.0.0
- !libfoo configured 1.0.0
- !bac configured 1.0.0
- !libbar configured 1.0.0
- libbaz configured !0.1.0 available 1.0.0
- !libfoo configured 1.0.0
- !fix configured 1.0.0
+ !bex configured 1.0.0
+ !libbar configured 1.0.0
+ !boo configured 1.0.0
+ !libbar configured 1.0.0
+ !biz configured 1.0.0
+ !boo configured 1.0.0
+ !libbar configured 1.0.0
+ !buz configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !tez configured 1.0.0
+ !libbar configured 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !bix configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !libbar configured 1.0.0
!foo configured 1.0.0
!libfoo configured 1.0.0
- !fex configured 1.0.0
- !foo configured 1.0.0
+ !fox configured 1.0.0
!libfoo configured 1.0.0
- !libfoo configured 1.0.0
- !bus configured 1.0.0
- !foo configured 1.0.0
+ !fux configured 1.0.0
+ !libfoo configured 1.0.0
+ !baz configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !bac configured 1.0.0
+ !libbar configured 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ !libfoo configured 1.0.0
+ !fix configured 1.0.0
+ !foo configured 1.0.0
+ !libfoo configured 1.0.0
+ !fex configured 1.0.0
+ !foo configured 1.0.0
+ !libfoo configured 1.0.0
!libfoo configured 1.0.0
- libbaz configured !0.1.0 available 1.0.0
- !bas configured 1.0.0
!bus configured 1.0.0
!foo configured 1.0.0
!libfoo configured 1.0.0
libbaz configured !0.1.0 available 1.0.0
- !libbar configured 1.0.0
- !box configured 1.0.0
- !libbar configured 1.0.0
- !libfoo configured 1.0.0
- !bax configured 1.0.0
- !libbar configured 1.0.0
- libbox configured !0.1.0 available 1.0.0
- !libfoo configured 1.0.0
- !buc configured 1.0.0
- !bux configured 1.0.0
+ !bas configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ !libfoo configured 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
!libbar configured 1.0.0
- !libfoo configured 1.0.0
- !tax configured 1.0.0
- !libbar configured 1.0.0
- !libfoo configured 1.0.0
- !tex configured 1.0.0
- !libbar configured 1.0.0
- !libfoo configured 1.0.0
- !tiz configured 1.0.0
- !libbar configured 1.0.0
+ !box configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !bax configured 1.0.0
+ !libbar configured 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !libfoo configured 1.0.0
+ !buc configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !tax configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
!tex configured 1.0.0
!libbar configured 1.0.0
!libfoo configured 1.0.0
- !dex configured 1.0.0
- !bar configured 1.0.0
+ !tiz configured 1.0.0
!libbar configured 1.0.0
- !libfoo configured 1.0.0
- !dox configured 1.0.0
+ !tex configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
!dex configured 1.0.0
!bar configured 1.0.0
!libbar configured 1.0.0
!libfoo configured 1.0.0
- !dix configured 1.0.0
!dox configured 1.0.0
!dex configured 1.0.0
!bar configured 1.0.0
!libbar configured 1.0.0
!libfoo configured 1.0.0
- !libbar configured 1.0.0
- libbox configured !0.1.0 available 1.0.0
- !diz configured 1.0.0
- !dox configured 1.0.0
+ !dix configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !libbar configured 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !diz configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !libbar configured 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ EOO
+
+ $pkg_drop libfoo libbar libbiz foo fox fux fix fex bar baz bac bat \
+ bas bus box bax bux bix bex boo biz buz buc tax tex tix tiz \
+ toz tez tuz tux dex dix diz dox
+ }
+
+ : upgrade
+ :
+ {
+ +$clone_cfg
+
+ : recursive
+ :
+ {
+ +$clone_cfg
+
+ : libs
+ :
+ {
+ $clone_cfg;
+
+ $* ?libfoo/0.1.0 libbar/0.1.0 ?libbaz/0.1.0 ?libbox/0.1.0 \
+ libbiz/0.1.0 foo fox fux fix fex bar baz bac bat bas bus \
+ box bax bux bix bex boo biz buz buc tax tex tix tiz toz \
+ tez tuz tux dex dix diz dox 2>!;
+
+ $pkg_status -r >>EOO;
+ !libbar configured !0.1.0 available 1.0.0
+ !libbiz configured !0.1.0 available 1.0.0
+ !bat configured 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tuz configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tux configured 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !bar configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !bux configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !bex configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !boo configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !biz configured 1.0.0
+ !boo configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !buz configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !tez configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !bix configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !bux configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !fox configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !fux configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !baz configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !bac configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !fix configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !fex configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ !bas configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !box configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !bax configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !buc configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !tax configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !tex configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !tiz configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !tex configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !dix configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !diz configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ EOO
+
+ $* --upgrade --recursive 2>&1 | $warn_to_info 2>!;
+
+ $pkg_status -r >>EOO;
+ !libbar configured 1.0.0
+ !libbiz configured 1.0.0
+ !libbar configured 1.0.0
+ !bat configured 1.0.0
+ libbaz configured !1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tuz configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tux configured 1.0.0
+ libbox configured !1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !bex configured 1.0.0
+ !libbar configured 1.0.0
+ !boo configured 1.0.0
+ !libbar configured 1.0.0
+ !biz configured 1.0.0
+ !boo configured 1.0.0
+ !libbar configured 1.0.0
+ !buz configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !tez configured 1.0.0
+ !libbar configured 1.0.0
+ libbox configured !1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !bix configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !libbar configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ !fox configured 1.0.0
+ libfoo configured !1.0.0
+ !fux configured 1.0.0
+ libfoo configured !1.0.0
+ !baz configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !bac configured 1.0.0
+ !libbar configured 1.0.0
+ libbaz configured !1.0.0
+ libfoo configured !1.0.0
+ !fix configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ !fex configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ libfoo configured !1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ libbaz configured !1.0.0
+ !bas configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ libbaz configured !1.0.0
+ !libbar configured 1.0.0
+ !box configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !bax configured 1.0.0
+ !libbar configured 1.0.0
+ libbox configured !1.0.0
+ libfoo configured !1.0.0
+ !buc configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !tax configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !tex configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !tiz configured 1.0.0
+ !libbar configured 1.0.0
+ !tex configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !dix configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !libbar configured 1.0.0
+ libbox configured !1.0.0
+ !diz configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !libbar configured 1.0.0
+ libbox configured !1.0.0
+ EOO
+
+ $pkg_drop libfoo libbar libbiz foo fox fux fix fex bar baz bac \
+ bat bas bus box bax bux bix bex boo biz buz buc \
+ tax tex tix tiz toz tez tuz tux dex dix diz dox
+ }
+
+ : all
+ :
+ {
+ $clone_cfg;
+
+ $* ?libfoo/0.1.0 ?libbar/0.1.0 ?libbaz/0.1.0 ?libbox/0.1.0 \
+ ?libbiz/0.1.0 foo/0.1.0 fox/0.1.0 fux/0.1.0 fix/0.1.0 fex/0.1.0 \
+ bar/0.1.0 baz/0.1.0 bac/1.0.0 bat/1.0.0 bas/1.0.0 bus/0.1.0 \
+ box/0.1.0 bax/1.0.0 bux/1.0.0 bix/1.0.0 bex/1.0.0 boo/1.0.0 \
+ biz/0.1.0 buz/1.0.0 buc/1.0.0 tax/1.0.0 tex/0.1.0 tix/0.1.0 \
+ tiz/1.0.0 toz/0.1.0 tez/1.0.0 tuz/1.0.0 tux/1.0.0 dex/1.0.0 \
+ dix/1.0.0 diz/1.0.0 dox/1.0.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !bat configured !1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ !biz configured !0.1.0 available 1.0.0
+ libbiz configured !0.1.0 available 1.0.0
+ !tix configured !0.1.0 available 1.0.0
+ !toz configured !0.1.0 available 1.0.0 0.2.0
+ !tuz configured !1.0.0
+ !toz configured !0.1.0 available 1.0.0 0.2.0
+ !box configured !0.1.0 available 1.0.0 0.2.0
+ libbox configured !0.1.0 available 1.0.0
+ !tux configured !1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !tix configured !0.1.0 available 1.0.0
+ !fox configured !0.1.0 available 1.0.0 0.2.0
+ libbar configured !0.1.0 available 1.0.0
+ !bar configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !bux configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !bex configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !boo configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !buz configured !1.0.0
+ !bux configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !tez configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !toz configured !0.1.0 available 1.0.0 0.2.0
+ !bix configured !1.0.0
+ !bar configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !bux configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !foo configured !0.1.0 available 1.0.0 0.2.0
+ libfoo configured !0.1.0 available 1.0.0
+ !fux configured !0.1.0 available 1.0.0 0.2.0 0.1.1
+ libfoo configured !0.1.0 available 1.0.0
+ !fex configured !0.1.0 available 1.0.0
+ !fux configured !0.1.0 available 1.0.0 0.2.0 0.1.1
+ libfoo configured !0.1.0 available 1.0.0
+ !baz configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !bac configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !fix configured !0.1.0 available 1.0.0
+ !foo configured !0.1.0 available 1.0.0 0.2.0
+ libfoo configured !0.1.0 available 1.0.0
+ !bus configured !0.1.0 available 1.0.0
+ !foo configured !0.1.0 available 1.0.0 0.2.0
+ libfoo configured !0.1.0 available 1.0.0
+ !bas configured !1.0.0
+ !bus configured !0.1.0 available 1.0.0
+ !foo configured !0.1.0 available 1.0.0 0.2.0
+ libfoo configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !bax configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !buc configured !1.0.0
+ !bux configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !tax configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !tex configured !0.1.0 available 1.0.0 0.3.0 0.2.0
+ libfoo configured !0.1.0 available 1.0.0
+ !tiz configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !tex configured !0.1.0 available 1.0.0 0.3.0 0.2.0
+ libfoo configured !0.1.0 available 1.0.0
+ !dex configured !1.0.0
+ !bar configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !dox configured !1.0.0
+ !dex configured !1.0.0
+ !bar configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !dix configured !1.0.0
+ !dox configured !1.0.0
+ !dex configured !1.0.0
+ !bar configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !diz configured !1.0.0
+ !dox configured !1.0.0
+ !dex configured !1.0.0
+ !bar configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ EOO
+
+ $* --upgrade --recursive 2>&1 | $warn_to_info 2>!;
+
+ $pkg_status -r >>EOO;
+ !bat configured 1.0.0
+ libbaz configured !1.0.0
+ !biz configured 1.0.0
+ !boo configured 1.0.0
+ libbar configured !1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tuz configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !box configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ !tux configured 1.0.0
+ libbox configured !1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !fox configured 1.0.0
+ libfoo configured !1.0.0
+ !bar configured 1.0.0
+ libbar configured !1.0.0
+ !bux configured 1.0.0
+ libbar configured !1.0.0
+ !bex configured 1.0.0
+ libbar configured !1.0.0
+ !boo configured 1.0.0
+ libbar configured !1.0.0
+ !buz configured 1.0.0
+ !bux configured 1.0.0
+ libbar configured !1.0.0
+ !tez configured 1.0.0
+ libbar configured !1.0.0
+ libbox configured !1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !bix configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured !1.0.0
+ !bux configured 1.0.0
+ libbar configured !1.0.0
+ libbar configured !1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ !fux configured 1.0.0
+ libfoo configured !1.0.0
+ !fex configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ libfoo configured !1.0.0
+ !baz configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ !bac configured 1.0.0
+ libbar configured !1.0.0
+ libbaz configured !1.0.0
+ libfoo configured !1.0.0
+ !fix configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ libbaz configured !1.0.0
+ !bas configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ libbaz configured !1.0.0
+ libbar configured !1.0.0
+ !bax configured 1.0.0
+ libbar configured !1.0.0
+ libbox configured !1.0.0
+ libfoo configured !1.0.0
+ !buc configured 1.0.0
+ !bux configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ !tax configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ !tex configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ !tiz configured 1.0.0
+ libbar configured !1.0.0
+ !tex configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ !dix configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ libbar configured !1.0.0
+ libbox configured !1.0.0
+ !diz configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ libbar configured !1.0.0
+ libbox configured !1.0.0
+ EOO
+
+ $pkg_drop foo fox fux fix fex bar baz bac bat bas bus box bax bux \
+ bix bex boo biz buz buc tax tex tix tiz toz tez tuz tux \
+ dex dix diz dox
+ }
+ }
+
+ : immediate
+ :
+ {
+ +$clone_cfg
+
+ : libs
+ :
+ {
+ $clone_cfg;
+
+ $* ?libfoo/0.1.0 libbar/0.1.0 ?libbaz/0.1.0 ?libbox/0.1.0 \
+ libbiz/0.1.0 foo fox fux fix fex bar baz bac bat bas bus \
+ box bax bux bix bex boo biz buz buc tax tex tix tiz toz \
+ tez tuz tux dex dix diz dox 2>!;
+
+ $pkg_status -r >>EOO;
+ !libbar configured !0.1.0 available 1.0.0
+ !libbiz configured !0.1.0 available 1.0.0
+ !bat configured 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tuz configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tux configured 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !bar configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !bux configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !bex configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !boo configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !biz configured 1.0.0
+ !boo configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !buz configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !tez configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !bix configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !bux configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !fox configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !fux configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !baz configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !bac configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !fix configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !fex configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ !bas configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !box configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !bax configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !buc configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !tax configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !tex configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !tiz configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !tex configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !dix configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !diz configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ EOO
+
+ $* --upgrade --immediate 2>&1 | $warn_to_info 2>!;
+
+ $pkg_status -r >>EOO;
+ !libbar configured 1.0.0
+ !libbiz configured 1.0.0
+ !libbar configured 1.0.0
+ !bat configured 1.0.0
+ libbaz configured !1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tuz configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tux configured 1.0.0
+ libbox configured !1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !bex configured 1.0.0
+ !libbar configured 1.0.0
+ !boo configured 1.0.0
+ !libbar configured 1.0.0
+ !biz configured 1.0.0
+ !boo configured 1.0.0
+ !libbar configured 1.0.0
+ !buz configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !tez configured 1.0.0
+ !libbar configured 1.0.0
+ libbox configured !1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !bix configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !libbar configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ !fox configured 1.0.0
+ libfoo configured !1.0.0
+ !fux configured 1.0.0
+ libfoo configured !1.0.0
+ !baz configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !bac configured 1.0.0
+ !libbar configured 1.0.0
+ libbaz configured !1.0.0
+ libfoo configured !1.0.0
+ !fix configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ !fex configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ libfoo configured !1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ libbaz configured !1.0.0
+ !bas configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ libbaz configured !1.0.0
+ !libbar configured 1.0.0
+ !box configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !bax configured 1.0.0
+ !libbar configured 1.0.0
+ libbox configured !1.0.0
+ libfoo configured !1.0.0
+ !buc configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !tax configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !tex configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !tiz configured 1.0.0
+ !libbar configured 1.0.0
+ !tex configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !dix configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !libbar configured 1.0.0
+ libbox configured !1.0.0
+ !diz configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured !1.0.0
+ !libbar configured 1.0.0
+ libbox configured !1.0.0
+ EOO
+
+ $pkg_drop libfoo libbar libbiz foo fox fux fix fex bar baz bac \
+ bat bas bus box bax bux bix bex boo biz buz buc tax \
+ tex tix tiz toz tez tuz tux dex dix diz dox
+ }
+
+ : all
+ :
+ {
+ $clone_cfg;
+
+ $* ?libfoo/0.1.0 ?libbar/0.1.0 ?libbaz/0.1.0 ?libbox/0.1.0 \
+ ?libbiz/0.1.0 foo/0.1.0 fox/0.1.0 fux/0.1.0 fix/0.1.0 fex/0.1.0 \
+ bar/0.1.0 baz/0.1.0 bac/1.0.0 bat/1.0.0 bas/1.0.0 bus/0.1.0 \
+ box/0.1.0 bax/1.0.0 bux/1.0.0 bix/1.0.0 bex/1.0.0 boo/1.0.0 \
+ biz/0.1.0 buz/1.0.0 buc/1.0.0 tax/1.0.0 tex/0.1.0 tix/0.1.0 \
+ tiz/1.0.0 toz/0.1.0 tez/1.0.0 tuz/1.0.0 tux/1.0.0 dex/1.0.0 \
+ dix/1.0.0 diz/1.0.0 dox/1.0.0 2>!;
+
+ $pkg_status -r >>EOO;
+ !bat configured !1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ !biz configured !0.1.0 available 1.0.0
+ libbiz configured !0.1.0 available 1.0.0
+ !tix configured !0.1.0 available 1.0.0
+ !toz configured !0.1.0 available 1.0.0 0.2.0
+ !tuz configured !1.0.0
+ !toz configured !0.1.0 available 1.0.0 0.2.0
+ !box configured !0.1.0 available 1.0.0 0.2.0
+ libbox configured !0.1.0 available 1.0.0
+ !tux configured !1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !tix configured !0.1.0 available 1.0.0
+ !fox configured !0.1.0 available 1.0.0 0.2.0
+ libbar configured !0.1.0 available 1.0.0
+ !bar configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !bux configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !bex configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !boo configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !buz configured !1.0.0
+ !bux configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !tez configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !toz configured !0.1.0 available 1.0.0 0.2.0
+ !bix configured !1.0.0
+ !bar configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !bux configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !foo configured !0.1.0 available 1.0.0 0.2.0
+ libfoo configured !0.1.0 available 1.0.0
+ !fux configured !0.1.0 available 1.0.0 0.2.0 0.1.1
+ libfoo configured !0.1.0 available 1.0.0
+ !fex configured !0.1.0 available 1.0.0
+ !fux configured !0.1.0 available 1.0.0 0.2.0 0.1.1
+ libfoo configured !0.1.0 available 1.0.0
+ !baz configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !bac configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !fix configured !0.1.0 available 1.0.0
+ !foo configured !0.1.0 available 1.0.0 0.2.0
+ libfoo configured !0.1.0 available 1.0.0
+ !bus configured !0.1.0 available 1.0.0
+ !foo configured !0.1.0 available 1.0.0 0.2.0
+ libfoo configured !0.1.0 available 1.0.0
+ !bas configured !1.0.0
+ !bus configured !0.1.0 available 1.0.0
+ !foo configured !0.1.0 available 1.0.0 0.2.0
+ libfoo configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !bax configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !buc configured !1.0.0
+ !bux configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !tax configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !tex configured !0.1.0 available 1.0.0 0.3.0 0.2.0
+ libfoo configured !0.1.0 available 1.0.0
+ !tiz configured !1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ !tex configured !0.1.0 available 1.0.0 0.3.0 0.2.0
+ libfoo configured !0.1.0 available 1.0.0
+ !dex configured !1.0.0
+ !bar configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !dox configured !1.0.0
+ !dex configured !1.0.0
+ !bar configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ !dix configured !1.0.0
+ !dox configured !1.0.0
+ !dex configured !1.0.0
+ !bar configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !diz configured !1.0.0
+ !dox configured !1.0.0
+ !dex configured !1.0.0
+ !bar configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ libbar configured !0.1.0 available 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ EOO
+
+ $* --upgrade --immediate 2>&1 | $warn_to_info 2>!;
+
+ $pkg_status -r >>EOO;
+ !bat configured 1.0.0
+ libbaz configured !1.0.0
+ !biz configured 1.0.0
+ !boo configured 1.0.0
+ libbar configured !1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tuz configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !box configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ !tux configured 1.0.0
+ libbox configured !1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !fox configured 1.0.0
+ libfoo configured !1.0.0
+ !bar configured 1.0.0
+ libbar configured !1.0.0
+ !bux configured 1.0.0
+ libbar configured !1.0.0
+ !bex configured 1.0.0
+ libbar configured !1.0.0
+ !boo configured 1.0.0
+ libbar configured !1.0.0
+ !buz configured 1.0.0
+ !bux configured 1.0.0
+ libbar configured !1.0.0
+ !tez configured 1.0.0
+ libbar configured !1.0.0
+ libbox configured !1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !bix configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured !1.0.0
+ !bux configured 1.0.0
+ libbar configured !1.0.0
+ libbar configured !1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ !fux configured 1.0.0
+ libfoo configured !1.0.0
+ !fex configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ libfoo configured !1.0.0
+ !baz configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ !bac configured 1.0.0
+ libbar configured !1.0.0
+ libbaz configured !1.0.0
+ libfoo configured !1.0.0
+ !fix configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ libbaz configured !1.0.0
+ !bas configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured !1.0.0
+ libbaz configured !1.0.0
+ libbar configured !1.0.0
+ !bax configured 1.0.0
+ libbar configured !1.0.0
+ libbox configured !1.0.0
+ libfoo configured !1.0.0
+ !buc configured 1.0.0
+ !bux configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ !tax configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ !tex configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ !tiz configured 1.0.0
+ libbar configured !1.0.0
+ !tex configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ !dix configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ libbar configured !1.0.0
+ libbox configured !1.0.0
+ !diz configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ libbar configured !1.0.0
+ libbox configured !1.0.0
+ EOO
+
+ $pkg_drop foo fox fux fix fex bar baz bac bat bas bus box bax bux \
+ bix bex boo biz buz buc tax tex tix tiz toz tez tuz tux \
+ dex dix diz dox
+ }
+ }
+ }
+
+ : incrementally
+ :
+ {
+ +$clone_cfg
+
+ : all
+ :
+ {
+ $clone_cfg;
+
+ ps = libfoo libbar libbaz libbox libbiz foo fox fux fix fex bar baz \
+ bac bat bas bus box bax bux bix bex boo biz buz buc tax tex \
+ tix tiz toz tez tuz tux dex dix diz dox;
+
+ for p: $ps
+ $* $p 2>&1 | $warn_to_info 2>!
+ end;
+
+ $pkg_status -r >>EOO;
+ !libfoo configured 1.0.0
+ !libbar configured 1.0.0
+ !libbaz configured 1.0.0
+ !libbox configured 1.0.0
+ !libbiz configured 1.0.0
+ !libbar configured 1.0.0
+ !foo configured 1.0.0
+ !libfoo configured 1.0.0
+ !fox configured 1.0.0
+ !libfoo configured 1.0.0
+ !fux configured 1.0.0
+ !libfoo configured 1.0.0
+ !fix configured 1.0.0
+ !foo configured 1.0.0
+ !libfoo configured 1.0.0
+ !fex configured 1.0.0
+ !foo configured 1.0.0
+ !libfoo configured 1.0.0
+ !libfoo configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !baz configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !bac configured 1.0.0
+ !libbar configured 1.0.0
+ !libbaz configured 1.0.0
+ !libfoo configured 1.0.0
+ !bat configured 1.0.0
+ !libbaz configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ !libfoo configured 1.0.0
+ !libbaz configured 1.0.0
+ !bas configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ !libfoo configured 1.0.0
+ !libbaz configured 1.0.0
+ !libbar configured 1.0.0
+ !box configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !bax configured 1.0.0
+ !libbar configured 1.0.0
+ !libbox configured 1.0.0
+ !libfoo configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !bix configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !libbar configured 1.0.0
+ !bex configured 1.0.0
+ !libbar configured 1.0.0
+ !boo configured 1.0.0
+ !libbar configured 1.0.0
+ !biz configured 1.0.0
+ !boo configured 1.0.0
+ !libbar configured 1.0.0
+ !buz configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !buc configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !tax configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !tex configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !tiz configured 1.0.0
+ !libbar configured 1.0.0
+ !tex configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tez configured 1.0.0
+ !libbar configured 1.0.0
+ !libbox configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tuz configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tux configured 1.0.0
+ !libbox configured 1.0.0
+ !tix configured 0.1.0 available 1.0.0
!dex configured 1.0.0
!bar configured 1.0.0
!libbar configured 1.0.0
!libfoo configured 1.0.0
- !libbar configured 1.0.0
- libbox configured !0.1.0 available 1.0.0
- EOO
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !dix configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !libbar configured 1.0.0
+ !libbox configured 1.0.0
+ !diz configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !libbar configured 1.0.0
+ !libbox configured 1.0.0
+ EOO
+
+ # Drop the configured packages by sequentially turning all of them
+ # into dependencies.
+ #
+ for p: $ps
+ $* ?$p 2>!
+ end
+ }
+
+ : applications
+ :
+ {
+ +$clone_cfg
+
+ : direct-order
+ :
+ {
+ $clone_cfg;
+
+ ps = foo fox fux fix fex bar baz bac bat bas bus \
+ box bax bux bix bex boo biz buz buc tax tex \
+ tix tiz toz tez tuz tux dex dix diz dox;
+
+ for p: $ps
+ $* $p 2>&1 | $warn_to_info 2>!
+ end;
- $pkg_drop libfoo libbar foo fox fux fix fex bar \
- baz bac bat bas bus box bax bux bix bex \
- boo biz buz buc tax tex tix tiz toz tez \
- tux dex dix diz dox
+ $pkg_status -r >>EOO;
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ !fox configured 1.0.0
+ libfoo configured 1.0.0
+ !fux configured 1.0.0
+ libfoo configured 1.0.0
+ !fix configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ !fex configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ libfoo configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured 1.0.0
+ !baz configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !bac configured 1.0.0
+ libbar configured 1.0.0
+ libbaz configured 1.0.0
+ libfoo configured 1.0.0
+ !bat configured 1.0.0
+ libbaz configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ libbaz configured 1.0.0
+ !bas configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ libbaz configured 1.0.0
+ libbar configured 1.0.0
+ !box configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 1.0.0
+ !bux configured 1.0.0
+ libbar configured 1.0.0
+ !bix configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured 1.0.0
+ !bux configured 1.0.0
+ libbar configured 1.0.0
+ libbar configured 1.0.0
+ !bex configured 1.0.0
+ libbar configured 1.0.0
+ !boo configured 1.0.0
+ libbar configured 1.0.0
+ !biz configured 1.0.0
+ !boo configured 1.0.0
+ libbar configured 1.0.0
+ !buz configured 1.0.0
+ !bux configured 1.0.0
+ libbar configured 1.0.0
+ !buc configured 1.0.0
+ !bux configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !tax configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !tiz configured 1.0.0
+ libbar configured 1.0.0
+ !tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tez configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tuz configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tux configured 1.0.0
+ libbox configured 1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !dix configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ !diz configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ EOO
+
+ # Drop the configured packages by sequentially turning all of them
+ # into dependencies.
+ #
+ for p: $ps
+ $* ?$p 2>&1 | $warn_to_info 2>!
+ end
+ }
+
+ : reverse-order
+ :
+ {
+ $clone_cfg;
+
+ ps = dox diz dix dex tux tuz tez toz tiz tix tex tax buc buz biz \
+ boo bex bix bux bax box bus bas bat bac baz bar fex fix fux \
+ fox foo;
+
+ for p: $ps
+ $* $p 2>&1 | $warn_to_info 2>!
+ end;
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ libbar configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !diz configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ !dix configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !tux configured 1.0.0
+ libbox configured 1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tuz configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tez configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !tiz configured 1.0.0
+ libbar configured 1.0.0
+ !tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !tax configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !bux configured 1.0.0
+ libbar configured 1.0.0
+ !buc configured 1.0.0
+ !bux configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !buz configured 1.0.0
+ !bux configured 1.0.0
+ libbar configured 1.0.0
+ !boo configured 1.0.0
+ libbar configured 1.0.0
+ !biz configured 1.0.0
+ !boo configured 1.0.0
+ libbar configured 1.0.0
+ !bex configured 1.0.0
+ libbar configured 1.0.0
+ !bix configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured 1.0.0
+ !bux configured 1.0.0
+ libbar configured 1.0.0
+ libbar configured 1.0.0
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ libfoo configured 1.0.0
+ !box configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ libbaz configured 1.0.0
+ !bas configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ libbaz configured 1.0.0
+ libbar configured 1.0.0
+ !bat configured 1.0.0
+ libbaz configured 1.0.0
+ !bac configured 1.0.0
+ libbar configured 1.0.0
+ libbaz configured 1.0.0
+ libfoo configured 1.0.0
+ !baz configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !fex configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ libfoo configured 1.0.0
+ !fix configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ !fux configured 1.0.0
+ libfoo configured 1.0.0
+ !fox configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ # Drop the configured packages by sequentially turning all of them
+ # into dependencies.
+ #
+ for p: $ps
+ $* ?$p 2>!
+ end
+ }
+
+ : reordered
+ :
+ : Vary the order of package builds. Note that the first order is the
+ : original direct package order and the last one is the reverse
+ : order.
+ :
+ if $all
+ {
+ $clone_cfg;
+
+ ds = foo fox fux fix fex bar baz bac bat bas bus box bax bux bix \
+ bex boo biz buz buc tax tex tix tiz toz tez tuz tux dex dix \
+ diz dox tvz '';
+
+ # Prepare the package build list.
+ #
+ for i: $integer.integer_sequence(1, $name.size($ds))
+ d = ($ds[$i])
+ ps =
+
+ prepend = true
+ for p: $ds
+ if ($p == $d)
+ prepend = false
+ end
+
+ if ($p != '')
+ if $prepend
+ ps =+ $p
+ else
+ ps += $p
+ end
+ end
+ end
+
+ echo $ps >&2 2>|
+
+ # Build the packages, one at a time, creating the list of
+ # successfully built packages.
+ #
+ # Note that a package build may potentially fail due to some
+ # ambiguity which requires user's additional input. We just
+ # silently ignore such failures.
+ #
+ cps =
+ for p: $ps
+ timeout 120
+ if $* $p 2>&1 | $warn_to_info 2>!
+ cps += $p
+ end
+ end
+
+ # Drop the configured packages by sequentially turning all of
+ # them into dependencies.
+ #
+ for p: $cps
+ timeout 120
+ $* ?$p 2>!
+ end
+ end
+ }
+ }
+ }
}
}
@@ -11733,7 +24428,7 @@ test.options += --no-progress
{
+$clone_root_cfg && $rep_add $rep/t13a && $rep_fetch
- : bar
+ : bar-baz-biz
:
{
$clone_cfg;
@@ -11763,7 +24458,75 @@ test.options += --no-progress
config.liba.backend = cli
EOO
- $pkg_drop bar
+ # Make sure that since baz doesn't reconfigure liba (it also accepts
+ # the cli backend for liba) the re-evaluated existing dependents bar
+ # and the liba dependency doesn't get reconfigured.
+ #
+ $* baz 2>>~%EOE%;
+ build plan:
+ new baz/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ configured baz/1.0.0
+ %info: .+baz.+ is up to date%
+ updated baz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ !baz configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.backend = cli
+ EOO
+
+ # Make sure that when biz reconfigures liba (it only accepts the gui
+ # backend for liba), the re-evaluated existing dependents bar and baz
+ # are also reconfigured.
+ #
+ $* biz 2>>~%EOE%;
+ build plan:
+ reconfigure/update liba/1.0.0 (required by bar, baz, biz)
+ config.liba.backend=gui (set by biz)
+ reconfigure baz/1.0.0 (dependent of liba)
+ reconfigure bar/1.0.0 (dependent of liba)
+ new biz/1.0.0
+ disfigured bar/1.0.0
+ disfigured baz/1.0.0
+ disfigured liba/1.0.0
+ fetched biz/1.0.0
+ unpacked biz/1.0.0
+ configured liba/1.0.0
+ configured baz/1.0.0
+ configured bar/1.0.0
+ configured biz/1.0.0
+ %info: .+biz.+ is up to date%
+ %info: .+baz.+ is up to date%
+ %info: .+bar.+ is up to date%
+ updated biz/1.0.0
+ updated baz/1.0.0
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ !baz configured 1.0.0
+ liba configured 1.0.0
+ !biz configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.backend = gui
+ EOO
+
+ $pkg_drop bar baz biz
}
: baz
@@ -11884,7 +24647,7 @@ test.options += --no-progress
$pkg_drop baz bar
}
- : bar-baz-biz
+ : bar-baz-biz-box
:
{
$clone_cfg;
@@ -11930,7 +24693,44 @@ test.options += --no-progress
config.liba.backend = gui
EOO
- $pkg_drop bar baz biz
+ # Make sure that since box doesn't reconfigure liba (it accepts any
+ # backend for liba and just reflects it in its own configuration) none
+ # of the re-evaluated existing dependents nor the liba dependency get
+ # reconfigured.
+ #
+ $* box 2>>~%EOE%;
+ build plan:
+ new box/1.0.0
+ config.box.liba_backend=gui (set by box)
+ fetched box/1.0.0
+ unpacked box/1.0.0
+ configured box/1.0.0
+ %info: .+box.+ is up to date%
+ updated box/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ !baz configured 1.0.0
+ liba configured 1.0.0
+ !biz configured 1.0.0
+ liba configured 1.0.0
+ !box configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.backend = gui
+ EOO
+
+ cat cfg/box-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.box.liba_backend = gui
+ EOO
+
+ $pkg_drop bar baz biz box
}
}
@@ -13582,6 +26382,155 @@ test.options += --no-progress
info: while satisfying libfoo-tests/1.0.0
EOE
}
+
+ : reflection-foo
+ :
+ {
+ $clone_cfg;
+
+ $* libbar-tests 2>>EOE != 0;
+ error: unable to select dependency alternative for package libbar-tests/1.0.0
+ info: explicitly specify dependency packages to manually select the alternative
+ info: alternative: libbar-baz
+ info: alternative: libbar-foo
+ info: while satisfying libbar-tests/1.0.0
+ EOE
+
+ $* libbar-foo libbar-tests 2>>~%EOE%;
+ fetched libbar-foo/1.0.0
+ unpacked libbar-foo/1.0.0
+ fetched libbar-tests/1.0.0
+ unpacked libbar-tests/1.0.0
+ configured libbar-foo/1.0.0
+ configured libbar-tests/1.0.0
+ %info: .+libbar-foo-1.0.0.+ is up to date%
+ %info: .+libbar-tests-1.0.0.+ is up to date%
+ updated libbar-foo/1.0.0
+ updated libbar-tests/1.0.0
+ EOE
+
+ cat cfg/libbar-tests-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.libbar_tests.test = libbar-foo
+ %.*
+ EOO
+
+ $* libbar-baz 2>>~%EOE%;
+ fetched libbar-baz/1.0.0
+ unpacked libbar-baz/1.0.0
+ configured libbar-baz/1.0.0
+ %info: .+libbar-baz-1.0.0.+ is up to date%
+ updated libbar-baz/1.0.0
+ EOE
+
+ cat cfg/libbar-tests-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.libbar_tests.test = libbar-foo
+ %.*
+ EOO
+
+ $pkg_status -r >>EOO;
+ !libbar-foo configured 1.0.0
+ !libbar-tests configured 1.0.0
+ !libbar-foo configured 1.0.0
+ !libbar-baz configured 1.0.0
+ EOO
+
+ $pkg_drop libbar-foo libbar-baz libbar-tests
+ }
+
+ : reflection-baz
+ :
+ {
+ $clone_cfg;
+
+ $* libbar-baz libbar-tests 2>>~%EOE%;
+ fetched libbar-baz/1.0.0
+ unpacked libbar-baz/1.0.0
+ fetched libbar-tests/1.0.0
+ unpacked libbar-tests/1.0.0
+ configured libbar-baz/1.0.0
+ configured libbar-tests/1.0.0
+ %info: .+libbar-baz-1.0.0.+ is up to date%
+ %info: .+libbar-tests-1.0.0.+ is up to date%
+ updated libbar-baz/1.0.0
+ updated libbar-tests/1.0.0
+ EOE
+
+ cat cfg/libbar-tests-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.libbar_tests.test = libbar-baz
+ %.*
+ EOO
+
+ $* libbar-foo 2>>~%EOE%;
+ fetched libbar-foo/1.0.0
+ unpacked libbar-foo/1.0.0
+ configured libbar-foo/1.0.0
+ %info: .+libbar-foo-1.0.0.+ is up to date%
+ updated libbar-foo/1.0.0
+ EOE
+
+ cat cfg/libbar-tests-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.libbar_tests.test = libbar-baz
+ %.*
+ EOO
+
+ $pkg_status -r >>EOO;
+ !libbar-baz configured 1.0.0
+ !libbar-tests configured 1.0.0
+ !libbar-baz configured 1.0.0
+ !libbar-foo configured 1.0.0
+ EOO
+
+ $pkg_drop libbar-baz libbar-foo libbar-tests
+ }
+
+ : reflection-both
+ :
+ {
+ $clone_cfg;
+
+ $* libbar-foo libbar-baz libbar-tests 2>!;
+
+ cat cfg/libbar-tests-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.libbar_tests.test = libbar-baz
+ %.*
+ EOO
+
+ $pkg_status -r >>EOO;
+ !libbar-foo configured 1.0.0
+ !libbar-baz configured 1.0.0
+ !libbar-tests configured 1.0.0
+ !libbar-baz configured 1.0.0
+ EOO
+
+ $pkg_drop libbar-foo libbar-baz libbar-tests
+ }
+
+ : configure-explicit
+ :
+ {
+ $clone_cfg;
+
+ $* --yes "config.libbar_tests.test = libbar-foo libbar-baz" -- libbar-tests 2>!;
+
+ cat cfg/libbar-tests-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.libbar_tests.test = libbar-foo libbar-baz
+ %.*
+ EOO
+
+ $pkg_status -r >>EOO;
+ !libbar-tests configured 1.0.0
+ libbar-baz configured 1.0.0
+ libbar-foo configured 1.0.0
+ EOO
+
+ $pkg_drop libbar-tests
+ }
}
: dependent
@@ -14039,6 +26988,32 @@ test.options += --no-progress
EOE
}
+ : unavailable-masked
+ :
+ : As above but using --mask-repository instead of rep-remove.
+ :
+ {
+ $clone_cfg;
+
+ $* '?sys:libbaz/0.0.3' 2>>EOE;
+ disfigured libbox/0.0.1
+ disfigured libfix/0.0.3
+ disfigured libbaz/0.0.3
+ disfigured libfoo/1.0.0
+ purged libfoo/1.0.0
+ purged libbaz/0.0.3
+ configured sys:libbaz/0.0.3
+ configured libfix/0.0.3
+ configured libbox/0.0.1
+ EOE
+
+ $rep_fetch $rep/t0b;
+
+ $* --mask-repository $rep/t0c ?libbaz --patch --yes 2>>EOE != 0
+ error: patch version for sys:libbaz/0.0.3 is not available from its dependents' repositories
+ EOE
+ }
+
-$pkg_drop libbox libfix libbaz libfoo
}
@@ -14436,6 +27411,7 @@ test.options += --no-progress
+cp -r $src/libhello-1.0.0 ./libhello
+cat <<EOI >+libhello/build/root.build
config [bool] config.libhello.develop ?= false
+ config [bool] config.libhello.extras ?= false
if ($build.mode != 'skeleton')
text "develop=$config.libhello.develop"
EOI
@@ -14451,9 +27427,9 @@ test.options += --no-progress
$clone_cfg;
$* libhello 2>!; # Update after output directory change.
- # Use bogus configuration variable to trigger reconfiguration.
+ # Specify a configuration variable to trigger reconfiguration.
#
- $* config.libhello.bogus=true -- libhello 2>>~%EOE%
+ $* config.libhello.extras=true -- libhello 2>>~%EOE%
disfigured libhello/1.0.0
%.*: develop=true%
configured libhello/1.0.0
@@ -14903,7 +27879,7 @@ else
: build-unpacked
:
: Test that the unpacked external package is properly built for the first
- : time and is not rebuilt afterwards via the directory argument.
+ : time and is replaced afterwards via the directory argument.
:
if! $remote
{
@@ -14919,6 +27895,9 @@ else
EOE
$* $d 2>>~%EOE%;
+ %disfigured style-basic/1\.1\.0-a\.0\.\d+\..+%
+ %using style-basic/1\.1\.0-a\.0\.\d+\..+%
+ %configured style-basic/1\.1\.0-a\.0\.\d+\..+%
%info: .+ is up to date%
%updated style-basic/1\.1\.0-a\.0\.\d+\..+%
EOE
@@ -14947,6 +27926,9 @@ else
EOE
$* $d +{ --config-id 1 } 2>>~%EOE%;
+ %disfigured style-basic/1\.1\.0-a\.0\.\d+\..+%
+ %using style-basic/1\.1\.0-a\.0\.\d+\..+%
+ %configured style-basic/1\.1\.0-a\.0\.\d+\..+%
%info: .+ is up to date%
%updated style-basic/1\.1\.0-a\.0\.\d+\..+%
EOE
@@ -15213,17 +28195,17 @@ else
$rep_add $rep/t7b && $rep_fetch;
$* libbar <'y' 2>>~%EOE%;
- % upgrade libbaz/1.1.0 \[cfg2.\] \(required by foo \[cfg2.\]\)%
% drop libbuild2-bar/1.0.0 \[cfg2..bpkg.build2.\] \(unused\)%
+ % upgrade libbaz/1.1.0 \[cfg2.\] \(required by foo \[cfg2.\]\)%
% upgrade foo/1.1.0 \[cfg2.\] \(required by libbar\)%
upgrade libbar/1.1.0
%continue\? \[Y/n\] disfigured libbar/1.0.0%
%disfigured foo/1.0.0 \[cfg2.\]%
- %disfigured libbuild2-bar/1.0.0 \[cfg2..bpkg.build2.\]%
%disfigured libbaz/1.0.0 \[cfg2.\]%
+ %disfigured libbuild2-bar/1.0.0 \[cfg2..bpkg.build2.\]%
+ %purged libbuild2-bar/1.0.0 \[cfg2..bpkg.build2.\]%
%fetched libbaz/1.1.0 \[cfg2.\]%
%unpacked libbaz/1.1.0 \[cfg2.\]%
- %purged libbuild2-bar/1.0.0 \[cfg2..bpkg.build2.\]%
%fetched foo/1.1.0 \[cfg2.\]%
%unpacked foo/1.1.0 \[cfg2.\]%
fetched libbar/1.1.0
@@ -15395,17 +28377,17 @@ else
$rep_add $rep/t7b && $rep_fetch;
$* libbar <'y' 2>>~%EOE%;
- % upgrade libbaz/1.1.0 \[cfg..bpkg.host.\] \(required by foo \[cfg..bpkg.host.\]\)%
% drop libbuild2-bar/1.0.0 \[cfg..bpkg.build2.\] \(unused\)%
+ % upgrade libbaz/1.1.0 \[cfg..bpkg.host.\] \(required by foo \[cfg..bpkg.host.\]\)%
% upgrade foo/1.1.0 \[cfg..bpkg.host.\] \(required by libbar\)%
upgrade libbar/1.1.0
%continue\? \[Y/n\] disfigured libbar/1.0.0%
%disfigured foo/1.0.0 \[cfg..bpkg.host.\]%
- %disfigured libbuild2-bar/1.0.0 \[cfg..bpkg.build2.\]%
%disfigured libbaz/1.0.0 \[cfg..bpkg.host.\]%
+ %disfigured libbuild2-bar/1.0.0 \[cfg..bpkg.build2.\]%
+ %purged libbuild2-bar/1.0.0 \[cfg..bpkg.build2.\]%
%fetched libbaz/1.1.0 \[cfg..bpkg.host.\]%
%unpacked libbaz/1.1.0 \[cfg..bpkg.host.\]%
- %purged libbuild2-bar/1.0.0 \[cfg..bpkg.build2.\]%
%fetched foo/1.1.0 \[cfg..bpkg.host.\]%
%unpacked foo/1.1.0 \[cfg..bpkg.host.\]%
fetched libbar/1.1.0
@@ -15465,17 +28447,17 @@ else
$rep_add $rep/t7b && $rep_fetch;
$* libbar <'y' 2>>~%EOE%;
- upgrade libbaz/1.1.0 (required by foo, libbar)
% drop libbuild2-bar/1.0.0 \[cfg..bpkg.build2.\] \(unused\)%
+ upgrade libbaz/1.1.0 (required by foo, libbar)
upgrade foo/1.1.0 (required by libbar)
upgrade libbar/1.1.0
continue? [Y/n] disfigured libbar/1.0.0
disfigured foo/1.0.0
- %disfigured libbuild2-bar/1.0.0 \[cfg..bpkg.build2.\]%
disfigured libbaz/1.0.0
+ %disfigured libbuild2-bar/1.0.0 \[cfg..bpkg.build2.\]%
+ %purged libbuild2-bar/1.0.0 \[cfg..bpkg.build2.\]%
fetched libbaz/1.1.0
unpacked libbaz/1.1.0
- %purged libbuild2-bar/1.0.0 \[cfg..bpkg.build2.\]%
fetched foo/1.1.0
unpacked foo/1.1.0
fetched libbar/1.1.0
@@ -15876,14 +28858,14 @@ else
y
y
EOI
- % new libbaz/1.0.0 \[t2.\]%
drop libbaz/1.0.0 (unused)
+ % new libbaz/1.0.0 \[t2.\]%
% reconfigure foo/1.0.0 \(dependent of libbaz \[t2.\]\)%
continue? [Y/n] update dependent packages? [Y/n] disfigured foo/1.0.0
disfigured libbaz/1.0.0
+ purged libbaz/1.0.0
%fetched libbaz/1.0.0 \[t2.\]%
%unpacked libbaz/1.0.0 \[t2.\]%
- purged libbaz/1.0.0
%configured libbaz/1.0.0 \[t2.\]%
configured foo/1.0.0
%info: t2.+libbaz-1.0.0.+ is up to date%
@@ -15964,10 +28946,10 @@ else
%.*
trace: execute_plan: simulate: yes
%.*
- % new libbaz/1.0.0 \[t2.\]%
% drop libbuild2-bar/1.0.0 \[t1..bpkg.build2.\] \(unused\)%
drop libbaz/1.0.0 (unused)
drop foo/1.0.0 (unused)
+ % new libbaz/1.0.0 \[t2.\]%
continue? [Y/n] trace: execute_plan: simulate: no
%.*
disfigured foo/1.0.0
@@ -15976,16 +28958,16 @@ else
%.*
%disfigured libbuild2-bar/1.0.0 \[t1..bpkg.build2.\]%
%.*
- %fetched libbaz/1.0.0 \[t2.\]%
- %.*
- %unpacked libbaz/1.0.0 \[t2.\]%
- %.*
%purged libbuild2-bar/1.0.0 \[t1..bpkg.build2.\]%
%.*
purged libbaz/1.0.0
%.*
purged foo/1.0.0
%.*
+ %fetched libbaz/1.0.0 \[t2.\]%
+ %.*
+ %unpacked libbaz/1.0.0 \[t2.\]%
+ %.*
%configured libbaz/1.0.0 \[t2.\]%
%.*
%info: .+t2.+libbaz-1.0.0.+ is up to date%
@@ -16024,15 +29006,15 @@ else
$* libbar libbaz +{ --config-name h2 } <<EOI 2>>~%EOE%;
y
EOI
- % new libbaz/1.0.0 \[h2.\]%
drop libbaz/1.0.0 (unused)
+ % new libbaz/1.0.0 \[h2.\]%
reconfigure/update foo/1.0.0 (required by libbar)
new libbar/1.0.0
continue? [Y/n] disfigured foo/1.0.0
disfigured libbaz/1.0.0
+ purged libbaz/1.0.0
%fetched libbaz/1.0.0 \[h2.\]%
%unpacked libbaz/1.0.0 \[h2.\]%
- purged libbaz/1.0.0
fetched libbar/1.0.0
unpacked libbar/1.0.0
%configured libbaz/1.0.0 \[h2.\]%
@@ -16081,23 +29063,23 @@ else
?libbaz +{ --config-name h2 } <<EOI 2>>~%EOE%;
y
EOI
- % new libbaz/1.0.0 \[h2.\] \(required by libbar\)%
% drop libbuild2-bar/1.0.0 \[h1..bpkg.build2.\] \(unused\)%
drop libbaz/1.0.0 (unused)
reconfigure/unhold sys:foo/1.2.0
+ % new libbaz/1.0.0 \[h2.\] \(required by libbar\)%
new libbar/1.0.0
continue? [Y/n] disfigured foo/1.0.0
disfigured libbaz/1.0.0
%disfigured libbuild2-bar/1.0.0 \[h1..bpkg.build2.\]%
- %fetched libbaz/1.0.0 \[h2.\]%
- %unpacked libbaz/1.0.0 \[h2.\]%
%purged libbuild2-bar/1.0.0 \[h1..bpkg.build2.\]%
purged libbaz/1.0.0
purged foo/1.0.0
+ %fetched libbaz/1.0.0 \[h2.\]%
+ %unpacked libbaz/1.0.0 \[h2.\]%
fetched libbar/1.0.0
unpacked libbar/1.0.0
- %configured libbaz/1.0.0 \[h2.\]%
configured sys:foo/1.2.0
+ %configured libbaz/1.0.0 \[h2.\]%
configured libbar/1.0.0
%info: h1.+libbar-1.0.0.+ is up to date%
updated libbar/1.0.0
@@ -16164,11 +29146,100 @@ else
$rep_add -d h2 $rep/t7a && $rep_fetch -d h2;
- $* libbaz +{ --config-name h2 } 2>>EOE != 0
+ $* libbaz +{ --config-name h2 } 2>>EOE != 0;
error: package foo/1.1.0 is orphaned
info: explicitly upgrade it to a new version
info: while satisfying foo/1.1.0
EOE
+
+ # While at it, test foo deorphaning.
+ #
+ $* foo +{ --deorphan } libbaz +{ --config-name h2 } --yes --plan "" 2>>~%EOE%;
+ drop libbaz/1.1.0 (unused)
+ % new libbuild2-bar/1.0.0 \[h1.\.bpkg.build2.\] \(required by foo\)%
+ % new libbaz/1.0.0 \[h2.\]%
+ replace/downgrade foo/1.0.0
+ disfigured foo/1.1.0
+ disfigured libbaz/1.1.0
+ purged libbaz/1.1.0
+ %fetched libbuild2-bar/1.0.0 \[h1.\.bpkg.build2.\]%
+ %unpacked libbuild2-bar/1.0.0 \[h1.\.bpkg.build2.\]%
+ %fetched libbaz/1.0.0 \[h2.\]%
+ %unpacked libbaz/1.0.0 \[h2.\]%
+ fetched foo/1.0.0
+ unpacked foo/1.0.0
+ %configured libbuild2-bar/1.0.0 \[h1.\.bpkg.build2.\]%
+ %configured libbaz/1.0.0 \[h2.\]%
+ configured foo/1.0.0
+ %info: h2.+libbaz-1.0.0.+ is up to date%
+ %info: h1.+foo-1.0.0.+ is up to date%
+ %updated libbaz/1.0.0 \[h2.\]%
+ updated foo/1.0.0
+ EOE
+
+ $pkg_status -d h1 -r >>/EOO
+ !foo configured 1.0.0
+ !libbaz [h2/] configured 1.0.0
+ libbuild2-bar [h1/.bpkg/build2/] configured 1.0.0
+ EOO
+ }
+
+ : orphan-repointed-masked
+ :
+ : As above but using --mask-repository instead of rep-remove.
+ :
+ {
+ $cfg_create -d h1 --type host --name h1 &h1/***;
+ $cfg_create -d h2 --type host --name h2 &h2/***;
+
+ $cfg_link -d h1 h2;
+
+ $rep_add -d h1 $rep/t7b && $rep_fetch -d h1;
+
+ test.arguments = $regex.apply($test.arguments, cfg, h1);
+
+ $* foo --yes 2>!;
+
+ $rep_add -d h1 $rep/t7a && $rep_fetch -d h1;
+ $rep_add -d h2 $rep/t7a && $rep_fetch -d h2;
+
+ $* libbaz +{ --config-name h2 } --mask-repository $rep/t7b 2>>EOE != 0;
+ error: package foo/1.1.0 is orphaned
+ info: explicitly upgrade it to a new version
+ info: while satisfying foo/1.1.0
+ EOE
+
+ # While at it, test foo deorphaning.
+ #
+ $* foo +{ --deorphan } libbaz +{ --config-name h2 } --yes --plan "" \
+ --mask-repository $rep/t7b 2>>~%EOE%;
+ drop libbaz/1.1.0 (unused)
+ % new libbuild2-bar/1.0.0 \[h1.\.bpkg.build2.\] \(required by foo\)%
+ % new libbaz/1.0.0 \[h2.\]%
+ replace/downgrade foo/1.0.0
+ disfigured foo/1.1.0
+ disfigured libbaz/1.1.0
+ purged libbaz/1.1.0
+ %fetched libbuild2-bar/1.0.0 \[h1.\.bpkg.build2.\]%
+ %unpacked libbuild2-bar/1.0.0 \[h1.\.bpkg.build2.\]%
+ %fetched libbaz/1.0.0 \[h2.\]%
+ %unpacked libbaz/1.0.0 \[h2.\]%
+ fetched foo/1.0.0
+ unpacked foo/1.0.0
+ %configured libbuild2-bar/1.0.0 \[h1.\.bpkg.build2.\]%
+ %configured libbaz/1.0.0 \[h2.\]%
+ configured foo/1.0.0
+ %info: h2.+libbaz-1.0.0.+ is up to date%
+ %info: h1.+foo-1.0.0.+ is up to date%
+ %updated libbaz/1.0.0 \[h2.\]%
+ updated foo/1.0.0
+ EOE
+
+ $pkg_status -d h1 -r >>/EOO
+ !foo configured 1.0.0 available 1.1.0
+ !libbaz [h2/] configured 1.0.0 available 1.1.0
+ libbuild2-bar [h1/.bpkg/build2/] configured 1.0.0
+ EOO
}
: unhold-repointed
@@ -16196,15 +29267,15 @@ else
$* libbar ?foo libbaz +{ --config-name h2 } <<EOI 2>>~%EOE%;
y
EOI
- % new libbaz/1.0.0 \[h2.\]%
drop libbaz/1.0.0 (unused)
+ % new libbaz/1.0.0 \[h2.\]%
reconfigure/update/unhold foo/1.0.0
new libbar/1.0.0
continue? [Y/n] disfigured foo/1.0.0
disfigured libbaz/1.0.0
+ purged libbaz/1.0.0
%fetched libbaz/1.0.0 \[h2.\]%
%unpacked libbaz/1.0.0 \[h2.\]%
- purged libbaz/1.0.0
fetched libbar/1.0.0
unpacked libbar/1.0.0
%configured libbaz/1.0.0 \[h2.\]%
@@ -16273,8 +29344,10 @@ else
$* ?libbaz/1.0.0 +{ --config-name h2 } 2>>~%EOE% != 0;
%error: unable to downgrade package libbaz/1.1.0 \[h2.\] to 1.0.0%
- % info: because package foo \[h2.\] depends on \(libbaz \^1.1.0\)%
- info: explicitly request up/downgrade of package foo
+ % info: because configured package foo/1.1.0 \[h2.\] depends on \(libbaz \^1.1.0\)%
+ info: re-run with -v for additional dependency information
+ info: consider re-trying with --upgrade|-u potentially combined with --recursive|-r
+ info: or explicitly request up/downgrade of package foo
info: or explicitly specify package libbaz version to manually satisfy these constraints
EOE
@@ -16282,8 +29355,8 @@ else
y
n
EOI
- % update libbaz/1.1.0 \[h2.\]%
drop libbaz/1.0.0 (unused)
+ % update libbaz/1.1.0 \[h2.\]%
% reconfigure foo/1.0.0 \(dependent of libbaz \[h2.\]\)%
continue? [Y/n] update dependent packages? [Y/n] disfigured foo/1.0.0
disfigured libbaz/1.0.0
@@ -16328,23 +29401,23 @@ else
$* libbar ?foo +{ --config-name h1 } <<EOI 2>>~%EOE%;
y
EOI
- % new libbaz/1.1.0 \[h1.\] \(required by foo \[h1.\]\)%
- % new foo/1.1.0 \[h1.\] \(required by libbar\)%
% drop libbuild2-bar/1.0.0 \[t1..bpkg.build2.\] \(unused\)%
% drop libbaz/1.0.0 \[t1..bpkg.host.\] \(unused\)%
% drop foo/1.0.0 \[t1..bpkg.host.\] \(unused\)%
+ % new libbaz/1.1.0 \[h1.\] \(required by foo \[h1.\]\)%
+ % new foo/1.1.0 \[h1.\] \(required by libbar\)%
upgrade libbar/1.1.0
continue? [Y/n] disfigured libbar/1.0.0
%disfigured foo/1.0.0 \[t1..bpkg.host.\]%
%disfigured libbaz/1.0.0 \[t1..bpkg.host.\]%
%disfigured libbuild2-bar/1.0.0 \[t1..bpkg.build2.\]%
+ %purged libbuild2-bar/1.0.0 \[t1..bpkg.build2.\]%
+ %purged libbaz/1.0.0 \[t1..bpkg.host.\]%
+ %purged foo/1.0.0 \[t1..bpkg.host.\]%
%fetched libbaz/1.1.0 \[h1.\]%
%unpacked libbaz/1.1.0 \[h1.\]%
%fetched foo/1.1.0 \[h1.\]%
%unpacked foo/1.1.0 \[h1.\]%
- %purged libbuild2-bar/1.0.0 \[t1..bpkg.build2.\]%
- %purged libbaz/1.0.0 \[t1..bpkg.host.\]%
- %purged foo/1.0.0 \[t1..bpkg.host.\]%
fetched libbar/1.1.0
unpacked libbar/1.1.0
%configured libbaz/1.1.0 \[h1.\]%
@@ -16390,19 +29463,19 @@ else
y
y
EOI
- % new libbaz/1.1.0 \[h2.\] \(required by foo, libbar\)%
% drop libbuild2-bar/1.0.0 \[h1..bpkg.build2.\] \(unused\)%
drop libbaz/1.0.0 (unused)
+ % new libbaz/1.1.0 \[h2.\] \(required by foo, libbar\)%
upgrade foo/1.1.0
upgrade libbar/1.1.0
continue? [Y/n] disfigured libbar/1.0.0
disfigured foo/1.0.0
disfigured libbaz/1.0.0
%disfigured libbuild2-bar/1.0.0 \[h1..bpkg.build2.\]%
- %fetched libbaz/1.1.0 \[h2.\]%
- %unpacked libbaz/1.1.0 \[h2.\]%
%purged libbuild2-bar/1.0.0 \[h1..bpkg.build2.\]%
purged libbaz/1.0.0
+ %fetched libbaz/1.1.0 \[h2.\]%
+ %unpacked libbaz/1.1.0 \[h2.\]%
fetched foo/1.1.0
unpacked foo/1.1.0
fetched libbar/1.1.0
@@ -16459,15 +29532,15 @@ else
y
y
EOI
- % upgrade libbaz/1.1.0 \[t2.\]%
drop libbaz/1.0.0 (unused)
+ % upgrade libbaz/1.1.0 \[t2.\]%
% reconfigure libbar/1.0.0 \(dependent of libbaz \[t2.\]\)%
continue? [Y/n] update dependent packages? [Y/n] disfigured libbar/1.0.0
- disfigured libbaz/1.0.0
%disfigured libbaz/1.0.0 \[t2.\]%
+ disfigured libbaz/1.0.0
+ purged libbaz/1.0.0
%fetched libbaz/1.1.0 \[t2.\]%
%unpacked libbaz/1.1.0 \[t2.\]%
- purged libbaz/1.0.0
%configured libbaz/1.1.0 \[t2.\]%
configured libbar/1.0.0
%info: t2.+libbaz-1.1.0.+ is up to date%
@@ -16587,45 +29660,45 @@ else
y
y
EOI
+ % drop libfax/1.0.0 \(unused\)%
% new libfax/1.0.0 \[t2.\]%
- % upgrade libbaz/1.1.0 \[h1.\] \(required by foo \[h1.\]\)%
% drop libbuild2-bar/1.0.0 \[h1..bpkg.build2.\] \(unused\)%
+ % upgrade libbaz/1.1.0 \[h1.\] \(required by foo \[h1.\]\)%
% upgrade foo/1.1.0 \[h1.\]%
- % reconfigure libbox \(dependent of foo \[h1.\]\)%
% reconfigure libbar \(dependent of foo \[h1.\]\)%
- % drop libfax/1.0.0 \(unused\)%
+ % reconfigure libbox \(dependent of foo \[h1.\]\)%
reconfigure/update libfix/1.0.0
continue? [Y/n] update dependent packages? [Y/n] disfigured libfix/1.0.0
- disfigured libfax/1.0.0
- disfigured libbar/1.0.0
disfigured libbox/1.0.0
+ disfigured libbar/1.0.0
%disfigured foo/1.0.0 \[h1.\]%
- %disfigured libbuild2-bar/1.0.0 \[h1..bpkg.build2.\]%
%disfigured libbaz/1.0.0 \[h1.\]%
+ %disfigured libbuild2-bar/1.0.0 \[h1..bpkg.build2.\]%
+ disfigured libfax/1.0.0
+ purged libfax/1.0.0
%fetched libfax/1.0.0 \[t2.\]%
%unpacked libfax/1.0.0 \[t2.\]%
+ %purged libbuild2-bar/1.0.0 \[h1..bpkg.build2.\]%
%fetched libbaz/1.1.0 \[h1.\]%
%unpacked libbaz/1.1.0 \[h1.\]%
- %purged libbuild2-bar/1.0.0 \[h1..bpkg.build2.\]%
%fetched foo/1.1.0 \[h1.\]%
%unpacked foo/1.1.0 \[h1.\]%
- purged libfax/1.0.0
%configured libfax/1.0.0 \[t2.\]%
%configured libbaz/1.1.0 \[h1.\]%
%configured foo/1.1.0 \[h1.\]%
- configured libbox/1.0.0
configured libbar/1.0.0
+ configured libbox/1.0.0
configured libfix/1.0.0
%info: t2.+libfax-1.0.0.+ is up to date%
%info: h1.+foo-1.1.0.+ is up to date%
%info: t1.+libfix-1.0.0.+ is up to date%
- %info: t1.+libbox-1.0.0.+ is up to date%
%info: t1.+libbar-1.0.0.+ is up to date%
+ %info: t1.+libbox-1.0.0.+ is up to date%
%updated libfax/1.0.0 \[t2.\]%
%updated foo/1.1.0 \[h1.\]%
updated libfix/1.0.0
- updated libbox/1.0.0
updated libbar/1.0.0
+ updated libbox/1.0.0
EOE
$pkg_status -d t1 --link -r >>/EOO
@@ -16905,25 +29978,25 @@ else
y
y
EOI
- % new libbuild2-bar/1.0.0 \[cfg4.\] \(required by foo \[cfg.\], foo \[cfg2.\]\)%
- % new libbaz/1.0.0 \[cfg5.\] \(required by foo \[cfg.\], foo \[cfg2.\]\)%
% drop libbaz/1.0.0 \[cfg2.\] \(unused\)%
% drop libbuild2-bar/1.0.0 \[cfg3.\] \(unused\)%
- % reconfigure foo/1.0.0 \[cfg2.\] \(dependent of libbaz \[cfg5.\], libbuild2-bar \[cfg4.\]\)%
% drop libbaz/1.0.0 \[cfg.\] \(unused\)%
+ % new libbuild2-bar/1.0.0 \[cfg4.\] \(required by foo \[cfg.\], foo \[cfg2.\]\)%
+ % new libbaz/1.0.0 \[cfg5.\] \(required by foo \[cfg.\], foo \[cfg2.\]\)%
+ % reconfigure foo/1.0.0 \[cfg2.\] \(dependent of libbaz \[cfg5.\], libbuild2-bar \[cfg4.\]\)%
% reconfigure foo/1.0.0 \[cfg.\] \(dependent of libbaz \[cfg5.\], libbuild2-bar \[cfg4.\]\)%
%continue\? \[Y/n\] update dependent packages\? \[Y/n\] disfigured foo/1.0.0 \[cfg.\]%
- %disfigured libbaz/1.0.0 \[cfg.\]%
%disfigured foo/1.0.0 \[cfg2.\]%
+ %disfigured libbaz/1.0.0 \[cfg.\]%
%disfigured libbuild2-bar/1.0.0 \[cfg3.\]%
%disfigured libbaz/1.0.0 \[cfg2.\]%
+ %purged libbaz/1.0.0 \[cfg2.\]%
+ %purged libbuild2-bar/1.0.0 \[cfg3.\]%
+ %purged libbaz/1.0.0 \[cfg.\]%
%fetched libbuild2-bar/1.0.0 \[cfg4.\]%
%unpacked libbuild2-bar/1.0.0 \[cfg4.\]%
%fetched libbaz/1.0.0 \[cfg5.\]%
%unpacked libbaz/1.0.0 \[cfg5.\]%
- %purged libbaz/1.0.0 \[cfg2.\]%
- %purged libbuild2-bar/1.0.0 \[cfg3.\]%
- %purged libbaz/1.0.0 \[cfg.\]%
%configured libbuild2-bar/1.0.0 \[cfg4.\]%
%configured libbaz/1.0.0 \[cfg5.\]%
%configured foo/1.0.0 \[cfg2.\]%
@@ -16981,15 +30054,15 @@ else
?libbaz +{ --config-uuid $cfg5_uuid } <<EOI 2>>~%EOE%;
y
EOI
- % upgrade libbaz/1.1.0 \[cfg5.\]%
% drop libbuild2-bar/1.0.0 \[cfg4.\] \(unused\)%
+ % upgrade libbaz/1.1.0 \[cfg5.\]%
% upgrade foo/1.1.0 \[cfg2.\]%
%continue\? \[Y/n\] disfigured foo/1.0.0 \[cfg2.\]%
- %disfigured libbuild2-bar/1.0.0 \[cfg4.\]%
%disfigured libbaz/1.0.0 \[cfg5.\]%
+ %disfigured libbuild2-bar/1.0.0 \[cfg4.\]%
+ %purged libbuild2-bar/1.0.0 \[cfg4.\]%
%fetched libbaz/1.1.0 \[cfg5.\]%
%unpacked libbaz/1.1.0 \[cfg5.\]%
- %purged libbuild2-bar/1.0.0 \[cfg4.\]%
%fetched foo/1.1.0 \[cfg2.\]%
%unpacked foo/1.1.0 \[cfg2.\]%
%configured libbaz/1.1.0 \[cfg5.\]%
@@ -17444,3 +30517,3837 @@ else
}
}
}
+
+: deorphan
+:
+{
+ test.arguments += --yes --plan ""
+
+ : dependency
+ :
+ {
+ : unhold
+ :
+ {
+ : basics
+ :
+ {
+ $clone_root_cfg;
+
+ cp -r $src/libfoo-1.1.0 libfoo;
+ $rep_add --type dir libfoo/ && $rep_fetch;
+
+ $* libfoo 2>!;
+ $rep_fetch $rep/t4b;
+
+ $* libbar 2>!;
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ !libfoo configured 1.1.0
+ EOO
+
+ echo "" >+ libfoo/manifest;
+ $rep_fetch;
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ !libfoo configured 1.1.0 available 1.1.0#1
+ EOO
+
+ # Deorphan libfoo/1.1.0 to libfoo/1.1.0#1.
+ #
+ # Note that libfoo/1.1.0 is considered as an orphan since its version
+ # is replaced with 1.1.0#1 in its existing repository fragment. This is
+ # in contrast to the subsequent tests where the package repository is
+ # removed.
+ #
+ $* --deorphan libfoo 2>>~%EOE%;
+ replace/upgrade libfoo/1.1.0#1
+ reconfigure libbar (dependent of libfoo)
+ disfigured libbar/1.1.0
+ disfigured libfoo/1.1.0
+ using libfoo/1.1.0#1 (external)
+ configured libfoo/1.1.0#1
+ configured libbar/1.1.0
+ %info: .+libfoo.+ is up to date%
+ %info: .+libbar-1.1.0.+ is up to date%
+ updated libfoo/1.1.0#1
+ updated libbar/1.1.0
+ EOE
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ !libfoo configured 1.1.0#1
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan libfoo 2>'info: nothing to build';
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ !libfoo configured 1.1.0#1
+ EOO
+
+ # Deorphan libfoo/1.1.0#1 to ?libfoo/1.1.0.
+ #
+ $rep_remove $~/libfoo/;
+
+ $* --deorphan ?libfoo 2>>~%EOE%;
+ replace/downgrade/unhold libfoo/1.1.0
+ reconfigure libbar (dependent of libfoo)
+ disfigured libbar/1.1.0
+ disfigured libfoo/1.1.0#1
+ fetched libfoo/1.1.0
+ unpacked libfoo/1.1.0
+ configured libfoo/1.1.0
+ configured libbar/1.1.0
+ %info: .+libbar-1.1.0.+ is up to date%
+ updated libbar/1.1.0
+ EOE
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ libfoo configured 1.1.0
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan ?libfoo;
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ libfoo configured 1.1.0
+ EOO
+
+ # Deorphan libfoo/1.1.0#1 to ?libfoo/1.1.0.
+ #
+ $rep_add --type dir libfoo/ && $rep_fetch;
+ $* libfoo 2>!;
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ !libfoo configured 1.1.0#1
+ EOO
+
+ $rep_remove $~/libfoo/;
+
+ $* --deorphan ?libfoo 2>>~%EOE%;
+ replace/downgrade/unhold libfoo/1.1.0
+ reconfigure libbar (dependent of libfoo)
+ disfigured libbar/1.1.0
+ disfigured libfoo/1.1.0#1
+ fetched libfoo/1.1.0
+ unpacked libfoo/1.1.0
+ configured libfoo/1.1.0
+ configured libbar/1.1.0
+ %info: .+libbar-1.1.0.+ is up to date%
+ updated libbar/1.1.0
+ EOE
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ libfoo configured 1.1.0
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan ?libfoo;
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ libfoo configured 1.1.0
+ EOO
+
+ $pkg_drop libbar
+ }
+
+ : basics-masked
+ :
+ : As above but using --mask-repository* instead of rep-remove.
+ :
+ {
+ $clone_root_cfg;
+
+ cp -r $src/libfoo-1.1.0 libfoo;
+ $rep_add --type dir libfoo/ && $rep_fetch;
+
+ $* libfoo 2>!;
+ $rep_fetch $rep/t4b;
+
+ $* libbar 2>!;
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ !libfoo configured 1.1.0
+ EOO
+
+ echo "" >+ libfoo/manifest;
+ $rep_fetch;
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ !libfoo configured 1.1.0 available 1.1.0#1
+ EOO
+
+ # Deorphan libfoo/1.1.0 to libfoo/1.1.0#1.
+ #
+ # Note that libfoo/1.1.0 is considered as an orphan since its version
+ # is replaced with 1.1.0#1 in its existing repository fragment. This is
+ # in contrast to the subsequent tests where the package repository is
+ # removed.
+ #
+ $* --deorphan libfoo 2>>~%EOE%;
+ replace/upgrade libfoo/1.1.0#1
+ reconfigure libbar (dependent of libfoo)
+ disfigured libbar/1.1.0
+ disfigured libfoo/1.1.0
+ using libfoo/1.1.0#1 (external)
+ configured libfoo/1.1.0#1
+ configured libbar/1.1.0
+ %info: .+libfoo.+ is up to date%
+ %info: .+libbar-1.1.0.+ is up to date%
+ updated libfoo/1.1.0#1
+ updated libbar/1.1.0
+ EOE
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ !libfoo configured 1.1.0#1
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan libfoo 2>'info: nothing to build';
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ !libfoo configured 1.1.0#1
+ EOO
+
+ # Deorphan libfoo/1.1.0#1 to ?libfoo/1.1.0.
+ #
+ # Note that on Windows the local repository canonical name path part
+ # is converted to lower case.
+ #
+ cn = "$canonicalize([dir_path] $~/libfoo)";
+ if! $posix
+ cn = $lcase([string] $cn)
+ end;
+ cn = "dir:$cn";
+
+ $* --mask-repository $cn --deorphan ?libfoo 2>>~%EOE%;
+ replace/downgrade/unhold libfoo/1.1.0
+ reconfigure libbar (dependent of libfoo)
+ disfigured libbar/1.1.0
+ disfigured libfoo/1.1.0#1
+ fetched libfoo/1.1.0
+ unpacked libfoo/1.1.0
+ configured libfoo/1.1.0
+ configured libbar/1.1.0
+ %info: .+libbar-1.1.0.+ is up to date%
+ updated libbar/1.1.0
+ EOE
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ libfoo configured 1.1.0 available 1.1.0#1
+ EOO
+
+ # Noop.
+ #
+ $* --mask-repository-uuid "$cfg_uuid=$cn" --deorphan ?libfoo;
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ libfoo configured 1.1.0 available 1.1.0#1
+ EOO
+
+ # Deorphan libfoo/1.1.0#1 to ?libfoo/1.1.0.
+ #
+ $* libfoo 2>!;
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ !libfoo configured 1.1.0#1
+ EOO
+
+ $* --mask-repository $cn --deorphan ?libfoo 2>>~%EOE%;
+ replace/downgrade/unhold libfoo/1.1.0
+ reconfigure libbar (dependent of libfoo)
+ disfigured libbar/1.1.0
+ disfigured libfoo/1.1.0#1
+ fetched libfoo/1.1.0
+ unpacked libfoo/1.1.0
+ configured libfoo/1.1.0
+ configured libbar/1.1.0
+ %info: .+libbar-1.1.0.+ is up to date%
+ updated libbar/1.1.0
+ EOE
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ libfoo configured 1.1.0 available 1.1.0#1
+ EOO
+
+ # Noop.
+ #
+ $* --mask-repository $cn --deorphan ?libfoo;
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ libfoo configured 1.1.0 available 1.1.0#1
+ EOO
+
+ $pkg_drop libbar
+ }
+
+ : drop
+ :
+ {
+ $clone_root_cfg;
+
+ cp -r $src/libfoo-1.1.0 libfoo;
+ $rep_add --type dir libfoo/ && $rep_fetch;
+
+ $* libfoo 2>!;
+ $rep_fetch $rep/t4b;
+
+ $* libbar 2>!;
+
+ echo "" >+ libfoo/manifest;
+ $rep_fetch;
+ $* libfoo 2>!;
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ !libfoo configured 1.1.0#1
+ EOO
+
+ $rep_remove $~/libfoo/;
+
+ $* --deorphan ?libfoo ?libbar 2>>EOE;
+ drop libfoo/1.1.0#1 (unused)
+ drop libbar/1.1.0 (unused)
+ disfigured libbar/1.1.0
+ disfigured libfoo/1.1.0#1
+ purged libfoo/1.1.0#1
+ purged libbar/1.1.0
+ EOE
+
+ $pkg_status -ar 2>'info: no packages in the configuration'
+ }
+
+ : drop-masked
+ :
+ : As above but using --mask-repository instead of rep-remove.
+ :
+ {
+ $clone_root_cfg;
+
+ cp -r $src/libfoo-1.1.0 libfoo;
+ $rep_add --type dir libfoo/ && $rep_fetch;
+
+ $* libfoo 2>!;
+ $rep_fetch $rep/t4b;
+
+ $* libbar 2>!;
+
+ echo "" >+ libfoo/manifest;
+ $rep_fetch;
+ $* libfoo 2>!;
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured 1.1.0
+ !libfoo configured 1.1.0#1
+ EOO
+
+ # Note that on Windows the local repository canonical name path part
+ # is converted to lower case.
+ #
+ cn = "$canonicalize([dir_path] $~/libfoo)";
+ if! $posix
+ cn = $lcase([string] $cn)
+ end;
+ cn = "dir:$cn";
+
+ $* --mask-repository $cn --deorphan ?libfoo ?libbar 2>>EOE;
+ drop libfoo/1.1.0#1 (unused)
+ drop libbar/1.1.0 (unused)
+ disfigured libbar/1.1.0
+ disfigured libfoo/1.1.0#1
+ purged libfoo/1.1.0#1
+ purged libbar/1.1.0
+ EOE
+
+ $pkg_status -ar 2>'info: no packages in the configuration'
+ }
+
+ : no-dependent
+ :
+ {
+ $clone_root_cfg;
+
+ cp -r $src/libfoo-1.1.0 libfoo;
+ $rep_add --type dir libfoo/ && $rep_fetch;
+
+ echo "" >+ libfoo/manifest;
+ $rep_fetch;
+ $* libfoo 2>!;
+
+ $rep_fetch $rep/t4b;
+ $rep_remove $~/libfoo/;
+
+ $pkg_status libfoo >'!libfoo configured 1.1.0';
+
+ $* --deorphan ?libfoo 2>>EOE;
+ drop libfoo/1.1.0 (unused)
+ disfigured libfoo/1.1.0
+ purged libfoo/1.1.0
+ EOE
+
+ $pkg_status -ar 2>'info: no packages in the configuration'
+ }
+
+ : no-dependent-masked
+ :
+ : As above but using --mask-repository instead of rep-remove.
+ :
+ {
+ $clone_root_cfg;
+
+ cp -r $src/libfoo-1.1.0 libfoo;
+ $rep_add --type dir libfoo/ && $rep_fetch;
+
+ echo "" >+ libfoo/manifest;
+ $rep_fetch;
+ $* libfoo 2>!;
+
+ $rep_fetch $rep/t4b;
+
+ $pkg_status libfoo >'!libfoo configured 1.1.0';
+
+ # Note that on Windows the local repository canonical name path part
+ # is converted to lower case.
+ #
+ cn = "$canonicalize([dir_path] $~/libfoo)";
+ if! $posix
+ cn = $lcase([string] $cn)
+ end;
+ cn = "dir:$cn";
+
+ $* --mask-repository $cn --deorphan ?libfoo 2>>EOE;
+ drop libfoo/1.1.0 (unused)
+ disfigured libfoo/1.1.0
+ purged libfoo/1.1.0
+ EOE
+
+ $pkg_status -ar 2>'info: no packages in the configuration'
+ }
+
+ : preference
+ :
+ {
+ $clone_root_cfg;
+
+ $tar -xf $src/t14d/libfoo-1.1.0+2.tar.gz &libfoo-1.1.0+2/***;
+ mv libfoo-1.1.0+2 libfoo;
+
+ $rep_add --type dir libfoo/ && $rep_fetch;
+
+ $* libfoo 2>!;
+
+ $tar -xf $src/t2/libbar-1.0.0.tar.gz &libbar-1.0.0/***;
+ mv libbar-1.0.0 libbar;
+
+ cat <<"EOI" >=libbar/repositories.manifest;
+ : 1
+ :
+ location: $rep/t14a
+ role: prerequisite
+ :
+ location: $rep/t14b
+ role: prerequisite
+ :
+ location: $rep/t14c
+ role: prerequisite
+ :
+ location: $rep/t14d
+ role: prerequisite
+ :
+ location: $rep/t14e
+ role: prerequisite
+ :
+ location: $rep/t14f
+ role: prerequisite
+ :
+ location: $rep/t14i
+ role: prerequisite
+ EOI
+
+ $rep_add --type dir libbar/ && $rep_fetch;
+ $* libbar 2>!;
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ !libfoo configured 1.1.0+2 available [1.2.0] [1.1.1] [1.1.0+3] (1.1.0+2) [1.1.0+1] [1.1.0] [1.0.0]
+ EOO
+
+ # Deorphan/unhold libfoo/1.1.0+2 to the exactly same version.
+ #
+ $rep_remove $~/libfoo/;
+
+ $* --deorphan ?libfoo 2>>~%EOE%;
+ replace/update/unhold libfoo/1.1.0+2
+ reconfigure libbar (dependent of libfoo)
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.1.0+2
+ fetched libfoo/1.1.0+2
+ unpacked libfoo/1.1.0+2
+ configured libfoo/1.1.0+2
+ configured libbar/1.0.0
+ %info: .+libbar.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured 1.1.0+2 available [1.2.0] [1.1.1] [1.1.0+3] (1.1.0+2) [1.1.0+1] [1.1.0] [1.0.0]
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan ?libfoo;
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured 1.1.0+2 available [1.2.0] [1.1.1] [1.1.0+3] (1.1.0+2) [1.1.0+1] [1.1.0] [1.0.0]
+ EOO
+
+ # Deorphan libfoo/1.1.0+2 to the later revision of same version
+ # (1.1.0+3).
+ #
+ cat <<"EOI" >=libbar/repositories.manifest;
+ : 1
+ :
+ location: $rep/t14a
+ role: prerequisite
+ :
+ location: $rep/t14b
+ role: prerequisite
+ :
+ location: $rep/t14c
+ role: prerequisite
+ :
+ location: $rep/t14e
+ role: prerequisite
+ :
+ location: $rep/t14f
+ role: prerequisite
+ :
+ location: $rep/t14i
+ role: prerequisite
+ EOI
+
+ $rep_fetch;
+
+ $* --deorphan ?libfoo 2>>~%EOE%;
+ replace/upgrade libfoo/1.1.0+3
+ reconfigure libbar (dependent of libfoo)
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.1.0+2
+ fetched libfoo/1.1.0+3
+ unpacked libfoo/1.1.0+3
+ configured libfoo/1.1.0+3
+ configured libbar/1.0.0
+ %info: .+libbar.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured 1.1.0+3 available [1.2.0] [1.1.1] (1.1.0+3) [1.1.0+1] [1.1.0] [1.0.0]
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan ?libfoo;
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured 1.1.0+3 available [1.2.0] [1.1.1] (1.1.0+3) [1.1.0+1] [1.1.0] [1.0.0]
+ EOO
+
+ # Deorphan libfoo/1.1.0+3 to the later patch of same version (1.1.1).
+ #
+ cat <<"EOI" >=libbar/repositories.manifest;
+ : 1
+ :
+ location: $rep/t14a
+ role: prerequisite
+ :
+ location: $rep/t14b
+ role: prerequisite
+ :
+ location: $rep/t14c
+ role: prerequisite
+ :
+ location: $rep/t14f
+ role: prerequisite
+ :
+ location: $rep/t14i
+ role: prerequisite
+ EOI
+
+ $rep_fetch;
+
+ $* --deorphan ?libfoo 2>>~%EOE%;
+ replace/upgrade libfoo/1.1.1
+ reconfigure libbar (dependent of libfoo)
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.1.0+3
+ fetched libfoo/1.1.1
+ unpacked libfoo/1.1.1
+ configured libfoo/1.1.1
+ configured libbar/1.0.0
+ %info: .+libbar.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured 1.1.1 available [1.2.0] (1.1.1) [1.1.0+1] [1.1.0] [1.0.0]
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan ?libfoo;
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured 1.1.1 available [1.2.0] (1.1.1) [1.1.0+1] [1.1.0] [1.0.0]
+ EOO
+
+ # Deorphan libfoo/1.1.1 to later minor of same version (1.2.0).
+ #
+ cat <<"EOI" >=libbar/repositories.manifest;
+ : 1
+ :
+ location: $rep/t14a
+ role: prerequisite
+ :
+ location: $rep/t14b
+ role: prerequisite
+ :
+ location: $rep/t14c
+ role: prerequisite
+ :
+ location: $rep/t14i
+ role: prerequisite
+ EOI
+
+ $rep_fetch;
+
+ $* --deorphan ?libfoo 2>>~%EOE%;
+ replace/upgrade libfoo/1.2.0
+ reconfigure libbar (dependent of libfoo)
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.1.1
+ fetched libfoo/1.2.0
+ unpacked libfoo/1.2.0
+ configured libfoo/1.2.0
+ configured libbar/1.0.0
+ %info: .+libbar.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured 1.2.0 available (1.2.0) [1.1.0+1] [1.1.0] [1.0.0]
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan ?libfoo;
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured 1.2.0 available (1.2.0) [1.1.0+1] [1.1.0] [1.0.0]
+ EOO
+
+ # Deorphan libfoo/1.2.0 to latest available version (1.1.0+1).
+ #
+ cat <<"EOI" >=libbar/repositories.manifest;
+ : 1
+ :
+ location: $rep/t14a
+ role: prerequisite
+ :
+ location: $rep/t14b
+ role: prerequisite
+ :
+ location: $rep/t14c
+ role: prerequisite
+ EOI
+
+ $rep_fetch;
+
+ $* --deorphan ?libfoo 2>>~%EOE%;
+ replace/downgrade libfoo/1.1.0+1
+ reconfigure libbar (dependent of libfoo)
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.2.0
+ fetched libfoo/1.1.0+1
+ unpacked libfoo/1.1.0+1
+ configured libfoo/1.1.0+1
+ configured libbar/1.0.0
+ %info: .+libbar.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured 1.1.0+1 available (1.1.0+1) [1.1.0] [1.0.0]
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan ?libfoo;
+
+ # Deorphan libfoo/1.1.0+1 to latest available version (1.1.0).
+ #
+ cat <<"EOI" >=libbar/repositories.manifest;
+ : 1
+ :
+ location: $rep/t14a
+ role: prerequisite
+ :
+ location: $rep/t14b
+ role: prerequisite
+ EOI
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured 1.1.0+1 available (1.1.0+1) [1.1.0] [1.0.0]
+ EOO
+
+ $rep_fetch;
+
+ $* --deorphan ?libfoo 2>>~%EOE%;
+ replace/downgrade libfoo/1.1.0
+ reconfigure libbar (dependent of libfoo)
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.1.0+1
+ fetched libfoo/1.1.0
+ unpacked libfoo/1.1.0
+ configured libfoo/1.1.0
+ configured libbar/1.0.0
+ %info: .+libbar.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured 1.1.0 available (1.1.0) [1.0.0]
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan ?libfoo;
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured 1.1.0 available (1.1.0) [1.0.0]
+ EOO
+
+ # Deorphan libfoo/1.1.0 to latest available version (1.0.0).
+ #
+ cat <<"EOI" >=libbar/repositories.manifest;
+ : 1
+ :
+ location: $rep/t14a
+ role: prerequisite
+ EOI
+
+ $rep_fetch;
+
+ $* --deorphan ?libfoo 2>>~%EOE%;
+ replace/downgrade libfoo/1.0.0
+ reconfigure libbar (dependent of libfoo)
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.1.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ %info: .+libbar.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured 1.0.0 available (1.0.0)
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan ?libfoo;
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured 1.0.0 available (1.0.0)
+ EOO
+
+ # Deorphan fails (none available).
+ #
+ cat <<"EOI" >=libbar/repositories.manifest;
+ : 1
+ EOI
+
+ $rep_fetch;
+
+ $* --deorphan ?libfoo 2>>/EOE != 0;
+ error: unknown package libfoo
+ EOE
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop libbar
+ }
+ }
+
+ : recursive
+ :
+ {
+ +$tar -xf $src/t2/libbar-1.0.0.tar.gz &libbar-1.0.0/***
+ +mv libbar-1.0.0 libbar
+
+ +cat <<"EOI" >=libbar/repositories.manifest
+ : 1
+ :
+ location: $rep/t14b
+ role: prerequisite
+ :
+ location: $rep/t14f
+ role: prerequisite
+ :
+ location: $rep/t14i
+ role: prerequisite
+ EOI
+
+ : immediate
+ :
+ {
+ $clone_root_cfg;
+ cp -rp ../libbar ./;
+
+ $rep_add --type dir libbar/ && $rep_fetch;
+ $* libbar ?libfoo/1.1.0 2>!;
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured !1.1.0 available [1.2.0] [1.1.1] (1.1.0)
+ EOO
+
+ $rep_remove $~/libbar/;
+ $rep_add $rep/t2 $rep/t4b $rep/t14c && $rep_fetch;
+
+ $* --deorphan --immediate libbar 2>>~%EOE%;
+ replace/downgrade libfoo/1.0.0
+ replace/update libbar/1.0.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.1.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ %info: .+libbar.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available 1.1.0 (1.0.0)
+ libfoo configured !1.0.0 available 1.1.0+1 [1.1.0] (1.0.0) 0.1.0
+ EOO
+
+ $pkg_drop libbar
+ }
+
+ : immediate-masked
+ :
+ : As above but using --mask-repository instead of rep-remove.
+ :
+ {
+ $clone_root_cfg;
+ cp -rp ../libbar ./;
+
+ $rep_add --type dir libbar/ && $rep_fetch;
+ $* libbar ?libfoo/1.1.0 2>!;
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured !1.1.0 available [1.2.0] [1.1.1] (1.1.0)
+ EOO
+
+ $rep_add $rep/t2 $rep/t4b $rep/t14c && $rep_fetch;
+
+ # Note that on Windows the local repository canonical name path part
+ # is converted to lower case.
+ #
+ cn = "$canonicalize([dir_path] $~/libbar)";
+ if! $posix
+ cn = $lcase([string] $cn)
+ end;
+ cn = "dir:$cn";
+
+ $* --mask-repository $cn --deorphan --immediate libbar 2>>~%EOE%;
+ replace/downgrade libfoo/1.0.0
+ replace/update libbar/1.0.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.1.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ %info: .+libbar.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available 1.1.0 (1.0.0)
+ libfoo configured !1.0.0 available [1.2.0] [1.1.1] 1.1.0+1 [1.1.0] (1.0.0) 0.1.0
+ EOO
+
+ $pkg_drop libbar
+ }
+
+ : recursive
+ :
+ {
+ $clone_root_cfg;
+ cp -rp ../libbar ./;
+
+ $rep_add --type dir libbar/ && $rep_fetch;
+ $* libbar ?libfoo/1.1.0 2>!;
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured !1.1.0 available [1.2.0] [1.1.1] (1.1.0)
+ EOO
+
+ $rep_remove $~/libbar/;
+ $rep_add $rep/t2 $rep/t4b $rep/t14c && $rep_fetch;
+
+ $* --deorphan --recursive libbar 2>>~%EOE%;
+ replace/downgrade libfoo/1.0.0
+ replace/update libbar/1.0.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.1.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ %info: .+libbar.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available 1.1.0 (1.0.0)
+ libfoo configured !1.0.0 available 1.1.0+1 [1.1.0] (1.0.0) 0.1.0
+ EOO
+
+ $pkg_drop libbar
+ }
+
+ : deorphan-immediate
+ :
+ {
+ $clone_root_cfg;
+ cp -rp ../libbar ./;
+
+ $rep_add --type dir libbar/ && $rep_fetch;
+ $* libbar ?libfoo/1.1.0 2>!;
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured !1.1.0 available [1.2.0] [1.1.1] (1.1.0)
+ EOO
+
+ cat <<"EOI" >=libbar/repositories.manifest;
+ : 1
+ :
+ location: $rep/t14f
+ role: prerequisite
+ :
+ location: $rep/t14i
+ role: prerequisite
+ EOI
+
+ $rep_fetch;
+
+ $* --deorphan-immediate libbar 2>>~%EOE%;
+ replace/upgrade libfoo/1.1.1
+ reconfigure/update libbar/1.0.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.1.0
+ fetched libfoo/1.1.1
+ unpacked libfoo/1.1.1
+ configured libfoo/1.1.1
+ configured libbar/1.0.0
+ %info: .+libbar.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured !1.1.1 available [1.2.0] (1.1.1)
+ EOO
+
+ $pkg_drop libbar
+ }
+
+ : deorphan-recursive
+ :
+ {
+ $clone_root_cfg;
+ cp -rp ../libbar ./;
+
+ $rep_add --type dir libbar/ && $rep_fetch;
+ $* libbar ?libfoo/1.1.0 2>!;
+
+ $rep_add $rep/t3 && $rep_fetch;
+ $* libbaz 2>!;
+
+ $pkg_status -or libbaz >>EOO;
+ !libbaz configured 1.0.0 available (1.0.0)
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured !1.1.0 available [1.2.0] [1.1.1] (1.1.0) [1.0.0] [0.1.0]
+ EOO
+
+ cat <<"EOI" >=libbar/repositories.manifest;
+ : 1
+ :
+ location: $rep/t14f
+ role: prerequisite
+ :
+ location: $rep/t14i
+ role: prerequisite
+ EOI
+
+ $rep_fetch;
+
+ $* --deorphan-recursive libbaz 2>>~%EOE%;
+ replace/upgrade libfoo/1.1.1
+ reconfigure libbar (dependent of libfoo)
+ reconfigure/update libbaz/1.0.0
+ disfigured libbaz/1.0.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.1.0
+ fetched libfoo/1.1.1
+ unpacked libfoo/1.1.1
+ configured libfoo/1.1.1
+ configured libbar/1.0.0
+ configured libbaz/1.0.0
+ %info: .+libbaz.+ is up to date%
+ %info: .+libbar.+ is up to date%
+ updated libbaz/1.0.0
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_status -or libbaz >>EOO;
+ !libbaz configured 1.0.0 available (1.0.0)
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured !1.1.1 available [1.2.0] (1.1.1) [1.0.0] [0.1.0]
+ EOO
+
+ $pkg_drop libbaz libbar
+ }
+ }
+
+ : recursive-all-held
+ :
+ : As above but uses 'deorphan all held packages form'.
+ :
+ {
+ +$tar -xf $src/t2/libbar-1.0.0.tar.gz &libbar-1.0.0/***
+ +mv libbar-1.0.0 libbar
+
+ +cat <<"EOI" >=libbar/repositories.manifest
+ : 1
+ :
+ location: $rep/t14b
+ role: prerequisite
+ :
+ location: $rep/t14f
+ role: prerequisite
+ :
+ location: $rep/t14i
+ role: prerequisite
+ EOI
+
+ : immediate
+ :
+ {
+ $clone_root_cfg;
+ cp -rp ../libbar ./;
+
+ $rep_add --type dir libbar/ && $rep_fetch;
+ $* libbar ?libfoo/1.1.0 2>!;
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured !1.1.0 available [1.2.0] [1.1.1] (1.1.0)
+ EOO
+
+ $rep_remove $~/libbar/;
+ $rep_add $rep/t2 $rep/t4b $rep/t14c && $rep_fetch;
+
+ $* --deorphan --immediate 2>>~%EOE%;
+ replace/downgrade libfoo/1.0.0
+ replace/update libbar/1.0.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.1.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ %info: .+libbar.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available 1.1.0 (1.0.0)
+ libfoo configured !1.0.0 available 1.1.0+1 [1.1.0] (1.0.0) 0.1.0
+ EOO
+
+ $pkg_drop libbar
+ }
+
+ : recursive
+ :
+ {
+ $clone_root_cfg;
+ cp -rp ../libbar ./;
+
+ $rep_add --type dir libbar/ && $rep_fetch;
+ $* libbar ?libfoo/1.1.0 2>!;
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available (1.0.0)
+ libfoo configured !1.1.0 available [1.2.0] [1.1.1] (1.1.0)
+ EOO
+
+ $rep_remove $~/libbar/;
+ $rep_add $rep/t2 $rep/t4b $rep/t14c && $rep_fetch;
+
+ $* --deorphan --recursive 2>>~%EOE%;
+ replace/downgrade libfoo/1.0.0
+ replace/update libbar/1.0.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.1.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ %info: .+libbar.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_status -or libbar >>EOO;
+ !libbar configured 1.0.0 available 1.1.0 (1.0.0)
+ libfoo configured !1.0.0 available 1.1.0+1 [1.1.0] (1.0.0) 0.1.0
+ EOO
+
+ $pkg_drop libbar
+ }
+ }
+
+ : same-version
+ :
+ {
+ : best-match
+ :
+ {
+ $clone_root_cfg;
+
+ $rep_add $rep/t1 && $rep_fetch;
+ $* libfoo 2>!;
+
+ $rep_add $rep/t2 && $rep_fetch;
+ $* libbar ?libfoo 2>!;
+
+ $rep_remove $rep/t1;
+
+ $* --deorphan ?libfoo 2>>~%EOE%;
+ replace/update libfoo/1.0.0
+ reconfigure libbar (dependent of libfoo)
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ %info: .+libbar-1.0.0.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_drop libbar
+ }
+
+ : constrained
+ :
+ {
+ $clone_root_cfg;
+
+ $rep_add $rep/t1 && $rep_fetch;
+ $* libfoo 2>!;
+
+ $rep_add $rep/t2 && $rep_fetch;
+ $* libbar ?libfoo 2>!;
+
+ $rep_remove $rep/t1;
+
+ $* --deorphan ?libfoo/1.0.0 2>>~%EOE%;
+ replace/update libfoo/1.0.0
+ reconfigure libbar (dependent of libfoo)
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ %info: .+libbar-1.0.0.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_drop libbar
+ }
+ }
+ }
+
+ : held
+ :
+ {
+ : basics
+ :
+ {
+ $clone_root_cfg;
+
+ cp -r $src/libfoo-1.1.0 libfoo;
+ sed -i -e 's/(version:).+/\1 1.0.0/' libfoo/manifest;
+
+ $rep_add --type dir libfoo/ && $rep_fetch;
+
+ $* libfoo 2>!;
+
+ echo "" >+ libfoo/manifest;
+ $rep_fetch;
+
+ $pkg_status -ro libfoo >>EOO;
+ !libfoo configured 1.0.0 available 1.0.0#1
+ EOO
+
+ # Deorphan libfoo/1.0.0 to libfoo/1.0.0#1.
+ #
+ $* --deorphan libfoo 2>>~%EOE%;
+ replace/upgrade libfoo/1.0.0#1
+ disfigured libfoo/1.0.0
+ using libfoo/1.0.0#1 (external)
+ configured libfoo/1.0.0#1
+ %info: .+libfoo.+ is up to date%
+ updated libfoo/1.0.0#1
+ EOE
+
+ $pkg_status -ro libfoo >>EOO;
+ !libfoo configured 1.0.0#1 available (1.0.0#1)
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan libfoo 2>'info: nothing to build';
+
+ $rep_fetch $rep/t4a $rep/t4c;
+
+ $pkg_status -ro libfoo >>EOO;
+ !libfoo configured 1.0.0#1 available 1.1.0 (1.0.0#1) 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.0.0#1 to libfoo/1.0.0.
+ #
+ $rep_remove $~/libfoo/;
+
+ $* --deorphan libfoo 2>>~%EOE%;
+ replace/downgrade libfoo/1.0.0
+ disfigured libfoo/1.0.0#1
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ %info: .+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';
+
+ # Noop.
+ #
+ $* --deorphan libfoo 2>'info: nothing to build';
+
+ $pkg_status libfoo >'!libfoo configured 1.0.0 available 1.1.0';
+
+ # Deorphan libfoo/1.0.0 to libfoo/1.1.0.
+ #
+ $rep_remove $rep/t4c;
+
+ # While at it, use the 'deorphan all held packages' form.
+ #
+ $* --deorphan 2>>~%EOE%;
+ replace/upgrade libfoo/1.1.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.1.0
+ unpacked libfoo/1.1.0
+ configured libfoo/1.1.0
+ %info: .+libfoo-1.1.0.+ is up to date%
+ updated libfoo/1.1.0
+ EOE
+
+ $pkg_status libfoo >'!libfoo configured 1.1.0';
+
+ # Noop.
+ #
+ $* --deorphan libfoo 2>'info: nothing to build';
+
+ $pkg_status libfoo >'!libfoo configured 1.1.0';
+
+ $pkg_drop libfoo
+ }
+
+ : basics-masked
+ :
+ : As above but using --mask-repository instead of rep-remove.
+ :
+ {
+ $clone_root_cfg;
+
+ cp -r $src/libfoo-1.1.0 libfoo;
+ sed -i -e 's/(version:).+/\1 1.0.0/' libfoo/manifest;
+
+ $rep_add --type dir libfoo/ && $rep_fetch;
+
+ $* libfoo 2>!;
+
+ echo "" >+ libfoo/manifest;
+ $rep_fetch;
+
+ $pkg_status -ro libfoo >>EOO;
+ !libfoo configured 1.0.0 available 1.0.0#1
+ EOO
+
+ # Deorphan libfoo/1.0.0 to libfoo/1.0.0#1.
+ #
+ $* --deorphan libfoo 2>>~%EOE%;
+ replace/upgrade libfoo/1.0.0#1
+ disfigured libfoo/1.0.0
+ using libfoo/1.0.0#1 (external)
+ configured libfoo/1.0.0#1
+ %info: .+libfoo.+ is up to date%
+ updated libfoo/1.0.0#1
+ EOE
+
+ $pkg_status -ro libfoo >>EOO;
+ !libfoo configured 1.0.0#1 available (1.0.0#1)
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan libfoo 2>'info: nothing to build';
+
+ $rep_fetch $rep/t4a $rep/t4c;
+
+ $pkg_status -ro libfoo >>EOO;
+ !libfoo configured 1.0.0#1 available 1.1.0 (1.0.0#1) 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.0.0#1 to libfoo/1.0.0.
+ #
+ # Note that on Windows the local repository canonical name path part is
+ # converted to lower case.
+ #
+ cn = "$canonicalize([dir_path] $~/libfoo)";
+ if! $posix
+ cn = $lcase([string] $cn)
+ end;
+ cn = "dir:$cn";
+
+ $* --mask-repository $cn --deorphan libfoo 2>>~%EOE%;
+ replace/downgrade libfoo/1.0.0
+ disfigured libfoo/1.0.0#1
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ %info: .+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 1.0.0#1';
+
+ # Noop.
+ #
+ $* --mask-repository $cn --deorphan libfoo 2>'info: nothing to build';
+
+ $pkg_status libfoo >'!libfoo configured 1.0.0 available 1.1.0 1.0.0#1';
+
+ # Deorphan libfoo/1.0.0 to libfoo/1.1.0.
+ #
+ # While at it, use the 'deorphan all held packages' form.
+ #
+ $* --mask-repository $cn --mask-repository $rep/t4c --deorphan 2>>~%EOE%;
+ replace/upgrade libfoo/1.1.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.1.0
+ unpacked libfoo/1.1.0
+ configured libfoo/1.1.0
+ %info: .+libfoo-1.1.0.+ is up to date%
+ updated libfoo/1.1.0
+ EOE
+
+ $pkg_status libfoo >'!libfoo configured 1.1.0';
+
+ # Noop.
+ #
+ $* --mask-repository $cn --mask-repository $rep/t4c --deorphan libfoo \
+ 2>'info: nothing to build';
+
+ $pkg_status libfoo >'!libfoo configured 1.1.0';
+
+ $pkg_drop libfoo
+ }
+
+ : preference
+ :
+ {
+ $clone_root_cfg;
+
+ $tar -xf $src/t14d/libfoo-1.1.0+2.tar.gz &libfoo-1.1.0+2/***;
+ mv libfoo-1.1.0+2 libfoo;
+
+ $rep_add --type dir libfoo/ && $rep_fetch;
+
+ $* libfoo 2>!;
+
+ $rep_fetch $rep/t14a $rep/t14b $rep/t14c $rep/t14d $rep/t14e $rep/t14f $rep/t14i;
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+2 available 1.2.0 1.1.1 1.1.0+3 (1.1.0+2) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.0+2 to the exactly same version.
+ #
+ $rep_remove $~/libfoo/;
+
+ $* --deorphan libfoo 2>>~%EOE%;
+ replace/update libfoo/1.1.0+2
+ disfigured libfoo/1.1.0+2
+ fetched libfoo/1.1.0+2
+ unpacked libfoo/1.1.0+2
+ configured libfoo/1.1.0+2
+ %info: .+libfoo-1.1.0\+2.+ is up to date%
+ updated libfoo/1.1.0+2
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+2 available 1.2.0 1.1.1 1.1.0+3 (1.1.0+2) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan libfoo 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+2 available 1.2.0 1.1.1 1.1.0+3 (1.1.0+2) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.0+2 to the later revision of same version (1.1.0+3).
+ #
+ $rep_remove $rep/t14d;
+
+ $* --deorphan libfoo 2>>~%EOE%;
+ replace/upgrade libfoo/1.1.0+3
+ disfigured libfoo/1.1.0+2
+ fetched libfoo/1.1.0+3
+ unpacked libfoo/1.1.0+3
+ configured libfoo/1.1.0+3
+ %info: .+libfoo-1.1.0\+3.+ is up to date%
+ updated libfoo/1.1.0+3
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+3 available 1.2.0 1.1.1 (1.1.0+3) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan libfoo 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+3 available 1.2.0 1.1.1 (1.1.0+3) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.0+3 to the later patch of same version (1.1.1).
+ #
+ $rep_remove $rep/t14e;
+
+ $* --deorphan libfoo 2>>~%EOE%;
+ replace/upgrade libfoo/1.1.1
+ disfigured libfoo/1.1.0+3
+ fetched libfoo/1.1.1
+ unpacked libfoo/1.1.1
+ configured libfoo/1.1.1
+ %info: .+libfoo-1.1.1.+ is up to date%
+ updated libfoo/1.1.1
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.1 available 1.2.0 (1.1.1) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan libfoo 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.1 available 1.2.0 (1.1.1) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.1 to later minor of same version (1.2.0).
+ #
+ $rep_remove $rep/t14f;
+
+ $* --deorphan libfoo 2>>~%EOE%;
+ replace/upgrade libfoo/1.2.0
+ disfigured libfoo/1.1.1
+ fetched libfoo/1.2.0
+ unpacked libfoo/1.2.0
+ configured libfoo/1.2.0
+ %info: .+libfoo-1.2.0.+ is up to date%
+ updated libfoo/1.2.0
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.2.0 available (1.2.0) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan libfoo 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.2.0 available (1.2.0) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.2.0 to latest available version (1.1.0+1).
+ #
+ $rep_remove $rep/t14i;
+
+ $* --deorphan libfoo 2>>~%EOE%;
+ replace/downgrade libfoo/1.1.0+1
+ disfigured libfoo/1.2.0
+ fetched libfoo/1.1.0+1
+ unpacked libfoo/1.1.0+1
+ configured libfoo/1.1.0+1
+ %info: .+libfoo-1.1.0\+1.+ is up to date%
+ updated libfoo/1.1.0+1
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+1 available (1.1.0+1) 1.1.0 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan libfoo 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+1 available (1.1.0+1) 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.0+1 to latest available version (1.1.0).
+ #
+ $rep_remove $rep/t14c;
+
+ $* --deorphan libfoo 2>>~%EOE%;
+ replace/downgrade libfoo/1.1.0
+ disfigured libfoo/1.1.0+1
+ fetched libfoo/1.1.0
+ unpacked libfoo/1.1.0
+ configured libfoo/1.1.0
+ %info: .+libfoo-1.1.0.+ is up to date%
+ updated libfoo/1.1.0
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0 available (1.1.0) 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan libfoo 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0 available (1.1.0) 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.0 to latest available version (1.0.0).
+ #
+ $rep_remove $rep/t14b;
+
+ $* --deorphan libfoo 2>>~%EOE%;
+ replace/downgrade libfoo/1.0.0
+ disfigured libfoo/1.1.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ %info: .+libfoo-1.0.0.+ is up to date%
+ updated libfoo/1.0.0
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.0.0 available (1.0.0)
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan libfoo 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.0.0 available (1.0.0)
+ EOO
+
+ # Deorphan fails (none available).
+ #
+ $rep_remove $rep/t14a;
+
+ $* --deorphan libfoo 2>>/EOE != 0;
+ error: unknown package libfoo
+ info: configuration cfg/ has no repositories
+ info: use 'bpkg rep-add' to add a repository
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop libfoo
+ }
+
+ : preference-all-held
+ :
+ : As above but uses 'deorphan all held packages form'.
+ :
+ {
+ $clone_root_cfg;
+
+ $tar -xf $src/t14d/libfoo-1.1.0+2.tar.gz &libfoo-1.1.0+2/***;
+ mv libfoo-1.1.0+2 libfoo;
+
+ $rep_add --type dir libfoo/ && $rep_fetch;
+
+ $* libfoo 2>!;
+
+ $rep_fetch $rep/t14a $rep/t14b $rep/t14c $rep/t14d $rep/t14e $rep/t14f $rep/t14i;
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+2 available 1.2.0 1.1.1 1.1.0+3 (1.1.0+2) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.0+2 to the exactly same version.
+ #
+ $rep_remove $~/libfoo/;
+
+ $* --deorphan 2>>~%EOE%;
+ replace/update libfoo/1.1.0+2
+ disfigured libfoo/1.1.0+2
+ fetched libfoo/1.1.0+2
+ unpacked libfoo/1.1.0+2
+ configured libfoo/1.1.0+2
+ %info: .+libfoo-1.1.0\+2.+ is up to date%
+ updated libfoo/1.1.0+2
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+2 available 1.2.0 1.1.1 1.1.0+3 (1.1.0+2) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+2 available 1.2.0 1.1.1 1.1.0+3 (1.1.0+2) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.0+2 to the later revision of same version (1.1.0+3).
+ #
+ $rep_remove $rep/t14d;
+
+ $* --deorphan 2>>~%EOE%;
+ replace/upgrade libfoo/1.1.0+3
+ disfigured libfoo/1.1.0+2
+ fetched libfoo/1.1.0+3
+ unpacked libfoo/1.1.0+3
+ configured libfoo/1.1.0+3
+ %info: .+libfoo-1.1.0\+3.+ is up to date%
+ updated libfoo/1.1.0+3
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+3 available 1.2.0 1.1.1 (1.1.0+3) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+3 available 1.2.0 1.1.1 (1.1.0+3) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.0+3 to the later patch of same version (1.1.1).
+ #
+ $rep_remove $rep/t14e;
+
+ $* --deorphan 2>>~%EOE%;
+ replace/upgrade libfoo/1.1.1
+ disfigured libfoo/1.1.0+3
+ fetched libfoo/1.1.1
+ unpacked libfoo/1.1.1
+ configured libfoo/1.1.1
+ %info: .+libfoo-1.1.1.+ is up to date%
+ updated libfoo/1.1.1
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.1 available 1.2.0 (1.1.1) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.1 available 1.2.0 (1.1.1) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.1 to later minor of same version (1.2.0).
+ #
+ $rep_remove $rep/t14f;
+
+ $* --deorphan 2>>~%EOE%;
+ replace/upgrade libfoo/1.2.0
+ disfigured libfoo/1.1.1
+ fetched libfoo/1.2.0
+ unpacked libfoo/1.2.0
+ configured libfoo/1.2.0
+ %info: .+libfoo-1.2.0.+ is up to date%
+ updated libfoo/1.2.0
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.2.0 available (1.2.0) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.2.0 available (1.2.0) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.2.0 to latest available version (1.1.0+1).
+ #
+ $rep_remove $rep/t14i;
+
+ $* --deorphan 2>>~%EOE%;
+ replace/downgrade libfoo/1.1.0+1
+ disfigured libfoo/1.2.0
+ fetched libfoo/1.1.0+1
+ unpacked libfoo/1.1.0+1
+ configured libfoo/1.1.0+1
+ %info: .+libfoo-1.1.0\+1.+ is up to date%
+ updated libfoo/1.1.0+1
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+1 available (1.1.0+1) 1.1.0 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+1 available (1.1.0+1) 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.0+1 to latest available version (1.1.0).
+ #
+ $rep_remove $rep/t14c;
+
+ $* --deorphan 2>>~%EOE%;
+ replace/downgrade libfoo/1.1.0
+ disfigured libfoo/1.1.0+1
+ fetched libfoo/1.1.0
+ unpacked libfoo/1.1.0
+ configured libfoo/1.1.0
+ %info: .+libfoo-1.1.0.+ is up to date%
+ updated libfoo/1.1.0
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0 available (1.1.0) 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0 available (1.1.0) 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.0 to latest available version (1.0.0).
+ #
+ $rep_remove $rep/t14b;
+
+ $* --deorphan 2>>~%EOE%;
+ replace/downgrade libfoo/1.0.0
+ disfigured libfoo/1.1.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ %info: .+libfoo-1.0.0.+ is up to date%
+ updated libfoo/1.0.0
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.0.0 available (1.0.0)
+ EOO
+
+ # Noop.
+ #
+ $* --deorphan 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.0.0 available (1.0.0)
+ EOO
+
+ # Deorphan fails (none available).
+ #
+ $rep_remove $rep/t14a;
+
+ $* --deorphan 2>>/EOE != 0;
+ error: libfoo is not available
+ info: configuration cfg/ has no repositories
+ info: use 'bpkg rep-add' to add a repository
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop libfoo
+ }
+
+ : preference-all-held-masked
+ :
+ : As above but using --mask-repository instead of rep-remove.
+ :
+ {
+ $clone_root_cfg;
+
+ $tar -xf $src/t14d/libfoo-1.1.0+2.tar.gz &libfoo-1.1.0+2/***;
+ mv libfoo-1.1.0+2 libfoo;
+
+ $rep_add --type dir libfoo/ && $rep_fetch;
+
+ $* libfoo 2>!;
+
+ $rep_fetch $rep/t14a $rep/t14b $rep/t14c $rep/t14d $rep/t14e $rep/t14f $rep/t14i;
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+2 available 1.2.0 1.1.1 1.1.0+3 (1.1.0+2) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.0+2 to the exactly same version.
+ #
+ # Note that on Windows the local repository canonical name path part is
+ # converted to lower case.
+ #
+ cn = "$canonicalize([dir_path] $~/libfoo)";
+ if! $posix
+ cn = $lcase([string] $cn)
+ end;
+ cn = "dir:$cn";
+
+ mask = --mask-repository $cn;
+
+ $* $mask --deorphan 2>>~%EOE%;
+ replace/update libfoo/1.1.0+2
+ disfigured libfoo/1.1.0+2
+ fetched libfoo/1.1.0+2
+ unpacked libfoo/1.1.0+2
+ configured libfoo/1.1.0+2
+ %info: .+libfoo-1.1.0\+2.+ is up to date%
+ updated libfoo/1.1.0+2
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+2 available 1.2.0 1.1.1 1.1.0+3 (1.1.0+2) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* $mask --deorphan 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+2 available 1.2.0 1.1.1 1.1.0+3 (1.1.0+2) 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.0+2 to the later revision of same version (1.1.0+3).
+ #
+ mask += --mask-repository $rep/t14d;
+
+ $* $mask --deorphan 2>>~%EOE%;
+ replace/upgrade libfoo/1.1.0+3
+ disfigured libfoo/1.1.0+2
+ fetched libfoo/1.1.0+3
+ unpacked libfoo/1.1.0+3
+ configured libfoo/1.1.0+3
+ %info: .+libfoo-1.1.0\+3.+ is up to date%
+ updated libfoo/1.1.0+3
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+3 available 1.2.0 1.1.1 (1.1.0+3) 1.1.0+2 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* $mask --deorphan 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+3 available 1.2.0 1.1.1 (1.1.0+3) 1.1.0+2 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.0+3 to the later patch of same version (1.1.1).
+ #
+ mask += --mask-repository $rep/t14e;
+
+ $* $mask --deorphan 2>>~%EOE%;
+ replace/upgrade libfoo/1.1.1
+ disfigured libfoo/1.1.0+3
+ fetched libfoo/1.1.1
+ unpacked libfoo/1.1.1
+ configured libfoo/1.1.1
+ %info: .+libfoo-1.1.1.+ is up to date%
+ updated libfoo/1.1.1
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.1 available 1.2.0 (1.1.1) 1.1.0+3 1.1.0+2 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* $mask --deorphan 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.1 available 1.2.0 (1.1.1) 1.1.0+3 1.1.0+2 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.1 to later minor of same version (1.2.0).
+ #
+ mask += --mask-repository $rep/t14f;
+
+ $* $mask --deorphan 2>>~%EOE%;
+ replace/upgrade libfoo/1.2.0
+ disfigured libfoo/1.1.1
+ fetched libfoo/1.2.0
+ unpacked libfoo/1.2.0
+ configured libfoo/1.2.0
+ %info: .+libfoo-1.2.0.+ is up to date%
+ updated libfoo/1.2.0
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.2.0 available (1.2.0) 1.1.1 1.1.0+3 1.1.0+2 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* $mask --deorphan 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.2.0 available (1.2.0) 1.1.1 1.1.0+3 1.1.0+2 1.1.0+1 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.2.0 to latest available version (1.1.0+1).
+ #
+ mask += --mask-repository $rep/t14i;
+
+ $* $mask --deorphan 2>>~%EOE%;
+ replace/downgrade libfoo/1.1.0+1
+ disfigured libfoo/1.2.0
+ fetched libfoo/1.1.0+1
+ unpacked libfoo/1.1.0+1
+ configured libfoo/1.1.0+1
+ %info: .+libfoo-1.1.0\+1.+ is up to date%
+ updated libfoo/1.1.0+1
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+1 available 1.2.0 1.1.1 1.1.0+3 1.1.0+2 (1.1.0+1) 1.1.0 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* $mask --deorphan 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0+1 available 1.2.0 1.1.1 1.1.0+3 1.1.0+2 (1.1.0+1) 1.1.0 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.0+1 to latest available version (1.1.0).
+ #
+ mask += --mask-repository $rep/t14c;
+
+ $* $mask --deorphan 2>>~%EOE%;
+ replace/downgrade libfoo/1.1.0
+ disfigured libfoo/1.1.0+1
+ fetched libfoo/1.1.0
+ unpacked libfoo/1.1.0
+ configured libfoo/1.1.0
+ %info: .+libfoo-1.1.0.+ is up to date%
+ updated libfoo/1.1.0
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0 available 1.2.0 1.1.1 1.1.0+3 1.1.0+2 1.1.0+1 (1.1.0) 1.0.0
+ EOO
+
+ # Noop.
+ #
+ $* $mask --deorphan 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.1.0 available 1.2.0 1.1.1 1.1.0+3 1.1.0+2 1.1.0+1 (1.1.0) 1.0.0
+ EOO
+
+ # Deorphan libfoo/1.1.0 to latest available version (1.0.0).
+ #
+ mask += --mask-repository $rep/t14b;
+
+ $* $mask --deorphan 2>>~%EOE%;
+ replace/downgrade libfoo/1.0.0
+ disfigured libfoo/1.1.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ %info: .+libfoo-1.0.0.+ is up to date%
+ updated libfoo/1.0.0
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.0.0 available 1.2.0 1.1.1 1.1.0+3 1.1.0+2 1.1.0+1 1.1.0 (1.0.0)
+ EOO
+
+ # Noop.
+ #
+ $* $mask --deorphan 2>'info: nothing to build';
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.0.0 available 1.2.0 1.1.1 1.1.0+3 1.1.0+2 1.1.0+1 1.1.0 (1.0.0)
+ EOO
+
+ # Deorphan fails (none available).
+ #
+ mask += --mask-repository $rep/t14a;
+
+ $* $mask --deorphan 2>>/EOE != 0;
+ error: libfoo is not available
+ EOE
+
+ $pkg_status -o libfoo >>EOO;
+ !libfoo configured 1.0.0 available 1.2.0 1.1.1 1.1.0+3 1.1.0+2 1.1.0+1 1.1.0 (1.0.0)
+ EOO
+
+ $pkg_drop libfoo
+ }
+ }
+}
+
+: compatibility
+:
+{
+ +$clone_cfg
+ +$rep_add $rep/t15 && $rep_fetch
+
+ test.arguments += --yes
+
+ : toolchain
+ :
+ {
+ +$clone_cfg
+
+ : build-satisfied
+ :
+ {
+ $clone_cfg;
+
+ $* libfoo libbar 2>>~%EOE%;
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ %info: .+libfoo-1.0.0.+ is up to date%
+ %info: .+libbar-1.0.0.+ is up to date%
+ updated libfoo/1.0.0
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_drop libfoo libbar
+ }
+
+ : build-fail-unsatisfied
+ :
+ {
+ $clone_cfg;
+
+ $* libbaz 2>>~%EOE% != 0
+ error: unable to satisfy constraint (build2 >= 65536.0.0) for package libbaz
+ % info: available build2 version is .+%
+ info: while satisfying libbaz/1.0.0
+ EOE
+ }
+
+ : build-fail-unsatisfied-dependency
+ :
+ {
+ $clone_cfg;
+
+ $* libbiz 2>>~%EOE% != 0
+ error: unable to satisfy constraint (build2 >= 65536.0.0) for package libbaz
+ % info: available build2 version is .+%
+ info: while satisfying libbaz/1.0.0
+ info: while satisfying libbiz/1.0.0
+ EOE
+ }
+ }
+}
+
+: existing-package
+:
+{
+ +$tar -xf $src/libbar-1.2.0.tar.gz &libbar-1.2.0/***
+ +$tar -xf $src/libbar-1.1.0.tar.gz &libbar-1.1.0/***
+ +$tar -xf $src/libbar-1.0.0.tar.gz &libbar-1.0.0/***
+ +$tar -xf $src/libbar-0.0.3.tar.gz &libbar-0.0.3/***
+ +$tar -xf $src/libbaz-1.1.0.tar.gz &libbaz-1.1.0/***
+ +$tar -xf $src/libfoo-1.1.0.tar.gz &libfoo-1.1.0/***
+ +$tar -xf $src/libfoo-1.0.0.tar.gz &libfoo-1.0.0/***
+
+ d = [dir_path] ../../../
+
+ test.arguments += --yes
+
+ : hold
+ :
+ {
+ : archive
+ :
+ {
+ : pick-archive
+ :
+ : Test that libbar/1.0.0 specified as an archive is picked as a
+ : dependency for libbaz, despite the fact the repository contains
+ : libbar/1.2.0.
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t5 && $rep_fetch;
+
+ $* $src/libbaz-1.1.0.tar.gz \
+ $src/libfoo-1.0.0.tar.gz \
+ $src/libbar-1.0.0.tar.gz 2>>~%EOE%;
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ fetched libbaz/1.1.0
+ unpacked libbaz/1.1.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libfoo-1.0.0.+ is up to date%
+ %info: .+libbar-1.0.0.+ is up to date%
+ %info: .+libbaz-1.1.0.+ is up to date%
+ updated libfoo/1.0.0
+ updated libbar/1.0.0
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ !libbar configured !1.0.0 available 1.2.0
+ !libfoo configured !1.0.0
+ !libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop libbaz libfoo libbar
+ }
+
+ : pick-repo
+ :
+ : Picks the libbar/1.2.0 dependency from the repository for the
+ : dependent libbaz/1.1.0 specified as an archive.
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t5 && $rep_fetch;
+
+ $* $src/libbaz-1.1.0.tar.gz $src/libfoo-1.0.0.tar.gz 2>>~%EOE%;
+ fetched libbar/1.2.0
+ unpacked libbar/1.2.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ fetched libbaz/1.1.0
+ unpacked libbaz/1.1.0
+ configured libbar/1.2.0
+ configured libfoo/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libfoo-1.0.0.+ is up to date%
+ %info: .+libbaz-1.1.0.+ is up to date%
+ updated libfoo/1.0.0
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured 1.2.0
+ !libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop libbaz libfoo libbar
+ }
+
+ : unsatisfactory
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t4b && $rep_fetch;
+
+ $* libbar $src/libfoo-1.0.0.tar.gz 2>>~%EOE% != 0
+ error: unable to satisfy constraints on package libfoo
+ info: command line depends on (libfoo == 1.0.0)
+ info: libbar/1.1.0 depends on (libfoo == 1.1.0)
+ info: available libfoo/1.0.0
+ info: available libfoo/1.1.0
+ info: while satisfying libbar/1.1.0
+ info: explicitly specify libfoo version to manually satisfy both constraints
+ EOE
+ }
+
+ : unsatisfactory-archive
+ :
+ : Same as above but the dependent is specified as an archive.
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t4a && $rep_fetch; # Note: libfoo/1.1.0 belongs to t4a.
+
+ $* $src/libbar-1.1.0.tar.gz $src/libfoo-1.0.0.tar.gz 2>>~%EOE% != 0
+ error: unable to satisfy constraints on package libfoo
+ info: command line depends on (libfoo == 1.0.0)
+ info: libbar/1.1.0 depends on (libfoo == 1.1.0)
+ command line requires (libbar == 1.1.0)
+ info: available libfoo/1.0.0
+ info: available libfoo/1.1.0
+ info: while satisfying libbar/1.1.0
+ info: explicitly specify libfoo version to manually satisfy both constraints
+ EOE
+ }
+
+ : dependency-alternative
+ :
+ : Note: by specifying an unsatisfactory dependency alternative as an
+ : archive we resolve the alternatives ambiguity here, building both
+ : libbar and libbaz packages as a result.
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t8a && $rep_fetch;
+
+ $* fox 2>>EOE != 0;
+ error: unable to select dependency alternative for package fox/1.0.0
+ info: explicitly specify dependency packages to manually select the alternative
+ info: alternative: libbar
+ info: alternative: libbaz
+ info: while satisfying fox/1.0.0
+ EOE
+
+ $* fox $src/libbar-0.0.3.tar.gz 2>>~%EOE%;
+ fetched libbaz/1.1.0
+ unpacked libbaz/1.1.0
+ fetched fox/1.0.0
+ unpacked fox/1.0.0
+ fetched libbar/0.0.3
+ unpacked libbar/0.0.3
+ configured libbaz/1.1.0
+ configured fox/1.0.0
+ configured libbar/0.0.3
+ %info: .+fox-1.0.0.+ is up to date%
+ %info: .+libbar-0.0.3.+ is up to date%
+ updated fox/1.0.0
+ updated libbar/0.0.3
+ EOE
+
+ $pkg_status -r fox libbar >>EOO;
+ !fox configured 1.0.0
+ libbaz configured 1.1.0
+ !libbar configured !0.0.3 available 1.0.0
+ libbaz configured 1.1.0
+ EOO
+
+ $pkg_drop fox libbar
+ }
+
+ : upgrade
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t4a $rep/t4b && $rep_fetch;
+
+ $* $src/libbaz-1.1.0.tar.gz \
+ $src/libfoo-1.0.0.tar.gz \
+ $src/libbar-1.0.0.tar.gz 2>!;
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ !libbar configured !1.0.0 available 1.1.0
+ !libfoo configured !1.0.0 available 1.1.0
+ !libfoo configured !1.0.0 available 1.1.0
+ EOO
+
+ $* --upgrade-recursive libbaz 2>>~%EOE%;
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.1.0
+ unpacked libfoo/1.1.0
+ fetched libbar/1.1.0
+ unpacked libbar/1.1.0
+ configured libfoo/1.1.0
+ configured libbar/1.1.0
+ configured libbaz/1.1.0
+ %info: .+libbaz-1.1.0.+ is up to date%
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured 1.1.0
+ !libbar configured !1.1.0
+ !libfoo configured !1.1.0
+ !libfoo configured !1.1.0
+ EOO
+
+ $pkg_drop libbaz libbar libfoo
+ }
+
+ : downgrade
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t5 && $rep_fetch;
+
+ $* libbar 2>!;
+
+ $* $src/libbar-1.0.0.tar.gz "?$src/libfoo-1.0.0.tar.gz" 2>>~%EOE%;
+ disfigured libbar/1.2.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ %info: .+libbar-1.0.0.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured !1.0.0 available 1.2.0
+ libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop libbar
+ }
+
+ : replace
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t2 && $rep_fetch;
+
+ $* libfoo 2>!;
+
+ $* $src/libfoo-1.0.0.tar.gz 2>>~%EOE%;
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ %info: .+libfoo-1.0.0.+ is up to date%
+ updated libfoo/1.0.0
+ EOE
+
+ $pkg_status -r libfoo >>EOO;
+ !libfoo configured !1.0.0
+ EOO
+
+ $* --plan "" $src/libfoo-1.0.0.tar.gz 2>>~%EOE%;
+ replace/update libfoo/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ %info: .+libfoo-1.0.0.+ is up to date%
+ updated libfoo/1.0.0
+ EOE
+
+ $pkg_status -r libfoo >>EOO;
+ !libfoo configured !1.0.0
+ EOO
+
+ $* --plan "" $d/libfoo-1.0.0/ 2>>~%EOE%;
+ replace/upgrade libfoo/1.0.0#1
+ disfigured libfoo/1.0.0
+ using libfoo/1.0.0#1 (external)
+ configured libfoo/1.0.0#1
+ %info: .+libfoo.+ is up to date%
+ updated libfoo/1.0.0#1
+ EOE
+
+ $pkg_status -r libfoo >>EOO;
+ !libfoo configured !1.0.0#1
+ EOO
+
+ $pkg_drop libfoo
+ }
+
+ : deorphan-existing-archive
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t2 && $rep_fetch;
+
+ $* $src/libbaz-1.1.0.tar.gz \
+ $src/libfoo-1.0.0.tar.gz \
+ $src/libbar-1.0.0.tar.gz 2>!;
+
+ $* --deorphan libfoo 2>>~%EOE%;
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libfoo-1.0.0.+ is up to date%
+ %info: .+libbar-1.0.0.+ is up to date%
+ %info: .+libbaz-1.1.0.+ is up to date%
+ updated libfoo/1.0.0
+ updated libbar/1.0.0
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ !libbar configured !1.0.0
+ !libfoo configured 1.0.0
+ !libfoo configured 1.0.0
+ EOO
+
+ $rep_add $rep/t3 && $rep_fetch;
+
+ $* --deorphan 2>>~%EOE%;
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ fetched libbaz/1.0.0
+ unpacked libbaz/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.0.0
+ %info: .+libbar-1.0.0.+ is up to date%
+ %info: .+libbaz-1.0.0.+ is up to date%
+ updated libbar/1.0.0
+ updated libbaz/1.0.0
+ EOE
+
+ $pkg_status -r libbaz libfoo >>EOO;
+ !libbaz configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop libbaz libbar libfoo
+ }
+
+ : deorphan-with-existing-archive
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t2 $rep/t3 && $rep_fetch;
+
+ $* libbaz libbar 2>!;
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $rep_remove $rep/t2 $rep/t3;
+
+ $* --deorphan $src/libfoo-1.0.0.tar.gz 2>>~%EOE%;
+ disfigured libbaz/1.0.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.0.0
+ %info: .+libfoo-1.0.0.+ is up to date%
+ %info: .+libbar-1.0.0.+ is up to date%
+ %info: .+libbaz-1.0.0.+ is up to date%
+ updated libfoo/1.0.0
+ updated libbar/1.0.0
+ updated libbaz/1.0.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured !1.0.0
+ EOO
+
+ $* --deorphan $src/libbar-1.2.0.tar.gz 2>>~%EOE%;
+ disfigured libbaz/1.0.0
+ disfigured libbar/1.0.0
+ fetched libbar/1.2.0
+ unpacked libbar/1.2.0
+ configured libbar/1.2.0
+ configured libbaz/1.0.0
+ %info: .+libbar-1.2.0.+ is up to date%
+ %info: .+libbaz-1.0.0.+ is up to date%
+ updated libbar/1.2.0
+ updated libbaz/1.0.0
+ EOE
+
+ $pkg_status -r libbaz libfoo >>EOO;
+ !libbaz configured 1.0.0
+ !libbar configured !1.2.0
+ !libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop libbaz libbar libfoo
+ }
+
+ : system
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t3 && $rep_fetch;
+
+ $* libbaz '?sys:libbar' 2>!;
+
+ $* $src/libbar-1.1.0.tar.gz "?$src/libfoo-1.1.0.tar.gz" 2>>~%EOE%;
+ disfigured libbaz/1.0.0
+ purged libbar/*
+ fetched libfoo/1.1.0
+ unpacked libfoo/1.1.0
+ fetched libbar/1.1.0
+ unpacked libbar/1.1.0
+ configured libfoo/1.1.0
+ configured libbar/1.1.0
+ configured libbaz/1.0.0
+ %info: .+libbar-1.1.0.+ is up to date%
+ %info: .+libbaz-1.0.0.+ is up to date%
+ updated libbar/1.1.0
+ updated libbaz/1.0.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured 1.0.0
+ !libbar configured !1.1.0
+ libfoo configured !1.1.0
+ EOO
+
+ $pkg_drop libbaz libbar
+ }
+ }
+
+ : directory
+ :
+ {
+ : pick-directory
+ :
+ : Test that libbar/1.0.0 specified as a directory is picked as a
+ : dependency for libbaz, despite the fact the repository contains
+ : libbar/1.2.0.
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t5 && $rep_fetch;
+
+ $* $d/libbaz-1.1.0/ \
+ $d/libfoo-1.0.0/ \
+ $d/libbar-1.0.0/ 2>>~%EOE%;
+ using libfoo/1.0.0 (external)
+ using libbar/1.0.0 (external)
+ using libbaz/1.1.0 (external)
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libfoo.+ is up to date%
+ %info: .+libbar.+ is up to date%
+ %info: .+libbaz.+ is up to date%
+ updated libfoo/1.0.0
+ updated libbar/1.0.0
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ !libbar configured !1.0.0 available 1.2.0
+ !libfoo configured !1.0.0
+ !libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop libbaz libfoo libbar
+ }
+
+ : pick-repo
+ :
+ : Picks the libbar/1.2.0 dependency from the repository for the
+ : dependent libbaz/1.1.0 specified as a directory.
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t5 && $rep_fetch;
+
+ $* $d/libbaz-1.1.0/ $d/libfoo-1.0.0/ 2>>~%EOE%;
+ fetched libbar/1.2.0
+ unpacked libbar/1.2.0
+ using libfoo/1.0.0 (external)
+ using libbaz/1.1.0 (external)
+ configured libbar/1.2.0
+ configured libfoo/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libfoo.+ is up to date%
+ %info: .+libbaz.+ is up to date%
+ updated libfoo/1.0.0
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured 1.2.0
+ !libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop libbaz libfoo libbar
+ }
+
+ : unsatisfactory
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t4b && $rep_fetch;
+
+ $* libbar $d/libfoo-1.0.0/ 2>>~%EOE% != 0
+ error: unable to satisfy constraints on package libfoo
+ info: command line depends on (libfoo == 1.0.0)
+ info: libbar/1.1.0 depends on (libfoo == 1.1.0)
+ info: available libfoo/1.0.0
+ info: available libfoo/1.1.0
+ info: while satisfying libbar/1.1.0
+ info: explicitly specify libfoo version to manually satisfy both constraints
+ EOE
+ }
+
+ : unsatisfactory-archive
+ :
+ : Same as above but the dependent is specified as a directory.
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t4a && $rep_fetch; # Note: libfoo/1.1.0 belongs to t4a.
+
+ $* $d/libbar-1.1.0/ $d/libfoo-1.0.0/ 2>>~%EOE% != 0
+ error: unable to satisfy constraints on package libfoo
+ info: command line depends on (libfoo == 1.0.0)
+ info: libbar/1.1.0 depends on (libfoo == 1.1.0)
+ command line requires (libbar == 1.1.0)
+ info: available libfoo/1.0.0
+ info: available libfoo/1.1.0
+ info: while satisfying libbar/1.1.0
+ info: explicitly specify libfoo version to manually satisfy both constraints
+ EOE
+ }
+
+ : dependency-alternative
+ :
+ : Note: by specifying an unsatisfactory dependency alternative as a
+ : directory we resolve the alternatives ambiguity here, building both
+ : libbar and libbaz packages as a result.
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t8a && $rep_fetch;
+
+ $* fox 2>>EOE != 0;
+ error: unable to select dependency alternative for package fox/1.0.0
+ info: explicitly specify dependency packages to manually select the alternative
+ info: alternative: libbar
+ info: alternative: libbaz
+ info: while satisfying fox/1.0.0
+ EOE
+
+ $* fox $d/libbar-0.0.3/ 2>>~%EOE%;
+ fetched libbaz/1.1.0
+ unpacked libbaz/1.1.0
+ fetched fox/1.0.0
+ unpacked fox/1.0.0
+ using libbar/0.0.3 (external)
+ configured libbaz/1.1.0
+ configured fox/1.0.0
+ configured libbar/0.0.3
+ %info: .+fox-1.0.0.+ is up to date%
+ %info: .+libbar.+ is up to date%
+ updated fox/1.0.0
+ updated libbar/0.0.3
+ EOE
+
+ $pkg_status -r fox libbar >>EOO;
+ !fox configured 1.0.0
+ libbaz configured 1.1.0
+ !libbar configured !0.0.3 available 1.0.0
+ libbaz configured 1.1.0
+ EOO
+
+ $pkg_drop fox libbar
+ }
+
+ : upgrade
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t4a $rep/t4b && $rep_fetch;
+
+ $* $d/libbaz-1.1.0/ \
+ $d/libfoo-1.0.0/ \
+ $d/libbar-1.0.0/ 2>!;
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ !libbar configured !1.0.0 available 1.1.0
+ !libfoo configured !1.0.0 available 1.1.0
+ !libfoo configured !1.0.0 available 1.1.0
+ EOO
+
+ $* --upgrade-recursive libbaz 2>>~%EOE%;
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.1.0
+ unpacked libfoo/1.1.0
+ fetched libbar/1.1.0
+ unpacked libbar/1.1.0
+ configured libfoo/1.1.0
+ configured libbar/1.1.0
+ configured libbaz/1.1.0
+ %info: .+libbaz.+ is up to date%
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured 1.1.0
+ !libbar configured !1.1.0
+ !libfoo configured !1.1.0
+ !libfoo configured !1.1.0
+ EOO
+
+ $pkg_drop libbaz libbar libfoo
+ }
+
+ : downgrade
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t5 && $rep_fetch;
+
+ $* libbar 2>!;
+
+ $* $d/libbar-1.0.0/ "?$d/libfoo-1.0.0/" 2>>~%EOE%;
+ disfigured libbar/1.2.0
+ using libfoo/1.0.0 (external)
+ using libbar/1.0.0 (external)
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ %info: .+libbar.+ is up to date%
+ updated libbar/1.0.0
+ EOE
+
+ $pkg_status -r libbar >>EOO;
+ !libbar configured !1.0.0 available 1.2.0
+ libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop libbar
+ }
+
+ : replace
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t2 && $rep_fetch;
+
+ $* libfoo 2>!;
+
+ $* $d/libfoo-1.0.0/ 2>>~%EOE%;
+ disfigured libfoo/1.0.0
+ using libfoo/1.0.0#1 (external)
+ configured libfoo/1.0.0#1
+ %info: .+libfoo.+ is up to date%
+ updated libfoo/1.0.0#1
+ EOE
+
+ $pkg_status -r libfoo >>EOO;
+ !libfoo configured !1.0.0#1
+ EOO
+
+ $* --plan "" $d/libfoo-1.0.0/ 2>>~%EOE%;
+ replace/update libfoo/1.0.0#1
+ disfigured libfoo/1.0.0#1
+ using libfoo/1.0.0#1 (external)
+ configured libfoo/1.0.0#1
+ %info: .+libfoo.+ is up to date%
+ updated libfoo/1.0.0#1
+ EOE
+
+ $pkg_status -r libfoo >>EOO;
+ !libfoo configured !1.0.0#1
+ EOO
+
+ $* --plan "" $src/libfoo-1.0.0.tar.gz 2>>~%EOE%;
+ replace/downgrade libfoo/1.0.0
+ disfigured libfoo/1.0.0#1
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ %info: .+libfoo-1.0.0.+ is up to date%
+ updated libfoo/1.0.0
+ EOE
+
+ $pkg_status -r libfoo >>EOO;
+ !libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop libfoo
+ }
+
+ : deorphan-existing-directory
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t2 && $rep_fetch;
+
+ $* $d/libbaz-1.1.0/ \
+ $d/libfoo-1.0.0/ \
+ $d/libbar-1.0.0/ 2>!;
+
+ $* --deorphan libfoo 2>>~%EOE%;
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libfoo-1.0.0.+ is up to date%
+ %info: .+libbar.+ is up to date%
+ %info: .+libbaz.+ is up to date%
+ updated libfoo/1.0.0
+ updated libbar/1.0.0
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ !libbar configured !1.0.0
+ !libfoo configured 1.0.0
+ !libfoo configured 1.0.0
+ EOO
+
+ $rep_add $rep/t3 && $rep_fetch;
+
+ $* --deorphan 2>>~%EOE%;
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ fetched libbaz/1.0.0
+ unpacked libbaz/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.0.0
+ %info: .+libbar-1.0.0.+ is up to date%
+ %info: .+libbaz-1.0.0.+ is up to date%
+ updated libbar/1.0.0
+ updated libbaz/1.0.0
+ EOE
+
+ $pkg_status -r libbaz libfoo >>EOO;
+ !libbaz configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop libbaz libbar libfoo
+ }
+
+ : deorphan-with-existing-directory
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t2 $rep/t3 && $rep_fetch;
+
+ $* libbaz libbar 2>!;
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured 1.0.0
+ !libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $rep_remove $rep/t2 $rep/t3;
+
+ $* --deorphan $d/libfoo-1.0.0/ 2>>~%EOE%;
+ disfigured libbaz/1.0.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ using libfoo/1.0.0#1 (external)
+ configured libfoo/1.0.0#1
+ configured libbar/1.0.0
+ configured libbaz/1.0.0
+ %info: .+libfoo.+ is up to date%
+ %info: .+libbar-1.0.0.+ is up to date%
+ %info: .+libbaz-1.0.0.+ is up to date%
+ updated libfoo/1.0.0#1
+ updated libbar/1.0.0
+ updated libbaz/1.0.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured !1.0.0#1
+ EOO
+
+ $* --deorphan $d/libbar-1.2.0/ 2>>~%EOE%;
+ disfigured libbaz/1.0.0
+ disfigured libbar/1.0.0
+ using libbar/1.2.0 (external)
+ configured libbar/1.2.0
+ configured libbaz/1.0.0
+ %info: .+libbar.+ is up to date%
+ %info: .+libbaz-1.0.0.+ is up to date%
+ updated libbar/1.2.0
+ updated libbaz/1.0.0
+ EOE
+
+ $pkg_status -r libbaz libfoo >>EOO;
+ !libbaz configured 1.0.0
+ !libbar configured !1.2.0
+ !libfoo configured !1.0.0#1
+ EOO
+
+ $pkg_drop libbaz libbar libfoo
+ }
+
+ : system
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t3 && $rep_fetch;
+
+ $* libbaz '?sys:libbar' 2>!;
+
+ $* $d/libbar-1.1.0/ "?$d/libfoo-1.1.0/" 2>>~%EOE%;
+ disfigured libbaz/1.0.0
+ purged libbar/*
+ using libfoo/1.1.0 (external)
+ using libbar/1.1.0 (external)
+ configured libfoo/1.1.0
+ configured libbar/1.1.0
+ configured libbaz/1.0.0
+ %info: .+libbar.+ is up to date%
+ %info: .+libbaz-1.0.0.+ is up to date%
+ updated libbar/1.1.0
+ updated libbaz/1.0.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured 1.0.0
+ !libbar configured !1.1.0
+ libfoo configured !1.1.0
+ EOO
+
+ $pkg_drop libbaz libbar
+ }
+ }
+ }
+
+ : dependency
+ :
+ {
+ : archive
+ :
+ {
+ : pick-archive
+ :
+ : Test that libbar/1.0.0 specified as an archive is picked as a
+ : dependency for libbaz, despite the fact the repository contains
+ : libbar/1.2.0.
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t5 && $rep_fetch;
+
+ $* $src/libbaz-1.1.0.tar.gz \
+ "?$src/libfoo-1.0.0.tar.gz" \
+ "?$src/libbar-1.0.0.tar.gz" 2>>~%EOE%;
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ fetched libbaz/1.1.0
+ unpacked libbaz/1.1.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libbaz-1.1.0.+ is up to date%
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured !1.0.0 available 1.2.0
+ libfoo configured !1.0.0
+ libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop libbaz
+ }
+
+ : unsatisfactory
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t4b && $rep_fetch;
+
+ $* libbar "?$src/libfoo-1.0.0.tar.gz" 2>>EOE != 0
+ error: package libfoo doesn't satisfy its dependents
+ info: libfoo/1.0.0 doesn't satisfy libbar/1.1.0
+ EOE
+ }
+
+ : unsatisfactory-archive
+ :
+ : Same as above but the dependent is specified as an archive.
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t4a && $rep_fetch;
+
+ $* $src/libbar-1.1.0.tar.gz "?$src/libfoo-1.0.0.tar.gz" 2>>EOE != 0
+ error: package libfoo doesn't satisfy its dependents
+ info: libfoo/1.0.0 doesn't satisfy libbar/1.1.0
+ EOE
+ }
+
+ : dependency-alternative
+ :
+ : Note: by specifying an unsatisfactory dependency alternative as an
+ : archive we resolve the alternatives ambiguity here, building libbaz and
+ : skipping unused libbar as a result.
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t8a && $rep_fetch;
+
+ $* fox 2>>EOE != 0;
+ error: unable to select dependency alternative for package fox/1.0.0
+ info: explicitly specify dependency packages to manually select the alternative
+ info: alternative: libbar
+ info: alternative: libbaz
+ info: while satisfying fox/1.0.0
+ EOE
+
+ $* fox "?$src/libbar-0.0.3.tar.gz" 2>>~%EOE%;
+ fetched libbaz/1.1.0
+ unpacked libbaz/1.1.0
+ fetched fox/1.0.0
+ unpacked fox/1.0.0
+ configured libbaz/1.1.0
+ configured fox/1.0.0
+ %info: .+fox-1.0.0.+ is up to date%
+ updated fox/1.0.0
+ EOE
+
+ $pkg_status -r fox libbar >>EOO;
+ !fox configured 1.0.0
+ libbaz configured 1.1.0
+ libbar available 1.0.0
+ EOO
+
+ $pkg_drop fox
+ }
+
+ : upgrade
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t4a $rep/t4b && $rep_fetch;
+
+ $* $src/libbaz-1.1.0.tar.gz \
+ "?$src/libfoo-1.0.0.tar.gz" \
+ "?$src/libbar-1.0.0.tar.gz" 2>!;
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured !1.0.0 available 1.1.0
+ libfoo configured !1.0.0 available 1.1.0
+ libfoo configured !1.0.0 available 1.1.0
+ EOO
+
+ $* --upgrade-recursive libbaz 2>>~%EOE%;
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.1.0
+ unpacked libfoo/1.1.0
+ fetched libbar/1.1.0
+ unpacked libbar/1.1.0
+ configured libfoo/1.1.0
+ configured libbar/1.1.0
+ configured libbaz/1.1.0
+ %info: .+libbaz-1.1.0.+ is up to date%
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured 1.1.0
+ libbar configured !1.1.0
+ libfoo configured !1.1.0
+ libfoo configured !1.1.0
+ EOO
+
+ $pkg_drop libbaz
+ }
+
+ : downgrade
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t5 && $rep_fetch;
+
+ $* $src/libbaz-1.1.0.tar.gz "?$src/libfoo-1.0.0.tar.gz" 2>>~%EOE%;
+ fetched libbar/1.2.0
+ unpacked libbar/1.2.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ fetched libbaz/1.1.0
+ unpacked libbaz/1.1.0
+ configured libbar/1.2.0
+ configured libfoo/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libbaz-1.1.0.+ is up to date%
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured 1.2.0
+ libfoo configured !1.0.0
+ EOO
+
+ $* --plan "" "?$src/libbar-1.0.0.tar.gz" 2>>~%EOE%;
+ replace/downgrade libbar/1.0.0
+ reconfigure libbaz (dependent of libbar)
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.2.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libbaz-1.1.0.+ is up to date%
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured !1.0.0 available 1.2.0
+ libfoo configured !1.0.0
+ libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop libbaz
+ }
+
+ : replace
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t2 && $rep_fetch;
+
+ $* $src/libbaz-1.1.0.tar.gz 2>!;
+
+ $* --plan "" "?$src/libfoo-1.0.0.tar.gz" 2>>~%EOE%;
+ replace/update libfoo/1.0.0
+ reconfigure libbar (dependent of libfoo)
+ reconfigure libbaz (dependent of libbar, libfoo)
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libbar-1.0.0.+ is up to date%
+ %info: .+libbaz-1.1.0.+ is up to date%
+ updated libbar/1.0.0
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured 1.0.0
+ libfoo configured !1.0.0
+ libfoo configured !1.0.0
+ EOO
+
+ $* --plan "" "?$src/libfoo-1.0.0.tar.gz" 2>>~%EOE%;
+ replace/update libfoo/1.0.0
+ reconfigure libbar (dependent of libfoo)
+ reconfigure libbaz (dependent of libbar, libfoo)
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libbar-1.0.0.+ is up to date%
+ %info: .+libbaz-1.1.0.+ is up to date%
+ updated libbar/1.0.0
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured 1.0.0
+ libfoo configured !1.0.0
+ libfoo configured !1.0.0
+ EOO
+
+ $* --plan "" "?$d/libfoo-1.0.0/" 2>>~%EOE%;
+ replace/upgrade libfoo/1.0.0#1
+ reconfigure libbar (dependent of libfoo)
+ reconfigure libbaz (dependent of libbar, libfoo)
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ using libfoo/1.0.0#1 (external)
+ configured libfoo/1.0.0#1
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libbar-1.0.0.+ is up to date%
+ %info: .+libbaz-1.1.0.+ is up to date%
+ updated libbar/1.0.0
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured 1.0.0
+ libfoo configured !1.0.0#1
+ libfoo configured !1.0.0#1
+ EOO
+
+ $pkg_drop libbaz
+ }
+
+ : deorphan-existing-archive
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t2 && $rep_fetch;
+
+ $* $src/libbaz-1.1.0.tar.gz \
+ "?$src/libfoo-1.0.0.tar.gz" \
+ "?$src/libbar-1.0.0.tar.gz" 2>!;
+
+ $* --deorphan ?libfoo 2>>~%EOE%;
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libbar-1.0.0.+ is up to date%
+ %info: .+libbaz-1.1.0.+ is up to date%
+ updated libbar/1.0.0
+ updated libbaz/1.1.0
+ EOE
+
+ $rep_add $rep/t3 && $rep_fetch;
+
+ $* --deorphan libbaz ?libbar 2>>~%EOE%;
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ fetched libbaz/1.0.0
+ unpacked libbaz/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.0.0
+ %info: .+libbaz-1.0.0.+ is up to date%
+ updated libbaz/1.0.0
+ EOE
+
+ $pkg_drop libbaz
+ }
+
+ : deorphan-with-existing-archive
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t5 && $rep_fetch;
+
+ $* $src/libbaz-1.1.0.tar.gz "?$src/libfoo-1.0.0.tar.gz" 2>!;
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured 1.2.0
+ libfoo configured !1.0.0
+ EOO
+
+ $rep_remove $rep/t5;
+
+ $* --deorphan "?$src/libbar-1.2.0.tar.gz" 2>>~%EOE%;
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.2.0
+ fetched libbar/1.2.0
+ unpacked libbar/1.2.0
+ configured libbar/1.2.0
+ configured libbaz/1.1.0
+ %info: .+libbaz-1.1.0.+ is up to date%
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured !1.2.0
+ libfoo configured !1.0.0
+ EOO
+
+ $* --deorphan "?$src/libbar-1.0.0.tar.gz" 2>>~%EOE%;
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.2.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libbaz-1.1.0.+ is up to date%
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop libbaz
+ }
+
+ : system
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t3 && $rep_fetch;
+
+ $* libbaz '?sys:libbar' 2>!;
+
+ $* "?$src/libbar-1.1.0.tar.gz" "?$src/libfoo-1.1.0.tar.gz" 2>>~%EOE%;
+ disfigured libbaz/1.0.0
+ purged libbar/*
+ fetched libfoo/1.1.0
+ unpacked libfoo/1.1.0
+ fetched libbar/1.1.0
+ unpacked libbar/1.1.0
+ configured libfoo/1.1.0
+ configured libbar/1.1.0
+ configured libbaz/1.0.0
+ %info: .+libbaz-1.0.0.+ is up to date%
+ updated libbaz/1.0.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured 1.0.0
+ libbar configured !1.1.0
+ libfoo configured !1.1.0
+ EOO
+
+ $pkg_drop libbaz
+ }
+ }
+
+ : directory
+ :
+ {
+ : pick-directory
+ :
+ : Test that libbar/1.0.0 specified as a directory is picked as a
+ : dependency for libbaz, despite the fact the repository contains
+ : libbar/1.2.0.
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t5 && $rep_fetch;
+
+ $* $d/libbaz-1.1.0/ \
+ "?$d/libfoo-1.0.0/" \
+ "?$d/libbar-1.0.0/" 2>>~%EOE%;
+ using libfoo/1.0.0 (external)
+ using libbar/1.0.0 (external)
+ using libbaz/1.1.0 (external)
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libbaz.+ is up to date%
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured !1.0.0 available 1.2.0
+ libfoo configured !1.0.0
+ libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop libbaz
+ }
+
+ : unsatisfactory
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t4b && $rep_fetch;
+
+ $* libbar "?$d/libfoo-1.0.0/" 2>>EOE != 0
+ error: package libfoo doesn't satisfy its dependents
+ info: libfoo/1.0.0 doesn't satisfy libbar/1.1.0
+ EOE
+ }
+
+ : unsatisfactory-archive
+ :
+ : Same as above but the dependent is specified as a directory.
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t4a && $rep_fetch;
+
+ $* $d/libbar-1.1.0/ "?$d/libfoo-1.0.0/" 2>>EOE != 0
+ error: package libfoo doesn't satisfy its dependents
+ info: libfoo/1.0.0 doesn't satisfy libbar/1.1.0
+ EOE
+ }
+
+ : dependency-alternative
+ :
+ : Note: by specifying an unsatisfactory dependency alternative as a
+ : directory we resolve the alternatives ambiguity here, building libbaz
+ : and skipping unused libbar as a result.
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t8a && $rep_fetch;
+
+ $* fox 2>>EOE != 0;
+ error: unable to select dependency alternative for package fox/1.0.0
+ info: explicitly specify dependency packages to manually select the alternative
+ info: alternative: libbar
+ info: alternative: libbaz
+ info: while satisfying fox/1.0.0
+ EOE
+
+ $* fox "?$d/libbar-0.0.3/" 2>>~%EOE%;
+ fetched libbaz/1.1.0
+ unpacked libbaz/1.1.0
+ fetched fox/1.0.0
+ unpacked fox/1.0.0
+ configured libbaz/1.1.0
+ configured fox/1.0.0
+ %info: .+fox-1.0.0.+ is up to date%
+ updated fox/1.0.0
+ EOE
+
+ $pkg_status -r fox libbar >>EOO;
+ !fox configured 1.0.0
+ libbaz configured 1.1.0
+ libbar available 1.0.0
+ EOO
+
+ $pkg_drop fox
+ }
+
+ : upgrade
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t4a $rep/t4b && $rep_fetch;
+
+ $* $d/libbaz-1.1.0/ \
+ "?$d/libfoo-1.0.0/" \
+ "?$d/libbar-1.0.0/" 2>!;
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured !1.0.0 available 1.1.0
+ libfoo configured !1.0.0 available 1.1.0
+ libfoo configured !1.0.0 available 1.1.0
+ EOO
+
+ $* --upgrade-recursive libbaz 2>>~%EOE%;
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.1.0
+ unpacked libfoo/1.1.0
+ fetched libbar/1.1.0
+ unpacked libbar/1.1.0
+ configured libfoo/1.1.0
+ configured libbar/1.1.0
+ configured libbaz/1.1.0
+ %info: .+libbaz.+ is up to date%
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured 1.1.0
+ libbar configured !1.1.0
+ libfoo configured !1.1.0
+ libfoo configured !1.1.0
+ EOO
+
+ $pkg_drop libbaz
+ }
+
+ : downgrade
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t5 && $rep_fetch;
+
+ $* $d/libbaz-1.1.0/ "?$d/libfoo-1.0.0/" 2>>~%EOE%;
+ fetched libbar/1.2.0
+ unpacked libbar/1.2.0
+ using libfoo/1.0.0 (external)
+ using libbaz/1.1.0 (external)
+ configured libbar/1.2.0
+ configured libfoo/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libbaz.+ is up to date%
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured 1.2.0
+ libfoo configured !1.0.0
+ EOO
+
+ $* --plan "" "?$d/libbar-1.0.0/" 2>>~%EOE%;
+ replace/downgrade libbar/1.0.0
+ reconfigure libbaz (dependent of libbar)
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.2.0
+ using libbar/1.0.0 (external)
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libbaz.+ is up to date%
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured !1.0.0 available 1.2.0
+ libfoo configured !1.0.0
+ libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop libbaz
+ }
+
+ : replace
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t2 && $rep_fetch;
+
+ $* $d/libbaz-1.1.0/ 2>!;
+
+ $* --plan "" "?$d/libfoo-1.0.0/" 2>>~%EOE%;
+ replace/upgrade libfoo/1.0.0#1
+ reconfigure libbar (dependent of libfoo)
+ reconfigure libbaz (dependent of libbar, libfoo)
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ using libfoo/1.0.0#1 (external)
+ configured libfoo/1.0.0#1
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libbar-1.0.0.+ is up to date%
+ %info: .+libbaz.+ is up to date%
+ updated libbar/1.0.0
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured 1.0.0
+ libfoo configured !1.0.0#1
+ libfoo configured !1.0.0#1
+ EOO
+
+ $* --plan "" "?$d/libfoo-1.0.0/" 2>>~%EOE%;
+ replace/update libfoo/1.0.0#1
+ reconfigure libbar (dependent of libfoo)
+ reconfigure libbaz (dependent of libbar, libfoo)
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0#1
+ using libfoo/1.0.0#1 (external)
+ configured libfoo/1.0.0#1
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libbar-1.0.0.+ is up to date%
+ %info: .+libbaz.+ is up to date%
+ updated libbar/1.0.0
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured 1.0.0
+ libfoo configured !1.0.0#1
+ libfoo configured !1.0.0#1
+ EOO
+
+ $* --plan "" "?$src/libfoo-1.0.0.tar.gz" 2>>~%EOE%;
+ replace/downgrade libfoo/1.0.0
+ reconfigure libbar (dependent of libfoo)
+ reconfigure libbaz (dependent of libbar, libfoo)
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0#1
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libbar-1.0.0.+ is up to date%
+ %info: .+libbaz.+ is up to date%
+ updated libbar/1.0.0
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured 1.0.0
+ libfoo configured !1.0.0
+ libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop libbaz
+ }
+
+ : deorphan-existing-directory
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t2 && $rep_fetch;
+
+ $* $d/libbaz-1.1.0/ \
+ "?$d/libfoo-1.0.0/" \
+ "?$d/libbar-1.0.0/" 2>!;
+
+ $* --deorphan ?libfoo 2>>~%EOE%;
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ disfigured libfoo/1.0.0
+ fetched libfoo/1.0.0
+ unpacked libfoo/1.0.0
+ configured libfoo/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libbar.+ is up to date%
+ %info: .+libbaz.+ is up to date%
+ updated libbar/1.0.0
+ updated libbaz/1.1.0
+ EOE
+
+ $rep_add $rep/t3 && $rep_fetch;
+
+ $* --deorphan libbaz ?libbar 2>>~%EOE%;
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.0.0
+ fetched libbar/1.0.0
+ unpacked libbar/1.0.0
+ fetched libbaz/1.0.0
+ unpacked libbaz/1.0.0
+ configured libbar/1.0.0
+ configured libbaz/1.0.0
+ %info: .+libbaz-1.0.0.+ is up to date%
+ updated libbaz/1.0.0
+ EOE
+
+ $pkg_drop libbaz
+ }
+
+ : deorphan-with-existing-directory
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t5 && $rep_fetch;
+
+ $* $d/libbaz-1.1.0/ "?$d/libfoo-1.0.0/" 2>!;
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured 1.2.0
+ libfoo configured !1.0.0
+ EOO
+
+ $rep_remove $rep/t5;
+
+ $* --deorphan "?$d/libbar-1.2.0/" 2>>~%EOE%;
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.2.0
+ using libbar/1.2.0#1 (external)
+ configured libbar/1.2.0#1
+ configured libbaz/1.1.0
+ %info: .+libbaz.+ is up to date%
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured !1.2.0#1
+ libfoo configured !1.0.0
+ EOO
+
+ # Suppress the 'dropping no longer used variable config.bin.exe.lib'
+ # and alike warnings.
+ #
+ rm cfg/libbar/build/config.build;
+
+ $* --deorphan "?$d/libbar-1.0.0/" 2>>~%EOE%;
+ disfigured libbaz/1.1.0
+ disfigured libbar/1.2.0#1
+ using libbar/1.0.0 (external)
+ configured libbar/1.0.0
+ configured libbaz/1.1.0
+ %info: .+libbaz.+ is up to date%
+ updated libbaz/1.1.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured !1.1.0
+ libbar configured !1.0.0
+ libfoo configured !1.0.0
+ libfoo configured !1.0.0
+ EOO
+
+ $pkg_drop libbaz
+ }
+
+ : system
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $rep/t3 && $rep_fetch;
+
+ $* libbaz '?sys:libbar' 2>!;
+
+ $* "?$d/libbar-1.1.0/" "?$d/libfoo-1.1.0/" 2>>~%EOE%;
+ disfigured libbaz/1.0.0
+ purged libbar/*
+ using libfoo/1.1.0 (external)
+ using libbar/1.1.0 (external)
+ configured libfoo/1.1.0
+ configured libbar/1.1.0
+ configured libbaz/1.0.0
+ %info: .+libbaz-1.0.0.+ is up to date%
+ updated libbaz/1.0.0
+ EOE
+
+ $pkg_status -r libbaz >>EOO;
+ !libbaz configured 1.0.0
+ libbar configured !1.1.0
+ libfoo configured !1.1.0
+ EOO
+
+ $pkg_drop libbaz
+ }
+ }
+ }
+}
diff --git a/tests/pkg-build/libbar-0.0.3.tar.gz b/tests/pkg-build/libbar-0.0.3.tar.gz
new file mode 120000
index 0000000..308e978
--- /dev/null
+++ b/tests/pkg-build/libbar-0.0.3.tar.gz
@@ -0,0 +1 @@
+../common/satisfy/libbar-0.0.3.tar.gz \ No newline at end of file
diff --git a/tests/pkg-build/libbar-1.1.0.tar.gz b/tests/pkg-build/libbar-1.1.0.tar.gz
new file mode 120000
index 0000000..12ae746
--- /dev/null
+++ b/tests/pkg-build/libbar-1.1.0.tar.gz
@@ -0,0 +1 @@
+../common/satisfy/libbar-1.1.0.tar.gz \ No newline at end of file
diff --git a/tests/pkg-build/libbar-1.2.0.tar.gz b/tests/pkg-build/libbar-1.2.0.tar.gz
new file mode 120000
index 0000000..3e4eff9
--- /dev/null
+++ b/tests/pkg-build/libbar-1.2.0.tar.gz
@@ -0,0 +1 @@
+../common/satisfy/libbar-1.2.0.tar.gz \ No newline at end of file
diff --git a/tests/pkg-build/t14a b/tests/pkg-build/t14a
new file mode 120000
index 0000000..34b7111
--- /dev/null
+++ b/tests/pkg-build/t14a
@@ -0,0 +1 @@
+../common/satisfy/t14a \ No newline at end of file
diff --git a/tests/pkg-build/t14b b/tests/pkg-build/t14b
new file mode 120000
index 0000000..eeff0af
--- /dev/null
+++ b/tests/pkg-build/t14b
@@ -0,0 +1 @@
+../common/satisfy/t14b \ No newline at end of file
diff --git a/tests/pkg-build/t14c b/tests/pkg-build/t14c
new file mode 120000
index 0000000..01ab194
--- /dev/null
+++ b/tests/pkg-build/t14c
@@ -0,0 +1 @@
+../common/satisfy/t14c \ No newline at end of file
diff --git a/tests/pkg-build/t14d b/tests/pkg-build/t14d
new file mode 120000
index 0000000..463084d
--- /dev/null
+++ b/tests/pkg-build/t14d
@@ -0,0 +1 @@
+../common/satisfy/t14d \ No newline at end of file
diff --git a/tests/pkg-build/t14e b/tests/pkg-build/t14e
new file mode 120000
index 0000000..a9f72b7
--- /dev/null
+++ b/tests/pkg-build/t14e
@@ -0,0 +1 @@
+../common/satisfy/t14e \ No newline at end of file
diff --git a/tests/pkg-build/t14f b/tests/pkg-build/t14f
new file mode 120000
index 0000000..94c4598
--- /dev/null
+++ b/tests/pkg-build/t14f
@@ -0,0 +1 @@
+../common/satisfy/t14f \ No newline at end of file
diff --git a/tests/pkg-build/t14i b/tests/pkg-build/t14i
new file mode 120000
index 0000000..bcc36b2
--- /dev/null
+++ b/tests/pkg-build/t14i
@@ -0,0 +1 @@
+../common/satisfy/t14i \ No newline at end of file
diff --git a/tests/pkg-build/t15 b/tests/pkg-build/t15
new file mode 120000
index 0000000..c7ad857
--- /dev/null
+++ b/tests/pkg-build/t15
@@ -0,0 +1 @@
+../common/compatibility/t15 \ No newline at end of file
diff --git a/tests/pkg-build/t4f b/tests/pkg-build/t4f
new file mode 120000
index 0000000..00f2c86
--- /dev/null
+++ b/tests/pkg-build/t4f
@@ -0,0 +1 @@
+../common/satisfy/t4f \ No newline at end of file
diff --git a/tests/pkg-build/t4i b/tests/pkg-build/t4i
new file mode 120000
index 0000000..41e500e
--- /dev/null
+++ b/tests/pkg-build/t4i
@@ -0,0 +1 @@
+../common/satisfy/t4i \ No newline at end of file
diff --git a/tests/pkg-build/t4j b/tests/pkg-build/t4j
new file mode 120000
index 0000000..3e18229
--- /dev/null
+++ b/tests/pkg-build/t4j
@@ -0,0 +1 @@
+../common/satisfy/t4j \ No newline at end of file
diff --git a/tests/pkg-build/t4k b/tests/pkg-build/t4k
new file mode 120000
index 0000000..a4fa90c
--- /dev/null
+++ b/tests/pkg-build/t4k
@@ -0,0 +1 @@
+../common/satisfy/t4k \ No newline at end of file
diff --git a/tests/pkg-checkout.testscript b/tests/pkg-checkout.testscript
index 69e211c..85fe5e3 100644
--- a/tests/pkg-checkout.testscript
+++ b/tests/pkg-checkout.testscript
@@ -72,7 +72,9 @@ else
$pkg_status style-basic | sed -n -e 's/style-basic available \[.+\] ([^ ]+)/\1/p' | set v;
- $* "style-basic/$v" 2>>"EOE";
+ $* "style-basic/$v" 2>>~"%EOE%";
+ verifying symlinks...
+ %fixing up symlinks...%?
distributing style-basic/$v
checked out style-basic/$v
EOE
@@ -151,6 +153,8 @@ else
$* links/0.0.1 2>>~%EOE%;
checking out links/0.0.1
+ verifying symlinks...
+ %fixing up symlinks...%?
distributing links/0.0.1
checked out links/0.0.1
EOE
@@ -178,12 +182,17 @@ else
if $posix
$* links/1.0.1 2>>~%EOE% != 0
checking out links/1.0.1
+ verifying symlinks...
+ %fixing up symlinks...%?
distributing links/1.0.1
+ %warning: skipping dangling symlink .+%
%error: unable to stat .+%
EOE
else
$* links/1.0.1 2>>~%EOE% != 0
checking out links/1.0.1
+ verifying symlinks...
+ %fixing up symlinks...%?
error: target 'bl' for symlink 'lc' does not exist
info: re-run with -v for more information
warning: repository state is now broken
@@ -193,16 +202,14 @@ else
# Cyclic symlinks in the repository.
#
+ $rep_fetch "$rep/links.git#v1.0.2";
+
if $posix
- $rep_fetch "$rep/links.git#v1.0.2" 2>>~%EOE% != 0
+ $* links/1.0.2 2>>~%EOE% != 0
%.*
%error: unable to iterate over .+%
- warning: repository state is now broken and will be cleaned up
- info: run 'bpkg rep-fetch' to update
EOE
else
- $rep_fetch "$rep/links.git#v1.0.2"
-
$* links/1.0.2 2>>~%EOE% != 0
checking out links/1.0.2
%.*
diff --git a/tests/pkg-configure.testscript b/tests/pkg-configure.testscript
index 2374460..8430cec 100644
--- a/tests/pkg-configure.testscript
+++ b/tests/pkg-configure.testscript
@@ -276,6 +276,11 @@ if ($posix && "$uid" != '0')
: 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
@@ -420,6 +425,11 @@ if ($posix && "$uid" != '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
diff --git a/tests/pkg-drop.testscript b/tests/pkg-drop.testscript
index a2e58f3..a3c48ab 100644
--- a/tests/pkg-drop.testscript
+++ b/tests/pkg-drop.testscript
@@ -386,12 +386,13 @@ $* libfoo/1.0.0 2>>~%EOE% != 0
: keep-drop-options
:
-: Test --drop-dependent, --keep-dependent, --keep-unused, option.
+: Test --drop-dependent, --keep-dependent, --dependent-exit, --keep-unused
+: options.
:
{
+$clone_cfg && $rep_add $rep/t4b && $rep_fetch
- : keep-drop-dependent
+ : keep-exit-drop-dependent
:
{
$clone_cfg && $pkg_build libbar;
@@ -401,6 +402,8 @@ $* libfoo/1.0.0 2>>~%EOE% != 0
libbar (requires libfoo)
EOE
+ $* --dependent-exit 100 libfoo == 100;
+
$* --drop-dependent libfoo 2>>EOE
disfigured libbar
disfigured libfoo
@@ -458,7 +461,9 @@ $* libfoo/1.0.0 2>>~%EOE% != 0
: linked-configs
:
{
- pkg_build = [cmdline] $0 pkg-build --yes 2>!
+ # Get rid of -d option.
+ #
+ pkg_build = [cmdline] $0 pkg-build --yes --sys-no-query 2>!
: 3-configs
:
diff --git a/tests/pkg-fetch.testscript b/tests/pkg-fetch.testscript
index 7d32523..5046c5d 100644
--- a/tests/pkg-fetch.testscript
+++ b/tests/pkg-fetch.testscript
@@ -160,7 +160,14 @@ $* libfoo/1.0.0 2>>/EOE != 0
$* -e $src/t1/libfoo-1.0.0.tar.gz 2>'using libfoo/1.0.0 (external)';
$pkg_status libfoo/1.0.0 1>'libfoo fetched 1.0.0';
- $pkg_purge libfoo 2>'purged libfoo/1.0.0'
+ $* libfoo/1.1.0 2>'fetched libfoo/1.1.0';
+ $pkg_unpack libfoo 2>'unpacked libfoo/1.1.0';
+ test -d cfg/libfoo-1.1.0;
+ $* libfoo/1.1.0 2>'fetched libfoo/1.1.0';
+ test -d cfg/libfoo-1.1.0 == 1;
+ $pkg_status libfoo/1.1.0 1>'libfoo fetched 1.1.0';
+
+ $pkg_purge libfoo 2>'purged libfoo/1.1.0'
}
: purge-existing
diff --git a/tests/pkg-system.testscript b/tests/pkg-system.testscript
index fc4f707..11ed1cc 100644
--- a/tests/pkg-system.testscript
+++ b/tests/pkg-system.testscript
@@ -711,11 +711,11 @@ rep_remove += -d cfg 2>!
$pkg_build foo 'sys:libbar/1' 2>>EOE != 0;
error: unable to satisfy constraints on package libbar
info: command line depends on (libbar == 1)
- info: foo depends on (libbar >= 2)
+ info: foo/2 depends on (libbar >= 2)
info: available sys:libbar/1
info: available sys:libbar/2
+ info: while satisfying foo/2
info: explicitly specify libbar version to manually satisfy both constraints
- info: while satisfying foo/2
EOE
$pkg_drop libbar
@@ -849,11 +849,6 @@ rep_remove += -d cfg 2>!
info: while satisfying foo/2
EOE
- $pkg_build 'sys:libbar' 2>>EOE != 0;
- error: unknown package sys:libbar
- info: consider specifying sys:libbar/*
- EOE
-
$pkg_build foo 'sys:libbar/1' 2>>EOE != 0;
error: dependency libbar >= 2 of package foo is not available in source
info: sys:libbar/1 does not satisfy the constrains
@@ -872,11 +867,26 @@ rep_remove += -d cfg 2>!
$pkg_status libbar >'libbar unknown'
}
+ : find-all
+ :
+ : Test that sys:libbar can be built to hold even if its stub package is not
+ : available from the configured repository but only from its prerequisite
+ : repository.
+ :
+ {
+ $clone_cfg;
+
+ $pkg_build 'sys:libbar' 2>>EOE;
+ configured sys:libbar/*
+ EOE
+
+ $pkg_status libbar >'!libbar configured,system !*'
+ }
+
: syslibbar1-foo-syslibbar-drop-foo
:
- : The overall plan is to build foo ?sys:libbar/2, fail to build sys:libbar
- : and foo 'sys:libbar', but succeed to build foo ?sys:libbar/3 and foo
- : ?sys:libbar.
+ : The overall plan is to build foo ?sys:libbar/2, then foo ?sys:libbar/3,
+ : and then foo ?sys:libbar.
:
{
$clone_cfg;
@@ -896,22 +906,6 @@ rep_remove += -d cfg 2>!
$pkg_status foo >'!foo configured 2';
$pkg_status libbar >'libbar configured,system !2';
- # Fail as libbar while being selected is still unknown (not present in t3
- # repo).
- #
- $pkg_build 'sys:libbar' 2>>EOE != 0;
- error: unknown package sys:libbar
- info: consider specifying sys:libbar/*
- EOE
-
- $pkg_build foo 'sys:libbar' 2>>EOE != 0;
- error: unknown package sys:libbar
- info: consider specifying sys:libbar/*
- EOE
-
- $pkg_status foo 1>'!foo configured 2';
- $pkg_status libbar 1>'libbar configured,system !2';
-
# Build foo and ?sys:libbar/3.
#
$pkg_build foo '?sys:libbar/3' 2>>~%EOE%;
diff --git a/tests/pkg-verify.testscript b/tests/pkg-verify.testscript
index 69c29b0..8057aab 100644
--- a/tests/pkg-verify.testscript
+++ b/tests/pkg-verify.testscript
@@ -8,6 +8,7 @@
# pkg-verify
# |-- foo-1.tar.gz
# |-- foo-2.tar.gz (manifest with unknown name)
+# |-- libbaz-1.0.0.tar.gz (manifest with unsatisfiable toolchain constraint)
# `-- not-a-package.tar.gz
: valid-package
@@ -88,6 +89,7 @@ $* --deep --ignore-unknown --manifest $src/foo-2.tar.gz >>EOO
* First public release.
\
+ changes-type: text/plain
url: http://www.example.org/foo
email: foo-users@example.org
depends: bar == 2
@@ -136,3 +138,29 @@ $* --ignore-unknown --manifest $src/foo-2.tar.gz >>EOO
%error: unable to find bootstrap.build file in package archive .+/foo-3.tar.gz%
EOE
}
+
+: compatibility
+:
+{
+ : fail
+ :
+ $* --manifest $src/libbaz-1.0.0.tar.gz 2>>/~%EOE% != 0
+ %error: unable to satisfy constraint \(build2 >= 65536.0.0\) for package .+/libbaz-1.0.0.tar.gz%
+ % info: available build2 version is .+%
+ EOE
+
+ : success
+ :
+ $* --manifest --ignore-unknown $src/libbaz-1.0.0.tar.gz >>EOO
+ : 1
+ name: libbaz
+ version: 1.0.0
+ summary: libbaz
+ license: MIT
+ description: libbaz library
+ url: http://example.org
+ email: pkg@example.org
+ depends: * build2 >= 65536.0.0
+ depends: * bpkg >= 65536.0.0
+ EOO
+}
diff --git a/tests/pkg-verify/libbaz-1.0.0.tar.gz b/tests/pkg-verify/libbaz-1.0.0.tar.gz
new file mode 120000
index 0000000..a95a5dc
--- /dev/null
+++ b/tests/pkg-verify/libbaz-1.0.0.tar.gz
@@ -0,0 +1 @@
+../common/compatibility/t15/libbaz-1.0.0.tar.gz \ No newline at end of file
diff --git a/tests/remote-git.testscript b/tests/remote-git.testscript
index b4ed398..377277d 100644
--- a/tests/remote-git.testscript
+++ b/tests/remote-git.testscript
@@ -72,6 +72,10 @@ end
# will use the same options as we do for unpacking of package archives (see
# pkg-unpack.cxx).
#
+# Note that on Windows we still use tar rather than bsdtar here, since the
+# later fails for dangling symlinks and we have such symlinks in the
+# repository archives which are used for testing.
+#
git_extract = [cmdline] \
($cxx.target.class != 'windows' \
? tar -C $out_git -xf \
diff --git a/tests/rep-fetch-git-refname.testscript b/tests/rep-fetch-git-refname.testscript
index e9aa4e9..0275d56 100644
--- a/tests/rep-fetch-git-refname.testscript
+++ b/tests/rep-fetch-git-refname.testscript
@@ -93,6 +93,8 @@
%fetching submodule 'libbar/extras' from .+style-basic\.git+%
$info4
%submodule path 'libbar/extras': checked out .+%
+ verifying symlinks...
+ %fixing up symlinks...%?
distributing libfoo/1.0.0
checked out libfoo/1.0.0
EOE
@@ -149,6 +151,8 @@
%fetching submodule 'libbaz' from .+libbaz\.git%
$info2
%submodule path 'libbaz': checked out .+%
+ verifying symlinks...
+ %fixing up symlinks...%?
distributing libfoo/1.0.0
checked out libfoo/1.0.0
EOE
diff --git a/tests/rep-fetch.testscript b/tests/rep-fetch.testscript
index b9b9e05..b713c0c 100644
--- a/tests/rep-fetch.testscript
+++ b/tests/rep-fetch.testscript
@@ -631,11 +631,15 @@ if! $remote
: unchanged-external
:
+ : Test that iteration is still incremented when a non-external package
+ : from a pkg repository is switched to the same unedited external
+ : package.
+ :
{
$clone_cfg && $rep_add $src/libhello-1.0.0;
$* 2>!;
- $pkg_status libhello >'libhello unpacked 1.0.0'
+ $pkg_status libhello >'libhello unpacked 1.0.0 available 1.0.0#1'
}
: changed-external
@@ -655,6 +659,9 @@ if! $remote
: git-rep
:
+ : Test that iteration is still incremented when a non-external package
+ : from a git repository is switched to the same unedited external package.
+ :
if ($git_supported && !$remote)
{
rep = $canonicalize([dir_path] $out_git/state0);
@@ -668,7 +675,7 @@ if! $remote
$rep_add $rep/style.git;
$* 2>!;
- $pkg_status style >"style unpacked 1.0.0";
+ $pkg_status style >"style unpacked 1.0.0 available 1.0.0#1";
$pkg_purge style 2>"purged style/1.0.0"
}
diff --git a/tests/rep-info.testscript b/tests/rep-info.testscript
index 8db405d..2c02c8f 100644
--- a/tests/rep-info.testscript
+++ b/tests/rep-info.testscript
@@ -13,6 +13,8 @@
# | |-- foo-1.tar.gz
# | `-- repositories.manifest
# |
+# |-- t15 (see pkg-build for details)
+# |
# `-- git
# |-- libbar.git -> style-basic.git (prerequisite)
# `-- style-basic.git
@@ -35,6 +37,11 @@
$rc --key $key $out/signed &$out/signed/packages.manifest \
&$out/signed/signature.manifest
+ # Create the compatibility repository.
+ #
+ cp -r $src/t15 $out/compatibility
+ $rc $out/compatibility &$out/compatibility/packages.manifest --ignore-unknown
+
# Create git repositories.
#
$git_extract $src/git/libbar.tar
@@ -125,6 +132,10 @@ $* --name $rep/testing >"pkg:build2.org/rep-info/testing ($rep/testing)"
: dir
:
{
+ # Note that on Windows we still use tar rather than bsdtar here, since
+ # the later fails for dangling symlinks and we have such symlinks in
+ # this repository archive.
+ #
tar ($posix ? : --force-local) -xf $src/git/libbar.tar &state0/***;
$* --type dir "state0/libbar.git" >>~%EOO%d;
@@ -432,3 +443,60 @@ else
EOO
}
}
+
+: compatibility
+:
+{
+ : packages
+ :
+ {
+ $* --packages $rep/compatibility >>EOO
+
+ libbar/1.0.0
+ libbaz/1.0.0
+ libbiz/1.0.0
+ libfoo/1.0.0
+ EOO
+ }
+
+ : package-manifests-ignore-toolchain
+ :
+ {
+ $* --packages --manifest --ignore-unknown $rep/compatibility >>~%EOO%
+ : 1
+ name: libbar
+ version: 1.0.0
+ %.+
+ depends: * build2 >= 0.16.0
+ depends: * bpkg >= 0.16.0
+ %.+
+ :
+ name: libbaz
+ version: 1.0.0
+ summary: libbaz
+ %.+
+ depends: * build2 >= 65536.0.0
+ depends: * bpkg >= 65536.0.0
+ %.+
+ :
+ name: libbiz
+ version: 1.0.0
+ summary: libbiz
+ %.+
+ :
+ name: libfoo
+ version: 1.0.0
+ summary: libfoo
+ %.+
+ EOO
+ }
+
+ : package-manifests-fail
+ :
+ {
+ $* --packages --manifest $rep/compatibility 2>>~%EOE% != 0
+ error: unable to satisfy constraint (build2 >= 65536.0.0) for package libbaz
+ % info: available build2 version is .+%
+ EOE
+ }
+}
diff --git a/tests/rep-info/t15 b/tests/rep-info/t15
new file mode 120000
index 0000000..c7ad857
--- /dev/null
+++ b/tests/rep-info/t15
@@ -0,0 +1 @@
+../common/compatibility/t15 \ No newline at end of file