opam-2.1.5/0002755000175000017500000000000014427463453011521 5ustar stephstephopam-2.1.5/tests/0002755000175000017500000000000014427463453012663 5ustar stephstephopam-2.1.5/tests/reftests/0002755000175000017500000000000014427463453014522 5ustar stephstephopam-2.1.5/tests/reftests/working-dir.test0000644000175000017500000002420414427463453017657 0ustar stephstephN0REP0 ### OPAMYES=1 OPAMJOBS=1 ### opam-version: "2.0" build: [[ "test" "-f" "ongoing.txt" ] [ "cat" "ongoing.txt" ]] ### versionned ### git -C ./ongoing init -q ### git -C ./ongoing config core.autocrlf false ### git -C ./ongoing add -A ### git -C ./ongoing commit -qm "init" ### opam switch create working-dir --empty ### opam pin ./ongoing Package ongoing does not exist, create as a NEW package? [Y/n] y ongoing is now pinned to git+file://${BASEDIR}/ongoing#master (version ~dev) The following actions will be performed: - install ongoing ~dev* <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved ongoing.~dev (no changes) -> installed ongoing.~dev Done. ### new! ### opam-version: "2.0" build: [[ "test" "-f" "newfile.txt" ] [ "cat" "newfile.txt" ]] ### opam remove ongoing The following actions will be performed: - remove ongoing ~dev* <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed ongoing.~dev Done. ### opam install ongoing -v | '.*(/|\\|")test(\.exe)?"? "' -> 'test "' | '.*(/|\\|")cat(\.exe)?"? "' -> 'cat "' <><> Synchronising pinned packages ><><><><><><><><><><><><><><><><><><><><><><> Processing 1/1: [NOTE] Ignoring uncommitted changes in ${BASEDIR}/ongoing (`--working-dir' not active). Processing 1/1: [ongoing.~dev: git] [ongoing.~dev] synchronised (no changes) The following actions will be performed: - install ongoing ~dev* <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Processing 1/3: [ongoing.~dev: git] -> retrieved ongoing.~dev (no changes) Processing 2/3: [ongoing: test ongoing.txt] test "-f" "ongoing.txt" (CWD=${BASEDIR}/OPAM/working-dir/.opam-switch/build/ongoing.~dev) Processing 2/3: [ongoing: cat ongoing.txt] cat "ongoing.txt" (CWD=${BASEDIR}/OPAM/working-dir/.opam-switch/build/ongoing.~dev) - versionned -> compiled ongoing.~dev -> installed ongoing.~dev Done. ### opam install ongoing --working-dir -v | '.*(/|\\|")test(\.exe)?"? "' -> 'test "' | '.*(/|\\|")cat(\.exe)?"? "' -> 'cat "' <><> Synchronising pinned packages ><><><><><><><><><><><><><><><><><><><><><><> Processing 1/1: [ongoing.~dev: git] [ongoing.~dev] synchronised (git+file://${BASEDIR}/ongoing#master) [ongoing] Installing new package description from upstream git+file://${BASEDIR}/ongoing#master The following actions will be performed: - recompile ongoing ~dev* <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Processing 1/3: [ongoing: test newfile.txt] test "-f" "newfile.txt" (CWD=${BASEDIR}/OPAM/working-dir/.opam-switch/build/ongoing.~dev) Processing 1/3: [ongoing: cat newfile.txt] cat "newfile.txt" (CWD=${BASEDIR}/OPAM/working-dir/.opam-switch/build/ongoing.~dev) - new! -> compiled ongoing.~dev -> removed ongoing.~dev -> installed ongoing.~dev Done. ### git -C ./ongoing add ongoing.opam ### git -C ./ongoing commit -qm "forgot a file" ### opam remove ongoing The following actions will be performed: - remove ongoing ~dev* <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed ongoing.~dev Done. ### opam install ongoing -v | grep -v "^#" | '.*(/|\\|")test(\.exe)?"? "' -> 'test "' <><> Synchronising pinned packages ><><><><><><><><><><><><><><><><><><><><><><> Processing 1/1: [NOTE] Ignoring uncommitted changes in ${BASEDIR}/ongoing (`--working-dir' not active). Processing 1/1: [ongoing.~dev: git] [ongoing.~dev] synchronised (no changes) The following actions will be performed: - install ongoing ~dev* <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Processing 1/3: [ongoing.~dev: git] -> retrieved ongoing.~dev (no changes) Processing 2/3: [ongoing: test newfile.txt] test "-f" "newfile.txt" (CWD=${BASEDIR}/OPAM/working-dir/.opam-switch/build/ongoing.~dev) [ERROR] The compilation of ongoing.~dev failed at "test -f newfile.txt". <><> Error report <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> +- The following actions failed | - build ongoing ~dev +- - No changes have been performed '${OPAM} install ongoing -v' failed. # Return code 31 # ### opam install ongoing --working-dir -v | '.*(/|\\|")test(\.exe)?"? "' -> 'test "' | '.*(/|\\|")cat(\.exe)?"? "' -> 'cat "' <><> Synchronising pinned packages ><><><><><><><><><><><><><><><><><><><><><><> Processing 1/1: [ongoing.~dev: git] [ongoing.~dev] synchronised (git+file://${BASEDIR}/ongoing#master) The following actions will be performed: - install ongoing ~dev* <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Processing 1/2: [ongoing: test newfile.txt] test "-f" "newfile.txt" (CWD=${BASEDIR}/OPAM/working-dir/.opam-switch/build/ongoing.~dev) Processing 1/2: [ongoing: cat newfile.txt] cat "newfile.txt" (CWD=${BASEDIR}/OPAM/working-dir/.opam-switch/build/ongoing.~dev) - new! -> compiled ongoing.~dev -> installed ongoing.~dev Done. ### : working dir and not pinned packages ### opam-version:"2.0" build:[ "test" "-f" "present"] ### basedir=`echo $BASEDIR | sed "s/\\\\\\\\/\\\\\\\\\\\\\\\\/g"` echo "url { src:\"file://${basedir}/qux\" }" >> REPO/packages/qux/qux.4/opam ### sh mkurl.sh ### opam update default <><> Updating package repositories ><><><><><><><><><><><><><><><><><><><><><><> [default] synchronised from file://${BASEDIR}/REPO Now run 'opam upgrade' to apply any package updates. ### true ### opam-version: "2.0" build: [[ "test" "-f" "ongoing.txt" ] [ "cat" "ongoing.txt" ]] ### git -C ./ongoing add ongoing.opam ### git -C ./ongoing commit -qm "mixed wd" ### opam-version: "2.0" build: [[ "test" "-f" "newfile.txt" ] [ "cat" "newfile.txt" ]] ### opam install qux The following actions will be performed: - install qux 4 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved qux.4 (file://${BASEDIR}/qux) -> installed qux.4 Done. ### opam remove qux The following actions will be performed: - remove qux 4 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed qux.4 Done. ### opam install qux --working-dir The following actions will be performed: - install qux 4 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> [ERROR] The compilation of qux.4 failed at "test -f present". <><> Error report <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> +- The following actions failed | - build qux 4 +- - No changes have been performed # Return code 31 # ### opam remove qux ongoing [NOTE] qux is not installed. The following actions will be performed: - remove ongoing ~dev* <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed ongoing.~dev Done. ### opam-version: "2.0" ### git -C ./ongoing add ongoing.opam ### git -C ./ongoing commit -qm "mixed wd" ### opam-version: "2.0" build: [[ "test" "-f" "newfile.txt" ] [ "cat" "newfile.txt" ]] ### opam install qux ongoing --working-dir -v | '.*(/|\\|")test(\.exe)?"? "' -> 'test "' | '.*(/|\\|")cat(\.exe)?"? "' -> 'cat "' | grep -v "switch import" <><> Synchronising pinned packages ><><><><><><><><><><><><><><><><><><><><><><> Processing 1/1: [ongoing.~dev: git] [ongoing.~dev] synchronised (git+file://${BASEDIR}/ongoing#master) The following actions will be performed: - install qux 4 - install ongoing ~dev* ===== 2 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Processing 1/4: [ongoing: test newfile.txt] test "-f" "newfile.txt" (CWD=${BASEDIR}/OPAM/working-dir/.opam-switch/build/ongoing.~dev) Processing 1/4: [ongoing: cat newfile.txt] cat "newfile.txt" (CWD=${BASEDIR}/OPAM/working-dir/.opam-switch/build/ongoing.~dev) - new! -> compiled ongoing.~dev Processing 2/4: [qux: test present] -> installed ongoing.~dev Processing 3/4: [qux: test present] test "-f" "present" (CWD=${BASEDIR}/OPAM/working-dir/.opam-switch/build/qux.4) [ERROR] The compilation of qux.4 failed at "test -f present". <><> Error report <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> +- The following actions failed | - build qux 4 +- +- The following changes have been performed | - install ongoing ~dev +- The former state can be restored with: '${OPAM} install qux ongoing --working-dir -v' failed. # Return code 31 # ### : Shows that opam correctly handles updated constraints with --working-dir ### : See https://github.com/ocaml/opam/issues/5178 ### opam pin remove ./ongoing Ok, ongoing is no longer pinned to git+file://${BASEDIR}/ongoing#master (version ~dev) The following actions will be performed: - remove ongoing ~dev <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed ongoing.~dev Done. ### opam-version:"2.0" ### opam-version: "2.0" depends: ["qux"] ### opam install ./ongoing --working-dir Package ongoing does not exist, create as a NEW package? [Y/n] y ongoing is now pinned to git+file://${BASEDIR}/ongoing#master (version ~dev) [ongoing.~dev] synchronised (git+file://${BASEDIR}/ongoing#master) The following actions will be performed: - install qux 4 [required by ongoing] - install ongoing ~dev* ===== 2 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved qux.4 (file://${BASEDIR}/qux) -> installed qux.4 -> installed ongoing.~dev Done. ### opam-version: "2.0" depends: ["qux" {= "1"}] ### opam install ./ongoing --working-dir --show-action [NOTE] Package ongoing is already installed (current version is ~dev). ### opam reinstall ./ongoing --working-dir --show-action <><> Synchronising pinned packages ><><><><><><><><><><><><><><><><><><><><><><> [ongoing.~dev] synchronised (git+file://${BASEDIR}/ongoing#master) [ongoing] Installing new package description from upstream git+file://${BASEDIR}/ongoing#master The following actions would be performed: - downgrade qux 4 to 1 [required by ongoing] - recompile ongoing ~dev* ===== 1 to recompile | 1 to downgrade ===== opam-2.1.5/tests/reftests/empty-conflicts-004.test0000644000175000017500000001216614427463453021050 0ustar stephsteph0070613707 ### OPAMYES=1 OPAMSTRICT=0 ### OPAMVAR_arch=arm64 OPAMVAR_os=linux OPAMVAR_os_family=arch OPAMVAR_os_distribution=archarm ### opam switch create test ocaml-variants.4.14.0+trunk --fake <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml-variants" {= "4.14.0+trunk"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-variants.4.14.0+trunk Faking installation of ocaml-config.2 Faking installation of ocaml.4.14.0 Done. ### opam install --show camlp5 GT ppxlib.0.25.0 [ERROR] Package conflict! * No agreement on the version of ppxlib: - GT -> ppxlib < 0.25 - ppxlib >= 0.25.0 * No agreement on the version of ocaml: - (invariant) -> ocaml-variants = 4.14.0+trunk -> ocaml = 4.14.0 - GT -> ocaml < 4.12 You can temporarily relax the switch invariant with `--update-invariant' * No agreement on the version of ocaml-variants: - (invariant) -> ocaml-variants = 4.14.0+trunk - GT -> ocaml-migrate-parsetree < 2 -> ocaml < 4.06.0 -> ocaml-variants < 4.02.1~ * Missing dependency: - GT -> ocaml < 4.12 -> ocaml-base-compiler < 3.07+1 | ocaml-system < 3.07+1 | ocaml-variants < 3.8~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions: 'sys-ocaml-version = "3.07"' no matching version * Missing dependency: - GT -> ocaml < 4.12 -> ocaml-base-compiler = 3.07+1 | ocaml-system = 3.07+1 | ocaml-variants < 3.8~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions: 'sys-ocaml-version = "3.07+1"' no matching version * Missing dependency: - GT -> ocaml < 4.12 -> ocaml-base-compiler = 3.07+2 | ocaml-system = 3.07+2 | ocaml-variants < 3.8~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions: 'sys-ocaml-version = "3.07+2"' no matching version * Missing dependency: - GT -> ocaml < 4.12 -> ocaml-base-compiler = 3.08.0 | ocaml-system < 3.08.1~ | ocaml-variants < 3.08.1~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions, e.g. 'sys-ocaml-version = "3.08.0"' no matching version * Missing dependency: - GT -> ocaml < 4.12 -> ocaml-base-compiler = 3.08.1 | ocaml-system < 3.08.2~ | ocaml-variants < 3.08.2~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions, e.g. 'sys-ocaml-version = "3.08.1"' no matching version * Missing dependency: - GT -> ocaml < 4.12 -> ocaml-base-compiler = 3.08.2 | ocaml-system < 3.08.3~ | ocaml-variants < 3.08.3~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions, e.g. 'sys-ocaml-version = "3.08.2"' no matching version * Missing dependency: - GT -> ocaml < 4.12 -> ocaml-base-compiler = 3.08.3 | ocaml-system < 3.08.4~ | ocaml-variants < 3.08.4~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions, e.g. 'sys-ocaml-version = "3.08.3"' no matching version * Missing dependency: - GT -> ocaml < 4.12 -> ocaml-base-compiler = 3.08.4 | ocaml-system < 3.08.5~ | ocaml-variants < 3.08.5~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions, e.g. 'sys-ocaml-version = "3.08.4"' no matching version * Missing dependency: - GT -> ocaml < 4.12 -> ocaml-base-compiler = 3.09.0 | ocaml-system < 3.09.1~ | ocaml-variants < 3.09.1~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions, e.g. 'sys-ocaml-version = "3.09.0"' no matching version * Missing dependency: - GT -> ocaml-migrate-parsetree < 2 -> ocaml < 4.09.0 -> ocaml-variants < 4.08.1~ -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' * Missing dependency: - GT -> ocaml-migrate-parsetree < 2 -> ocaml < 4.09.0 -> ocaml-variants < 4.08.3~ -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' * Missing dependency: - GT -> ocaml-migrate-parsetree < 2 -> ocaml < 4.10 -> ocaml-variants < 4.09.3~ -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' * Missing dependency: - GT -> ocaml-migrate-parsetree < 2 -> ocaml < 4.11 -> ocaml-variants < 4.10.1~ -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' * Missing dependency: - GT -> ocaml-migrate-parsetree < 2 -> ocaml < 4.11 -> ocaml-variants < 4.10.4~ -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' * Missing dependency: - GT -> ocaml-migrate-parsetree < 2 -> ocaml < 4.12 -> ocaml-variants < 4.11.3~ -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' No solution found, exiting # Return code 20 # opam-2.1.5/tests/reftests/empty-conflicts-001.test0000644000175000017500000000513514427463453021043 0ustar stephsteph297366c ### OPAMYES=1 OPAMSTRICT=0 ### OPAMVAR_arch=x86_64 OPAMVAR_os=linux OPAMVAR_os_family=arch OPAMVAR_os_distribution=archarm ### opam switch create test ocaml-base-compiler.4.07.1 --fake <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml-base-compiler" {= "4.07.1"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-base-compiler.4.07.1 Faking installation of ocaml-config.1 Faking installation of ocaml.4.07.1 Done. ### opam install --show h2-mirage.0.9.0 [ERROR] Package conflict! * No agreement on the version of ocaml: - (invariant) -> ocaml-base-compiler = 4.07.1 -> ocaml = 4.07.1 - h2-mirage >= 0.9.0 -> conduit-mirage >= 2.0.2 -> ocaml >= 4.08.0 You can temporarily relax the switch invariant with `--update-invariant' * No agreement on the version of ocaml-base-compiler: - (invariant) -> ocaml-base-compiler = 4.07.1 - h2-mirage >= 0.9.0 -> conduit-mirage >= 2.0.2 -> tls -> ocaml >= 4.08.0 -> ocaml-base-compiler = 4.08.0 * No agreement on the version of cstruct: - h2-mirage >= 0.9.0 -> conduit-mirage >= 2.0.2 -> tls -> cstruct < 4.0.0 - h2-mirage >= 0.9.0 -> gluten-mirage >= 0.3.0 -> cstruct >= 6.0.0 * No agreement on the version of cstruct: - h2-mirage >= 0.9.0 -> conduit-mirage >= 2.0.2 -> tls -> cstruct < 6.0.0 - h2-mirage >= 0.9.0 -> gluten-mirage >= 0.3.0 -> cstruct >= 6.0.0 * Missing dependency: - h2-mirage >= 0.9.0 -> conduit-mirage >= 2.0.2 -> dns-client >= 5.0.0 -> mirage-crypto-rng >= 0.8.0 -> mirage-crypto = 0.8.1 unmet availability conditions: 'false' * Missing dependency: - h2-mirage >= 0.9.0 -> conduit-mirage >= 2.0.2 -> dns-client >= 5.0.0 -> mirage-crypto-rng >= 0.8.0 -> mirage-crypto = 0.8.2 unmet availability conditions: 'false' * Missing dependency: - h2-mirage >= 0.9.0 -> conduit-mirage >= 2.0.2 -> dns-client >= 5.0.0 -> mirage-crypto-rng >= 0.8.0 -> mirage-crypto = 0.8.3 unmet availability conditions: 'false' * Missing dependency: - h2-mirage >= 0.9.0 -> conduit-mirage >= 2.0.2 -> dns-client >= 5.0.0 -> mirage-crypto-rng >= 0.8.0 -> mirage-crypto = 0.8.4 unmet availability conditions: 'false' * Missing dependency: - h2-mirage >= 0.9.0 -> conduit-mirage >= 2.0.2 -> tls -> nocrypto < 0.2.0 -> ocaml < 4.02.0 -> ocaml-variants >= 3.09.3 -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' No solution found, exiting # Return code 20 # opam-2.1.5/tests/reftests/empty-conflicts-006.test0000644000175000017500000000330514427463453021045 0ustar stephstephc1842d168d ### OPAMYES=1 OPAMSTRICT=0 ### OPAMVAR_arch=arm64 OPAMVAR_os=linux OPAMVAR_os_family=arch OPAMVAR_os_distribution=archarm ### opam var --global enable-ocaml-beta-repository=true Added '[enable-ocaml-beta-repository "true" "Set through 'opam var'"]' to field global-variables in global configuration ### opam switch create test ocaml-variants.4.12.0+trunk --fake <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml-variants" {= "4.12.0+trunk"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-beta.disabled Faking installation of ocaml-variants.4.12.0+trunk Faking installation of ocaml-config.1 Faking installation of ocaml.4.12.0 Done. ### : Fixed by https://github.com/ocaml/opam/pull/4982 ### opam install --show gen_js_api.1.0.6 [ERROR] Package conflict! * No agreement on the version of ocaml: - (invariant) -> ocaml-variants = 4.12.0+trunk -> ocaml = 4.12.0 - gen_js_api >= 1.0.6 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.06.0 You can temporarily relax the switch invariant with `--update-invariant' * No agreement on the version of ocaml-migrate-parsetree: - gen_js_api >= 1.0.6 -> ocaml-migrate-parsetree < 2.0.0 - gen_js_api >= 1.0.6 -> ppxlib >= 0.9 -> ocaml-migrate-parsetree >= 2.1.0 * No agreement on the version of ocaml-variants: - (invariant) -> ocaml-variants = 4.12.0+trunk - gen_js_api >= 1.0.6 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.06.0 -> ocaml-variants < 3.09.2~ No solution found, exiting # Return code 20 # opam-2.1.5/tests/reftests/legacy-git.test0000644000175000017500000011363614427463453017460 0ustar stephstephN0REP0 ### : UTILITARY SCRIPTS : ### set -ue cd $1 git init >/dev/null 2>&1 git config --local core.autocrlf false echo '*.sh text eol=lf' >.gitattributes [ $# -lt 2 ] || touch "$2" git add -A git config --local user.name 'OPAM test environment' git config --local user.email noreply@ocaml.org git commit -qm "Initial commit" echo "OK" ### set -ue PKG=$1; shift ARCHIVE=$1; shift if [ ! -e "packages/${ARCHIVE}" ]; then ( cd packages && tar czf ${ARCHIVE} ${ARCHIVE%.tar.gz}; ) fi MD5=$(openssl md5 packages/${ARCHIVE} | cut -d' ' -f2) echo 'src: "http://dev.null" checksum: "'$MD5'"' > REPO/packages/${PKG}/url CACHEDIR=REPO/cache/md5/$(echo $MD5 |head -c2) mkdir -p $CACHEDIR cp "packages/$ARCHIVE" "$CACHEDIR/$MD5" ### : INIT : ### rm REPO/repo ### rmdir REPO/packages ### sh git-init.sh REPO README OK ### opam repo add test REPO --set-default --yes [test] Initialised [WARNING] The repository 'test' at git+file://${BASEDIR}/REPO doesn't have a 'repo' file, and might not be compatible with this version of opam. [NOTE] Repository at git+file://${BASEDIR}/REPO doesn't define its version, assuming it's 1.2. <><> Upgrading repositories from older opam format ><><><><><><><><><><><><><><> Upgrading repository "test"... ### opam repo remove default -a ### : GEN FILES : ### (* API version *) opam-version: "1" name: "P1" version: "0" setenv: [P1 = "version0"] substs: [ "P1.config" "P1.install" ] build: [ [ "ocamlc" "-a" "p1.ml" "-o" "p1.cma" ] [ "ocamlopt" "-a" "p1.ml" "-o" "p1.cmxa" ] ] depends: ["ocaml"] ### (* API version *) opam-version: "1" name: "P1" # Test # Toto (* Version are arbitrary strings *) version: "1" maintainer: "contact@ocamlpro.com" (* The command to run *) build: [ ["./build.sh"] # HAHAH ["this" "should" "never" "run"] {ocaml:version > "z100"} [make "this" ocaml:version "also"] {os = "NO"} ["echo" "HAHA!"] {ocaml:version = "10"} ["echo" make share ocaml:version] ["this as well" {os = "myOS"}] ] available: os != "NO" | os != "NO" & os != "YES" (* List of files to substitute env variables *) substs: [ "P1.config" "P1.install" ] (* Libraries *) libraries: [ "p1" ] (* External dependencies *) depexts: [ [ ["debian" "amd64"] ["apt" "dpkg"] ] [ ["osx" ] ["curl"] ] ] messages: [ "I ll always bother you displaying this message" ] post-messages: [ "Thanks SO MUCH for installing this humble package" "Everything went well" {success} "Nooo, something went wrong, this makes me feel sooo sad..." {failure} ] bug-reports: "TEST.com" setenv: [P1 = "version1"] depends: [ "ocaml" {(!= "20" | != "10") & (= "20" | = "10" | = "10+a+b" | = "system")} ] ### opam-version: "1" name: "P1" version: "2" depends: [ "ocaml" {<= "10" | = "system"} ] maintainer: "contact@ocamlpro.com" substs: [ "P1.config" "P1.install" ] libraries: [ "p1" ] build: [ "./build.sh" ] setenv: [P1 = "version2"] ### opam-version: "1" name: "P2" version: "1" maintainer: "contact@ocamlpro.com" substs: [ "config" "P2.config" "P2.install" ] depends: ["ocaml" "P1"] libraries: [ "p2" ] build: [ "./build.sh" ] ### opam-version: "1" name: "P3" version: "1~weird-version.test" maintainer: "contact@ocamlpro.com" depends: ["ocaml" "P1"] substs: [ "P3.config" "P3.install" ] build: [ "./build.sh" ] ### opam-version: "1" name: "P4" version: "1" maintainer: "contact@ocamlpro.com" depends: ["ocaml" "P2" "P3"] build: [ "./build.sh" ] ### opam-version: "1" name: "P4" version: "2" maintainer: "contact@ocamlpro.com" depends: [ "P1" { <= "1" } "P2" "P3" ] build: [ "./build.sh" ] ### opam-version: "1" name: "P4" version: "3" maintainer: "contact@ocamlpro.com" depends: [ "P2" "P3" ] build: [ "./build.sh" ] ### (* API version *) opam-version: "1" name: "P5" version: "1" maintainer: "contact@ocamlpro.com" depends: ["ocaml" "P1"] depopts: [ "P2" ] build: [ [ "./build.sh" ] ] install: [ [ "mkdir" "-p" "%{lib}%/p5" ] [ "touch" "%{lib}%/p5/p2_present" ] {P2:installed} [ "touch" "%{lib}%/p5/p2_absent" ] {!P2:installed} ] remove: [ "rm" "-rf" "%{lib}%/p5" ] ### opam-version: "1.3~dev4" variables { compiler: "10+a+b" native: true native-tools: true native-dynlink: true stubsdir: "%{lib}%/stublibs" } ### opam-version: "1.3" maintainer: "contact@ocamlpro.com" # depends: ["P1" "P2" "P3" "P4"] flags: compiler setenv: TEST = "1" ### opam-version: "1.3~dev4" variables { compiler: "20" native: true native-tools: true native-dynlink: true stubsdir: "%{lib}%/stublibs" } ### opam-version: "1.3" maintainer: "contact@ocamlpro.com" flags: compiler setenv: TEST = "1" ### #!/bin/sh -ue if ! OCAMLC=$(command -v ocamlc); then echo "No OCaml compiler was found on the system" >&2 exit 2 fi if [ $($OCAMLC -config | sed -ne "s/os_type: //p" | tr -d '\r') = Win32 ] ; then OCAMLC_FILE=$(echo $OCAMLC| cygpath -w -f - | sed -e 's/\\/\\\\/g') LIBDIR=$("$OCAMLC" -where | tr -d '\r' | cygpath -f -) else OCAMLC_FILE=$OCAMLC LIBDIR=$("$OCAMLC" -where) fi STUBLIBS=$(cat "$LIBDIR/ld.conf" | tr -d '\r' | tr '\n' ':' | sed -e 's/\\/\\\\/g') echo "Using ocaml compiler found at $OCAMLC with base lib at $LIBDIR" bool() { if "$@"; then echo "true"; else echo "false"; fi } cat >ocaml.config < opam-version: "1.3.0~dev4" maintainer: "louis.gesbert@ocamlpro.com" build: ["sh" "-uex" "./gen.sh"] setenv: [CAML_LD_LIBRARY_PATH = "%{lib}%:%{_:ocaml-stublibs}%"] depends: [ ] flags: compiler ### (* API version *) opam-version: "1" name: "P1" version: "0" setenv: [P1 = "version0"] substs: [ "P1.config" "P1.install" ] build: [ [ "ocamlc" "-a" "p1.ml" "-o" "p1.cma" ] [ "ocamlopt" "-a" "p1.ml" "-o" "p1.cmxa" ] ] depends: ["ocaml"] ### opam-version: "1.3" variables { asmcomp: "-I %{lib}%/P1" bytecomp: "-I %{lib}%/P1" asmlink: "-I %{lib}%/P1 p1.cmxa" bytelink: "-I %{lib}%/P1 p1.cma" LOCAL: "local" l: "L" FOO: "foo" bar: true } ### lib: [ "p1.cmi" "p1.cma" "p1.cmxa" "p1.%{ext_lib}%" ] ### let x () = try Random.int 10 with _ -> 0 ### #! /bin/sh -eu if [ -n "${P1:-}" ]; then echo "P1 ('$P1') should not be set yet" >&2 exit 12 fi ocamlc -a p1.ml -o p1.cma ocamlopt -a p1.ml -o p1.cmxa ### chmod a+x packages/P1-1/build.sh ### (* API version *) opam-version: "1" name: "P1" # Test # Toto (* Version are arbitrary strings *) version: "1" maintainer: "contact@ocamlpro.com" (* The command to run *) build: [ ["./build.sh"] # HAHAH ["this" "should" "never" "run"] {ocaml:version > "z100"} [make "this" ocaml:version "also"] {os = "NO"} ["echo" "HAHA!"] {ocaml:version = "10"} ["echo" make share ocaml:version] ["this as well" {os = "myOS"}] ] available: os != "NO" | os != "NO" & os != "YES" (* List of files to substitute env variables *) substs: [ "P1.config" "P1.install" ] (* Libraries *) libraries: [ "p1" ] (* External dependencies *) depexts: [ [ ["debian" "amd64"] ["apt" "dpkg"] ] [ ["osx" ] ["curl"] ] ] messages: [ "I ll always bother you displaying this message" ] post-messages: [ "Thanks SO MUCH for installing this humble package" "Everything went well" {success} "Nooo, something went wrong, this makes me feel sooo sad..." {failure} ] bug-reports: "TEST.com" setenv: [P1 = "version1"] depends: [ "ocaml" {(!= "20" | != "10") & (= "20" | = "10" | = "10+a+b" | = "system")} ] ### opam-version: "1.3" variables { asmcomp: "-I %{lib}%/P1" bytecomp: "-I %{lib}%/P1" asmlink: "-I %{lib}%/P1 p1.cmxa" bytelink: "-I %{lib}%/P1 p1.cma" LOCAL: "local" l: "L" FOO: "foo" bar: true } ### lib: [ "p1.cmi" "p1.cma" "p1.cmxa" "p1.%{ext_lib}%" "?this_file_will_not_exist_but_that's_ok" ] share: [ "build.sh" ] doc: [ "p1.cmi" { "foo/bar/index.html" } ] ### let x () = try Random.int 10 with _ -> 0 ### A very useful package ### #! /bin/sh -eu if [ -n "${P1:-}" ]; then echo "P1 ('$P1') should not be set yet" >&2 exit 12 fi ocamlc -a p1.ml -o p1.cma ocamlopt -a p1.ml -o p1.cmxa ### chmod a+x packages/P1-2/build.sh ### opam-version: "1" name: "P1" version: "2" depends: [ "ocaml" {<= "10" | = "system"} ] maintainer: "contact@ocamlpro.com" substs: [ "P1.config" "P1.install" ] libraries: [ "p1" ] build: [ "./build.sh" ] setenv: [P1 = "version2"] ### opam-version: "1.3" variables { asmcomp: "-I %{lib}%/P1" bytecomp: "-I %{lib}%/P1" asmlink: "-I %{lib}%/P1 p1.cmxa" bytelink: "-I %{lib}%/P1 p1.cma" LOCAL: "local" l: "L" FOO: "foo" bar: true } ### lib: [ "p1.cma" "p1.cmxa" "p1.%{ext_lib}%" "p1.cmi" ] ### let x () = failwith "the new version is not very good" ### A very useful package ### #! /bin/sh -eu OFLAGS="`opam var P1:asmcomp | tr -d '\r'`" CFLAGS="`opam var P1:bytecomp | tr -d '\r'`" echo "Bytecode Compilation" ocamlc ${CFLAGS} -a p2.ml -o p2.cma if which ocamlopt >/dev/null 2>&1; then echo "Native Compilation" ocamlopt ${OFLAGS} -a p2.ml -o p2.cmxa fi ### chmod a+x packages/P2/build.sh ### Foo is %{P1:FOO}% Foo also contains a variable with %{P1:l}%. Funny, isn\'t it? ### opam-version: "1" name: "P2" version: "1" maintainer: "contact@ocamlpro.com" substs: [ "config" "P2.config" "P2.install" ] depends: ["ocaml" "P1"] libraries: [ "p2" ] build: [ "./build.sh" ] ### opam-version: "1.3" variables { asmcomp: "-I %{lib}%/P2" bytecomp: "-I %{lib}%/P2" asmlink: "-I %{lib}%/P2 p2.cmxa" bytelink: "-I %{lib}%/P2 p2.cma" requires: "p1" } ### lib: [ "p2.cma" "p2.cmxa" "p2.%{ext_lib}%" "p2.cmi" ] ### let g () = P1.x () ### An other very useful package The description can go on multiple lines. The first line is the package synopsis, and the rest is the package description. ### #! /bin/sh -eu OPAM=$(cygpath ${OPAM} 2>/dev/null || echo ${OPAM}) echo "Building P3 version ${OPAM_PACKAGE_VERSION}" if [ "x${OPAM_PACKAGE_NAME}" = "xP3" ]; then LIB=$(${OPAM} var lib | tr -d '\r') ocamlc -a -I $LIB/P1 -I $LIB/P2 p3.ml -o p3.cma ocamlopt -a -I $LIB/P1 -I $LIB/P2 p3.ml -o p3.cmxa ocamlc -a -I $LIB/P1 -I $LIB/P2 p3_bar.ml -o p3_bar.cma ocamlopt -a -I $LIB/P1 -I $LIB/P2 p3_bar.ml -o p3_bar.cmxa else exit 1 fi ### chmod a+x packages/P3/build.sh ### opam-version: "1" name: "P3" version: "1~weird-version.test" maintainer: "contact@ocamlpro.com" depends: ["ocaml" "P1"] substs: [ "P3.config" "P3.install" ] build: [ "./build.sh" ] ### let f () = Printf.printf "foo\n%!" let _ = P3.z () ### opam-version: "1.3" variables { asmcomp : "-I %{lib}%/P3" bytecomp: "-I %{lib}%/P3" asmlink : "-I %{lib}%/P3 p3.cmxa p3_bar.cmxa" bytelink: "-I %{lib}%/P3 p3.cma p3_bar.cma" requires: "p1" } ### lib: [ (* p3 *) "p3.cma" "p3.cmxa" "p3.%{ext_lib}%" "p3.cmi" (* p3_bar *) "p3_bar.cma" "p3_bar.cmxa" "p3_bar.%{ext_lib}%" "p3_bar.cmi" ] ### let z () = try P1.x () with _ -> 0 ### Testing version names ### opam-version: "1" name: "P4" version: "1" maintainer: "contact@ocamlpro.com" depends: ["ocaml" "P2" "P3"] build: [ "./build.sh" ] ### opam-version: "1" name: "P4" version: "2" maintainer: "contact@ocamlpro.com" depends: [ "P1" { <= "1" } "P2" "P3" ] build: [ "./build.sh" ] ### opam-version: "1" name: "P4" version: "3" maintainer: "contact@ocamlpro.com" depends: [ "P2" "P3" ] build: [ "./build.sh" ] ### #! /bin/sh -ex OPAM=$(cygpath ${OPAM} 2>/dev/null || echo ${OPAM}) opam() { $OPAM "$@" | tr -d '\r'; } if [ $OPAM_PACKAGE_VERSION -eq 2 ]; then if [ "X${P1:-}" != "Xversion1" ]; then echo "P1 not set to version1 while P1.1 should be installed" >&2 exit 12 fi else if [ -z "X${P1:-}" ]; then echo "P1 not set while P1 should be installed" >&2 exit 12 fi fi echo "Building P4 with ${OPAM}" COMP="-I $(opam var P1:lib) -I $(opam var P2:lib) -I $(opam var P3:lib)" LINK="p1.cmxa p2.cmxa p3.cmxa p3_bar.cmxa" OCAMLC=ocamlc if which ocamlopt >/dev/null 2>&1; then OCAMLC=ocamlopt; fi $OCAMLC ${COMP} ${LINK} p4.ml -o p4.foo.exe echo "TEST=${TEST}" ### chmod a+x packages/P4/build.sh ### bin: [ "p4.foo.exe" { "p4.exe" } "p4.foo.exe" ] ### let f = try P3_bar.f (); P1.x () with _ -> P3.z () let () = let t = try Sys.getenv "TEST" with _ -> "" in Printf.printf "TEST=%s\n%!" t ### Testing transitive closure ### #! /bin/sh -eu OPAM=$(cygpath ${OPAM} 2>/dev/null || echo ${OPAM}) FLAGS="-I `${OPAM} var P1:lib | tr -d '\r'`" echo "Bytecode Compilation" ocamlc ${FLAGS} -a p5.ml -o p5.cma if which ocamlopt >/dev/null 2>&1; then echo "Native Compilation" ocamlopt ${FLAGS} -a p5.ml -o p5.cmxa fi ### chmod a+x packages/P5/build.sh ### (* API version *) opam-version: "1" name: "P5" version: "1" maintainer: "contact@ocamlpro.com" depends: ["ocaml" "P1"] depopts: [ "P2" ] build: [ [ "./build.sh" ] ] install: [ [ "mkdir" "-p" "%{lib}%/p5" ] [ "touch" "%{lib}%/p5/p2_present" ] {P2:installed} [ "touch" "%{lib}%/p5/p2_absent" ] {!P2:installed} ] remove: [ "rm" "-rf" "%{lib}%/p5" ] ### let g () = P1.x () ### Testing optional dependencies ### : UPLOAD : ### cp -r packages/ocaml REPO/packages ### mkdir -p REPO/packages/P1.0 ### cp packages/P1-0.opam REPO/packages/P1.0/opam ### sh mkurl.sh P1.0 P1-0.tar.gz ### mkdir -p REPO/packages/P1.1 ### cp packages/P1-1.opam REPO/packages/P1.1/opam ### cp packages/P1-1/README REPO/packages/P1.1/descr ### sh mkurl.sh P1.1 P1-1.tar.gz ### mkdir -p REPO/packages/P2.1 ### cp packages/P2/README REPO/packages/P2.1/descr ### cp packages/P2.opam REPO/packages/P2.1/opam ### sh mkurl.sh P2.1 P2.tar.gz ### mkdir -p REPO/packages/P3.1~weird-version.test ### cp packages/P3.opam REPO/packages/P3.1~weird-version.test/opam ### cp packages/P3/README REPO/packages/P3.1~weird-version.test/descr ### sh mkurl.sh P3.1~weird-version.test P3.tar.gz ### mkdir -p REPO/packages/P4.1 ### cp packages/P4-1.opam REPO/packages/P4.1/opam ### cp packages/P4/README REPO/packages/P4.1/descr ### sh mkurl.sh P4.1 P4.tar.gz ### mkdir -p REPO/packages/P5.1 ### cp packages/P5.opam REPO/packages/P5.1/opam ### cp packages/P5/README REPO/packages/P5.1/descr ### sh mkurl.sh P5.1 P5.tar.gz ### git -C REPO/packages/ocaml.system add * ### git -C REPO/packages/ocaml.system commit -qm "Adding ocaml.system" ### git -C REPO/packages/ocaml.20 add * ### git -C REPO/packages/ocaml.20 commit -qm "Adding ocaml.20" ### git -C REPO/packages/ocaml.10+a+b add * ### git -C REPO/packages/ocaml.10+a+b commit -qm "Adding ocaml.10+a+b" ### git: "GIT/P1-0" ### git -C REPO/packages/P1.0/ add * ### git -C REPO/packages/P1.0/ commit -qm "Adding P0" ### git: "GIT/P1-1" ### git -C REPO/packages/P1.1/ add * ### git -C REPO/packages/P1.1/ commit -qm "Adding P1" ### git: "GIT/P2" ### git -C REPO/packages/P2.1/ add * ### git -C REPO/packages/P2.1/ commit -qm "Adding P2" ### git: "GIT/P3" ### git -C REPO/packages/P3.1~weird-version.test/ add * ### git -C REPO/packages/P3.1~weird-version.test/ commit -qm "Adding P3" ### git: "GIT/P4" ### git -C REPO/packages/P4.1/ add * ### git -C REPO/packages/P4.1/ commit -qm "Adding P4" ### git: "GIT/P5" ### git -C REPO/packages/P5.1/ add * ### git -C REPO/packages/P5.1/ commit -qm "Adding P5" ### rm -rf GIT ### mkdir GIT ### cp -r packages/P1-0 GIT/ ### cp -r packages/P1-1 GIT/ ### cp -r packages/P2 GIT/ ### cp -r packages/P3 GIT/ ### cp -r packages/P4 GIT/ ### cp -r packages/P5 GIT/ ### sh git-init.sh GIT/P1-0 OK ### sh git-init.sh GIT/P1-1 OK ### sh git-init.sh GIT/P2 OK ### sh git-init.sh GIT/P3 OK ### sh git-init.sh GIT/P4 OK ### sh git-init.sh GIT/P5 OK ### opam update <><> Updating package repositories ><><><><><><><><><><><><><><><><><><><><><><> [test] synchronised from git+file://${BASEDIR}/REPO [WARNING] The repository 'test' at git+file://${BASEDIR}/REPO doesn't have a 'repo' file, and might not be compatible with this version of opam. [NOTE] Repository at git+file://${BASEDIR}/REPO doesn't define its version, assuming it's 1.2. <><> Upgrading repositories from older opam format ><><><><><><><><><><><><><><> Upgrading repository "test"... Updated ${OPAMTMP}/test/packages/P1.0/opam Updated ${OPAMTMP}/test/packages/P1.1/opam Updated ${OPAMTMP}/test/packages/P2.1/opam Updated ${OPAMTMP}/test/packages/P3.1~weird-version.test/opam Updated ${OPAMTMP}/test/packages/P4.1/opam Updated ${OPAMTMP}/test/packages/P5.1/opam Now run 'opam upgrade' to apply any package updates. ### opam switch create system "--formula=[\"ocaml\" {= \"system\"}]" <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml" {= "system"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed ocaml.system Done. ### opam exec -- ocamlc -config | grep '^ext_lib:' | '^.*\.' -> '' >$ LIB_EXT ### opam var ext_lib=$LIB_EXT --switch system | '.*' -> '\c' ### : INSTALL-REMOVE : ### opam list -is --columns=package ocaml.system ### opam install P1 The following actions will be performed: - install P1 1 I ll always bother you displaying this message <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (git+file://${BASEDIR}/GIT/P1-1) -> installed P1.1 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### opam list -is --columns=package ocaml.system P1.1 ### opam remove P1 The following actions will be performed: - remove P1 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed P1.1 Done. ### opam list -is --columns=package ocaml.system ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml system P1 -- A very useful package P2 -- An other very useful package P3 -- Testing version names P4 -- Testing transitive closure P5 -- Testing optional dependencies ### : INSTALL-OPT : ### opam list -is --columns=package ocaml.system ### opam install --yes P5 | unordered The following actions will be performed: - install P1 1 [required by P5] I ll always bother you displaying this message - install P5 1 ===== 2 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (git+file://${BASEDIR}/GIT/P1-1) -> retrieved P5.1 (git+file://${BASEDIR}/GIT/P5) -> installed P1.1 -> installed P5.1 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### test -f ${OPAMROOT}/system/lib/p5/p2_absent ### opam list -is --columns=package ocaml.system P1.1 P5.1 ### opam remove P5 The following actions will be performed: - remove P5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed P5.1 Done. ### opam list -is --columns=package ocaml.system P1.1 ### opam install P5 The following actions will be performed: - install P5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P5.1 (git+file://${BASEDIR}/GIT/P5) -> installed P5.1 Done. ### opam list -is --columns=package ocaml.system P1.1 P5.1 ### opam remove P5 -a --yes The following actions will be performed: - remove P5 1 - remove P1 1 ===== 2 to remove ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed P5.1 -> removed P1.1 Done. ### opam list -is --columns=package ocaml.system ### opam install P5 --yes | unordered The following actions will be performed: - install P1 1 [required by P5] I ll always bother you displaying this message - install P5 1 ===== 2 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (git+file://${BASEDIR}/GIT/P1-1) -> retrieved P5.1 (git+file://${BASEDIR}/GIT/P5) -> installed P1.1 -> installed P5.1 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### opam list -is --columns=package ocaml.system P1.1 P5.1 ### opam install P2 --yes | unordered The following actions will be performed: - install P2 1 - recompile P5 1 [uses P2] ===== 1 to install | 1 to recompile ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P2.1 (git+file://${BASEDIR}/GIT/P2) -> retrieved P5.1 (no changes) -> removed P5.1 -> installed P2.1 -> installed P5.1 Done. ### test -f ${OPAMROOT}/system/lib/p5/p2_present ### opam list -is --columns=package ocaml.system P1.1 P2.1 P5.1 ### opam remove P5 -a The following actions will be performed: - remove P5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed P5.1 Done. ### opam list -is --columns=package ocaml.system P1.1 P2.1 ### opam remove P2 -a --yes The following actions will be performed: - remove P2 1 - remove P1 1 ===== 2 to remove ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed P2.1 -> removed P1.1 Done. ### opam list -is --columns=package ocaml.system ### opam install P1 P2 P5 | unordered The following actions will be performed: - install P1 1 I ll always bother you displaying this message - install P2 1 - install P5 1 ===== 3 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (git+file://${BASEDIR}/GIT/P1-1) -> retrieved P2.1 (git+file://${BASEDIR}/GIT/P2) -> installed P1.1 -> retrieved P5.1 (git+file://${BASEDIR}/GIT/P5) -> installed P2.1 -> installed P5.1 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### test -f ${OPAMROOT}/system/lib/p5/p2_present ### opam list -is --columns=package ocaml.system P1.1 P2.1 P5.1 ### opam remove P2 -a --yes The following actions will be performed: - remove P2 1 - recompile P5 1 [uses P2] ===== 1 to recompile | 1 to remove ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P5.1 (no changes) -> removed P5.1 -> removed P2.1 -> installed P5.1 Done. ### test -f ${OPAMROOT}/system/lib/p5/p2_absent ### opam list -is --columns=package ocaml.system P1.1 P5.1 ### opam remove P1 --yes The following actions will be performed: - remove P5 1 [uses P1] - remove P1 1 ===== 2 to remove ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed P5.1 -> removed P1.1 Done. ### opam list -is --columns=package ocaml.system ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml system P1 -- A very useful package P2 -- An other very useful package P3 -- Testing version names P4 -- Testing transitive closure P5 -- Testing optional dependencies ### : INSTALL : ### opam list -is --columns=package ocaml.system ### opam install P1 The following actions will be performed: - install P1 1 I ll always bother you displaying this message <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (git+file://${BASEDIR}/GIT/P1-1) -> installed P1.1 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### opam list -is --columns=package ocaml.system P1.1 ### opam install P2 The following actions will be performed: - install P2 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P2.1 (git+file://${BASEDIR}/GIT/P2) -> installed P2.1 Done. ### opam list -is --columns=package ocaml.system P1.1 P2.1 ### opam install P3 The following actions will be performed: - install P3 1~weird-version.test <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P3.1~weird-version.test (git+file://${BASEDIR}/GIT/P3) -> installed P3.1~weird-version.test Done. ### opam list -is --columns=package ocaml.system P1.1 P2.1 P3.1~weird-version.test ### opam install P4 The following actions will be performed: - install P4 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P4.1 (git+file://${BASEDIR}/GIT/P4) -> installed P4.1 Done. ### opam list -is --columns=package ocaml.system P1.1 P2.1 P3.1~weird-version.test P4.1 ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml system P1 1 A very useful package P2 1 An other very useful package P3 1~weird-version.test Testing version names P4 1 Testing transitive closure P5 -- Testing optional dependencies ### : REINSTALL : ### opam list -is --columns=package ocaml.system P1.1 P2.1 P3.1~weird-version.test P4.1 ### opam reinstall P1 --yes | unordered The following actions will be performed: - recompile P1 1 I ll always bother you displaying this message - recompile P3 1~weird-version.test [uses P1] - recompile P2 1 [uses P1] - recompile P4 1 [uses P2, P3] ===== 4 to recompile ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (no changes) -> retrieved P2.1 (no changes) -> retrieved P3.1~weird-version.test (no changes) -> retrieved P4.1 (no changes) -> removed P4.1 -> removed P2.1 -> removed P3.1~weird-version.test -> removed P1.1 -> installed P1.1 -> installed P2.1 -> installed P3.1~weird-version.test -> installed P4.1 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### opam list -is --columns=package ocaml.system P1.1 P2.1 P3.1~weird-version.test P4.1 ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml system P1 1 A very useful package P2 1 An other very useful package P3 1~weird-version.test Testing version names P4 1 Testing transitive closure P5 -- Testing optional dependencies ### : UPLOAD-NEW : ### mkdir REPO/packages/P4.2 ### cp packages/P4-2.opam REPO/packages/P4.2/opam ### cp packages/P4/README REPO/packages/P4.2/descr ### sh mkurl.sh P4.2 P4.tar.gz ### mkdir REPO/packages/P4.3 ### cp packages/P4-3.opam REPO/packages/P4.3/opam ### cp packages/P4/README REPO/packages/P4.3/descr ### sh mkurl.sh P4.3 P4.tar.gz ### let x () = try Random.int 10 with _ -> 0 (* new line *) ### git -C GIT/P1-1 commit -a -qm "a small change" ### git: "GIT/P4" ### git: "GIT/P4" ### git -C REPO add * ### git -C REPO commit -qm "Adding P4.2 and P4.3" ### opam update <><> Updating package repositories ><><><><><><><><><><><><><><><><><><><><><><> [test] synchronised from git+file://${BASEDIR}/REPO [WARNING] The repository 'test' at git+file://${BASEDIR}/REPO doesn't have a 'repo' file, and might not be compatible with this version of opam. [NOTE] Repository at git+file://${BASEDIR}/REPO doesn't define its version, assuming it's 1.2. <><> Upgrading repositories from older opam format ><><><><><><><><><><><><><><> Upgrading repository "test"... Updated ${OPAMTMP}/test/packages/P1.0/opam Updated ${OPAMTMP}/test/packages/P1.1/opam Updated ${OPAMTMP}/test/packages/P2.1/opam Updated ${OPAMTMP}/test/packages/P3.1~weird-version.test/opam Updated ${OPAMTMP}/test/packages/P4.1/opam Updated ${OPAMTMP}/test/packages/P4.2/opam Updated ${OPAMTMP}/test/packages/P4.3/opam Updated ${OPAMTMP}/test/packages/P5.1/opam <><> Synchronising development packages <><><><><><><><><><><><><><><><><><><><> [P1.1] synchronised (git+file://${BASEDIR}/GIT/P1-1) [P2.1] synchronised (no changes) [P3.1~weird-version.test] synchronised (no changes) [P4.1] synchronised (no changes) Now run 'opam upgrade' to apply any package updates. ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml system P1 1 A very useful package P2 1 An other very useful package P3 1~weird-version.test Testing version names P4 1 Testing transitive closure P5 -- Testing optional dependencies ### : UPGRADE : ### opam list -is --columns=package ocaml.system P1.1 P2.1 P3.1~weird-version.test P4.1 ### opam env --sexp | grep '"P1"' ("P1" "version1") ### opam upgrade --yes | unordered The following actions will be performed: - recompile P1 1 [upstream or system changes] I ll always bother you displaying this message - recompile P3 1~weird-version.test [uses P1] - recompile P2 1 [uses P1] - upgrade P4 1 to 3 ===== 3 to recompile | 1 to upgrade ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (no changes) -> retrieved P2.1 (no changes) -> retrieved P3.1~weird-version.test (no changes) -> retrieved P4.3 (git+file://${BASEDIR}/GIT/P4) -> removed P4.1 -> removed P2.1 -> removed P3.1~weird-version.test -> removed P1.1 -> installed P1.1 -> installed P2.1 -> installed P3.1~weird-version.test -> installed P4.3 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### opam list -is --columns=package ocaml.system P1.1 P2.1 P3.1~weird-version.test P4.3 ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml system P1 1 A very useful package P2 1 An other very useful package P3 1~weird-version.test Testing version names P4 3 Testing transitive closure P5 -- Testing optional dependencies ### : DOWNGRADE : ### opam list -is --columns=package ocaml.system P1.1 P2.1 P3.1~weird-version.test P4.3 ### opam install P4.2 --yes | unordered The following actions will be performed: - downgrade P4 3 to 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P4.2 (git+file://${BASEDIR}/GIT/P4) -> removed P4.3 -> installed P4.2 Done. ### opam list -is --columns=package ocaml.system P1.1 P2.1 P3.1~weird-version.test P4.2 ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml system P1 1 A very useful package P2 1 An other very useful package P3 1~weird-version.test Testing version names P4 2 Testing transitive closure P5 -- Testing optional dependencies ### : SWITCH-ALIAS : ### opam list -is --columns=package ocaml.system P1.1 P2.1 P3.1~weird-version.test P4.2 ### opam remove P3.1~weird-version.test P4.2 The following actions will be performed: - remove P4 2 - remove P3 1~weird-version.test ===== 2 to remove ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed P4.2 -> removed P3.1~weird-version.test Done. ### opam list -is --columns=package ocaml.system P1.1 P2.1 ### opam switch export test.export ### opam switch create test system <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml" {= "system"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed ocaml.system Done. ### opam var ext_lib=$LIB_EXT --switch test | '.*' -> '\c' ### opam list -is --columns=package ocaml.system ### opam switch import test.export | unordered The following actions will be performed: - install P1 1 I ll always bother you displaying this message - install P2 1 ===== 2 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (git+file://${BASEDIR}/GIT/P1-1) -> retrieved P2.1 (git+file://${BASEDIR}/GIT/P2) -> installed P1.1 -> installed P2.1 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### opam list -is --columns=package ocaml.system P1.1 P2.1 ### opam switch create test2 20 <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml" {= "20"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed ocaml.20 Done. ### opam var ext_lib=$LIB_EXT --switch test2 | '.*' -> '\c' ### opam list -is --columns=package ocaml.20 ### opam install P1 The following actions will be performed: - install P1 1 I ll always bother you displaying this message <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (git+file://${BASEDIR}/GIT/P1-1) -> installed P1.1 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### opam list -is --columns=package ocaml.20 P1.1 ### opam switch system ### opam list -is --columns=package ocaml.system P1.1 P2.1 ### opam switch remove test test2 --yes Switch test and all its packages will be wiped. Are you sure? [Y/n] y Switch test2 and all its packages will be wiped. Are you sure? [Y/n] y ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml system P1 1 A very useful package P2 1 An other very useful package P3 -- Testing version names P4 -- Testing transitive closure P5 -- Testing optional dependencies ### : SWITCH-ENV-PACKAGES : ### opam list -is --columns=package ocaml.system P1.1 P2.1 ### opam switch create 10+a+b --empty ### opam var ext_lib=$LIB_EXT --switch 10+a+b | '.*' -> '\c' ### opam install ocaml.10+a+b P1 P2 P3 P4 | unordered The following actions will be performed: - install ocaml 10+a+b - install P1 1 I ll always bother you displaying this message - install P3 1~weird-version.test - install P2 1 - install P4 3 ===== 5 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed ocaml.10+a+b -> retrieved P1.1 (git+file://${BASEDIR}/GIT/P1-1) -> retrieved P2.1 (git+file://${BASEDIR}/GIT/P2) -> retrieved P3.1~weird-version.test (git+file://${BASEDIR}/GIT/P3) -> installed P1.1 -> retrieved P4.3 (git+file://${BASEDIR}/GIT/P4) -> installed P2.1 -> installed P3.1~weird-version.test -> installed P4.3 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### opam list -is --columns=package ocaml.10+a+b P1.1 P2.1 P3.1~weird-version.test P4.3 ### sh -c '. ${OPAMROOT}/opam-init/variables.sh && echo "PASS $TEST"' PASS 1 ### : REPO : ### opam repo add REPO2 REPO -k git [REPO2] Initialised [WARNING] The repository 'REPO2' at git+file://${BASEDIR}/REPO doesn't have a 'repo' file, and might not be compatible with this version of opam. [NOTE] Repository at git+file://${BASEDIR}/REPO doesn't define its version, assuming it's 1.2. <><> Upgrading repositories from older opam format ><><><><><><><><><><><><><><> Upgrading repository "REPO2"... Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P1.0/opam Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P1.1/opam Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P2.1/opam Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P3.1~weird-version.test/opam Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P4.1/opam Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P4.2/opam Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P4.3/opam Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P5.1/opam [NOTE] Repository REPO2 has been added to the selections of switch 10+a+b only. Run `opam repository add REPO2 --all-switches|--set-default' to use it in all existing switches, or in newly created switches, respectively. ### opam repo remove REPO2 --all ### opam repo remove test --all ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml 10+a+b P1 1 A very useful package P2 1 An other very useful package P3 1~weird-version.test Testing version names P4 3 Testing transitive closure opam-2.1.5/tests/reftests/dune.inc0000644000175000017500000005061314427463453016153 0ustar stephsteph (alias (name reftest-avoid-version) (action (diff avoid-version.test avoid-version.out))) (alias (name reftest) (deps (alias reftest-avoid-version))) (rule (targets avoid-version.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:avoid-version.test} %{read-lines:testing-env})))) (alias (name reftest-cli-versioning) (action (diff cli-versioning.test cli-versioning.out))) (alias (name reftest) (deps (alias reftest-cli-versioning))) (rule (targets cli-versioning.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:cli-versioning.test} %{read-lines:testing-env})))) (alias (name reftest-conflict-4373) (action (diff conflict-4373.test conflict-4373.out))) (alias (name reftest) (deps (alias reftest-conflict-4373))) (rule (targets conflict-4373.out) (deps root-c1d23f0e) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:conflict-4373.test} %{read-lines:testing-env})))) (alias (name reftest-conflict-badversion) (action (diff conflict-badversion.test conflict-badversion.out))) (alias (name reftest) (deps (alias reftest-conflict-badversion))) (rule (targets conflict-badversion.out) (deps root-f372039d) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:conflict-badversion.test} %{read-lines:testing-env})))) (alias (name reftest-conflict-camlp4) (action (diff conflict-camlp4.test conflict-camlp4.out))) (alias (name reftest) (deps (alias reftest-conflict-camlp4))) (rule (targets conflict-camlp4.out) (deps root-f372039d) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:conflict-camlp4.test} %{read-lines:testing-env})))) (alias (name reftest-conflict-core) (action (diff conflict-core.test conflict-core.out))) (alias (name reftest) (deps (alias reftest-conflict-core))) (rule (targets conflict-core.out) (deps root-f372039d) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:conflict-core.test} %{read-lines:testing-env})))) (alias (name reftest-conflict-resto) (action (diff conflict-resto.test conflict-resto.out))) (alias (name reftest) (deps (alias reftest-conflict-resto))) (rule (targets conflict-resto.out) (deps root-a5d7cdc0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:conflict-resto.test} %{read-lines:testing-env})))) (alias (name reftest-conflict-solo5) (action (diff conflict-solo5.test conflict-solo5.out))) (alias (name reftest) (deps (alias reftest-conflict-solo5))) (rule (targets conflict-solo5.out) (deps root-f372039d) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:conflict-solo5.test} %{read-lines:testing-env})))) (alias (name reftest-cudf-preprocess) (action (diff cudf-preprocess.test cudf-preprocess.out))) (alias (name reftest) (deps (alias reftest-cudf-preprocess))) (rule (targets cudf-preprocess.out) (deps root-ad4dd344) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:cudf-preprocess.test} %{read-lines:testing-env})))) (alias (name reftest-dot-install) (action (diff dot-install.test dot-install.out))) (alias (name reftest) (deps (alias reftest-dot-install))) (rule (targets dot-install.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:dot-install.test} %{read-lines:testing-env})))) (alias (name reftest-empty-conflicts-001) (action (diff empty-conflicts-001.test empty-conflicts-001.out))) (alias (name reftest) (deps (alias reftest-empty-conflicts-001))) (rule (targets empty-conflicts-001.out) (deps root-297366c) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:empty-conflicts-001.test} %{read-lines:testing-env})))) (alias (name reftest-empty-conflicts-002) (action (diff empty-conflicts-002.test empty-conflicts-002.out))) (alias (name reftest) (deps (alias reftest-empty-conflicts-002))) (rule (targets empty-conflicts-002.out) (deps root-11ea1cb) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:empty-conflicts-002.test} %{read-lines:testing-env})))) (alias (name reftest-empty-conflicts-003) (action (diff empty-conflicts-003.test empty-conflicts-003.out))) (alias (name reftest) (deps (alias reftest-empty-conflicts-003))) (rule (targets empty-conflicts-003.out) (deps root-3235916) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:empty-conflicts-003.test} %{read-lines:testing-env})))) (alias (name reftest-empty-conflicts-004) (action (diff empty-conflicts-004.test empty-conflicts-004.out))) (alias (name reftest) (deps (alias reftest-empty-conflicts-004))) (rule (targets empty-conflicts-004.out) (deps root-0070613707) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:empty-conflicts-004.test} %{read-lines:testing-env})))) (alias (name reftest-empty-conflicts-005) (action (diff empty-conflicts-005.test empty-conflicts-005.out))) (alias (name reftest) (deps (alias reftest-empty-conflicts-005))) (rule (targets empty-conflicts-005.out) (deps root-de897adf36c4230dfea812f40c98223b31c4521a) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:empty-conflicts-005.test} %{read-lines:testing-env})))) (alias (name reftest-empty-conflicts-006) (action (diff empty-conflicts-006.test empty-conflicts-006.out))) (alias (name reftest) (deps (alias reftest-empty-conflicts-006))) (rule (targets empty-conflicts-006.out) (deps root-c1842d168d) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:empty-conflicts-006.test} %{read-lines:testing-env})))) (alias (name reftest-env) (action (diff env.test env.out))) (alias (name reftest) (deps (alias reftest-env))) (rule (targets env.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:env.test} %{read-lines:testing-env})))) (alias (name reftest-init) (action (diff init.test init.out))) (alias (name reftest) (deps (alias reftest-init))) (rule (targets init.out) (deps root-009e00fa) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:init.test} %{read-lines:testing-env})))) (alias (name reftest-install-pgocaml) (action (diff install-pgocaml.test install-pgocaml.out))) (alias (name reftest) (deps (alias reftest-install-pgocaml))) (rule (targets install-pgocaml.out) (deps root-f372039d) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:install-pgocaml.test} %{read-lines:testing-env})))) (alias (name reftest-legacy-git) (action (diff legacy-git.test legacy-git.out))) (alias (name reftest) (deps (alias reftest-legacy-git))) (rule (targets legacy-git.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:legacy-git.test} %{read-lines:testing-env})))) (alias (name reftest-legacy-local) (action (diff legacy-local.test legacy-local.out))) (alias (name reftest) (deps (alias reftest-legacy-local))) (rule (targets legacy-local.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:legacy-local.test} %{read-lines:testing-env})))) (alias (name reftest-list.unix) (enabled_if (= %{os_type} "Unix")) (action (diff list.unix.test list.unix.out))) (alias (name reftest) (enabled_if (= %{os_type} "Unix")) (deps (alias reftest-list.unix))) (rule (targets list.unix.out) (deps root-f372039d) (enabled_if (= %{os_type} "Unix")) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:list.unix.test} %{read-lines:testing-env})))) (alias (name reftest-local-cache) (action (diff local-cache.test local-cache.out))) (alias (name reftest) (deps (alias reftest-local-cache))) (rule (targets local-cache.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:local-cache.test} %{read-lines:testing-env})))) (alias (name reftest-opamroot-versions) (action (diff opamroot-versions.test opamroot-versions.out))) (alias (name reftest) (deps (alias reftest-opamroot-versions))) (rule (targets opamroot-versions.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:opamroot-versions.test} %{read-lines:testing-env})))) (alias (name reftest-opamrt-big-upgrade) (action (diff opamrt-big-upgrade.test opamrt-big-upgrade.out))) (alias (name reftest) (deps (alias reftest-opamrt-big-upgrade))) (rule (targets opamrt-big-upgrade.out) (deps root-7090735c) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:opamrt-big-upgrade.test} %{read-lines:testing-env})))) (alias (name reftest-opamrt-dep-cycle) (action (diff opamrt-dep-cycle.test opamrt-dep-cycle.out))) (alias (name reftest) (deps (alias reftest-opamrt-dep-cycle))) (rule (targets opamrt-dep-cycle.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:opamrt-dep-cycle.test} %{read-lines:testing-env})))) (alias (name reftest-opamrt-reinstall) (action (diff opamrt-reinstall.test opamrt-reinstall.out))) (alias (name reftest) (deps (alias reftest-opamrt-reinstall))) (rule (targets opamrt-reinstall.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:opamrt-reinstall.test} %{read-lines:testing-env})))) (alias (name reftest-orphans) (action (diff orphans.test orphans.out))) (alias (name reftest) (deps (alias reftest-orphans))) (rule (targets orphans.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:orphans.test} %{read-lines:testing-env})))) (alias (name reftest-pat-sub) (action (diff pat-sub.test pat-sub.out))) (alias (name reftest) (deps (alias reftest-pat-sub))) (rule (targets pat-sub.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:pat-sub.test} %{read-lines:testing-env})))) (alias (name reftest-pin) (action (diff pin.test pin.out))) (alias (name reftest) (deps (alias reftest-pin))) (rule (targets pin.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:pin.test} %{read-lines:testing-env})))) (alias (name reftest-pin.unix) (enabled_if (= %{os_type} "Unix")) (action (diff pin.unix.test pin.unix.out))) (alias (name reftest) (enabled_if (= %{os_type} "Unix")) (deps (alias reftest-pin.unix))) (rule (targets pin.unix.out) (deps root-N0REP0) (enabled_if (= %{os_type} "Unix")) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:pin.unix.test} %{read-lines:testing-env})))) (alias (name reftest-remove) (action (diff remove.test remove.out))) (alias (name reftest) (deps (alias reftest-remove))) (rule (targets remove.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:remove.test} %{read-lines:testing-env})))) (alias (name reftest-show) (action (diff show.test show.out))) (alias (name reftest) (deps (alias reftest-show))) (rule (targets show.out) (deps root-009e00fa) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:show.test} %{read-lines:testing-env})))) (alias (name reftest-switch-creation) (action (diff switch-creation.test switch-creation.out))) (alias (name reftest) (deps (alias reftest-switch-creation))) (rule (targets switch-creation.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:switch-creation.test} %{read-lines:testing-env})))) (alias (name reftest-switch-invariant) (action (diff switch-invariant.test switch-invariant.out))) (alias (name reftest) (deps (alias reftest-switch-invariant))) (rule (targets switch-invariant.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:switch-invariant.test} %{read-lines:testing-env})))) (alias (name reftest-upgrade-format) (action (diff upgrade-format.test upgrade-format.out))) (alias (name reftest) (deps (alias reftest-upgrade-format))) (rule (targets upgrade-format.out) (deps root-009e00fa) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:upgrade-format.test} %{read-lines:testing-env})))) (alias (name reftest-upgrade-two-point-o) (action (diff upgrade-two-point-o.test upgrade-two-point-o.out))) (alias (name reftest) (deps (alias reftest-upgrade-two-point-o))) (rule (targets upgrade-two-point-o.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:upgrade-two-point-o.test} %{read-lines:testing-env})))) (alias (name reftest-var-option) (action (diff var-option.test var-option.out))) (alias (name reftest) (deps (alias reftest-var-option))) (rule (targets var-option.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:var-option.test} %{read-lines:testing-env})))) (alias (name reftest-working-dir) (action (diff working-dir.test working-dir.out))) (alias (name reftest) (deps (alias reftest-working-dir))) (rule (targets working-dir.out) (deps root-N0REP0) (action (with-stdout-to %{targets} (run ./run.exe %{bin:opam} %{dep:working-dir.test} %{read-lines:testing-env})))) (rule (targets opam-repo-N0REP0) (action (progn (run mkdir -p %{targets}/packages) (write-file repo "opam-version:\"2.0\"") (run cp repo %{targets}/repo)))) (rule (targets root-N0REP0) (action (progn (ignore-stdout (run %{bin:opam} init --root=%{targets} --no-setup --bypass-checks --no-opamrc --bare file://%{dep:opam-repo-N0REP0}))))) (rule (targets opam-archive-0070613707.tar.gz) (action (run wget --quiet -O %{targets} https://github.com/ocaml/opam-repository/archive/0070613707.tar.gz))) (rule (targets opam-repo-0070613707) (action (progn (run mkdir -p %{targets}) (run tar -C %{targets} -xzf %{dep:opam-archive-0070613707.tar.gz} --strip-components=1)))) (rule (targets root-0070613707) (action (progn (ignore-stdout (run %{bin:opam} init --root=%{targets} --no-setup --bypass-checks --no-opamrc --bare file://%{dep:opam-repo-0070613707}))))) (rule (targets opam-archive-009e00fa.tar.gz) (action (run wget --quiet -O %{targets} https://github.com/ocaml/opam-repository/archive/009e00fa.tar.gz))) (rule (targets opam-repo-009e00fa) (action (progn (run mkdir -p %{targets}) (run tar -C %{targets} -xzf %{dep:opam-archive-009e00fa.tar.gz} --strip-components=1)))) (rule (targets root-009e00fa) (action (progn (ignore-stdout (run %{bin:opam} init --root=%{targets} --no-setup --bypass-checks --no-opamrc --bare file://%{dep:opam-repo-009e00fa}))))) (rule (targets opam-archive-11ea1cb.tar.gz) (action (run wget --quiet -O %{targets} https://github.com/ocaml/opam-repository/archive/11ea1cb.tar.gz))) (rule (targets opam-repo-11ea1cb) (action (progn (run mkdir -p %{targets}) (run tar -C %{targets} -xzf %{dep:opam-archive-11ea1cb.tar.gz} --strip-components=1)))) (rule (targets root-11ea1cb) (action (progn (ignore-stdout (run %{bin:opam} init --root=%{targets} --no-setup --bypass-checks --no-opamrc --bare file://%{dep:opam-repo-11ea1cb}))))) (rule (targets opam-archive-297366c.tar.gz) (action (run wget --quiet -O %{targets} https://github.com/ocaml/opam-repository/archive/297366c.tar.gz))) (rule (targets opam-repo-297366c) (action (progn (run mkdir -p %{targets}) (run tar -C %{targets} -xzf %{dep:opam-archive-297366c.tar.gz} --strip-components=1)))) (rule (targets root-297366c) (action (progn (ignore-stdout (run %{bin:opam} init --root=%{targets} --no-setup --bypass-checks --no-opamrc --bare file://%{dep:opam-repo-297366c}))))) (rule (targets opam-archive-3235916.tar.gz) (action (run wget --quiet -O %{targets} https://github.com/ocaml/opam-repository/archive/3235916.tar.gz))) (rule (targets opam-repo-3235916) (action (progn (run mkdir -p %{targets}) (run tar -C %{targets} -xzf %{dep:opam-archive-3235916.tar.gz} --strip-components=1)))) (rule (targets root-3235916) (action (progn (ignore-stdout (run %{bin:opam} init --root=%{targets} --no-setup --bypass-checks --no-opamrc --bare file://%{dep:opam-repo-3235916}))))) (rule (targets opam-archive-7090735c.tar.gz) (action (run wget --quiet -O %{targets} https://github.com/ocaml/opam-repository/archive/7090735c.tar.gz))) (rule (targets opam-repo-7090735c) (action (progn (run mkdir -p %{targets}) (run tar -C %{targets} -xzf %{dep:opam-archive-7090735c.tar.gz} --strip-components=1)))) (rule (targets root-7090735c) (action (progn (ignore-stdout (run %{bin:opam} init --root=%{targets} --no-setup --bypass-checks --no-opamrc --bare file://%{dep:opam-repo-7090735c}))))) (rule (targets opam-archive-a5d7cdc0.tar.gz) (action (run wget --quiet -O %{targets} https://github.com/ocaml/opam-repository/archive/a5d7cdc0.tar.gz))) (rule (targets opam-repo-a5d7cdc0) (action (progn (run mkdir -p %{targets}) (run tar -C %{targets} -xzf %{dep:opam-archive-a5d7cdc0.tar.gz} --strip-components=1)))) (rule (targets root-a5d7cdc0) (action (progn (ignore-stdout (run %{bin:opam} init --root=%{targets} --no-setup --bypass-checks --no-opamrc --bare file://%{dep:opam-repo-a5d7cdc0}))))) (rule (targets opam-archive-ad4dd344.tar.gz) (action (run wget --quiet -O %{targets} https://github.com/ocaml/opam-repository/archive/ad4dd344.tar.gz))) (rule (targets opam-repo-ad4dd344) (action (progn (run mkdir -p %{targets}) (run tar -C %{targets} -xzf %{dep:opam-archive-ad4dd344.tar.gz} --strip-components=1)))) (rule (targets root-ad4dd344) (action (progn (ignore-stdout (run %{bin:opam} init --root=%{targets} --no-setup --bypass-checks --no-opamrc --bare file://%{dep:opam-repo-ad4dd344}))))) (rule (targets opam-archive-c1842d168d.tar.gz) (action (run wget --quiet -O %{targets} https://github.com/ocaml/opam-repository/archive/c1842d168d.tar.gz))) (rule (targets opam-repo-c1842d168d) (action (progn (run mkdir -p %{targets}) (run tar -C %{targets} -xzf %{dep:opam-archive-c1842d168d.tar.gz} --strip-components=1)))) (rule (targets root-c1842d168d) (action (progn (ignore-stdout (run %{bin:opam} init --root=%{targets} --no-setup --bypass-checks --no-opamrc --bare file://%{dep:opam-repo-c1842d168d}))))) (rule (targets opam-archive-c1d23f0e.tar.gz) (action (run wget --quiet -O %{targets} https://github.com/ocaml/opam-repository/archive/c1d23f0e.tar.gz))) (rule (targets opam-repo-c1d23f0e) (action (progn (run mkdir -p %{targets}) (run tar -C %{targets} -xzf %{dep:opam-archive-c1d23f0e.tar.gz} --strip-components=1)))) (rule (targets root-c1d23f0e) (action (progn (ignore-stdout (run %{bin:opam} init --root=%{targets} --no-setup --bypass-checks --no-opamrc --bare file://%{dep:opam-repo-c1d23f0e}))))) (rule (targets opam-archive-de897adf36c4230dfea812f40c98223b31c4521a.tar.gz) (action (run wget --quiet -O %{targets} https://github.com/ocaml/opam-repository/archive/de897adf36c4230dfea812f40c98223b31c4521a.tar.gz))) (rule (targets opam-repo-de897adf36c4230dfea812f40c98223b31c4521a) (action (progn (run mkdir -p %{targets}) (run tar -C %{targets} -xzf %{dep:opam-archive-de897adf36c4230dfea812f40c98223b31c4521a.tar.gz} --strip-components=1)))) (rule (targets root-de897adf36c4230dfea812f40c98223b31c4521a) (action (progn (ignore-stdout (run %{bin:opam} init --root=%{targets} --no-setup --bypass-checks --no-opamrc --bare file://%{dep:opam-repo-de897adf36c4230dfea812f40c98223b31c4521a}))))) (rule (targets opam-archive-f372039d.tar.gz) (action (run wget --quiet -O %{targets} https://github.com/ocaml/opam-repository/archive/f372039d.tar.gz))) (rule (targets opam-repo-f372039d) (action (progn (run mkdir -p %{targets}) (run tar -C %{targets} -xzf %{dep:opam-archive-f372039d.tar.gz} --strip-components=1)))) (rule (targets root-f372039d) (action (progn (ignore-stdout (run %{bin:opam} init --root=%{targets} --no-setup --bypass-checks --no-opamrc --bare file://%{dep:opam-repo-f372039d}))))) opam-2.1.5/tests/reftests/testing-env0000644000175000017500000000001514427463453016702 0ustar stephstephOPAMSTRICT=1 opam-2.1.5/tests/reftests/cudf-preprocess.test0000644000175000017500000004454514427463453020541 0ustar stephstephad4dd344 ### : Github issue #4624 ### OPAMFAKE=1 ### opam switch create 4.11.0 <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml-base-compiler" {= "4.11.0"} | "ocaml-system" {= "4.11.0"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-base-compiler.4.11.0 Faking installation of ocaml-config.1 Faking installation of ocaml.4.11.0 Done. ### opam install git-unix git-cohttp-mirage git-cohttp-unix git-cohttp git carton-git carton-lwt carton decompress checkseum optint.0.0.4 --yes | unordered The following actions will be faked: - install seq base [required by psq] - install conf-gmp 3 [required by conf-gmp-powm-sec, zarith] - install mirage-no-xen 1 [required by mirage-crypto-pk] - install ocamlbuild 0.14.0 [required by bos] - install conf-pkg-config 2 [required by checkseum] - install ocamlfind 1.9.1 [required by git-unix] - install mirage-no-solo5 1 [required by mirage-crypto-pk] - install cmdliner 1.0.4 [required by decompress, carton, git-unix] - install dune 2.8.5 [required by git-unix, git-cohttp-mirage, git, etc.] - install conf-gmp-powm-sec 3 [required by mirage-crypto-pk] - install uchar 0.0.2 [required by uutf, jsonm] - install zarith 1.12 [required by awa] - install topkg 1.0.3 [required by bos] - install num 1.4 [required by sexplib] - install base-bytes base [required by checkseum, decompress] - install stdlib-shims 0.3.0 [required by ocamlgraph, digestif, duff, cohttp] - install sexplib0 v0.14.0 [required by cohttp, cohttp-lwt] - install result 1.5 [required by git-cohttp-unix, git-cohttp, carton-git, etc.] - install re 1.9.0 [required by cohttp] - install psq 0.2.0 [required by carton, git] - install ppx_derivers 1.2.1 [required by ppxlib] - install pecu 0.5 [required by emile] - install optint 0.0.4 - install ocaml-syntax-shims 1.0.0 [required by angstrom] - install ocaml-migrate-parsetree 2.1.0 [required by ppxlib] - install ocaml-compiler-libs v0.12.3 [required by ppxlib] - install mmap 1.1.0 [required by carton-git, carton, git-unix] - install mirage-clock 3.1.0 [required by git-unix] - install magic-mime 1.1.3 [required by cohttp-mirage, cohttp-lwt-unix] - install macaddr 5.0.1 [required by tcpip] - install gmap 0.3.0 [required by dns, x509] - install duration 0.1.3 [required by tcpip] - install csexp 1.5.1 [required by dune-configurator] - install cppo 1.6.7 [required by lwt] - install bigarray-compat 1.0.0 [required by git, checkseum, carton, etc.] - install base64 3.5.0 [required by git] - install uutf 1.0.2 [required by emile] - install mtime 1.2.0 [required by git-unix] - install astring 0.8.5 [required by git, carton-git, git-unix] - install stringext 1.6.0 [required by uri, cohttp] - install ocamlgraph 2.0.0 [required by git] - install fmt 0.8.9 [required by git-cohttp-unix, git-cohttp, carton-git, etc.] - install rresult 0.6.0 [required by git-cohttp-unix, git-cohttp, carton, etc.] - install ptime 0.8.5 [required by tls-mirage, tls, ca-certs] - install lru 0.3.0 [required by tcpip] - install ppxlib 0.22.0 [required by ppx_fields_conv, ppx_sexp_conv] - install dune-configurator 2.8.5 [required by checkseum] - install ocplib-endian 1.1 [required by lwt, mirage-profile] - install cstruct 6.0.0 [required by carton, git] - install bigstringaf 0.7.0 [required by git, carton-git, carton, etc.] - install jsonm 1.0.1 [required by cohttp] - install fpath 0.7.3 [required by git, carton, carton-git, git-unix] - install metrics 0.2.0 [required by dns] - install ke 0.4 [required by carton, git] - install duff 0.4 [required by carton] - install domain-name 0.3.0 [required by git, git-unix] - install mirage-clock-unix 3.1.0 [required by git-unix] - install checkseum 0.3.0 - install base v0.14.1 [required by ppx_fields_conv, fieldslib, ppx_sexp_conv] - install lwt 5.4.0 [required by git-cohttp-unix, git-cohttp, carton-lwt, etc.] - install randomconv 0.1.3 [required by tcpip] - install mirage-random 2.0.0 [required by tcpip] - install macaddr-cstruct 5.0.1 [required by tcpip] - install io-page 2.4.0 [required by vchan] - install hex 1.4.0 [required by fiat-p256] - install eqaf 0.7 [required by digestif] - install cstruct-unix 6.0.0 [required by awa] - install asn1-combinators 0.2.5 [required by x509] - install angstrom 0.15.0 [required by git] - install ipaddr 5.0.1 [required by git, git-unix] - install decompress 1.3.0 - install ppx_sexp_conv v0.14.3 [required by cohttp-lwt, cohttp, awa] - install parsexp v0.14.0 [required by sexplib] - install fieldslib v0.14.0 [required by cohttp] - install mirage-time 2.0.1 [required by tcpip] - install mirage-flow 2.0.1 [required by git, git-unix] - install mirage-device 2.0.0 [required by mirage-net] - install lwt-dllist 1.0.0 [required by tcpip] - install logs 0.7.0 [required by git, carton, git-unix] - install hxd 0.3.1 [required by carton] - install cstruct-lwt 6.0.0 [required by tcpip] - install mirage-crypto 0.9.0 [required by awa] - install hacl_x25519 0.2.2 [required by awa] - install fiat-p256 0.2.3 [required by tls, tls-mirage] - install digestif 1.0.0 [required by git, carton, git-unix] - install uri 4.1.0 [required by git-cohttp-mirage, git, git-cohttp, git-cohttp-unix] - install encore 0.8 [required by git] - install emile 1.1 [required by git] - install ipaddr-sexp 5.0.1 [required by conduit-mirage, conduit, conduit-lwt-unix] - install sexplib v0.14.0 [required by awa] - install ppx_fields_conv v0.14.2 [required by cohttp] - install mirage-protocols 5.0.0 [required by tcpip] - install mirage-net 3.0.1 [required by tcpip] - install mirage-kv 3.0.1 [required by cohttp-mirage] - install mirage-flow-combinators 2.0.1 [required by conduit-mirage] - install mirage-channel 4.0.1 [required by cohttp-mirage] - install mimic 0.0.2 [required by git, git-cohttp-mirage] - install dns 4.6.3 [required by dns-client] - install bos 0.2.0 [required by carton, git-unix] - install mirage-crypto-rng 0.9.0 [required by awa] - install hkdf 1.0.4 [required by tls] - install uri-sexp 4.1.0 [required by cohttp] - install ppx_cstruct 6.0.0 [required by awa, tcpip] - install cstruct-sexp 6.0.0 [required by awa] - install conduit 2.3.0 [required by cohttp-mirage] - install mirage-stack 2.2.0 [required by tcpip] - install carton 0.4.0 - install mirage-crypto-pk 0.9.0 [required by awa] - install cohttp 2.5.5 [required by git-cohttp-mirage, git-cohttp, git-cohttp-unix] - install xenstore 2.1.1 [required by conduit-mirage] - install mirage-profile 0.9.1 [required by tcpip] - install conduit-lwt 2.3.0 [required by conduit-mirage, conduit-lwt-unix] - install dns-client 4.6.3 [required by conduit-mirage] - install carton-lwt 0.4.0 - install x509 0.11.2 [required by awa] - install cohttp-lwt 2.5.5 [required by git-cohttp-mirage, git-cohttp, git-cohttp-unix] - install xenstore_transport 1.3.0 [required by vchan] - install ethernet 2.2.0 [required by tcpip] - install carton-git 0.4.0 - install tls 0.12.8 [required by conduit-mirage, conduit-lwt-unix] - install ca-certs 0.2.0 [required by conduit-lwt-unix] - install awa 0.0.1 [required by git-unix] - install vchan 6.0.0 [required by conduit-mirage] - install tcpip 6.1.0 [required by git-unix] - install git 3.3.3 - install tls-mirage 0.12.8 [required by conduit-mirage] - install conduit-lwt-unix 2.3.0 [required by cohttp-lwt-unix] - install awa-mirage 0.0.1 [required by git-unix] - install git-cohttp 3.3.3 - install conduit-mirage 2.2.1 [required by cohttp-mirage] - install cohttp-lwt-unix 2.5.5 [required by git-cohttp-unix, git-unix] - install cohttp-mirage 2.5.5 [required by git-cohttp-mirage] - install git-cohttp-unix 3.3.3 - install git-cohttp-mirage 3.3.3 - install git-unix 3.3.3 ===== 135 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of cmdliner.1.0.4 Faking installation of conf-gmp.3 Faking installation of conf-gmp-powm-sec.3 Faking installation of conf-pkg-config.2 Faking installation of dune.2.8.5 Faking installation of base64.3.5.0 Faking installation of bigarray-compat.1.0.0 Faking installation of bigstringaf.0.7.0 Faking installation of cppo.1.6.7 Faking installation of csexp.1.5.1 Faking installation of cstruct.6.0.0 Faking installation of cstruct-unix.6.0.0 Faking installation of duration.0.1.3 Faking installation of eqaf.0.7 Faking installation of gmap.0.3.0 Faking installation of hacl_x25519.0.2.2 Faking installation of hex.1.4.0 Faking installation of io-page.2.4.0 Faking installation of macaddr.5.0.1 Faking installation of macaddr-cstruct.5.0.1 Faking installation of magic-mime.1.1.3 Faking installation of mirage-clock.3.1.0 Faking installation of mirage-no-solo5.1 Faking installation of mirage-no-xen.1 Faking installation of mirage-random.2.0.0 Faking installation of mmap.1.1.0 Faking installation of ocaml-compiler-libs.v0.12.3 Faking installation of ocaml-migrate-parsetree.2.1.0 Faking installation of ocaml-syntax-shims.1.0.0 Faking installation of ocamlbuild.0.14.0 Faking installation of ocamlfind.1.9.1 Faking installation of base-bytes.base Faking installation of num.1.4 Faking installation of ocplib-endian.1.1 Faking installation of optint.0.0.4 Faking installation of pecu.0.5 Faking installation of ppx_derivers.1.2.1 Faking installation of randomconv.0.1.3 Faking installation of result.1.5 Faking installation of angstrom.0.15.0 Faking installation of dune-configurator.2.8.5 Faking installation of checkseum.0.3.0 Faking installation of decompress.1.3.0 Faking installation of fiat-p256.0.2.3 Faking installation of mirage-clock-unix.3.1.0 Faking installation of mirage-crypto.0.9.0 Faking installation of hkdf.1.0.4 Faking installation of seq.base Faking installation of lwt.5.4.0 Faking installation of cstruct-lwt.6.0.0 Faking installation of hxd.0.3.1 Faking installation of lwt-dllist.1.0.0 Faking installation of mirage-time.2.0.1 Faking installation of psq.0.2.0 Faking installation of lru.0.3.0 Faking installation of re.1.9.0 Faking installation of sexplib0.v0.14.0 Faking installation of base.v0.14.1 Faking installation of fieldslib.v0.14.0 Faking installation of parsexp.v0.14.0 Faking installation of sexplib.v0.14.0 Faking installation of cstruct-sexp.6.0.0 Faking installation of stdlib-shims.0.3.0 Faking installation of digestif.1.0.0 Faking installation of ocamlgraph.2.0.0 Faking installation of ppxlib.0.22.0 Faking installation of ppx_cstruct.6.0.0 Faking installation of mirage-profile.0.9.1 Faking installation of ppx_fields_conv.v0.14.2 Faking installation of ppx_sexp_conv.v0.14.3 Faking installation of stringext.1.6.0 Faking installation of topkg.1.0.3 Faking installation of astring.0.8.5 Faking installation of fmt.0.8.9 Faking installation of domain-name.0.3.0 Faking installation of duff.0.4 Faking installation of encore.0.8 Faking installation of fpath.0.7.3 Faking installation of ipaddr.5.0.1 Faking installation of ipaddr-sexp.5.0.1 Faking installation of ke.0.4 Faking installation of logs.0.7.0 Faking installation of metrics.0.2.0 Faking installation of mirage-device.2.0.0 Faking installation of mirage-flow.2.0.1 Faking installation of mirage-channel.4.0.1 Faking installation of mirage-flow-combinators.2.0.1 Faking installation of mirage-kv.3.0.1 Faking installation of mirage-net.3.0.1 Faking installation of mirage-protocols.5.0.0 Faking installation of mirage-stack.2.2.0 Faking installation of mtime.1.2.0 Faking installation of mirage-crypto-rng.0.9.0 Faking installation of ptime.0.8.5 Faking installation of rresult.0.6.0 Faking installation of bos.0.2.0 Faking installation of carton.0.4.0 Faking installation of carton-lwt.0.4.0 Faking installation of carton-git.0.4.0 Faking installation of dns.4.6.3 Faking installation of dns-client.4.6.3 Faking installation of ethernet.2.2.0 Faking installation of mimic.0.0.2 Faking installation of tcpip.6.1.0 Faking installation of uchar.0.0.2 Faking installation of uri.4.1.0 Faking installation of conduit.2.3.0 Faking installation of conduit-lwt.2.3.0 Faking installation of uri-sexp.4.1.0 Faking installation of uutf.1.0.2 Faking installation of emile.1.1 Faking installation of git.3.3.3 Faking installation of jsonm.1.0.1 Faking installation of cohttp.2.5.5 Faking installation of cohttp-lwt.2.5.5 Faking installation of git-cohttp.3.3.3 Faking installation of xenstore.2.1.1 Faking installation of xenstore_transport.1.3.0 Faking installation of vchan.6.0.0 Faking installation of zarith.1.12 Faking installation of asn1-combinators.0.2.5 Faking installation of mirage-crypto-pk.0.9.0 Faking installation of x509.0.11.2 Faking installation of awa.0.0.1 Faking installation of awa-mirage.0.0.1 Faking installation of ca-certs.0.2.0 Faking installation of tls.0.12.8 Faking installation of conduit-lwt-unix.2.3.0 Faking installation of cohttp-lwt-unix.2.5.5 Faking installation of git-cohttp-unix.3.3.3 Faking installation of git-unix.3.3.3 Faking installation of tls-mirage.0.12.8 Faking installation of conduit-mirage.2.2.1 Faking installation of cohttp-mirage.2.5.5 Faking installation of git-cohttp-mirage.3.3.3 Done. ### OPAMSHOW=1 ### opam install git.3.3.3 optint.0.1.0 [NOTE] Package git is already installed (current version is 3.3.3). The following actions would be faked: - upgrade optint 0.0.4 to 0.1.0 - upgrade checkseum 0.3.0 to 0.3.1 [required by git] - recompile decompress 1.3.0 [uses optint] - recompile carton 0.4.0 [uses optint] - recompile carton-lwt 0.4.0 [uses optint] - recompile carton-git 0.4.0 [uses carton, decompress] - recompile git 3.3.3 - recompile git-cohttp-mirage 3.3.3 [uses git] - recompile git-cohttp 3.3.3 [uses git] - recompile git-cohttp-unix 3.3.3 [uses git] - recompile git-unix 3.3.3 [uses git] ===== 9 to recompile | 2 to upgrade ===== ### opam install optint.0.1.0 The following actions would be faked: - upgrade optint 0.0.4 to 0.1.0 - upgrade checkseum 0.3.0 to 0.3.1 [uses optint] - recompile decompress 1.3.0 [uses optint] - recompile carton 0.4.0 [uses optint] - recompile carton-lwt 0.4.0 [uses optint] - recompile carton-git 0.4.0 [uses carton] - recompile git 3.3.3 [uses optint] - recompile git-cohttp-mirage 3.3.3 [uses git] - recompile git-cohttp 3.3.3 [uses git] - recompile git-cohttp-unix 3.3.3 [uses git] - recompile git-unix 3.3.3 [uses decompress] ===== 9 to recompile | 2 to upgrade ===== ### OPAMCUDFTRIM=0 opam install optint.0.1.0 The following actions would be faked: - upgrade optint 0.0.4 to 0.1.0 - upgrade checkseum 0.3.0 to 0.3.1 [uses optint] - recompile decompress 1.3.0 [uses optint] - recompile carton 0.4.0 [uses optint] - recompile carton-lwt 0.4.0 [uses optint] - recompile carton-git 0.4.0 [uses carton] - recompile git 3.3.3 [uses optint] - recompile git-cohttp-mirage 3.3.3 [uses git] - recompile git-cohttp 3.3.3 [uses git] - recompile git-cohttp-unix 3.3.3 [uses git] - recompile git-unix 3.3.3 [uses decompress] ===== 9 to recompile | 2 to upgrade ===== ### OPAMCUDFTRIM=simple opam install optint.0.1.0 The following actions would be faked: - upgrade optint 0.0.4 to 0.1.0 - upgrade checkseum 0.3.0 to 0.3.1 [uses optint] - recompile decompress 1.3.0 [uses optint] - recompile carton 0.4.0 [uses optint] - recompile carton-lwt 0.4.0 [uses optint] - recompile carton-git 0.4.0 [uses carton] - recompile git 3.3.3 [uses optint] - recompile git-cohttp-mirage 3.3.3 [uses git] - recompile git-cohttp 3.3.3 [uses git] - recompile git-cohttp-unix 3.3.3 [uses git] - recompile git-unix 3.3.3 [uses decompress] ===== 9 to recompile | 2 to upgrade ===== opam-2.1.5/tests/reftests/dune0000644000175000017500000000136714427463453015405 0ustar stephsteph; Reftests are set up using aliases so that they can be run individually: ; ; - each test has its own alias (e.g. dune build @reftest-conflict-camlp4) ; - all tests are attached to @reftest (dune build @reftest runs all) ; - this alias is attached to @runtest too (so dune runtest will run these) (executable (name run) (libraries opam-core opam-file-format) (modules run)) (executable (name gen) (libraries opam-core) (modules gen)) (rule (target dune.inc.gen) (deps (glob_files *.test)) (action (with-stdout-to %{target} (run ./gen.exe)))) (alias (name runtest) (deps (alias reftest))) (alias (name reftest) (deps (alias reftest-gen))) (alias (name reftest-gen) (action (diff dune.inc dune.inc.gen))) (include dune.inc) opam-2.1.5/tests/reftests/show.test0000644000175000017500000002257414427463453016413 0ustar stephsteph009e00fa ### opam show "conf-llvm>7.0.0" <><> conf-llvm: information on all versions <><><><><><><><><><><><><><><><><><> name conf-llvm all-versions 3.4 3.8 3.9 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 <><> Version-specific details <><><><><><><><><><><><><><><><><><><><><><><><><> version 10.0.0 repository default homepage "http://llvm.org" bug-reports "https://llvm.org/bugs/" authors "The LLVM team" maintainer "Kate " license "MIT" flags conf synopsis Virtual package relying on llvm library installation ### opam show --all-versions "conf-llvm>7.0.0" <><> conf-llvm: information on all versions <><><><><><><><><><><><><><><><><><> name conf-llvm all-versions 3.4 3.8 3.9 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 <><> Version-specific details <><><><><><><><><><><><><><><><><><><><><><><><><> version 8.0.0 repository default homepage "http://llvm.org" bug-reports "https://llvm.org/bugs/" authors "The LLVM team" maintainer "Kate " license "MIT" flags conf synopsis Virtual package relying on llvm library installation <><> Version-specific details <><><><><><><><><><><><><><><><><><><><><><><><><> version 9.0.0 repository default homepage "http://llvm.org" bug-reports "https://llvm.org/bugs/" authors "The LLVM team" maintainer "Kate " license "MIT" flags conf synopsis Virtual package relying on llvm library installation <><> Version-specific details <><><><><><><><><><><><><><><><><><><><><><><><><> version 10.0.0 repository default homepage "http://llvm.org" bug-reports "https://llvm.org/bugs/" authors "The LLVM team" maintainer "Kate " license "MIT" flags conf synopsis Virtual package relying on llvm library installation ### opam show "conf-llvm>7.0.0" --raw opam-version: "2.0" name: "conf-llvm" version: "10.0.0" synopsis: "Virtual package relying on llvm library installation" maintainer: "Kate " authors: "The LLVM team" license: "MIT" homepage: "http://llvm.org" bug-reports: "https://llvm.org/bugs/" flags: conf build: ["bash" "-ex" "configure.sh" version] depexts: [ ["llvm@10"] {os-distribution = "homebrew" & os = "macos"} ["llvm-10.0"] {os-distribution = "macports" & os = "macos"} ["llvm-10-dev"] {os-family = "debian"} ["llvm10-dev"] {os-distribution = "alpine"} ["llvm10-devel"] {os-family = "suse"} ["devel/llvm10"] {os = "freebsd"} ] extra-files: ["configure.sh" "md5=b22c1cc2fb7743accdf5d72b9f480307"] ### opam show "conf-llvm>7.0.0" --raw --sort opam-version: "2.0" name: "conf-llvm" version: "10.0.0" synopsis: "Virtual package relying on llvm library installation" maintainer: "Kate " authors: "The LLVM team" license: "MIT" homepage: "http://llvm.org" bug-reports: "https://llvm.org/bugs/" flags: conf build: ["bash" "-ex" "configure.sh" version] depexts: [ ["devel/llvm10"] {os = "freebsd"} ["llvm-10-dev"] {os-family = "debian"} ["llvm-10.0"] {os-distribution = "macports" & os = "macos"} ["llvm10-dev"] {os-distribution = "alpine"} ["llvm10-devel"] {os-family = "suse"} ["llvm@10"] {os-distribution = "homebrew" & os = "macos"} ] extra-files: ["configure.sh" "md5=b22c1cc2fb7743accdf5d72b9f480307"] ### opam show "conf-llvm>7.0.0" --sort <><> conf-llvm: information on all versions <><><><><><><><><><><><><><><><><><> name conf-llvm all-versions 3.4 3.8 3.9 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 <><> Version-specific details <><><><><><><><><><><><><><><><><><><><><><><><><> version 10.0.0 repository default homepage "http://llvm.org" bug-reports "https://llvm.org/bugs/" authors "The LLVM team" maintainer "Kate " license "MIT" flags conf synopsis Virtual package relying on llvm library installation ### opam show "conf-llvm>7.0.0" -f depexts: --sort ["devel/llvm10"] {os = "freebsd"} ["llvm-10-dev"] {os-family = "debian"} ["llvm-10.0"] {os-distribution = "macports" & os = "macos"} ["llvm10-dev"] {os-distribution = "alpine"} ["llvm10-devel"] {os-family = "suse"} ["llvm@10"] {os-distribution = "homebrew" & os = "macos"} ### opam-version: "2.0" name: "showtest" version: "1.0" synopsis: "A word" description: "Two words." maintainer: "opam-devel@lists.ocaml.org" authors: [ "Z" "A" "R" ] homepage: "x" bug-reports: "x" depends: [ "ocaml" {>= "4.02.3"} "base-unix" "base-bigarray" "ocamlgraph" "re" {>= "1.5.0"} "dune" {>= "1.2.1"} "cppo" {build} ] conflicts: ["extlib-compat"] build: [ [ "./configure" ] [ make ] ] dev-repo: "git+https://github.com/ocaml/opam.git" ### opam show ./showtest.opam --sort --raw opam-version: "2.0" name: "showtest" version: "1.0" synopsis: "A word" description: "Two words." maintainer: "opam-devel@lists.ocaml.org" authors: ["A" "R" "Z"] homepage: "x" bug-reports: "x" depends: [ "base-bigarray" "base-unix" "ocamlgraph" "cppo" {build} "dune" {>= "1.2.1"} "ocaml" {>= "4.02.3"} "re" {>= "1.5.0"} ] conflicts: ["extlib-compat"] build: [ ["./configure"] [make] ] dev-repo: "git+https://github.com/ocaml/opam.git" ### opam show ./showtest.opam --sort <><> showtest: information on all versions ><><><><><><><><><><><><><><><><><><> name showtest all-versions 1.0 <><> Version-specific details <><><><><><><><><><><><><><><><><><><><><><><><><> version 1.0 pin -- homepage "x" bug-reports "x" dev-repo "git+https://github.com/ocaml/opam.git" authors "A" "R" "Z" maintainer "opam-devel@lists.ocaml.org" depends "base-bigarray" "base-unix" "ocamlgraph" "cppo" {build} "dune" {>= "1.2.1"} "ocaml" {>= "4.02.3"} "re" {>= "1.5.0"} conflicts "extlib-compat" synopsis A word description Two words. ### opam show ./showtest.opam --sort --just-file opam-version: "2.0" name: "showtest" version: "1.0" synopsis: "A word" description: "Two words." maintainer: "opam-devel@lists.ocaml.org" authors: ["A" "R" "Z"] homepage: "x" bug-reports: "x" depends: [ "base-bigarray" "base-unix" "ocamlgraph" "cppo" {build} "dune" {>= "1.2.1"} "ocaml" {>= "4.02.3"} "re" {>= "1.5.0"} ] conflicts: ["extlib-compat"] build: [ ["./configure"] [make] ] dev-repo: "git+https://github.com/ocaml/opam.git" ### opam show ./showtest.opam -f depends: --sort "base-bigarray" "base-unix" "ocamlgraph" "cppo" {build} "dune" {>= "1.2.1"} "ocaml" {>= "4.02.3"} "re" {>= "1.5.0"} ### OPAMDEBUGSECTIONS=AUXCMD opam show ./showtest.opam --debug-level=-1 --debug --just-file opam-version: "2.0" name: "showtest" version: "1.0" synopsis: "A word" description: "Two words." maintainer: "opam-devel@lists.ocaml.org" authors: ["Z" "A" "R"] homepage: "x" bug-reports: "x" depends: [ "ocaml" {>= "4.02.3"} "base-unix" "base-bigarray" "ocamlgraph" "re" {>= "1.5.0"} "dune" {>= "1.2.1"} "cppo" {build} ] conflicts: ["extlib-compat"] build: [ ["./configure"] [make] ] dev-repo: "git+https://github.com/ocaml/opam.git" ### OPAMDEBUGSECTIONS=AUXCMD opam show ./showtest.opam --debug-level=-1 AUXCMD autopin: { showtest => file://${BASEDIR} } <><> showtest: information on all versions ><><><><><><><><><><><><><><><><><><> name showtest all-versions 1.0 <><> Version-specific details <><><><><><><><><><><><><><><><><><><><><><><><><> version 1.0 pin -- homepage "x" bug-reports "x" dev-repo "git+https://github.com/ocaml/opam.git" authors "Z" "A" "R" maintainer "opam-devel@lists.ocaml.org" depends "ocaml" {>= "4.02.3"} "base-unix" "base-bigarray" "ocamlgraph" "re" {>= "1.5.0"} "dune" {>= "1.2.1"} "cppo" {build} conflicts "extlib-compat" synopsis A word description Two words. ### opam show ./showtest.opam --normalise -f depends: ["ocaml" {>= "4.02.3"} "base-unix" "base-bigarray" "ocamlgraph" "re" {>= "1.5.0"} "dune" {>= "1.2.1"} "cppo" {build}] ### OPAMVAR_os=freebsd opam show "conf-llvm>7.0.0" -f name,version,depexts: --all-versions name conf-llvm version 8.0.0 depexts: ["llvm@8"] {os-distribution = "homebrew" & os = "macos"} ["llvm-8.0"] {os-distribution = "macports" & os = "macos"} ["llvm-8-dev"] {os-family = "debian"} ["llvm8-dev"] {os-distribution = "alpine"} ["llvm8-devel"] {os-family = "suse"} ["devel/llvm80"] {os = "freebsd"} name conf-llvm version 9.0.0 depexts: ["llvm@9"] {os-distribution = "homebrew" & os = "macos"} ["llvm-9.0"] {os-distribution = "macports" & os = "macos"} ["llvm-9-dev"] {os-family = "debian"} ["llvm9-dev"] {os-distribution = "alpine"} ["llvm9-devel"] {os-family = "suse"} ["devel/llvm90"] {os = "freebsd"} name conf-llvm version 10.0.0 depexts: ["llvm@10"] {os-distribution = "homebrew" & os = "macos"} ["llvm-10.0"] {os-distribution = "macports" & os = "macos"} ["llvm-10-dev"] {os-family = "debian"} ["llvm10-dev"] {os-distribution = "alpine"} ["llvm10-devel"] {os-family = "suse"} ["devel/llvm10"] {os = "freebsd"} ### OPAMVAR_os=freebsd OPAMVAR_os_family=debian opam show "conf-llvm>7.0.0" -f name,version,depexts --all-versions name conf-llvm version 8.0.0 depexts devel/llvm80 llvm-8-dev name conf-llvm version 9.0.0 depexts devel/llvm90 llvm-9-dev name conf-llvm version 10.0.0 depexts devel/llvm10 llvm-10-dev opam-2.1.5/tests/reftests/conflict-badversion.test0000644000175000017500000000323314427463453021355 0ustar stephstephf372039d ### OPAMVAR_arch=x86_64 OPAMVAR_os=linux OPAMVAR_os_family=arch OPAMVAR_os_distribution=archarm ### opam switch create --fake ocaml-base-compiler.4.02.3 <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml-base-compiler" {= "4.02.3"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-base-compiler.4.02.3 Faking installation of ocaml-config.1 Faking installation of ocaml.4.02.3 Faking installation of base-ocamlbuild.base Done. ### opam install 'core>112.17.00' 'core<112.17.00' --show [ERROR] Package conflict! * No agreement on the version of core: - core != 112.17.00 * No agreement on the version of ocaml: - (invariant) -> ocaml-base-compiler = 4.02.3 -> ocaml = 4.02.3 - core != 112.17.00 -> ocaml < 4.00.1 You can temporarily relax the switch invariant with `--update-invariant' * No agreement on the version of ocaml-base-compiler: - (invariant) -> ocaml-base-compiler = 4.02.3 - core != 112.17.00 -> ocaml < 4.00.1 -> ocaml-base-compiler < 3.07+1 * Missing dependency: - core != 112.17.00 -> ocaml < 4.00.1 -> ocaml-variants -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' No solution found, exiting # Return code 20 # ### opam remove ocaml --show * Incompatible packages: - (invariant) -> ocaml-base-compiler = 4.02.3 - (request) You can temporarily relax the switch invariant with `--update-invariant' No solution found, exiting # Return code 20 # opam-2.1.5/tests/reftests/remove.test0000644000175000017500000000213214427463453016714 0ustar stephstephN0REP0 ### :::::: removal of partial dependencies (#4727) ### opam-version: "2.0" ### opam-version: "2.0" ### opam-version: "2.0" depends: "a" | "b" ### opam switch create default --empty ### opam install a b c The following actions will be performed: - install b 1 - install a 1 - install c 1 ===== 3 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed a.1 -> installed b.1 -> installed c.1 Done. ### opam remove a --show The following actions would be performed: - remove c 1 [uses a] - remove a 1 ===== 2 to remove ===== ### opam remove --auto --show Nothing to do. ### opam remove a --auto --show The following actions would be performed: - remove c 1 [uses a] - remove a 1 ===== 2 to remove ===== ### :::::: message on removal of an unavailable package (#4890) ### opam-version: "2.0" available: false ### opam-version: "2.0" depends: "z" ### opam remove z [ERROR] z unmet availability conditions: 'false' # Return code 5 # ### opam remove w [NOTE] w is not installed. Nothing to do. opam-2.1.5/tests/reftests/run.mli0000644000175000017500000000001414427463453016022 0ustar stephsteph(* empty *) opam-2.1.5/tests/reftests/opamrt-dep-cycle.test0000644000175000017500000000427114427463453020572 0ustar stephstephN0REP0 ### OPAMYES=true ### : init_u ### opam-version: "2.0" install: [ "mkdir" _:lib ] depends: "b" {= version} build: [ "test" "-d" b:lib ] remove: [ "test" "-d" b:lib ] ### opam-version: "2.0" install: [ "mkdir" _:lib ] ### opam-version: "2.0" install: [ "mkdir" _:lib ] ### opam-version: "2.0" install: [ "mkdir" _:lib ] depends: "a" {= version} build: [ "test" "-d" a:lib ] remove: [ "test" "-d" a:lib ] ### opam switch create system --empty ### opam install a.1 The following actions will be performed: - install b 1 [required by a] - install a 1 ===== 2 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed b.1 -> installed a.1 Done. ### opam list -sV a.1 b.1 ### opam upgrade The following actions will be performed: - upgrade a 1 to 2 - upgrade b 1 to 2 ===== 2 to upgrade ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed a.1 -> removed b.1 -> installed a.2 -> installed b.2 Done. ### opam list -sV a.2 b.2 ### opam install a.1 The following actions will be performed: - downgrade b 2 to 1 [required by a] - downgrade a 2 to 1 ===== 2 to downgrade ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed b.2 -> removed a.2 -> installed b.1 -> installed a.1 Done. ### opam list -sV a.1 b.1 ### opam upgrade The following actions will be performed: - upgrade a 1 to 2 - upgrade b 1 to 2 ===== 2 to upgrade ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed a.1 -> removed b.1 -> installed a.2 -> installed b.2 Done. ### opam list -sV a.2 b.2 ### opam remove b The following actions will be performed: - remove b 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed b.2 Done. ### opam install a.1 The following actions will be performed: - install b 1 [required by a] - downgrade a 2 to 1 ===== 1 to install | 1 to downgrade ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed a.2 -> installed b.1 -> installed a.1 Done. ### opam list -sV a.1 b.1 opam-2.1.5/tests/reftests/empty-conflicts-002.test0000644000175000017500000000636214427463453021047 0ustar stephsteph11ea1cb ### OPAMYES=1 OPAMSTRICT=0 ### OPAMVAR_arch=x86_64 OPAMVAR_os=linux OPAMVAR_os_family=arch OPAMVAR_os_distribution=archarm ### opam switch create test ocaml-base-compiler.4.14.0 --fake <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml-base-compiler" {= "4.14.0"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-base-compiler.4.14.0 Faking installation of ocaml-config.2 Faking installation of ocaml.4.14.0 Faking installation of ocaml-options-vanilla.1 Done. ### opam pin add -k version -n ppx_deriving_yojson.3.7.0 3.7.0 ppx_deriving_yojson is now pinned to version 3.7.0 ### opam install ppx_deriving_yojson.3.7.0 --fake The following actions will be faked: - install seq base [required by yojson] - install ocamlfind 1.9.5 [required by ppx_deriving] - install dune 3.4.1 [required by ppx_deriving_yojson] - install stdlib-shims 0.3.0 [required by ppxlib] - install sexplib0 v0.15.1 [required by ppxlib] - install result 1.5 [required by ppx_deriving_yojson] - install ppx_derivers 1.2.1 [required by ppx_deriving] - install ocaml-compiler-libs v0.12.4 [required by ppxlib] - install cppo 1.6.9 [required by ppx_deriving, yojson] - install ppxlib 0.27.0 [required by ppx_deriving_yojson] - install yojson 2.0.2 [required by ppx_deriving_yojson] - install ppx_deriving 5.2.1 [required by ppx_deriving_yojson] - install ppx_deriving_yojson 3.7.0* ===== 13 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of dune.3.4.1 Faking installation of cppo.1.6.9 Faking installation of ocaml-compiler-libs.v0.12.4 Faking installation of ocamlfind.1.9.5 Faking installation of ppx_derivers.1.2.1 Faking installation of result.1.5 Faking installation of seq.base Faking installation of sexplib0.v0.15.1 Faking installation of stdlib-shims.0.3.0 Faking installation of ppxlib.0.27.0 Faking installation of ppx_deriving.5.2.1 Faking installation of yojson.2.0.2 Faking installation of ppx_deriving_yojson.3.7.0 Done. ### opam install --show fstar.2022.01.15 [ERROR] Package conflict! * No agreement on the version of ocaml: - (invariant) -> ocaml-base-compiler = 4.14.0 -> ocaml = 4.14.0 - fstar >= 2022.01.15 -> ppxlib < 0.26.0 -> ocaml < 4.14 You can temporarily relax the switch invariant with `--update-invariant' * No agreement on the version of ocaml-base-compiler: - (invariant) -> ocaml-base-compiler = 4.14.0 - fstar >= 2022.01.15 -> ppxlib < 0.26.0 -> ocaml < 4.08.0 -> ocaml-base-compiler = 4.04.1 * No agreement on the version of ppxlib: - fstar >= 2022.01.15 -> ppx_deriving_yojson -> ppxlib >= 0.26.0 - fstar >= 2022.01.15 -> ppxlib < 0.26.0 * Missing dependency: - fstar >= 2022.01.15 -> ppxlib < 0.26.0 -> ocaml < 4.08.0 -> ocaml-variants >= 4.02.4 -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' No solution found, exiting # Return code 20 # opam-2.1.5/tests/reftests/orphans.test0000644000175000017500000000510314427463453017072 0ustar stephstephN0REP0 ### opam-version: "2.0" install: ["touch" "%{lib}%/foo.1"] ### opam-version: "2.0" depends: "foo" {= "1"} ### opam-version: "2.0" ### OPAMYES=1 ### opam switch create sw --empty ### opam install bar The following actions will be performed: - install foo 1 [required by bar] - install bar 1 ===== 2 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed foo.1 -> installed bar.1 Done. ### opam-version: "2.0" available: false ### opam reinstall foo [ERROR] Sorry, these packages are no longer available from the repositories: foo (= 1) # Return code 5 # ### : no action should be triggered on foo ### opam install baz --show The following actions would be performed: - install baz 1 ### opam reinstall --list-pending foo.1 ### opam upgrade --show The following actions would be performed: - remove bar 1 - remove foo 1 ===== 2 to remove ===== ### : dependency foo is installed but no longer available ### opam upgrade bar The following actions will be performed: - recompile foo 1 [upstream or system changes] - recompile bar 1 ===== 2 to recompile ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed bar.1 -> removed foo.1 -> installed foo.1 -> installed bar.1 Done. ### opam clean -s Cleaning up switch sw ### opam upgrade bar Already up-to-date. Nothing to do. ### : replay the same sequence but with another version of `foo` present ### opam-version: "2.0" ### opam upgrade --show [WARNING] Upgrade is not possible because of conflicts or packages that are no longer available: - Missing dependency: - foo < 2 unmet availability conditions: 'false' You may run "opam upgrade --fixup" to let opam fix the current state. # Return code 20 # ### opam-version: "2.0" depends: "foo" {>= "1"} ### opam upgrade --show The following actions would be performed: - upgrade foo 1 to 2 - upgrade bar 1 to 2 ===== 2 to upgrade ===== ### opam upgrade --show --fixup The following actions would be performed: - upgrade foo 1 to 2 - upgrade bar 1 to 2 ===== 2 to upgrade ===== ### opam reinstall baz baz is not installed. Install it? [Y/n] y The following actions will be performed: - install baz 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed baz.1 Done. ### opam upgrade bar The following actions will be performed: - upgrade bar 1 to 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed bar.1 -> installed bar.2 Done. opam-2.1.5/tests/reftests/opamroot-versions.test0000644000175000017500000031127114427463453021134 0ustar stephstephN0REP0 ### opam option opam-root-version --global | '"' -> '' >$ OPAMROOTVERSION ### OPAMYES=1 OPAMDEBUG=-1 OPAMSTRICT=0 OPAMDEBUGSECTIONS="FMT_UPG FORMAT GSTATE RSTATE STATE" ### : setup ### let current = Sys.argv.(1) let opam_version = Printf.sprintf "opam-version: %S" let root_version = Printf.sprintf "opam-root-version: %S" let switches = {| installed-switches: "foo" switch: "foo" |} let neant = "neant: 0" let repo = {|repositories: [ "default" {"file:///${BASEDIR/dontexist"} ]|} let switch_config = {|synopsis: "foo"|} let _ = let configs = ( let opam_v = opam_version "2.0" in List.map (fun v -> [ "config."^v, [ opam_v ; root_version v ]; "config-w-swfoo."^v, [ opam_v; root_version v; switches ]; ]) ["2.0"; current; "4.8"] |> List.flatten) @ (let opam_v = opam_version current in let v = "9.6" in [ "config."^v, [ opam_v; root_version v ]; "config-w-swfoo."^v, [ opam_v; root_version v; switches ]; ]) in let files = [ "repos-config", [ repo ]; "switch-config", [ opam_version "2.0"; switch_config ]; ] @ configs in let errs = List.map (fun (n,c) -> n^".err" , c@[neant]) files @ (let v = current in let opam_v = opam_version current in [ "config."^v^".wrong", [ opam_v; root_version v ]; "switch-config.wrong", [ opam_v; switch_config ]; ]) in List.iter (fun (name, content) -> let fd = open_out name in List.iter (fun l -> output_string fd (l^"\n")) content; close_out fd) (files @ errs) ### ocaml generate.ml $OPAMROOTVERSION ### opam-version: "2.0" ### mkdir root-config/packages ### : : ### :I: Current opam root : ### : : ### :I:1:a: Bad config file ### cp config.$OPAMROOTVERSION.err $OPAMROOT/config ### # ro global state ### opam switch [WARNING] Errors in ${BASEDIR}/OPAM/config, some fields have been ignored: - At ${BASEDIR}/OPAM/config:3:0-3:8:: Invalid field neant GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [WARNING] Errors in ${BASEDIR}/OPAM/config, some fields have been ignored: - At ${BASEDIR}/OPAM/config:3:0-3:8:: Invalid field neant # switch compiler description ### :I:1:b: Good config file ### cp config.$OPAMROOTVERSION $OPAMROOT/config ### # ro global state ### opam switch GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM # switch compiler description ### :I:2:a: Bad repo config file : ### cp repos-config.err $OPAMROOT/repo/repos-config ### # ro global state, ro repo state ### opam list --no-switch GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM [WARNING] Errors in ${BASEDIR}/OPAM/repo/repos-config, some fields have been ignored: - At ${BASEDIR}/OPAM/repo/repos-config:2:0-2:8:: Invalid field neant RSTATE Cache found # No matches found ### # ro global state, rw repo state ### opam repo add root-config ./root-config --set-default GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM [WARNING] Errors in ${BASEDIR}/OPAM/repo/repos-config, some fields have been ignored: - At ${BASEDIR}/OPAM/repo/repos-config:2:0-2:8:: Invalid field neant RSTATE Cache found [root-config] Initialised ### opam repo remove root-config --all --debug-level=0 ### :I:2:b: Good repo config file : ### cp repos-config $OPAMROOT/repo/repos-config ### # ro global state, ro repo state ### opam list --no-switch GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found # No matches found ### # ro global state, rw repo state ### opam repo add root-config ./root-config --set-default GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found [root-config] Initialised ### opam switch create foo --empty --debug-level=0 ### :I:3:a: Bad switch config file : ### cp switch-config.err $OPAMROOT/foo/.opam-switch/switch-config ### # ro global state, ro repo state, ro switch state ### opam list GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ foo [WARNING] Errors in ${BASEDIR}/OPAM/foo/.opam-switch/switch-config, some fields have been ignored: - At ${BASEDIR}/OPAM/foo/.opam-switch/switch-config:3:0-3:8:: Invalid field neant STATE Inferred invariant: from base packages {}, (roots {}) => [] STATE Switch state loaded in 0.000s # Packages matching: installed # No matches found ### # ro global state, ro repo state, rw switch state ### opam install bar GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ foo [WARNING] Errors in ${BASEDIR}/OPAM/foo/.opam-switch/switch-config, some fields have been ignored: - At ${BASEDIR}/OPAM/foo/.opam-switch/switch-config:3:0-3:8:: Invalid field neant STATE Inferred invariant: from base packages {}, (roots {}) => [] STATE Switch state loaded in 0.000s [ERROR] No package named bar found. # Return code 5 # ### :I:3:b: Good switch config file : ### cp switch-config $OPAMROOT/foo/.opam-switch/switch-config ### # ro global state, ro repo state, ro switch state ### opam list GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ foo STATE Inferred invariant: from base packages {}, (roots {}) => [] STATE Switch state loaded in 0.000s # Packages matching: installed # No matches found ### # ro global state, ro repo state, rw switch state ### opam install bar GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ foo STATE Inferred invariant: from base packages {}, (roots {}) => [] STATE Switch state loaded in 0.000s [ERROR] No package named bar found. # Return code 5 # ### :I:1:a: Bad config file ### cp config-w-swfoo.$OPAMROOTVERSION.err $OPAMROOT/config ### # rw global state ### opam switch remove foo [WARNING] Errors in ${BASEDIR}/OPAM/config, some fields have been ignored: - At ${BASEDIR}/OPAM/config:7:0-7:8:: Invalid field neant GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [WARNING] Errors in ${BASEDIR}/OPAM/config, some fields have been ignored: - At ${BASEDIR}/OPAM/config:7:0-7:8:: Invalid field neant Switch foo and all its packages will be wiped. Are you sure? [Y/n] y ### :I:1:b: Good config file ### opam switch create foo --empty --debug-level=0 ### cp config-w-swfoo.$OPAMROOTVERSION $OPAMROOT/config ### # rw global state ### opam switch remove foo GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Switch foo and all its packages will be wiped. Are you sure? [Y/n] y ### : : ### :II: Current opam root & newer opam file version : ### : : ### :II:1: config with newer opam version file & no update of root version ### cp config.$OPAMROOTVERSION.wrong $OPAMROOT/config ### # ro global state ### opam switch GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Fatal error: In ${BASEDIR}/OPAM/config: unsupported or missing file format version; should be 2.0 or older # Return code 99 # ### opam option jobs GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Fatal error: In ${BASEDIR}/OPAM/config: unsupported or missing file format version; should be 2.0 or older # Return code 99 # ### # rw global state ### opam switch bar GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Fatal error: In ${BASEDIR}/OPAM/config: unsupported or missing file format version; should be 2.0 or older # Return code 99 # ### :II:2: switch-config with newer opam version file & no update of root version ### cp config.$OPAMROOTVERSION $OPAMROOT/config ### opam switch create foo --empty --debug-level=0 ### cp switch-config.wrong $OPAMROOT/foo/.opam-switch/switch-config ### # ro global state ### opam option jobs GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM ### # rw global state ### # opam option synopsis="bar" --switch foo ### opam switch foo GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ foo Fatal error: In ${BASEDIR}/OPAM/foo/.opam-switch/switch-config: unsupported or missing file format version; should be 2.0 or older # Return code 99 # ### : : ### : III:Newer opam root : ### : : ### :III:1:a: Bad config file ### cp config.4.8.err $OPAMROOT/config ### # ro global state ### opam switch | "(${OPAMROOTVERSION})" -> "current" FORMAT File errors in ${BASEDIR}/OPAM/config, ignored fields: At ${BASEDIR}/OPAM/config:3:0-3:8:: Invalid field neant GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FORMAT File errors in ${BASEDIR}/OPAM/config, ignored fields: At ${BASEDIR}/OPAM/config:3:0-3:8:: Invalid field neant GSTATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) # switch compiler description ### :III:1:b: Good config file ### cp config.4.8 $OPAMROOT/config ### # ro global state ### opam switch | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM GSTATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) # switch compiler description ### :III:2:a: Bad repo config file : ### cp repos-config.err $OPAMROOT/repo/repos-config ### # ro global state, ro repo state ### opam list --no-switch | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM GSTATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM FORMAT File errors in ${BASEDIR}/OPAM/repo/repos-config, ignored fields: At ${BASEDIR}/OPAM/repo/repos-config:2:0-2:8:: Invalid field neant RSTATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) RSTATE Cache found # No matches found ### # ro global state, rw repo state ### opam repo add root-config ./root-config --set-default | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM GSTATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM [ERROR] Refusing write access to ${BASEDIR}/OPAM, which is more recent than this version of opam (4.8 > current), aborting. # Return code 15 # ### :III:2:b: Good repo config file : ### cp repos-config $OPAMROOT/repo/repos-config ### # ro global state, ro repo state ### opam list --no-switch | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM GSTATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) RSTATE Cache found # No matches found ### # ro global state, rw repo state ### opam repo add root-config ./root-config --set-default | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM GSTATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM [ERROR] Refusing write access to ${BASEDIR}/OPAM, which is more recent than this version of opam (4.8 > current), aborting. # Return code 15 # ### cp config.$OPAMROOTVERSION $OPAMROOT/config ### cp config-w-swfoo.4.8 $OPAMROOT/config ### :III:3:a: Bad switch config file : ### cp switch-config.err $OPAMROOT/foo/.opam-switch/switch-config ### # ro global state, ro repo state, ro switch state ### opam list | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM GSTATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) RSTATE Cache found STATE LOAD-SWITCH-STATE @ foo FORMAT File errors in ${BASEDIR}/OPAM/foo/.opam-switch/switch-config, ignored fields: At ${BASEDIR}/OPAM/foo/.opam-switch/switch-config:3:0-3:8:: Invalid field neant STATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) STATE Inferred invariant: from base packages {}, (roots {}) => [] STATE Switch state loaded in 0.000s # Packages matching: installed # No matches found ### # ro global state, ro repo state, rw switch state ### opam install bar | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM GSTATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) RSTATE Cache found STATE LOAD-SWITCH-STATE @ foo [ERROR] Refusing write access to ${BASEDIR}/OPAM, which is more recent than this version of opam (4.8 > current), aborting. # Return code 15 # ### :III:3:b: Good switch config file : ### cp switch-config $OPAMROOT/foo/.opam-switch/switch-config ### # ro global state, ro repo state, ro switch state ### opam list | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM GSTATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) RSTATE Cache found STATE LOAD-SWITCH-STATE @ foo STATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) STATE Inferred invariant: from base packages {}, (roots {}) => [] STATE Switch state loaded in 0.000s # Packages matching: installed # No matches found ### # ro global state, ro repo state, rw switch state ### opam install bar | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM GSTATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE root version (4.8) is greater than running binary's (current); load with best-effort (read-only) RSTATE Cache found STATE LOAD-SWITCH-STATE @ foo [ERROR] Refusing write access to ${BASEDIR}/OPAM, which is more recent than this version of opam (4.8 > current), aborting. # Return code 15 # ### :III:1:a: Bad config file ### cp config-w-swfoo.4.8.err $OPAMROOT/config ### # rw global state ### opam switch remove foo | "(${OPAMROOTVERSION})" -> "current" FORMAT File errors in ${BASEDIR}/OPAM/config, ignored fields: At ${BASEDIR}/OPAM/config:7:0-7:8:: Invalid field neant GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [ERROR] Refusing write access to ${BASEDIR}/OPAM, which is more recent than this version of opam (4.8 > current), aborting. # Return code 15 # ### :III:1:b: Good config file ### cp config-w-swfoo.4.8 $OPAMROOT/config ### # rw global state ### opam switch remove foo | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [ERROR] Refusing write access to ${BASEDIR}/OPAM, which is more recent than this version of opam (4.8 > current), aborting. # Return code 15 # ### : : ### : IV:Newer opam root & new file version : ### : : ### :IV:1:a: Bad config file ### cp config.9.6.err $OPAMROOT/config ### # ro global state ### opam switch GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Fatal error: In ${BASEDIR}/OPAM/config: unsupported or missing file format version; should be 2.0 or older # Return code 99 # ### :IV:1:b: Good config file ### cp config.9.6 $OPAMROOT/config ### # ro global state ### opam switch GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Fatal error: In ${BASEDIR}/OPAM/config: unsupported or missing file format version; should be 2.0 or older # Return code 99 # ### :IV:2:a: Bad repo config file : ### cp repos-config.err $OPAMROOT/repo/repos-config ### # ro global state, ro repo state ### opam list --no-switch GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Fatal error: In ${BASEDIR}/OPAM/config: unsupported or missing file format version; should be 2.0 or older # Return code 99 # ### # ro global state, rw repo state ### opam repo add root-config ./root-config --set-default GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Fatal error: In ${BASEDIR}/OPAM/config: unsupported or missing file format version; should be 2.0 or older # Return code 99 # ### :IV:2:b: Good repo config file : ### cp repos-config $OPAMROOT/repo/repos-config ### # ro global state, ro repo state ### opam list --no-switch GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Fatal error: In ${BASEDIR}/OPAM/config: unsupported or missing file format version; should be 2.0 or older # Return code 99 # ### # ro global state, rw repo state ### opam repo add root-config ./root-config --set-default GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Fatal error: In ${BASEDIR}/OPAM/config: unsupported or missing file format version; should be 2.0 or older # Return code 99 # ### cp config.$OPAMROOTVERSION $OPAMROOT/config ### #opam switch create foo --empty --debug-level=0 ### cp config-w-swfoo.9.6 $OPAMROOT/config ### :IV:3:a: Bad switch config file : ### cp switch-config.err $OPAMROOT/foo/.opam-switch/switch-config ### # ro global state, ro repo state, ro switch state ### opam list GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Fatal error: In ${BASEDIR}/OPAM/config: unsupported or missing file format version; should be 2.0 or older # Return code 99 # ### # ro global state, ro repo state, rw switch state ### opam install bar GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Fatal error: In ${BASEDIR}/OPAM/config: unsupported or missing file format version; should be 2.0 or older # Return code 99 # ### :IV:3:b: Good switch config file : ### cp switch-config $OPAMROOT/foo/.opam-switch/switch-config ### # ro global state, ro repo state, ro switch state ### opam list GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Fatal error: In ${BASEDIR}/OPAM/config: unsupported or missing file format version; should be 2.0 or older # Return code 99 # ### # ro global state, ro repo state, rw switch state ### opam install bar GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Fatal error: In ${BASEDIR}/OPAM/config: unsupported or missing file format version; should be 2.0 or older # Return code 99 # ### :IV:1:a: Bad config file ### cp config-w-swfoo.9.6.err $OPAMROOT/config ### # rw global state ### opam switch remove foo | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [ERROR] Refusing write access to ${BASEDIR}/OPAM, which is more recent than this version of opam (9.6 > current), aborting. # Return code 15 # ### :IV:1:b: Good config file ### cp config-w-swfoo.9.6 $OPAMROOT/config ### # rw global state ### opam switch remove foo | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [ERROR] Refusing write access to ${BASEDIR}/OPAM, which is more recent than this version of opam (9.6 > current), aborting. # Return code 15 # ### : : ### : V:Older opam root, intermediate upgrade from 2.0 to current : ### : : ### let content = {|opam-version: "2.0" synopsis: "One-line description" maintainer: "Name " authors: "Name " license: "MIT" homepage: " " bug-reports: " " dev-repo: "git://url.net/name"|} let compiler="flags: compiler" let files = [ "repo", [{|opam-version: "2.0"|}]; "packages/i-am-compiler/i-am-compiler.1/opam", [ content; compiler ]; "packages/i-am-compiler/i-am-compiler.2/opam", [ content; compiler ]; "packages/i-am-sys-compiler/i-am-sys-compiler.1/opam", [ content; compiler; {|available: sys-comp-version = "1"|}]; "packages/i-am-sys-compiler/i-am-sys-compiler.2/opam", [ content; compiler; {|available: sys-comp-version = "2"|}]; "packages/i-am-package/i-am-package.1/opam", [ content; {|depends: ["i-am-compiler"|"i-am-sys-compiler"]|} ]; "packages/i-am-package/i-am-package.2/opam", [ content; {|depends: ["i-am-compiler"|"i-am-sys-compiler"]|} ]; "packages/i-am-another-package/i-am-another-package.1/opam", [ content; {|depends: "i-am-package"|} ]; "packages/i-am-another-package/i-am-another-package.2/opam", [ content; {|depends: "i-am-package"|} ]; ] let _ = List.iter (fun (name, content) -> let fd = open_out name in List.iter (fun l -> output_string fd (l^"\n")) content; close_out fd) (List.map (fun (n,c) -> "default/"^n, c) files) ### for d in i-am-compiler i-am-sys-compiler i-am-package i-am-another-package; do for v in 1 2 ; do mkdir -p default/packages/$d/$d.$v done done ### sh generate_dirs.sh ### ocaml generate_repo.ml ### #load "unix.cma";; let rec mkdir_p dir = if Sys.file_exists dir then () else let () = mkdir_p (Filename.dirname dir) in if not (Sys.file_exists dir) then Unix.mkdir dir 0o777 else () let mode = if Array.length Sys.argv = 2 then `Root else let version = if Array.length Sys.argv = 3 then Sys.argv.(1) else Sys.argv.(3) in match Sys.argv.(2) with | "local" -> `Local version | "orphaned" -> `Orphaned version | s -> failwith s let opam_version = Printf.sprintf "opam-version: %S" let opam_version_2_0 = opam_version "2.0" let opam_version_2_1 = opam_version "2.1" let repo = {|repositories: "default"|} let installed_switches = let local_switch = match mode with | `Local _ -> Printf.sprintf " %S" (Sys.getcwd ()) | _ -> "" in Format.sprintf {| installed-switches: ["sw-sys-comp" "sw-comp"%s "default" %S "this-internal-error"] switch: "sw-sys-comp" |} local_switch (Filename.concat (Sys.getcwd ()) "why-did-you-delete-me") let default_compiler = {|default-compiler: ["i-am-sys-compiler" "i-am-compiler"]|} let default_invariant = {|default-invariant: ["i-am-sys-compiler"]|} let depext = {| depext: true depext-run-installs: true depext-cannot-install: false |} let eval = {|eval-variables: [ sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version" ]|} let sw_state_default = {| compiler: ["i-am-sys-compiler.2"] roots: ["i-am-sys-compiler.2"] installed: ["i-am-sys-compiler.2"] |} let sw_state_sw_comp = {| compiler: ["i-am-compiler.2"] roots: ["i-am-package.2" "i-am-compiler.2"] installed: ["i-am-compiler.2" "i-am-package.2"] |} let sw_state_sw_sys_comp = {| compiler: ["i-am-sys-compiler.1"] roots: ["i-am-another-package.2" "i-am-sys-compiler.1"] installed: ["i-am-another-package.2" "i-am-package.2" "i-am-sys-compiler.1"] |} let invariant_default = {|invariant: ["i-am-sys-compiler" | "i-am-compiler"]|} let invariant_sw_comp = {|invariant: ["i-am-compiler"]|} let invariant_sw_sys_comp = {|invariant: ["i-am-sys-compiler"]|} let root_version = Printf.sprintf "opam-root-version: %S" let synopsis = Printf.sprintf "synopsis: %S" let opam_root = Printf.sprintf "opam-root: %S" (Sys.getenv "OPAMROOT") let opam_20 = [ "config", [ opam_version_2_0; repo; installed_switches; eval; default_compiler ]; "default/.opam-switch/switch-config", [ opam_version_2_0; synopsis "default switch" ]; "default/.opam-switch/switch-state", [ opam_version_2_0; sw_state_default ]; "sw-comp/.opam-switch/switch-config", [ opam_version_2_0; synopsis "switch with compiler" ]; "sw-comp/.opam-switch/switch-state", [ opam_version_2_0; sw_state_sw_comp ]; "sw-sys-comp/.opam-switch/switch-config", [ opam_version_2_0; synopsis "switch with system compiler" ]; "sw-sys-comp/.opam-switch/switch-state", [ opam_version_2_0; sw_state_sw_sys_comp ] ], [ "_opam/.opam-switch/switch-config", [ opam_version_2_0; synopsis "local switch"; opam_root ]; "_opam/.opam-switch/switch-state", [ opam_version_2_0; sw_state_default ]; ] let opam_21alpha = [ "config", [ opam_version_2_0; repo; installed_switches; eval; default_compiler ]; "default/.opam-switch/switch-config", [ opam_version_2_1; synopsis "default switch"; invariant_default ]; "default/.opam-switch/switch-state", [ opam_version_2_0; sw_state_default ]; "sw-comp/.opam-switch/switch-config", [ opam_version_2_1; synopsis "switch with compiler"; invariant_sw_comp ]; "sw-comp/.opam-switch/switch-state", [ opam_version_2_0; sw_state_sw_comp ]; "sw-sys-comp/.opam-switch/switch-config", [ opam_version_2_1; synopsis "switch with system compiler"; invariant_sw_sys_comp ]; "sw-sys-comp/.opam-switch/switch-state", [ opam_version_2_0; sw_state_sw_sys_comp ] ], [ "_opam/.opam-switch/switch-config", [ opam_version_2_1; synopsis "local switch"; invariant_default; opam_root ]; "_opam/.opam-switch/switch-state", [ opam_version_2_0; sw_state_default ]; ] let opam_21alpha2 = [ "config", [ opam_version_2_1; repo; installed_switches; eval; default_compiler; depext; ]; "default/.opam-switch/switch-config", [ opam_version_2_1; synopsis "default switch"; invariant_default ]; "default/.opam-switch/switch-state", [ opam_version_2_0; sw_state_default ]; "sw-comp/.opam-switch/switch-config", [ opam_version_2_1; synopsis "switch with compiler"; invariant_sw_comp ]; "sw-comp/.opam-switch/switch-state", [ opam_version_2_0; sw_state_sw_comp ]; "sw-sys-comp/.opam-switch/switch-config", [ opam_version_2_1; synopsis "switch with system compiler"; invariant_sw_sys_comp ]; "sw-sys-comp/.opam-switch/switch-state", [ opam_version_2_0; sw_state_sw_sys_comp ] ], [ "_opam/.opam-switch/switch-config", [ opam_version_2_1; synopsis "local switch"; invariant_default; opam_root ]; "_opam/.opam-switch/switch-state", [ opam_version_2_0; sw_state_default ]; ] let opam_21rc = let root_version = {|opam-root-version: "2.1~rc"|} in [ "config", [ opam_version_2_0; root_version; repo; installed_switches; eval; default_compiler; default_invariant; depext ]; "default/.opam-switch/switch-config", [ opam_version_2_0; synopsis "default switch"; invariant_default ]; "default/.opam-switch/switch-state", [ opam_version_2_0; sw_state_default ]; "sw-comp/.opam-switch/switch-config", [ opam_version_2_0; synopsis "switch with compiler"; invariant_sw_comp ]; "sw-comp/.opam-switch/switch-state", [ opam_version_2_0; sw_state_sw_comp ]; "sw-sys-comp/.opam-switch/switch-config", [ opam_version_2_0; synopsis "switch with system compiler"; invariant_sw_sys_comp ]; "sw-sys-comp/.opam-switch/switch-state", [ opam_version_2_0; sw_state_sw_sys_comp ] ], [ "_opam/.opam-switch/switch-config", [ opam_version_2_0; synopsis "local switch"; invariant_default; opam_root ]; "_opam/.opam-switch/switch-state", [ opam_version_2_0; sw_state_default ]; ] let opam_current v = [ "config", [ opam_version_2_0; root_version v; repo; installed_switches; eval; default_compiler; default_invariant; depext ]; "default/.opam-switch/switch-config", [ opam_version_2_0; synopsis "default switch"; invariant_default ]; "default/.opam-switch/switch-state", [ opam_version_2_0; sw_state_default ]; "sw-comp/.opam-switch/switch-config", [ opam_version_2_0; synopsis "switch with compiler"; invariant_sw_comp ]; "sw-comp/.opam-switch/switch-state", [ opam_version_2_0; sw_state_sw_comp ]; "sw-sys-comp/.opam-switch/switch-config", [ opam_version_2_0; synopsis "switch with system compiler"; invariant_sw_sys_comp ]; "sw-sys-comp/.opam-switch/switch-state", [ opam_version_2_0; sw_state_sw_sys_comp ] ], [ "_opam/.opam-switch/switch-config", [ opam_version_2_0; synopsis "local switch"; invariant_default; opam_root ]; "_opam/.opam-switch/switch-state", [ opam_version_2_0; sw_state_default ]; ] let _ = let get_files = function | "2.0" -> opam_20 | "2.1~alpha" -> opam_21alpha | "2.1~alpha2" -> opam_21alpha2 | "2.1~rc" -> opam_21rc | v -> opam_current v in let write dir (name, content) = let name = Filename.concat dir name in mkdir_p (Filename.dirname name); let fd = open_out name in List.iter (fun l -> output_string fd (l^"\n")) content; close_out fd in let root,_ = get_files Sys.argv.(1) in List.iter (write (Sys.getenv "OPAMROOT")) root; match mode with | `Local v | `Orphaned v -> let _, local = get_files v in List.iter (write (Sys.getcwd ())) local | _ -> () ### rm -rf $OPAMROOT ### OPAMSYSCOMP=2 ### opam init -na default ./default --bare --bypass-checks --no-opamrc --debug-level=0 No configuration file found, using built-in defaults. <><> Fetching repository information ><><><><><><><><><><><><><><><><><><><><><> [default] Initialised ### mkdir -p $OPAMROOT $OPAMROOT/repo $OPAMROOT/default/.opam-switch $OPAMROOT/sw-comp/.opam-switch $OPAMROOT/sw-sys-comp/.opam-switch ### :V:1:a: From 2.0 root, global ### ocaml generate.ml 2.0 ### # ro global state ### opam option jobs | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG On-the-fly config upgrade, from 2.0 to current FMT_UPG Format upgrade done ### # ro global state, ro repo state, ro switch state ### opam list | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG On-the-fly config upgrade, from 2.0 to current FMT_UPG Format upgrade done RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ sw-sys-comp STATE Inferred invariant: from base packages { i-am-sys-compiler.1 }, (roots { i-am-sys-compiler.1 }) => ["i-am-sys-compiler"] STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-another-package 2 One-line description i-am-package 2 One-line description i-am-sys-compiler 1 One-line description ### # ro global state, ro repo state, rw switch state ### opam install i-am-another-package --switch sw-comp | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG On-the-fly config upgrade, from 2.0 to current FMT_UPG Format upgrade done RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ sw-comp STATE Definition missing for installed package i-am-compiler.2, copying from repo STATE Definition missing for installed package i-am-package.2, copying from repo STATE Inferred invariant: from base packages { i-am-compiler.2 }, (roots { i-am-compiler.2 }) => ["i-am-compiler" {>= "2"}] STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-another-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-another-package.2 Done. ### # rw global state ### opam switch sw-comp | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [WARNING] Removing global switch 'this-internal-error' as it no longer exists FMT_UPG Light config upgrade, from 2.0 to current This version of opam requires an update to the layout of ${BASEDIR}/OPAM from version 2.0 to version current, which can't be reverted. You may want to back it up before going further. Continue? [Y/n] y Format upgrade done. RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ sw-comp STATE Switch state loaded in 0.000s ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 1 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default"] opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-comp" ### opam-cat $OPAMROOT/sw-comp/.opam-switch/switch-config invariant: ["i-am-compiler" {>= "2"}] opam-version: "2.0" synopsis: "switch with compiler" paths { } variables { } ### opam-cat $OPAMROOT/sw-comp/.opam-switch/switch-state compiler: ["i-am-compiler.2"] installed: ["i-am-another-package.2" "i-am-compiler.2" "i-am-package.2"] opam-version: "2.0" roots: ["i-am-another-package.2" "i-am-compiler.2" "i-am-package.2"] ### :V:1:b: From 2.0 root, local ### ocaml generate.ml 2.0 local ### # ro global state, ro repo state, ro switch state ### opam list | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG On-the-fly config upgrade, from 2.0 to current FMT_UPG Format upgrade done RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Inferred invariant: from base packages { i-am-sys-compiler.2 }, (roots { i-am-sys-compiler.2 }) => ["i-am-sys-compiler"] STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-sys-compiler 2 One-line description ### # ro global state, ro repo state, rw switch state ### opam install i-am-package | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG On-the-fly config upgrade, from 2.0 to current FMT_UPG Format upgrade done RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Definition missing for installed package i-am-sys-compiler.2, copying from repo STATE Inferred invariant: from base packages { i-am-sys-compiler.2 }, (roots { i-am-sys-compiler.2 }) => ["i-am-sys-compiler"] STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-package.2 Done. ### opam option jobs=4 | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [WARNING] Removing global switch 'this-internal-error' as it no longer exists FMT_UPG Light config upgrade, from 2.0 to current This version of opam requires an update to the layout of ${BASEDIR}/OPAM from version 2.0 to version current, which can't be reverted. You may want to back it up before going further. Continue? [Y/n] y Format upgrade done. Set to '4' the field jobs in global configuration ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 1 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "${BASEDIR}" "default"] jobs: 4 opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" ### opam-cat _opam/.opam-switch/switch-config invariant: ["i-am-sys-compiler"] opam-root: "${BASEDIR}/OPAM" opam-version: "2.0" synopsis: "local switch" paths { } variables { } ### opam-cat _opam/.opam-switch/switch-state compiler: ["i-am-sys-compiler.2"] installed: ["i-am-package.2" "i-am-sys-compiler.2"] opam-version: "2.0" roots: ["i-am-package.2" "i-am-sys-compiler.2"] ### rm -rf _opam ### :V:1:c: From 2.0 root, local unknown from config ### ocaml generate.ml 2.0 orphaned ### # ro global state, ro repo state, ro switch state ### opam list | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG On-the-fly config upgrade, from 2.0 to current FMT_UPG Format upgrade done RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Inferred invariant: from base packages { i-am-sys-compiler.2 }, (roots { i-am-sys-compiler.2 }) => ["i-am-sys-compiler"] STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-sys-compiler 2 One-line description ### # ro global state, ro repo state, rw switch state ### opam install i-am-package | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG On-the-fly config upgrade, from 2.0 to current FMT_UPG Format upgrade done RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Definition missing for installed package i-am-sys-compiler.2, copying from repo STATE Inferred invariant: from base packages { i-am-sys-compiler.2 }, (roots { i-am-sys-compiler.2 }) => ["i-am-sys-compiler"] STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-package.2 Done. ### opam option jobs=4 | "(${OPAMROOTVERSION})" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [WARNING] Removing global switch 'this-internal-error' as it no longer exists FMT_UPG Light config upgrade, from 2.0 to current This version of opam requires an update to the layout of ${BASEDIR}/OPAM from version 2.0 to version current, which can't be reverted. You may want to back it up before going further. Continue? [Y/n] y Format upgrade done. Set to '4' the field jobs in global configuration ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 1 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default"] jobs: 4 opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" ### opam-cat _opam/.opam-switch/switch-config invariant: ["i-am-sys-compiler"] opam-root: "${BASEDIR}/OPAM" opam-version: "2.0" synopsis: "local switch" paths { } variables { } ### opam-cat _opam/.opam-switch/switch-state compiler: ["i-am-sys-compiler.2"] installed: ["i-am-package.2" "i-am-sys-compiler.2"] opam-version: "2.0" roots: ["i-am-package.2" "i-am-sys-compiler.2"] ### :V:1:d: Upgraded root and local 2.0 switch not recorded ### ocaml generate.ml $OPAMROOTVERSION orphaned 2.0 ### # ro global state, ro repo state, ro switch state ### opam list GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Inferred invariant: from base packages { i-am-sys-compiler.2 }, (roots { i-am-sys-compiler.2 }) => ["i-am-sys-compiler"] STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-sys-compiler 2 One-line description ### # ro global state, ro repo state, rw switch state ### opam install i-am-package GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Inferred invariant: from base packages { i-am-sys-compiler.2 }, (roots { i-am-sys-compiler.2 }) => ["i-am-sys-compiler"] STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-package.2 Done. ### opam option jobs=4 GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Set to '4' the field jobs in global configuration ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["i-am-sys-compiler"] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 1 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default" "this-internal-error"] jobs: 4 opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" ### opam-cat _opam/.opam-switch/switch-config invariant: ["i-am-sys-compiler"] opam-root: "${BASEDIR}/OPAM" opam-version: "2.0" synopsis: "local switch" paths { } variables { } ### opam-cat _opam/.opam-switch/switch-state compiler: ["i-am-sys-compiler.2"] installed: ["i-am-package.2" "i-am-sys-compiler.2"] opam-version: "2.0" roots: ["i-am-package.2" "i-am-sys-compiler.2"] ### :V:1:e: reinit from 2.0 ### ocaml generate.ml 2.0 ### opam init --reinit --bypass-checks --no-setup | "(${OPAMROOTVERSION})" -> "current" No configuration file found, using built-in defaults. GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [WARNING] Removing global switch 'this-internal-error' as it no longer exists FMT_UPG Light config upgrade, from 2.0 to current This version of opam requires an update to the layout of ${BASEDIR}/OPAM from version 2.0 to version current, which can't be reverted. You may want to back it up before going further. Continue? [Y/n] y Format upgrade done. RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found <><> Updating repositories ><><><><><><><><><><><><><><><><><><><><><><><><><><> [default] no changes from file://${BASEDIR}/default ### opam switch --short GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM ${BASEDIR} default sw-comp sw-sys-comp ### opam list GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-package 2 One-line description i-am-sys-compiler 2 One-line description ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["ocaml" {>= "4.05.0"}] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 3 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default"] opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" wrap-build-commands: ["%{hooks}%/sandbox.sh" "build"] {os = "linux" | os = "macos"} wrap-install-commands: ["%{hooks}%/sandbox.sh" "install"] {os = "linux" | os = "macos"} wrap-remove-commands: ["%{hooks}%/sandbox.sh" "remove"] {os = "linux" | os = "macos"} ### rm -rf _opam ### :V:2:a: From 2.1~alpha root, global ### ocaml generate.ml 2.1~alpha ### opam list | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [WARNING] Removing global switch 'this-internal-error' as it no longer exists FMT_UPG Hard config upgrade, from 2.1~alpha to current This version of opam requires an update to the layout of ${BASEDIR}/OPAM from version 2.1~alpha to version current which can't be reverted. You may want to back it up before going further. Perform the update and continue? [Y/n] y Format upgrade done. <><> Rerunning init and update ><><><><><><><><><><><><><><><><><><><><><><><><> GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found <><> Updating repositories ><><><><><><><><><><><><><><><><><><><><><><><><><><> [default] no changes from file://${BASEDIR}/default Update done, please now retry your command. # Return code 10 # ### # ro global state, ro repo state, ro switch state ### opam list GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ sw-sys-comp STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-another-package 2 One-line description i-am-package 2 One-line description i-am-sys-compiler 1 One-line description ### # ro global state, ro repo state, rw switch state ### opam install i-am-another-package --switch sw-comp GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ sw-comp STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-another-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-another-package.2 Done. ### # rw global state ### opam switch sw-comp GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ sw-comp STATE Switch state loaded in 0.000s ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["ocaml" {>= "4.05.0"}] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 3 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default"] opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-comp" wrap-build-commands: ["%{hooks}%/sandbox.sh" "build"] {os = "linux" | os = "macos"} wrap-install-commands: ["%{hooks}%/sandbox.sh" "install"] {os = "linux" | os = "macos"} wrap-remove-commands: ["%{hooks}%/sandbox.sh" "remove"] {os = "linux" | os = "macos"} ### opam-cat $OPAMROOT/sw-comp/.opam-switch/switch-config invariant: ["i-am-compiler"] opam-version: "2.0" synopsis: "switch with compiler" paths { } variables { } ### opam-cat $OPAMROOT/sw-comp/.opam-switch/switch-state compiler: ["i-am-compiler.2"] installed: ["i-am-another-package.2" "i-am-compiler.2" "i-am-package.2"] opam-version: "2.0" roots: ["i-am-another-package.2" "i-am-compiler.2" "i-am-package.2"] ### :V:2:b: From 2.1~alpha root, local ### ocaml generate.ml 2.1~alpha local ### opam list | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [WARNING] Removing global switch 'this-internal-error' as it no longer exists FMT_UPG Hard config upgrade, from 2.1~alpha to current This version of opam requires an update to the layout of ${BASEDIR}/OPAM from version 2.1~alpha to version current which can't be reverted. You may want to back it up before going further. Perform the update and continue? [Y/n] y Format upgrade done. <><> Rerunning init and update ><><><><><><><><><><><><><><><><><><><><><><><><> GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found <><> Updating repositories ><><><><><><><><><><><><><><><><><><><><><><><><><><> [default] no changes from file://${BASEDIR}/default Update done, please now retry your command. # Return code 10 # ### opam install i-am-package GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Definition missing for installed package i-am-sys-compiler.2, copying from repo STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-package.2 Done. ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["ocaml" {>= "4.05.0"}] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 3 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "${BASEDIR}" "default"] opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" wrap-build-commands: ["%{hooks}%/sandbox.sh" "build"] {os = "linux" | os = "macos"} wrap-install-commands: ["%{hooks}%/sandbox.sh" "install"] {os = "linux" | os = "macos"} wrap-remove-commands: ["%{hooks}%/sandbox.sh" "remove"] {os = "linux" | os = "macos"} ### opam-cat _opam/.opam-switch/switch-config invariant: ["i-am-sys-compiler" | "i-am-compiler"] opam-root: "${BASEDIR}/OPAM" opam-version: "2.0" synopsis: "local switch" paths { } variables { } ### opam-cat _opam/.opam-switch/switch-state compiler: ["i-am-sys-compiler.2"] installed: ["i-am-package.2" "i-am-sys-compiler.2"] opam-version: "2.0" roots: ["i-am-package.2" "i-am-sys-compiler.2"] ### rm -rf _opam ### :V:2:c: From 2.1~alpha root, local unknown from config ### ocaml generate.ml 2.1~alpha orphaned ### opam list | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [WARNING] Removing global switch 'this-internal-error' as it no longer exists FMT_UPG Hard config upgrade, from 2.1~alpha to current This version of opam requires an update to the layout of ${BASEDIR}/OPAM from version 2.1~alpha to version current which can't be reverted. You may want to back it up before going further. Perform the update and continue? [Y/n] y Format upgrade done. <><> Rerunning init and update ><><><><><><><><><><><><><><><><><><><><><><><><> GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found <><> Updating repositories ><><><><><><><><><><><><><><><><><><><><><><><><><><> [default] no changes from file://${BASEDIR}/default Update done, please now retry your command. # Return code 10 # ### opam install i-am-package FILE(switch-config) Wrote ${BASEDIR}/_opam/.opam-switch/switch-config in 0.000s GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Definition missing for installed package i-am-sys-compiler.2, copying from repo STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-package.2 Done. ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["ocaml" {>= "4.05.0"}] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 3 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default"] opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" wrap-build-commands: ["%{hooks}%/sandbox.sh" "build"] {os = "linux" | os = "macos"} wrap-install-commands: ["%{hooks}%/sandbox.sh" "install"] {os = "linux" | os = "macos"} wrap-remove-commands: ["%{hooks}%/sandbox.sh" "remove"] {os = "linux" | os = "macos"} ### opam-cat _opam/.opam-switch/switch-config invariant: ["i-am-sys-compiler" | "i-am-compiler"] opam-root: "${BASEDIR}/OPAM" opam-version: "2.0" synopsis: "local switch" paths { } variables { } ### opam-cat _opam/.opam-switch/switch-state compiler: ["i-am-sys-compiler.2"] installed: ["i-am-package.2" "i-am-sys-compiler.2"] opam-version: "2.0" roots: ["i-am-package.2" "i-am-sys-compiler.2"] ### :V:2:d: Upgraded root and local 2.1~alpha switch not recorded ### ocaml generate.ml $OPAMROOTVERSION orphaned 2.1~alpha ### # ro global state, ro repo state, ro switch state ### opam list FILE(switch-config) Wrote ${BASEDIR}/_opam/.opam-switch/switch-config in 0.000s GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-sys-compiler 2 One-line description ### # ro global state, ro repo state, rw switch state ### opam install i-am-package GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-package.2 Done. ### opam option jobs=4 GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Set to '4' the field jobs in global configuration ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["i-am-sys-compiler"] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 1 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default" "this-internal-error"] jobs: 4 opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" ### opam-cat _opam/.opam-switch/switch-config invariant: ["i-am-sys-compiler" | "i-am-compiler"] opam-root: "${BASEDIR}/OPAM" opam-version: "2.0" synopsis: "local switch" paths { } variables { } ### opam-cat _opam/.opam-switch/switch-state compiler: ["i-am-sys-compiler.2"] installed: ["i-am-package.2" "i-am-sys-compiler.2"] opam-version: "2.0" roots: ["i-am-package.2" "i-am-sys-compiler.2"] ### :V:2:e: reinit from 2.1~alpha ### ocaml generate.ml 2.1~alpha ### opam init --reinit --bypass-checks --no-setup | "${OPAMROOTVERSION}($|,)" -> "current" No configuration file found, using built-in defaults. GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [WARNING] Removing global switch 'this-internal-error' as it no longer exists FMT_UPG Hard config upgrade, from 2.1~alpha to current This version of opam requires an update to the layout of ${BASEDIR}/OPAM from version 2.1~alpha to version current which can't be reverted. You may want to back it up before going further. Perform the update and continue? [Y/n] y Format upgrade done. <><> Rerunning init and update ><><><><><><><><><><><><><><><><><><><><><><><><> GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found <><> Updating repositories ><><><><><><><><><><><><><><><><><><><><><><><><><><> [default] no changes from file://${BASEDIR}/default Update done, please now retry your command. # Return code 10 # ### opam switch --short GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM ${BASEDIR} default sw-comp sw-sys-comp ### opam list GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-package 2 One-line description i-am-sys-compiler 2 One-line description ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["ocaml" {>= "4.05.0"}] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 3 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default"] opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" wrap-build-commands: ["%{hooks}%/sandbox.sh" "build"] {os = "linux" | os = "macos"} wrap-install-commands: ["%{hooks}%/sandbox.sh" "install"] {os = "linux" | os = "macos"} wrap-remove-commands: ["%{hooks}%/sandbox.sh" "remove"] {os = "linux" | os = "macos"} ### rm -rf _opam ### :V:3:a: From 2.1~alpha2 root, global ### ocaml generate.ml 2.1~alpha2 ### # ro global state ### opam option jobs | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG Intermediate opam root detected, launch hard upgrade FMT_UPG Downgrade config opam-version to fix up [WARNING] Removing global switch 'this-internal-error' as it no longer exists FMT_UPG Hard config upgrade, from 2.1~alpha2 to current This version of opam requires an update to the layout of ${BASEDIR}/OPAM from version 2.1~alpha2 to version current which can't be reverted. You may want to back it up before going further. Perform the update and continue? [Y/n] y Format upgrade done. <><> Rerunning init and update ><><><><><><><><><><><><><><><><><><><><><><><><> GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found <><> Updating repositories ><><><><><><><><><><><><><><><><><><><><><><><><><><> [default] no changes from file://${BASEDIR}/default Update done, please now retry your command. # Return code 10 # ### # ro global state, ro repo state, ro switch state ### opam list GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ sw-sys-comp STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-another-package 2 One-line description i-am-package 2 One-line description i-am-sys-compiler 1 One-line description ### # ro global state, ro repo state, rw switch state ### opam install i-am-another-package --switch sw-comp GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ sw-comp STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-another-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-another-package.2 Done. ### # rw global state ### opam switch sw-comp GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ sw-comp STATE Switch state loaded in 0.000s ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["ocaml" {>= "4.05.0"}] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 3 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default"] opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-comp" wrap-build-commands: ["%{hooks}%/sandbox.sh" "build"] {os = "linux" | os = "macos"} wrap-install-commands: ["%{hooks}%/sandbox.sh" "install"] {os = "linux" | os = "macos"} wrap-remove-commands: ["%{hooks}%/sandbox.sh" "remove"] {os = "linux" | os = "macos"} ### opam-cat $OPAMROOT/sw-comp/.opam-switch/switch-config invariant: ["i-am-compiler"] opam-version: "2.0" synopsis: "switch with compiler" paths { } variables { } ### opam-cat $OPAMROOT/sw-comp/.opam-switch/switch-state compiler: ["i-am-compiler.2"] installed: ["i-am-another-package.2" "i-am-compiler.2" "i-am-package.2"] opam-version: "2.0" roots: ["i-am-another-package.2" "i-am-compiler.2" "i-am-package.2"] ### :V:3:b: From 2.1~alpha2 root, local ### ocaml generate.ml 2.1~alpha2 local ### opam list | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG Intermediate opam root detected, launch hard upgrade FMT_UPG Downgrade config opam-version to fix up [WARNING] Removing global switch 'this-internal-error' as it no longer exists FMT_UPG Hard config upgrade, from 2.1~alpha2 to current This version of opam requires an update to the layout of ${BASEDIR}/OPAM from version 2.1~alpha2 to version current which can't be reverted. You may want to back it up before going further. Perform the update and continue? [Y/n] y Format upgrade done. <><> Rerunning init and update ><><><><><><><><><><><><><><><><><><><><><><><><> GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found <><> Updating repositories ><><><><><><><><><><><><><><><><><><><><><><><><><><> [default] no changes from file://${BASEDIR}/default Update done, please now retry your command. # Return code 10 # ### opam install i-am-package GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Definition missing for installed package i-am-sys-compiler.2, copying from repo STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-package.2 Done. ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["ocaml" {>= "4.05.0"}] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 3 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "${BASEDIR}" "default"] opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" wrap-build-commands: ["%{hooks}%/sandbox.sh" "build"] {os = "linux" | os = "macos"} wrap-install-commands: ["%{hooks}%/sandbox.sh" "install"] {os = "linux" | os = "macos"} wrap-remove-commands: ["%{hooks}%/sandbox.sh" "remove"] {os = "linux" | os = "macos"} ### opam-cat _opam/.opam-switch/switch-config invariant: ["i-am-sys-compiler" | "i-am-compiler"] opam-root: "${BASEDIR}/OPAM" opam-version: "2.0" synopsis: "local switch" paths { } variables { } ### opam-cat _opam/.opam-switch/switch-state compiler: ["i-am-sys-compiler.2"] installed: ["i-am-package.2" "i-am-sys-compiler.2"] opam-version: "2.0" roots: ["i-am-package.2" "i-am-sys-compiler.2"] ### rm -rf _opam ### :V:3:c: From 2.1~alpha2 root, local unknown from config ### ocaml generate.ml 2.1~alpha2 orphaned ### opam list | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG Intermediate opam root detected, launch hard upgrade FMT_UPG Downgrade config opam-version to fix up [WARNING] Removing global switch 'this-internal-error' as it no longer exists FMT_UPG Hard config upgrade, from 2.1~alpha2 to current This version of opam requires an update to the layout of ${BASEDIR}/OPAM from version 2.1~alpha2 to version current which can't be reverted. You may want to back it up before going further. Perform the update and continue? [Y/n] y Format upgrade done. <><> Rerunning init and update ><><><><><><><><><><><><><><><><><><><><><><><><> GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found <><> Updating repositories ><><><><><><><><><><><><><><><><><><><><><><><><><><> [default] no changes from file://${BASEDIR}/default Update done, please now retry your command. # Return code 10 # ### opam install i-am-package FILE(switch-config) Wrote ${BASEDIR}/_opam/.opam-switch/switch-config in 0.000s GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Definition missing for installed package i-am-sys-compiler.2, copying from repo STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-package.2 Done. ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["ocaml" {>= "4.05.0"}] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 3 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default"] opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" wrap-build-commands: ["%{hooks}%/sandbox.sh" "build"] {os = "linux" | os = "macos"} wrap-install-commands: ["%{hooks}%/sandbox.sh" "install"] {os = "linux" | os = "macos"} wrap-remove-commands: ["%{hooks}%/sandbox.sh" "remove"] {os = "linux" | os = "macos"} ### opam-cat _opam/.opam-switch/switch-config invariant: ["i-am-sys-compiler" | "i-am-compiler"] opam-root: "${BASEDIR}/OPAM" opam-version: "2.0" synopsis: "local switch" paths { } variables { } ### opam-cat _opam/.opam-switch/switch-state compiler: ["i-am-sys-compiler.2"] installed: ["i-am-package.2" "i-am-sys-compiler.2"] opam-version: "2.0" roots: ["i-am-package.2" "i-am-sys-compiler.2"] ### :V:3:d: Upgraded root and local 2.1~alpha2 switch not recorded ### ocaml generate.ml $OPAMROOTVERSION orphaned 2.1~alpha2 ### # ro global state, ro repo state, ro switch state ### opam list FILE(switch-config) Wrote ${BASEDIR}/_opam/.opam-switch/switch-config in 0.000s GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-sys-compiler 2 One-line description ### # ro global state, ro repo state, rw switch state ### opam install i-am-package GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-package.2 Done. ### opam option jobs=4 GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Set to '4' the field jobs in global configuration ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["i-am-sys-compiler"] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 1 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default" "this-internal-error"] jobs: 4 opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" ### opam-cat _opam/.opam-switch/switch-config invariant: ["i-am-sys-compiler" | "i-am-compiler"] opam-root: "${BASEDIR}/OPAM" opam-version: "2.0" synopsis: "local switch" paths { } variables { } ### opam-cat _opam/.opam-switch/switch-state compiler: ["i-am-sys-compiler.2"] installed: ["i-am-package.2" "i-am-sys-compiler.2"] opam-version: "2.0" roots: ["i-am-package.2" "i-am-sys-compiler.2"] ### :V:3:e: reinit from 2.1~alpha2 ### ocaml generate.ml 2.1~alpha2 ### opam init --reinit --bypass-checks --no-setup | "${OPAMROOTVERSION}($|,)" -> "current" No configuration file found, using built-in defaults. FMT_UPG Intermediate opam root detected, launch hard upgrade FMT_UPG Downgrade config opam-version to fix up [WARNING] Removing global switch 'this-internal-error' as it no longer exists FMT_UPG Hard config upgrade, from 2.1~alpha2 to current This version of opam requires an update to the layout of ${BASEDIR}/OPAM from version 2.1~alpha2 to version current which can't be reverted. You may want to back it up before going further. Perform the update and continue? [Y/n] y Format upgrade done. <><> Rerunning init and update ><><><><><><><><><><><><><><><><><><><><><><><><> GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found <><> Updating repositories ><><><><><><><><><><><><><><><><><><><><><><><><><><> [default] no changes from file://${BASEDIR}/default Update done. ### opam switch --short GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM ${BASEDIR} default sw-comp sw-sys-comp ### opam list GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-package 2 One-line description i-am-sys-compiler 2 One-line description ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["ocaml" {>= "4.05.0"}] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 3 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default"] opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" wrap-build-commands: ["%{hooks}%/sandbox.sh" "build"] {os = "linux" | os = "macos"} wrap-install-commands: ["%{hooks}%/sandbox.sh" "install"] {os = "linux" | os = "macos"} wrap-remove-commands: ["%{hooks}%/sandbox.sh" "remove"] {os = "linux" | os = "macos"} ### rm -rf _opam ### :V:4:a: From 2.1~rc root, global ### ocaml generate.ml 2.1~rc ### # ro global state ### opam option jobs | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG On-the-fly config upgrade, from 2.1~rc to current FMT_UPG Format upgrade done ### # ro global state, ro repo state, ro switch state ### opam list | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG On-the-fly config upgrade, from 2.1~rc to current FMT_UPG Format upgrade done RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ sw-sys-comp STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-another-package 2 One-line description i-am-package 2 One-line description i-am-sys-compiler 1 One-line description ### # ro global state, ro repo state, rw switch state ### opam install i-am-another-package --switch sw-comp | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG On-the-fly config upgrade, from 2.1~rc to current FMT_UPG Format upgrade done RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ sw-comp STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-another-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-another-package.2 Done. ### opam option jobs=4 | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [WARNING] Removing global switch 'this-internal-error' as it no longer exists FMT_UPG Light config upgrade, from 2.1~rc to current This version of opam requires an update to the layout of ${BASEDIR}/OPAM from version 2.1~rc to version current which can't be reverted. You may want to back it up before going further. Continue? [Y/n] y Format upgrade done. Set to '4' the field jobs in global configuration ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["i-am-sys-compiler"] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 1 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default"] jobs: 4 opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" ### opam-cat $OPAMROOT/sw-comp/.opam-switch/switch-config invariant: ["i-am-compiler"] opam-version: "2.0" synopsis: "switch with compiler" ### opam-cat $OPAMROOT/sw-comp/.opam-switch/switch-state compiler: ["i-am-compiler.2"] installed: ["i-am-another-package.2" "i-am-compiler.2" "i-am-package.2"] opam-version: "2.0" roots: ["i-am-another-package.2" "i-am-compiler.2" "i-am-package.2"] ### :V:4:b: From 2.1~rc root, local ### ocaml generate.ml 2.1~rc local ### opam list | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG On-the-fly config upgrade, from 2.1~rc to current FMT_UPG Format upgrade done RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-sys-compiler 2 One-line description ### opam install i-am-package | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG On-the-fly config upgrade, from 2.1~rc to current FMT_UPG Format upgrade done RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Definition missing for installed package i-am-sys-compiler.2, copying from repo STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-package.2 Done. ### opam option jobs=4 | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [WARNING] Removing global switch 'this-internal-error' as it no longer exists FMT_UPG Light config upgrade, from 2.1~rc to current This version of opam requires an update to the layout of ${BASEDIR}/OPAM from version 2.1~rc to version current which can't be reverted. You may want to back it up before going further. Continue? [Y/n] y Format upgrade done. Set to '4' the field jobs in global configuration ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["i-am-sys-compiler"] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 1 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "${BASEDIR}" "default"] jobs: 4 opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" ### opam-cat _opam/.opam-switch/switch-config invariant: ["i-am-sys-compiler" | "i-am-compiler"] opam-root: "${BASEDIR}/OPAM" opam-version: "2.0" synopsis: "local switch" ### opam-cat _opam/.opam-switch/switch-state compiler: ["i-am-sys-compiler.2"] installed: ["i-am-package.2" "i-am-sys-compiler.2"] opam-version: "2.0" roots: ["i-am-package.2" "i-am-sys-compiler.2"] ### rm -rf _opam ### :V:4:c: From 2.1~rc root, local unknown from config ### ocaml generate.ml 2.1~rc local ### opam list | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG On-the-fly config upgrade, from 2.1~rc to current FMT_UPG Format upgrade done RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-sys-compiler 2 One-line description ### opam install i-am-package | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM FMT_UPG On-the-fly config upgrade, from 2.1~rc to current FMT_UPG Format upgrade done RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Definition missing for installed package i-am-sys-compiler.2, copying from repo STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-package.2 Done. ### opam option jobs=4 | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [WARNING] Removing global switch 'this-internal-error' as it no longer exists FMT_UPG Light config upgrade, from 2.1~rc to current This version of opam requires an update to the layout of ${BASEDIR}/OPAM from version 2.1~rc to version current which can't be reverted. You may want to back it up before going further. Continue? [Y/n] y Format upgrade done. Set to '4' the field jobs in global configuration ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["i-am-sys-compiler"] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 1 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "${BASEDIR}" "default"] jobs: 4 opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" ### opam-cat _opam/.opam-switch/switch-config invariant: ["i-am-sys-compiler" | "i-am-compiler"] opam-root: "${BASEDIR}/OPAM" opam-version: "2.0" synopsis: "local switch" ### opam-cat _opam/.opam-switch/switch-state compiler: ["i-am-sys-compiler.2"] installed: ["i-am-package.2" "i-am-sys-compiler.2"] opam-version: "2.0" roots: ["i-am-package.2" "i-am-sys-compiler.2"] ### :V:4:d: Upgraded root and local 2.1~rc switch not recorded ### ocaml generate.ml $OPAMROOTVERSION orphaned 2.1~rc ### # ro global state, ro repo state, ro switch state ### opam list GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-sys-compiler 2 One-line description ### # ro global state, ro repo state, rw switch state ### opam install i-am-package GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-package.2 Done. ### opam option jobs=4 GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Set to '4' the field jobs in global configuration ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["i-am-sys-compiler"] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 1 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default" "this-internal-error"] jobs: 4 opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" ### opam-cat _opam/.opam-switch/switch-config invariant: ["i-am-sys-compiler" | "i-am-compiler"] opam-root: "${BASEDIR}/OPAM" opam-version: "2.0" synopsis: "local switch" ### opam-cat _opam/.opam-switch/switch-state compiler: ["i-am-sys-compiler.2"] installed: ["i-am-package.2" "i-am-sys-compiler.2"] opam-version: "2.0" roots: ["i-am-package.2" "i-am-sys-compiler.2"] ### :V:4:e: reinit from 2.1~rc ### ocaml generate.ml 2.1~rc ### opam init --reinit --bypass-checks --no-setup | "${OPAMROOTVERSION}($|,)" -> "current" No configuration file found, using built-in defaults. GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM [WARNING] Removing global switch 'this-internal-error' as it no longer exists FMT_UPG Light config upgrade, from 2.1~rc to current This version of opam requires an update to the layout of ${BASEDIR}/OPAM from version 2.1~rc to version current which can't be reverted. You may want to back it up before going further. Continue? [Y/n] y Format upgrade done. RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found <><> Updating repositories ><><><><><><><><><><><><><><><><><><><><><><><><><><> [default] no changes from file://${BASEDIR}/default ### opam switch --short GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM ${BASEDIR} default sw-comp sw-sys-comp ### opam list GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-package 2 One-line description i-am-sys-compiler 2 One-line description ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["i-am-sys-compiler"] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 3 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default"] opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" wrap-build-commands: ["%{hooks}%/sandbox.sh" "build"] {os = "linux" | os = "macos"} wrap-install-commands: ["%{hooks}%/sandbox.sh" "install"] {os = "linux" | os = "macos"} wrap-remove-commands: ["%{hooks}%/sandbox.sh" "remove"] {os = "linux" | os = "macos"} ### rm -rf _opam ### :V:5:a: From 2.1 root, global ### ocaml generate.ml 2.1 ### # ro global state ### opam option jobs GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM ### # ro global state, ro repo state, ro switch state ### opam list GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ sw-sys-comp STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-another-package 2 One-line description i-am-package 2 One-line description i-am-sys-compiler 1 One-line description ### # ro global state, ro repo state, rw switch state ### opam install i-am-another-package --switch sw-comp GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ sw-comp STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-another-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-another-package.2 Done. ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["i-am-sys-compiler"] depext: true depext-cannot-install: false depext-run-installs: true eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default" "${BASEDIR}/why-did-you-delete-me" "this-internal-error"] opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" ### opam-cat $OPAMROOT/sw-comp/.opam-switch/switch-config invariant: ["i-am-compiler"] opam-version: "2.0" synopsis: "switch with compiler" ### opam-cat $OPAMROOT/sw-comp/.opam-switch/switch-state compiler: ["i-am-compiler.2"] installed: ["i-am-another-package.2" "i-am-compiler.2" "i-am-package.2"] opam-version: "2.0" roots: ["i-am-another-package.2" "i-am-compiler.2" "i-am-package.2"] ### :V:5:b: From 2.1 root, local ### ocaml generate.ml 2.1 local ### opam list | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-sys-compiler 2 One-line description ### opam install i-am-package GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Definition missing for installed package i-am-sys-compiler.2, copying from repo STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-package.2 Done. ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["i-am-sys-compiler"] depext: true depext-cannot-install: false depext-run-installs: true eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "${BASEDIR}" "default" "${BASEDIR}/why-did-you-delete-me" "this-internal-error"] opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" ### opam-cat _opam/.opam-switch/switch-config invariant: ["i-am-sys-compiler" | "i-am-compiler"] opam-root: "${BASEDIR}/OPAM" opam-version: "2.0" synopsis: "local switch" ### opam-cat _opam/.opam-switch/switch-state compiler: ["i-am-sys-compiler.2"] installed: ["i-am-package.2" "i-am-sys-compiler.2"] opam-version: "2.0" roots: ["i-am-package.2" "i-am-sys-compiler.2"] ### :V:5:c: From 2.1 root, local unknown from config ### ocaml generate.ml 2.1 local ### opam list | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-sys-compiler 2 One-line description ### opam install i-am-package | "${OPAMROOTVERSION}($|,)" -> "current" GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-package.2 Done. ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["i-am-sys-compiler"] depext: true depext-cannot-install: false depext-run-installs: true eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "${BASEDIR}" "default" "${BASEDIR}/why-did-you-delete-me" "this-internal-error"] opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" ### opam-cat _opam/.opam-switch/switch-config invariant: ["i-am-sys-compiler" | "i-am-compiler"] opam-root: "${BASEDIR}/OPAM" opam-version: "2.0" synopsis: "local switch" ### opam-cat _opam/.opam-switch/switch-state compiler: ["i-am-sys-compiler.2"] installed: ["i-am-package.2" "i-am-sys-compiler.2"] opam-version: "2.0" roots: ["i-am-package.2" "i-am-sys-compiler.2"] ### :V:5:d: Upgraded root and local 2.1 switch not recorded ### ocaml generate.ml 2.1 orphaned 2.1 ### # ro global state, ro repo state, ro switch state ### opam list GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-sys-compiler 2 One-line description ### # ro global state, ro repo state, rw switch state ### opam install i-am-package GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} The following actions will be performed: - install i-am-package 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed i-am-package.2 Done. ### opam option jobs=4 GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM Set to '4' the field jobs in global configuration ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["i-am-sys-compiler"] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 1 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default" "this-internal-error"] jobs: 4 opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" ### opam-cat _opam/.opam-switch/switch-config invariant: ["i-am-sys-compiler" | "i-am-compiler"] opam-root: "${BASEDIR}/OPAM" opam-version: "2.0" synopsis: "local switch" ### opam-cat _opam/.opam-switch/switch-state compiler: ["i-am-sys-compiler.2"] installed: ["i-am-package.2" "i-am-sys-compiler.2"] opam-version: "2.0" roots: ["i-am-package.2" "i-am-sys-compiler.2"] ### :V:5:e: reinit from 2.1 ### ocaml generate.ml 2.1 ### opam init --reinit --bypass-checks --no-setup No configuration file found, using built-in defaults. GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found <><> Updating repositories ><><><><><><><><><><><><><><><><><><><><><><><><><><> [default] no changes from file://${BASEDIR}/default ### opam-cat $OPAMROOT/config | '"${OPAMROOTVERSION}"' -> "current" default-compiler: ["i-am-sys-compiler" "i-am-compiler"] default-invariant: ["i-am-sys-compiler"] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 3 eval-variables: [sys-comp-version ["sh" "-c" "echo $OPAMSYSCOMP"] "comp version"] installed-switches: ["sw-sys-comp" "sw-comp" "default" "${BASEDIR}/why-did-you-delete-me" "this-internal-error"] opam-root-version: current opam-version: "2.0" repositories: "default" switch: "sw-sys-comp" wrap-build-commands: ["%{hooks}%/sandbox.sh" "build"] {os = "linux" | os = "macos"} wrap-install-commands: ["%{hooks}%/sandbox.sh" "install"] {os = "linux" | os = "macos"} wrap-remove-commands: ["%{hooks}%/sandbox.sh" "remove"] {os = "linux" | os = "macos"} ### opam switch --short GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM ${BASEDIR} default sw-comp sw-sys-comp this-internal-error ### opam list GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM RSTATE LOAD-REPOSITORY-STATE @ ${BASEDIR}/OPAM RSTATE Cache found STATE LOAD-SWITCH-STATE @ ${BASEDIR} STATE Switch state loaded in 0.000s # Packages matching: installed # Name # Installed # Synopsis i-am-package 2 One-line description i-am-sys-compiler 2 One-line description opam-2.1.5/tests/reftests/pin.test0000644000175000017500000000276214427463453016216 0ustar stephstephN0REP0 ### opam switch create pinning --empty ### # disabled as non implemented ### # ### opam pin --current foo ### # [ERROR] foo is not installed, invalid flag `--current' ### # # Return code 2 # ### # ### ### # opam-version:"2.0" ### # build: [ "echo" "foo" ] ### # ### opam pin --current foo ### # [ERROR] foo is not installed, invalid flag `--current' ### # # Return code 2 # ### # ### opam install foo ### # The following actions will be performed: ### # - install foo 1 ### # ### # <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> ### # -> installed foo.1 ### # Done. ### # ### opam pin --current foo.2 ### # [ERROR] foo.2 is not installed (version 1 is), invalid flag `--current' ### # # Return code 2 # ### # ### opam pin --current foo ### # foo is now pinned locally (version 1) ### # ### opam unpin foo ### # Ok, foo is no longer pinned locally (version 1) ### # Nothing to do. ### # ### rm -rf REPO/packages/foo ### # ### opam update ### # ### # <><> Updating package repositories ><><><><><><><><><><><><><><><><><><><><><><> ### # [default] synchronised from file://${BASEDIR}/REPO ### # Now run 'opam upgrade' to apply any package updates. ### # ### opam list --available --repo=default ### # # Packages matching: from-repository(default) & available ### # # No matches found ### # ### opam list -A ### # # Packages matching: any ### # # Name # Installed # Synopsis ### # foo 1 ### # ### opam pin --current foo ### # foo is now pinned locally (version 1) opam-2.1.5/tests/reftests/camelus.test.disabled0000644000175000017500000000341714427463453020625 0ustar stephstephc7f8804c ### opam switch create camelus ocaml-base-compiler.4.08.0 --fake <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml-base-compiler" {= "4.08.0"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-base-compiler.4.08.0 Faking installation of ocaml-config.1 Faking installation of ocaml.4.08.0 Done. ### opam-version: "2.0" synopsis: "Test" authors: "x" homepage: "x" bug-reports: "x" maintainer: "Louis Gesbert " depends: [ "cohttp-lwt-unix" { < "2.0.0" } "dune" "git-unix" {>= "1.13" & < "2.0" | = "1.11.5" } "github" "github-unix" "opam-format" {>= "2.0.0~beta5"} "opam-solver" {>= "2.0.0~beta5"} "opam-state" { >= "2.0.1"} "tls" "yojson" ("ago" | ("utop")) ("fpath" | "abella") "lwt_ppx" { build } "fpath" ] ### opam install . --deps-only --show [ERROR] Package conflict! * No agreement on the version of ocaml-base-compiler: - (invariant) -> ocaml-base-compiler = 4.08.0 - camelus -> tls -> nocrypto < 0.2.0 | ppx_sexp_conv < v0.11.0 | sexplib < 113.01.00 -> ocaml < 4.03.0 -> ocaml-base-compiler = 3.08.4 You can temporarily relax the switch invariant with `--update-invariant' * Incompatible packages: - (invariant) -> ocaml-base-compiler = 4.08.0 -> ocaml = 4.08.0 - camelus -> tls -> nocrypto >= 0.5.4 * Missing dependency: - camelus -> tls -> nocrypto < 0.2.0 | ppx_sexp_conv < v0.11.0 | sexplib < 113.01.00 -> ocaml < 4.03.0 -> ocaml-variants -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' No solution found, exiting opam-2.1.5/tests/reftests/gen.mli0000644000175000017500000000001414427463453015767 0ustar stephsteph(* empty *) opam-2.1.5/tests/reftests/install-pgocaml.test0000644000175000017500000000254114427463453020511 0ustar stephstephf372039d ### OPAMVAR_arch=x86_64 OPAMVAR_os=linux OPAMVAR_os_family=arch OPAMVAR_os_distribution=archarm ### opam switch create --fake 4.06.1 <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml-base-compiler" {= "4.06.1"} | "ocaml-system" {= "4.06.1"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-base-compiler.4.06.1 Faking installation of ocaml-config.1 Faking installation of ocaml.4.06.1 Done. ### opam install 'pgocaml<2.0' 'pgocaml>=1.7.1' --show [ERROR] Package conflict! * No agreement on the version of ocaml-base-compiler: - (invariant) -> ocaml-base-compiler = 4.06.1 - pgocaml < 2.0 -> ocaml < 4.06.0 -> ocaml-base-compiler = 4.05.0 You can temporarily relax the switch invariant with `--update-invariant' * No agreement on the version of ocaml: - (invariant) -> ocaml-base-compiler = 4.06.1 -> ocaml = 4.06.1 - pgocaml < 2.0 -> extlib = 1.5.3 -> ocaml < 4.05.0 * Missing dependency: - pgocaml < 2.0 -> extlib = 1.5.3 -> ocaml < 4.05.0 -> ocaml-variants >= 3.10.1 -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' No solution found, exiting # Return code 20 # opam-2.1.5/tests/reftests/pin.unix.test0000644000175000017500000000554714427463453017204 0ustar stephstephN0REP0 ### : depext update : ### OPAMYES=1 ### opam option depext-run-installs=false Set to 'false' the field depext-run-installs in global configuration ### opam-version: "2.0" depends: "qux" depexts: [ "inexistant" ] ### echo "pin-depends: [ \"qux.dev\" \"file://$BASEDIR/qux\" ]" >> bar/bar.opam ### sh add_pin_depends.sh ### opam-version: "2.0" depexts: [ "another-inexistant" ] ### opam switch create pinning --empty ### opam pin ./bar | '(apt-get|brew|port)' -> 'syspkgmanager' Package bar does not exist, create as a NEW package? [Y/n] y The following additional pinnings are required by bar.~dev: - qux.dev at file://${BASEDIR}/qux Pin and install them? [Y/n] y Package qux does not exist, create as a NEW package? [Y/n] y [qux.dev] synchronised (no changes) qux is now pinned to file://${BASEDIR}/qux (version dev) bar is now pinned to file://${BASEDIR}/bar (version ~dev) The following actions will be performed: - install qux dev* - install bar ~dev* ===== 2 to install ===== The following system packages will first need to be installed: another-inexistant inexistant <><> Handling external dependencies <><><><><><><><><><><><><><><><><><><><><><> This command should get the requirements installed: syspkgmanager install another-inexistant inexistant You can retry with '--assume-depexts' to skip this check, or run 'opam option depext=false' to permanently disable handling of system packages altogether. [NOTE] Pinning command successful, but your installed packages may be out of sync. # Return code 10 # ### opam unpin bar qux Ok, qux is no longer pinned to file://${BASEDIR}/qux (version dev) Ok, bar is no longer pinned to file://${BASEDIR}/bar (version ~dev) ### opam option 'depext-bypass-=["another-inexistant" "inexistant"]' No modification in switch pinning ### opam install ./bar | '(apt-get|brew|port)' -> 'syspkgmanager' Package bar does not exist, create as a NEW package? [Y/n] y The following additional pinnings are required by bar.~dev: - qux.dev at file://${BASEDIR}/qux Pin and install them? [Y/n] y Package qux does not exist, create as a NEW package? [Y/n] y [qux.dev] synchronised (no changes) qux is now pinned to file://${BASEDIR}/qux (version dev) bar is now pinned to file://${BASEDIR}/bar (version ~dev) The following actions will be performed: - install qux dev* [required by bar] - install bar ~dev* ===== 2 to install ===== The following system packages will first need to be installed: another-inexistant inexistant <><> Handling external dependencies <><><><><><><><><><><><><><><><><><><><><><> This command should get the requirements installed: syspkgmanager install another-inexistant inexistant You can retry with '--assume-depexts' to skip this check, or run 'opam option depext=false' to permanently disable handling of system packages altogether. # Return code 10 # opam-2.1.5/tests/reftests/dot-install.test0000644000175000017500000001370514427463453017661 0ustar stephstephN0REP0 ### #load "str.cma" let read file = let ic = open_in file in let rec aux lines = try aux (input_line ic :: lines) with End_of_file -> lines in let r = Str.regexp "/\\|\\\\\\\\" in try List.rev_map (Str.global_replace r "-") (aux []) with Sys_error _ -> ["Not found: "^file] let cat header path = Printf.printf "==> %s\n" header; let contents = read path in Printf.printf "%s\n" (String.concat "\n" contents) let pkg = (Sys.argv).(1) let root = Sys.getenv "OPAMROOT" let (/) = Filename.concat let share = root / "inst" / "share" let inst_file = share / pkg / "file" let changes = root / "inst" / ".opam-switch" / "install" / pkg ^ ".changes" let _ = cat (pkg ^" installed file") inst_file; cat (pkg^" changes") changes ### opam-version: "2.0" depends: "nodot" ### share: [ "file" ] ### hellow ### opam-version: "2.0" install: [ "echo" "hellow" ] ### share: [ "file" ] ### hellow ### opam-version: "2.0" install: [ "echo" "hellow" ] substs: "lot-of-files.install" ### lib: [ "file" "fichier" "dosiero" ] bin: [ "fichier" ] etc: [ "dosiero" "file" ] share: [ "fichier" "dosiero" ] misc: [ "file" {"%{root}%/dosiero"} ] ### opam-version: "2.0" variables { lot: true } ### hellow ### bonjour ### saluton ### OPAMYES=1 ### opam switch create inst --empty ### OPAMPRECISETRACKING=1 OPAMDEBUGSECTIONS="TRACK ACTION" OPAMDEBUG=-1 ### opam install nodot The following actions will be performed: - install nodot ~dev <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> ACTION download_package: nodot.~dev ACTION prepare_package_source: nodot.~dev at ${BASEDIR}/OPAM/inst/.opam-switch/build/nodot.~dev ACTION Installing nodot.~dev. ACTION creating ${BASEDIR}/OPAM/inst/share/nodot TRACK after install: 19 elements, 3 added, scanned in 0.000s -> installed nodot.~dev Done. ### ocaml cat.ml nodot ==> nodot installed file hellow ==> nodot changes opam-version: "2.0" added: [ "share" {"D"} "share-nodot" {"D"} "share-nodot-file" {"F:12fc204edeae5b57713c5ad7dcb97d39"} ] ### opam install dot The following actions will be performed: - install dot ~dev <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> ACTION download_package: dot.~dev ACTION prepare_package_source: dot.~dev at ${BASEDIR}/OPAM/inst/.opam-switch/build/dot.~dev ACTION Installing dot.~dev. ACTION creating ${BASEDIR}/OPAM/inst/share/dot TRACK after install: 2 elements, 2 added, scanned in 0.000s -> installed dot.~dev Done. ### ocaml cat.ml dot ==> dot installed file hellow ==> dot changes opam-version: "2.0" added: [ "share-dot" {"D"} "share-dot-file" {"F:12fc204edeae5b57713c5ad7dcb97d39"} ] ### OPAMDEBUGSECTIONS="SYSTEM FILE(.config)" OPAMDEBUG=-1 ### : check install files ordering : ### opam install lot-of-files | grep "mkdir\|install\|FILE" - install lot-of-files ~dev SYSTEM mkdir ${BASEDIR}/OPAM/inst/.opam-switch/build/lot-of-files.~dev SYSTEM mkdir ${OPAMTMP} SYSTEM copy ${OPAMTMP}/default/packages/lot-of-files/lot-of-files.~dev/files/lot-of-files.install.in -> ${BASEDIR}/OPAM/inst/.opam-switch/build/lot-of-files.~dev/lot-of-files.install.in FILE(.config) Wrote ${BASEDIR}/OPAM/inst/.opam-switch/config/lot-of-files.config in 0.000s SYSTEM install ${BASEDIR}/OPAM/inst/.opam-switch/build/lot-of-files.~dev/fichier -> ${BASEDIR}/OPAM/inst/bin/fichier (755) SYSTEM mkdir ${BASEDIR}/OPAM/inst/lib/lot-of-files SYSTEM install ${BASEDIR}/OPAM/inst/.opam-switch/build/lot-of-files.~dev/file -> ${BASEDIR}/OPAM/inst/lib/lot-of-files/file (644) SYSTEM install ${BASEDIR}/OPAM/inst/.opam-switch/build/lot-of-files.~dev/fichier -> ${BASEDIR}/OPAM/inst/lib/lot-of-files/fichier (644) SYSTEM install ${BASEDIR}/OPAM/inst/.opam-switch/build/lot-of-files.~dev/dosiero -> ${BASEDIR}/OPAM/inst/lib/lot-of-files/dosiero (644) SYSTEM mkdir ${BASEDIR}/OPAM/inst/share/lot-of-files SYSTEM install ${BASEDIR}/OPAM/inst/.opam-switch/build/lot-of-files.~dev/fichier -> ${BASEDIR}/OPAM/inst/share/lot-of-files/fichier (644) SYSTEM install ${BASEDIR}/OPAM/inst/.opam-switch/build/lot-of-files.~dev/dosiero -> ${BASEDIR}/OPAM/inst/share/lot-of-files/dosiero (644) SYSTEM mkdir ${BASEDIR}/OPAM/inst/etc SYSTEM mkdir ${BASEDIR}/OPAM/inst/etc/lot-of-files SYSTEM install ${BASEDIR}/OPAM/inst/.opam-switch/build/lot-of-files.~dev/dosiero -> ${BASEDIR}/OPAM/inst/etc/lot-of-files/dosiero (644) SYSTEM install ${BASEDIR}/OPAM/inst/.opam-switch/build/lot-of-files.~dev/file -> ${BASEDIR}/OPAM/inst/etc/lot-of-files/file (644) SYSTEM install ${BASEDIR}/OPAM/inst/.opam-switch/build/lot-of-files.~dev/file -> ${BASEDIR}/OPAM/dosiero (644) -> installed lot-of-files.~dev SYSTEM mkdir ${BASEDIR}/OPAM/inst/.opam-switch/packages/lot-of-files.~dev SYSTEM mkdir ${BASEDIR}/OPAM/inst/.opam-switch/packages/lot-of-files.~dev/files SYSTEM copy ${OPAMTMP}/default/packages/lot-of-files/lot-of-files.~dev/files/lot-of-files.install.in -> ${BASEDIR}/OPAM/inst/.opam-switch/packages/lot-of-files.~dev/files/lot-of-files.install.in opam-2.1.5/tests/reftests/cli-versioning.test0000644000175000017500000001425714427463453020362 0ustar stephstephN0REP0 ### opam-version: "2.0" flags: compiler ### opam-version: "2.0" flags: compiler ### opam option depext=false Set to 'false' the field depext in global configuration ### opam switch install cli-versioning --empty opam: install was removed in version 2.1 of the opam CLI, but version 2.1 has been requested. Use create instead or set OPAMCLI environment variable to 2.0. # Return code 2 # ### OPAMCLI=2.0 opam switch install cli-versioning --empty [WARNING] OPAMNODEPEXTS was ignored because CLI 2.0 was requested and it was introduced in 2.1. ### OPAMSHOW=1 ### opam list --cli 31.4 [ERROR] opam command-line version 31.4 is not supported. # Return code 2 # ### opam install baz --assume-depexts --cli 2.1 The following actions would be performed: - install baz 2 ### OPAMCLI=2.0 opam install baz --assume-depexts opam: --assume-depexts was added in version 2.1 of the opam CLI, but version 2.0 has been requested, which is older. # Return code 2 # ### opam config set cli version [WARNING] set was deprecated in version 2.1 of the opam CLI. Use opam var instead or set OPAMCLI environment variable to 2.0. Added 'cli: "version"' to field variables in switch cli-versioning ### OPAMCLI=2.0 opam config set cli version [WARNING] OPAMNODEPEXTS was ignored because CLI 2.0 was requested and it was introduced in 2.1. Added 'cli: "version"' to field variables in switch cli-versioning ### OPAMSHOW=0 opam switch set-invariant baz.1 The switch invariant was set to baz = 1 ### OPAMCLI=2.0 opam install baz.2 [WARNING] OPAMNODEPEXTS was ignored because CLI 2.0 was requested and it was introduced in 2.1. [ERROR] Package conflict! * No agreement on the version of baz: - (invariant) -> baz < 2 - baz >= 2 You can temporarily relax the switch invariant with `--update-invariant' No solution found, exiting # Return code 20 # ### opam install baz.2 [ERROR] Package conflict! * No agreement on the version of baz: - (invariant) -> baz < 2 - baz >= 2 You can temporarily relax the switch invariant with `--update-invariant' No solution found, exiting # Return code 20 # ### OPAMCLI=2.0 opam install baz.2 --update-invariant opam: --update-invariant was added in version 2.1 of the opam CLI, but version 2.0 has been requested, which is older. # Return code 2 # ### opam install baz.2 --update-invariant The following actions would be performed: - install baz 2 ### OPAMCLI=2.0 opam install baz.2 --unlock-base [WARNING] OPAMNODEPEXTS was ignored because CLI 2.0 was requested and it was introduced in 2.1. The following actions would be performed: - install baz 2 ### opam install baz.2 --unlock-base opam: --unlock-base was removed in version 2.1 of the opam CLI, but version 2.1 has been requested. Use --update-invariant instead or set OPAMCLI environment variable to 2.0. # Return code 2 # ### # opam option uses mk_command_ret ### opam option foo [ERROR] No option named 'foo' found. Use 'opam option [--global]' to list them # Return code 2 # ### OPAMCLI=2.0 opam option foo opam: option was added in version 2.1 of the opam CLI, but version 2.0 has been requested, which is older. # Return code 2 # ### opam option foo --global [ERROR] Field or section foo not found # Return code 5 # ### OPAMCLI=2.0 opam option foo --global opam: --global was added in version 2.1 of the opam CLI, but version 2.0 has been requested, which is older. # Return code 2 # ### # opam lock uses mk_command ### opam lock foo [ERROR] No package matching foo # Return code 5 # ### OPAMCLI=2.0 opam lock foo opam: lock was added in version 2.1 of the opam CLI, but version 2.0 has been requested, which is older. # Return code 2 # ### # Check for build test env ### # Note: you must have an installed opam with cli version enabled to pass these tests ### OPAMSHOW=0 ### opam-version: "2.0" build: ["sh" "-c" "env | grep -qFx 'OPAMCLI=2.0'"] install: ["sh" "-c" "env | grep -qFx 'OPAMCLI=2.0'"] remove: ["sh" "-c" "env | grep -qFx 'OPAMCLI=2.0'"] ### opam-version: "2.0" build-env: [OPAMCLI = "2.1"] build: ["sh" "-c" "env | grep -qFx 'OPAMCLI=2.1'"] install: ["sh" "-c" "env | grep -qFx 'OPAMCLI=2.1'"] remove: ["sh" "-c" "env | grep -qFx 'OPAMCLI=2.1'"] ### opam switch set-invariant --formula "[]" The switch invariant was set to [] ### opam install env-2-0 The following actions will be performed: - install env-2-0 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed env-2-0.1 Done. ### opam install env-2-1 The following actions will be performed: - install env-2-1 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed env-2-1.1 Done. ### opam remove env-2-0 The following actions will be performed: - remove env-2-0 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed env-2-0.1 Done. ### opam remove env-2-1 The following actions will be performed: - remove env-2-1 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed env-2-1.1 Done. ### # Environement variables cli versioning ### OPAMBUILDDOC=1 opam var share [WARNING] OPAMBUILDDOC was ignored because CLI 2.1 was requested and it was removed in 2.1, set OPAMCLI environment variable to 2.0. ${BASEDIR}/OPAM/cli-versioning/share ### OPAMCLI=2.0 OPAMBUILDDOC=1 opam config var share [WARNING] OPAMNODEPEXTS was ignored because CLI 2.0 was requested and it was introduced in 2.1. ${BASEDIR}/OPAM/cli-versioning/share ### # Switch creation with packages & formulaes ### opam switch create errored baz --packages baz.2 [ERROR] Individual package and option '--packages' can not be specified at the same time. Use just '--packages' instead, e.g. opam switch create flambda --packages=ocaml.4.12.0,ocaml-option-flambda or '--formula' opam switch create flambda --formula='["ocaml" {="4.12.0"} "ocaml-option-flambda"]' # Return code 2 # ### OPAMCLI=2.0 opam switch create working baz --packages baz.2 --show [WARNING] OPAMNODEPEXTS was ignored because CLI 2.0 was requested and it was introduced in 2.1. <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["baz" "baz" {= "2"}] The following actions would be performed: - install baz 2 opam-2.1.5/tests/reftests/conflict-camlp4.test0000644000175000017500000000073414427463453020404 0ustar stephstephf372039d ### opam switch create test "--formula=[\"camlp4\" \"ocaml-system\"]" --show --yes <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["camlp4" "ocaml-system"] [ERROR] Could not determine which packages to install for this switch: * Incompatible packages: - (invariant) -> camlp4 - (invariant) -> ocaml-system You can temporarily relax the switch invariant with `--update-invariant' # Return code 20 # opam-2.1.5/tests/reftests/legacy-local.test0000644000175000017500000010667214427463453017771 0ustar stephstephN0REP0 ### : UTILITARY SCRIPTS : ### set -ue PKG=$1; shift ARCHIVE=$1; shift if [ ! -e "packages/${ARCHIVE}" ]; then ( cd packages && tar czf ${ARCHIVE} ${ARCHIVE%.tar.gz}; ) fi MD5=$(openssl md5 packages/${ARCHIVE} | cut -d' ' -f2) echo 'src: "http://dev.null" checksum: "'$MD5'"' > REPO/packages/${PKG}/url CACHEDIR=REPO/cache/md5/$(echo $MD5 |head -c2) mkdir -p $CACHEDIR cp "packages/$ARCHIVE" "$CACHEDIR/$MD5" ### : INIT : ### rm REPO/repo ### rmdir REPO/packages ### opam repo add test REPO --set-default --yes "file://${BASEDIR}/REPO" doesn't contain a "packages" directory. Is it really the directory of your repo? [Y/n] y [test] Initialised [WARNING] The repository 'test' at file://${BASEDIR}/REPO doesn't have a 'repo' file, and might not be compatible with this version of opam. [NOTE] Repository at file://${BASEDIR}/REPO doesn't define its version, assuming it's 1.2. <><> Upgrading repositories from older opam format ><><><><><><><><><><><><><><> Upgrading repository "test"... ### opam repo remove default -a ### : GEN FILES : ### (* API version *) opam-version: "1" name: "P1" version: "0" setenv: [P1 = "version0"] substs: [ "P1.config" "P1.install" ] build: [ [ "ocamlc" "-a" "p1.ml" "-o" "p1.cma" ] [ "ocamlopt" "-a" "p1.ml" "-o" "p1.cmxa" ] ] depends: ["ocaml"] ### (* API version *) opam-version: "1" name: "P1" # Test # Toto (* Version are arbitrary strings *) version: "1" maintainer: "contact@ocamlpro.com" (* The command to run *) build: [ ["./build.sh"] # HAHAH ["this" "should" "never" "run"] {ocaml:version > "z100"} [make "this" ocaml:version "also"] {os = "NO"} ["echo" "HAHA!"] {ocaml:version = "10"} ["echo" make share ocaml:version] ["this as well" {os = "myOS"}] ] available: os != "NO" | os != "NO" & os != "YES" (* List of files to substitute env variables *) substs: [ "P1.config" "P1.install" ] (* Libraries *) libraries: [ "p1" ] (* External dependencies *) depexts: [ [ ["debian" "amd64"] ["apt" "dpkg"] ] [ ["osx" ] ["curl"] ] ] messages: [ "I ll always bother you displaying this message" ] post-messages: [ "Thanks SO MUCH for installing this humble package" "Everything went well" {success} "Nooo, something went wrong, this makes me feel sooo sad..." {failure} ] bug-reports: "TEST.com" setenv: [P1 = "version1"] depends: [ "ocaml" {(!= "20" | != "10") & (= "20" | = "10" | = "10+a+b" | = "system")} ] ### opam-version: "1" name: "P1" version: "2" depends: [ "ocaml" {<= "10" | = "system"} ] maintainer: "contact@ocamlpro.com" substs: [ "P1.config" "P1.install" ] libraries: [ "p1" ] build: [ "./build.sh" ] setenv: [P1 = "version2"] ### opam-version: "1" name: "P2" version: "1" maintainer: "contact@ocamlpro.com" substs: [ "config" "P2.config" "P2.install" ] depends: ["ocaml" "P1"] libraries: [ "p2" ] build: [ "./build.sh" ] ### opam-version: "1" name: "P3" version: "1~weird-version.test" maintainer: "contact@ocamlpro.com" depends: ["ocaml" "P1"] substs: [ "P3.config" "P3.install" ] build: [ "./build.sh" ] ### opam-version: "1" name: "P4" version: "1" maintainer: "contact@ocamlpro.com" depends: ["ocaml" "P2" "P3"] build: [ "./build.sh" ] ### opam-version: "1" name: "P4" version: "2" maintainer: "contact@ocamlpro.com" depends: [ "P1" { <= "1" } "P2" "P3" ] build: [ "./build.sh" ] ### opam-version: "1" name: "P4" version: "3" maintainer: "contact@ocamlpro.com" depends: [ "P2" "P3" ] build: [ "./build.sh" ] ### (* API version *) opam-version: "1" name: "P5" version: "1" maintainer: "contact@ocamlpro.com" depends: ["ocaml" "P1"] depopts: [ "P2" ] build: [ [ "./build.sh" ] ] install: [ [ "mkdir" "-p" "%{lib}%/p5" ] [ "touch" "%{lib}%/p5/p2_present" ] {P2:installed} [ "touch" "%{lib}%/p5/p2_absent" ] {!P2:installed} ] remove: [ "rm" "-rf" "%{lib}%/p5" ] ### opam-version: "1.3~dev4" variables { compiler: "10+a+b" native: true native-tools: true native-dynlink: true stubsdir: "%{lib}%/stublibs" } ### opam-version: "1.3" maintainer: "contact@ocamlpro.com" # depends: ["P1" "P2" "P3" "P4"] flags: compiler setenv: TEST = "1" ### opam-version: "1.3~dev4" variables { compiler: "20" native: true native-tools: true native-dynlink: true stubsdir: "%{lib}%/stublibs" } ### opam-version: "1.3" maintainer: "contact@ocamlpro.com" flags: compiler setenv: TEST = "1" ### #!/bin/sh -ue if ! OCAMLC=$(command -v ocamlc); then echo "No OCaml compiler was found on the system" >&2 exit 2 fi if [ $($OCAMLC -config | sed -ne "s/os_type: //p" | tr -d '\r') = Win32 ] ; then OCAMLC_FILE=$(echo $OCAMLC| cygpath -w -f - | sed -e 's/\\/\\\\/g') LIBDIR=$("$OCAMLC" -where | tr -d '\r' | cygpath -f -) else OCAMLC_FILE=$OCAMLC LIBDIR=$("$OCAMLC" -where) fi STUBLIBS=$(cat "$LIBDIR/ld.conf" | tr -d '\r' | tr '\n' ':' | sed -e 's/\\/\\\\/g') echo "Using ocaml compiler found at $OCAMLC with base lib at $LIBDIR" bool() { if "$@"; then echo "true"; else echo "false"; fi } cat >ocaml.config < opam-version: "1.3.0~dev4" maintainer: "louis.gesbert@ocamlpro.com" build: ["sh" "-uex" "./gen.sh"] setenv: [CAML_LD_LIBRARY_PATH = "%{lib}%:%{_:ocaml-stublibs}%"] depends: [ ] flags: compiler ### (* API version *) opam-version: "1" name: "P1" version: "0" setenv: [P1 = "version0"] substs: [ "P1.config" "P1.install" ] build: [ [ "ocamlc" "-a" "p1.ml" "-o" "p1.cma" ] [ "ocamlopt" "-a" "p1.ml" "-o" "p1.cmxa" ] ] depends: ["ocaml"] ### opam-version: "1.3" variables { asmcomp: "-I %{lib}%/P1" bytecomp: "-I %{lib}%/P1" asmlink: "-I %{lib}%/P1 p1.cmxa" bytelink: "-I %{lib}%/P1 p1.cma" LOCAL: "local" l: "L" FOO: "foo" bar: true } ### lib: [ "p1.cmi" "p1.cma" "p1.cmxa" "p1.%{ext_lib}%" ] ### let x () = try Random.int 10 with _ -> 0 ### #! /bin/sh -eu if [ -n "${P1:-}" ]; then echo "P1 ('$P1') should not be set yet" >&2 exit 12 fi ocamlc -a p1.ml -o p1.cma ocamlopt -a p1.ml -o p1.cmxa ### chmod a+x packages/P1-1/build.sh ### (* API version *) opam-version: "1" name: "P1" # Test # Toto (* Version are arbitrary strings *) version: "1" maintainer: "contact@ocamlpro.com" (* The command to run *) build: [ ["./build.sh"] # HAHAH ["this" "should" "never" "run"] {ocaml:version > "z100"} [make "this" ocaml:version "also"] {os = "NO"} ["echo" "HAHA!"] {ocaml:version = "10"} ["echo" make share ocaml:version] ["this as well" {os = "myOS"}] ] available: os != "NO" | os != "NO" & os != "YES" (* List of files to substitute env variables *) substs: [ "P1.config" "P1.install" ] (* Libraries *) libraries: [ "p1" ] (* External dependencies *) depexts: [ [ ["debian" "amd64"] ["apt" "dpkg"] ] [ ["osx" ] ["curl"] ] ] messages: [ "I ll always bother you displaying this message" ] post-messages: [ "Thanks SO MUCH for installing this humble package" "Everything went well" {success} "Nooo, something went wrong, this makes me feel sooo sad..." {failure} ] bug-reports: "TEST.com" setenv: [P1 = "version1"] depends: [ "ocaml" {(!= "20" | != "10") & (= "20" | = "10" | = "10+a+b" | = "system")} ] ### opam-version: "1.3" variables { asmcomp: "-I %{lib}%/P1" bytecomp: "-I %{lib}%/P1" asmlink: "-I %{lib}%/P1 p1.cmxa" bytelink: "-I %{lib}%/P1 p1.cma" LOCAL: "local" l: "L" FOO: "foo" bar: true } ### lib: [ "p1.cmi" "p1.cma" "p1.cmxa" "p1.%{ext_lib}%" "?this_file_will_not_exist_but_that's_ok" ] share: [ "build.sh" ] doc: [ "p1.cmi" { "foo/bar/index.html" } ] ### let x () = try Random.int 10 with _ -> 0 ### A very useful package ### #! /bin/sh -eu if [ -n "${P1:-}" ]; then echo "P1 ('$P1') should not be set yet" >&2 exit 12 fi ocamlc -a p1.ml -o p1.cma ocamlopt -a p1.ml -o p1.cmxa ### chmod a+x packages/P1-2/build.sh ### opam-version: "1" name: "P1" version: "2" depends: [ "ocaml" {<= "10" | = "system"} ] maintainer: "contact@ocamlpro.com" substs: [ "P1.config" "P1.install" ] libraries: [ "p1" ] build: [ "./build.sh" ] setenv: [P1 = "version2"] ### opam-version: "1.3" variables { asmcomp: "-I %{lib}%/P1" bytecomp: "-I %{lib}%/P1" asmlink: "-I %{lib}%/P1 p1.cmxa" bytelink: "-I %{lib}%/P1 p1.cma" LOCAL: "local" l: "L" FOO: "foo" bar: true } ### lib: [ "p1.cma" "p1.cmxa" "p1.%{ext_lib}%" "p1.cmi" ] ### let x () = failwith "the new version is not very good" ### A very useful package ### #! /bin/sh -eu OFLAGS="`opam var P1:asmcomp | tr -d '\r'`" CFLAGS="`opam var P1:bytecomp | tr -d '\r'`" echo "Bytecode Compilation" ocamlc ${CFLAGS} -a p2.ml -o p2.cma if which ocamlopt >/dev/null 2>&1; then echo "Native Compilation" ocamlopt ${OFLAGS} -a p2.ml -o p2.cmxa fi ### chmod a+x packages/P2/build.sh ### Foo is %{P1:FOO}% Foo also contains a variable with %{P1:l}%. Funny, isn\'t it? ### opam-version: "1" name: "P2" version: "1" maintainer: "contact@ocamlpro.com" substs: [ "config" "P2.config" "P2.install" ] depends: ["ocaml" "P1"] libraries: [ "p2" ] build: [ "./build.sh" ] ### opam-version: "1.3" variables { asmcomp: "-I %{lib}%/P2" bytecomp: "-I %{lib}%/P2" asmlink: "-I %{lib}%/P2 p2.cmxa" bytelink: "-I %{lib}%/P2 p2.cma" requires: "p1" } ### lib: [ "p2.cma" "p2.cmxa" "p2.%{ext_lib}%" "p2.cmi" ] ### let g () = P1.x () ### An other very useful package The description can go on multiple lines. The first line is the package synopsis, and the rest is the package description. ### #! /bin/sh -eu OPAM=$(cygpath ${OPAM} 2>/dev/null || echo ${OPAM}) echo "Building P3 version ${OPAM_PACKAGE_VERSION}" if [ "x${OPAM_PACKAGE_NAME}" = "xP3" ]; then LIB=$(${OPAM} var lib | tr -d '\r') ocamlc -a -I $LIB/P1 -I $LIB/P2 p3.ml -o p3.cma ocamlopt -a -I $LIB/P1 -I $LIB/P2 p3.ml -o p3.cmxa ocamlc -a -I $LIB/P1 -I $LIB/P2 p3_bar.ml -o p3_bar.cma ocamlopt -a -I $LIB/P1 -I $LIB/P2 p3_bar.ml -o p3_bar.cmxa else exit 1 fi ### chmod a+x packages/P3/build.sh ### opam-version: "1" name: "P3" version: "1~weird-version.test" maintainer: "contact@ocamlpro.com" depends: ["ocaml" "P1"] substs: [ "P3.config" "P3.install" ] build: [ "./build.sh" ] ### let f () = Printf.printf "foo\n%!" let _ = P3.z () ### opam-version: "1.3" variables { asmcomp : "-I %{lib}%/P3" bytecomp: "-I %{lib}%/P3" asmlink : "-I %{lib}%/P3 p3.cmxa p3_bar.cmxa" bytelink: "-I %{lib}%/P3 p3.cma p3_bar.cma" requires: "p1" } ### lib: [ (* p3 *) "p3.cma" "p3.cmxa" "p3.%{ext_lib}%" "p3.cmi" (* p3_bar *) "p3_bar.cma" "p3_bar.cmxa" "p3_bar.%{ext_lib}%" "p3_bar.cmi" ] ### let z () = try P1.x () with _ -> 0 ### Testing version names ### opam-version: "1" name: "P4" version: "1" maintainer: "contact@ocamlpro.com" depends: ["ocaml" "P2" "P3"] build: [ "./build.sh" ] ### opam-version: "1" name: "P4" version: "2" maintainer: "contact@ocamlpro.com" depends: [ "P1" { <= "1" } "P2" "P3" ] build: [ "./build.sh" ] ### opam-version: "1" name: "P4" version: "3" maintainer: "contact@ocamlpro.com" depends: [ "P2" "P3" ] build: [ "./build.sh" ] ### #! /bin/sh -ex OPAM=$(cygpath ${OPAM} 2>/dev/null || echo ${OPAM}) opam() { $OPAM "$@" | tr -d '\r'; } if [ $OPAM_PACKAGE_VERSION -eq 2 ]; then if [ "X${P1:-}" != "Xversion1" ]; then echo "P1 not set to version1 while P1.1 should be installed" >&2 exit 12 fi else if [ -z "X${P1:-}" ]; then echo "P1 not set while P1 should be installed" >&2 exit 12 fi fi echo "Building P4 with ${OPAM}" COMP="-I $(opam var P1:lib) -I $(opam var P2:lib) -I $(opam var P3:lib)" LINK="p1.cmxa p2.cmxa p3.cmxa p3_bar.cmxa" OCAMLC=ocamlc if which ocamlopt >/dev/null 2>&1; then OCAMLC=ocamlopt; fi $OCAMLC ${COMP} ${LINK} p4.ml -o p4.foo.exe echo "TEST=${TEST}" ### chmod a+x packages/P4/build.sh ### bin: [ "p4.foo.exe" { "p4.exe" } "p4.foo.exe" ] ### let f = try P3_bar.f (); P1.x () with _ -> P3.z () let () = let t = try Sys.getenv "TEST" with _ -> "" in Printf.printf "TEST=%s\n%!" t ### Testing transitive closure ### #! /bin/sh -eu OPAM=$(cygpath ${OPAM} 2>/dev/null || echo ${OPAM}) FLAGS="-I `${OPAM} var P1:lib | tr -d '\r'`" echo "Bytecode Compilation" ocamlc ${FLAGS} -a p5.ml -o p5.cma if which ocamlopt >/dev/null 2>&1; then echo "Native Compilation" ocamlopt ${FLAGS} -a p5.ml -o p5.cmxa fi ### chmod a+x packages/P5/build.sh ### (* API version *) opam-version: "1" name: "P5" version: "1" maintainer: "contact@ocamlpro.com" depends: ["ocaml" "P1"] depopts: [ "P2" ] build: [ [ "./build.sh" ] ] install: [ [ "mkdir" "-p" "%{lib}%/p5" ] [ "touch" "%{lib}%/p5/p2_present" ] {P2:installed} [ "touch" "%{lib}%/p5/p2_absent" ] {!P2:installed} ] remove: [ "rm" "-rf" "%{lib}%/p5" ] ### let g () = P1.x () ### Testing optional dependencies ### : UPLOAD : ### cp -r packages/ocaml REPO/packages ### mkdir -p REPO/packages/P1.0 ### cp packages/P1-0.opam REPO/packages/P1.0/opam ### sh mkurl.sh P1.0 P1-0.tar.gz ### mkdir -p REPO/packages/P1.1 ### cp packages/P1-1.opam REPO/packages/P1.1/opam ### cp packages/P1-1/README REPO/packages/P1.1/descr ### sh mkurl.sh P1.1 P1-1.tar.gz ### mkdir -p REPO/packages/P2.1 ### cp packages/P2/README REPO/packages/P2.1/descr ### cp packages/P2.opam REPO/packages/P2.1/opam ### sh mkurl.sh P2.1 P2.tar.gz ### mkdir -p REPO/packages/P3.1~weird-version.test ### cp packages/P3.opam REPO/packages/P3.1~weird-version.test/opam ### cp packages/P3/README REPO/packages/P3.1~weird-version.test/descr ### sh mkurl.sh P3.1~weird-version.test P3.tar.gz ### mkdir -p REPO/packages/P4.1 ### cp packages/P4-1.opam REPO/packages/P4.1/opam ### cp packages/P4/README REPO/packages/P4.1/descr ### sh mkurl.sh P4.1 P4.tar.gz ### mkdir -p REPO/packages/P5.1 ### cp packages/P5.opam REPO/packages/P5.1/opam ### cp packages/P5/README REPO/packages/P5.1/descr ### sh mkurl.sh P5.1 P5.tar.gz ### archive-mirrors: "cache" ### opam update <><> Updating package repositories ><><><><><><><><><><><><><><><><><><><><><><> [test] synchronised from file://${BASEDIR}/REPO [NOTE] Repository at file://${BASEDIR}/REPO doesn't define its version, assuming it's 1.2. <><> Upgrading repositories from older opam format ><><><><><><><><><><><><><><> Upgrading repository "test"... Updated ${OPAMTMP}/test/packages/P1.0/opam Updated ${OPAMTMP}/test/packages/P1.1/opam Updated ${OPAMTMP}/test/packages/P2.1/opam Updated ${OPAMTMP}/test/packages/P3.1~weird-version.test/opam Updated ${OPAMTMP}/test/packages/P4.1/opam Updated ${OPAMTMP}/test/packages/P5.1/opam Now run 'opam upgrade' to apply any package updates. ### opam switch create system "--formula=[\"ocaml\" {= \"system\"}]" <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml" {= "system"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed ocaml.system Done. ### opam exec -- ocamlc -config | grep '^ext_lib:' | '^.*\.'-> '' >$ LIB_EXT ### opam var ext_lib=$LIB_EXT --switch system | .* -> '\c' ### : INSTALL-REMOVE : ### opam list -is --columns=package ocaml.system ### opam install P1 The following actions will be performed: - install P1 1 I ll always bother you displaying this message <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (${BASEDIR}/REPO/cache) -> installed P1.1 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### opam list -is --columns=package ocaml.system P1.1 ### opam remove P1 The following actions will be performed: - remove P1 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed P1.1 Done. ### opam list -is --columns=package ocaml.system ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml system P1 -- A very useful package P2 -- An other very useful package P3 -- Testing version names P4 -- Testing transitive closure P5 -- Testing optional dependencies ### : INSTALL-OPT : ### opam list -is --columns=package ocaml.system ### opam install --yes P5 | unordered The following actions will be performed: - install P1 1 [required by P5] I ll always bother you displaying this message - install P5 1 ===== 2 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (cached) -> retrieved P5.1 (${BASEDIR}/REPO/cache) -> installed P1.1 -> installed P5.1 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### test -f ${OPAMROOT}/system/lib/p5/p2_absent ### opam list -is --columns=package ocaml.system P1.1 P5.1 ### opam remove P5 The following actions will be performed: - remove P5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed P5.1 Done. ### opam list -is --columns=package ocaml.system P1.1 ### opam install P5 The following actions will be performed: - install P5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P5.1 (cached) -> installed P5.1 Done. ### opam list -is --columns=package ocaml.system P1.1 P5.1 ### opam remove P5 -a --yes The following actions will be performed: - remove P5 1 - remove P1 1 ===== 2 to remove ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed P5.1 -> removed P1.1 Done. ### opam list -is --columns=package ocaml.system ### opam install P5 --yes | unordered The following actions will be performed: - install P1 1 [required by P5] I ll always bother you displaying this message - install P5 1 ===== 2 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (cached) -> retrieved P5.1 (cached) -> installed P1.1 -> installed P5.1 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### opam list -is --columns=package ocaml.system P1.1 P5.1 ### opam install P2 --yes | unordered The following actions will be performed: - install P2 1 - recompile P5 1 [uses P2] ===== 1 to install | 1 to recompile ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P2.1 (${BASEDIR}/REPO/cache) -> retrieved P5.1 (cached) -> removed P5.1 -> installed P2.1 -> installed P5.1 Done. ### test -f ${OPAMROOT}/system/lib/p5/p2_present ### opam list -is --columns=package ocaml.system P1.1 P2.1 P5.1 ### opam remove P5 -a The following actions will be performed: - remove P5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed P5.1 Done. ### opam list -is --columns=package ocaml.system P1.1 P2.1 ### opam remove P2 -a --yes The following actions will be performed: - remove P2 1 - remove P1 1 ===== 2 to remove ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed P2.1 -> removed P1.1 Done. ### opam list -is --columns=package ocaml.system ### opam install P1 P2 P5 | unordered The following actions will be performed: - install P1 1 I ll always bother you displaying this message - install P2 1 - install P5 1 ===== 3 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (cached) -> retrieved P2.1 (cached) -> retrieved P5.1 (cached) -> installed P1.1 -> installed P2.1 -> installed P5.1 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### test -f ${OPAMROOT}/system/lib/p5/p2_present ### opam list -is --columns=package ocaml.system P1.1 P2.1 P5.1 ### opam remove P2 -a --yes The following actions will be performed: - remove P2 1 - recompile P5 1 [uses P2] ===== 1 to recompile | 1 to remove ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P5.1 (cached) -> removed P5.1 -> removed P2.1 -> installed P5.1 Done. ### test -f ${OPAMROOT}/system/lib/p5/p2_absent ### opam list -is --columns=package ocaml.system P1.1 P5.1 ### opam remove P1 --yes The following actions will be performed: - remove P5 1 [uses P1] - remove P1 1 ===== 2 to remove ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed P5.1 -> removed P1.1 Done. ### opam list -is --columns=package ocaml.system ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml system P1 -- A very useful package P2 -- An other very useful package P3 -- Testing version names P4 -- Testing transitive closure P5 -- Testing optional dependencies ### : INSTALL : ### opam list -is --columns=package ocaml.system ### opam install P1 The following actions will be performed: - install P1 1 I ll always bother you displaying this message <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (cached) -> installed P1.1 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### opam list -is --columns=package ocaml.system P1.1 ### opam install P2 The following actions will be performed: - install P2 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P2.1 (cached) -> installed P2.1 Done. ### opam list -is --columns=package ocaml.system P1.1 P2.1 ### opam install P3 The following actions will be performed: - install P3 1~weird-version.test <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P3.1~weird-version.test (${BASEDIR}/REPO/cache) -> installed P3.1~weird-version.test Done. ### opam list -is --columns=package ocaml.system P1.1 P2.1 P3.1~weird-version.test ### opam install P4 The following actions will be performed: - install P4 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P4.1 (${BASEDIR}/REPO/cache) -> installed P4.1 Done. ### opam list -is --columns=package ocaml.system P1.1 P2.1 P3.1~weird-version.test P4.1 ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml system P1 1 A very useful package P2 1 An other very useful package P3 1~weird-version.test Testing version names P4 1 Testing transitive closure P5 -- Testing optional dependencies ### : REINSTALL : ### opam list -is --columns=package ocaml.system P1.1 P2.1 P3.1~weird-version.test P4.1 ### opam reinstall P1 --yes | unordered The following actions will be performed: - recompile P1 1 I ll always bother you displaying this message - recompile P3 1~weird-version.test [uses P1] - recompile P2 1 [uses P1] - recompile P4 1 [uses P2, P3] ===== 4 to recompile ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (cached) -> retrieved P2.1 (cached) -> retrieved P3.1~weird-version.test (cached) -> retrieved P4.1 (cached) -> removed P4.1 -> removed P2.1 -> removed P3.1~weird-version.test -> removed P1.1 -> installed P1.1 -> installed P2.1 -> installed P3.1~weird-version.test -> installed P4.1 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### opam list -is --columns=package ocaml.system P1.1 P2.1 P3.1~weird-version.test P4.1 ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml system P1 1 A very useful package P2 1 An other very useful package P3 1~weird-version.test Testing version names P4 1 Testing transitive closure P5 -- Testing optional dependencies ### : UPLOAD-NEW : ### mkdir REPO/packages/P4.2 ### cp packages/P4-2.opam REPO/packages/P4.2/opam ### cp packages/P4/README REPO/packages/P4.2/descr ### sh mkurl.sh P4.2 P4.tar.gz ### mkdir REPO/packages/P4.3 ### cp packages/P4-3.opam REPO/packages/P4.3/opam ### cp packages/P4/README REPO/packages/P4.3/descr ### sh mkurl.sh P4.3 P4.tar.gz ### mkdir REPO/packages/P1.2 ### cp packages/P1-2.opam REPO/packages/P1.2/opam ### cp packages/P1-2/README REPO/packages/P1.2/descr ### sh mkurl.sh P1.2 P1-2.tar.gz ### opam update <><> Updating package repositories ><><><><><><><><><><><><><><><><><><><><><><> [test] synchronised from file://${BASEDIR}/REPO [NOTE] Repository at file://${BASEDIR}/REPO doesn't define its version, assuming it's 1.2. <><> Upgrading repositories from older opam format ><><><><><><><><><><><><><><> Upgrading repository "test"... Updated ${OPAMTMP}/test/packages/P1.0/opam Updated ${OPAMTMP}/test/packages/P1.1/opam Updated ${OPAMTMP}/test/packages/P1.2/opam Updated ${OPAMTMP}/test/packages/P2.1/opam Updated ${OPAMTMP}/test/packages/P3.1~weird-version.test/opam Updated ${OPAMTMP}/test/packages/P4.1/opam Updated ${OPAMTMP}/test/packages/P4.2/opam Updated ${OPAMTMP}/test/packages/P4.3/opam Updated ${OPAMTMP}/test/packages/P5.1/opam Now run 'opam upgrade' to apply any package updates. ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml system P1 1 A very useful package P2 1 An other very useful package P3 1~weird-version.test Testing version names P4 1 Testing transitive closure P5 -- Testing optional dependencies ### : UPGRADE : ### opam list -is --columns=package ocaml.system P1.1 P2.1 P3.1~weird-version.test P4.1 ### opam env --sexp | grep '"P1"' ("P1" "version1") ### opam upgrade --yes | unordered The following actions will be performed: - upgrade P1 1 to 2 - recompile P3 1~weird-version.test [uses P1] - recompile P2 1 [uses P1] - upgrade P4 1 to 3 ===== 2 to recompile | 2 to upgrade ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.2 (${BASEDIR}/REPO/cache) -> retrieved P2.1 (cached) -> retrieved P3.1~weird-version.test (cached) -> retrieved P4.3 (cached) -> removed P4.1 -> removed P2.1 -> removed P3.1~weird-version.test -> removed P1.1 -> installed P1.2 -> installed P2.1 -> installed P3.1~weird-version.test -> installed P4.3 Done. ### opam list -is --columns=package ocaml.system P1.2 P2.1 P3.1~weird-version.test P4.3 ### opam env --sexp | grep '"P1"' ("P1" "version2") ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml system P1 2 A very useful package P2 1 An other very useful package P3 1~weird-version.test Testing version names P4 3 Testing transitive closure P5 -- Testing optional dependencies ### : DOWNGRADE : ### opam list -is --columns=package ocaml.system P1.2 P2.1 P3.1~weird-version.test P4.3 ### opam install P4.2 --yes | unordered The following actions will be performed: - downgrade P1 2 to 1 [required by P4] I ll always bother you displaying this message - recompile P3 1~weird-version.test [uses P1] - recompile P2 1 [uses P1] - downgrade P4 3 to 2 ===== 2 to recompile | 2 to downgrade ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (cached) -> retrieved P2.1 (cached) -> retrieved P3.1~weird-version.test (cached) -> retrieved P4.2 (cached) -> removed P4.3 -> removed P2.1 -> removed P3.1~weird-version.test -> removed P1.2 -> installed P1.1 -> installed P2.1 -> installed P3.1~weird-version.test -> installed P4.2 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### opam list -is --columns=package ocaml.system P1.1 P2.1 P3.1~weird-version.test P4.2 ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml system P1 1 A very useful package P2 1 An other very useful package P3 1~weird-version.test Testing version names P4 2 Testing transitive closure P5 -- Testing optional dependencies ### : SWITCH-ALIAS : ### opam list -is --columns=package ocaml.system P1.1 P2.1 P3.1~weird-version.test P4.2 ### opam remove P3.1~weird-version.test P4.2 The following actions will be performed: - remove P4 2 - remove P3 1~weird-version.test ===== 2 to remove ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed P4.2 -> removed P3.1~weird-version.test Done. ### opam list -is --columns=package ocaml.system P1.1 P2.1 ### opam switch export test.export ### opam switch create test system <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml" {= "system"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed ocaml.system Done. ### opam var ext_lib=$LIB_EXT --switch test | '.*' -> '\c' ### opam list -is --columns=package ocaml.system ### opam switch import test.export | unordered The following actions will be performed: - install P1 1 I ll always bother you displaying this message - install P2 1 ===== 2 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (cached) -> retrieved P2.1 (cached) -> installed P1.1 -> installed P2.1 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### opam list -is --columns=package ocaml.system P1.1 P2.1 ### opam switch create test2 20 <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml" {= "20"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed ocaml.20 Done. ### opam var ext_lib=$LIB_EXT --switch test2 | '.*' -> '\c' ### opam list -is --columns=package ocaml.20 ### opam install P1 The following actions will be performed: - install P1 1 I ll always bother you displaying this message <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved P1.1 (cached) -> installed P1.1 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### opam list -is --columns=package ocaml.20 P1.1 ### opam switch system ### opam list -is --columns=package ocaml.system P1.1 P2.1 ### opam switch remove test test2 --yes Switch test and all its packages will be wiped. Are you sure? [Y/n] y Switch test2 and all its packages will be wiped. Are you sure? [Y/n] y ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml system P1 1 A very useful package P2 1 An other very useful package P3 -- Testing version names P4 -- Testing transitive closure P5 -- Testing optional dependencies ### : SWITCH-ENV-PACKAGES : ### opam list -is --columns=package ocaml.system P1.1 P2.1 ### opam switch create 10+a+b --empty ### opam var ext_lib=$LIB_EXT --switch 10+a+b | '.*' -> '\c' ### opam install ocaml.10+a+b P1 P2 P3 P4 | unordered The following actions will be performed: - install ocaml 10+a+b - install P1 1 I ll always bother you displaying this message - install P3 1~weird-version.test - install P2 1 - install P4 3 ===== 5 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed ocaml.10+a+b -> retrieved P1.1 (cached) -> retrieved P2.1 (cached) -> retrieved P3.1~weird-version.test (cached) -> retrieved P4.3 (cached) -> installed P1.1 -> installed P2.1 -> installed P3.1~weird-version.test -> installed P4.3 Done. <><> P1.1 installed successfully ><><><><><><><><><><><><><><><><><><><><><><><> => Thanks SO MUCH for installing this humble package => Everything went well ### opam list -is --columns=package ocaml.10+a+b P1.1 P2.1 P3.1~weird-version.test P4.3 ### sh -c '. ${OPAMROOT}/opam-init/variables.sh && echo "PASS $TEST"' PASS 1 ### : REPO : ### opam repo add REPO2 REPO -k local [REPO2] Initialised [NOTE] Repository at file://${BASEDIR}/REPO doesn't define its version, assuming it's 1.2. <><> Upgrading repositories from older opam format ><><><><><><><><><><><><><><> Upgrading repository "REPO2"... Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P1.0/opam Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P1.1/opam Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P1.2/opam Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P2.1/opam Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P3.1~weird-version.test/opam Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P4.1/opam Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P4.2/opam Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P4.3/opam Updated ${BASEDIR}/OPAM/repo/REPO2/packages/P5.1/opam [NOTE] Repository REPO2 has been added to the selections of switch 10+a+b only. Run `opam repository add REPO2 --all-switches|--set-default' to use it in all existing switches, or in newly created switches, respectively. ### opam repo remove REPO2 --all ### opam repo remove test --all ### : LIST : ### opam list -A # Packages matching: any # Name # Installed # Synopsis ocaml 10+a+b P1 1 A very useful package P2 1 An other very useful package P3 1~weird-version.test Testing version names P4 3 Testing transitive closure opam-2.1.5/tests/reftests/list.unix.test0000644000175000017500000000021414427463453017353 0ustar stephstephf372039d ### sh -c "opam list --depends-on dune -s --all-versions | head -n1" 0install.2.14 Fatal error: exception Sys_error("Broken pipe") opam-2.1.5/tests/reftests/conflict-resto.test0000644000175000017500000003714514427463453020366 0ustar stephstepha5d7cdc0 ### opam-version: "2.0" synopsis: "A minimal OCaml library for type-safe HTTP/JSON RPCs" maintainer: "contact@nomadic-labs.com" authors: ["Nomadic Labs" "Ocamlpro"] license: "MIT" homepage: "https://gitlab.com/nomadic-labs/resto" bug-reports: "https://gitlab.com/nomadic-labs/resto/issues" depends: [ "ocaml" {>= "4.08"} "dune" {>= "1.11"} "ezresto" {= version} "resto-directory" {= version} "resto" {= version} "resto-lwt" {= version} "lwt" {>= "3.0.0" & < "6.0.0"} "cohttp" {>= "4.0.0" & with-test} "cohttp-lwt" {>= "4.0.0" & with-test} "cohttp-lwt-unix" {>= "4.0.0" & with-test} "ezjsonm" {>= "1.3.0" & with-test} "json-data-encoding" {>= "0.9.1"} "json-data-encoding-bson" {>= "0.9.1" & with-test} "conduit-lwt-unix" {>= "5.0.0" & with-test} "uri" {>= "4.2.0" & with-test} ] build: ["dune" "build" "-p" name "-j" jobs] dev-repo: "git+https://gitlab.com/nomadic-labs/resto" ### opam-version: "2.0" synopsis: "A minimal OCaml library for type-safe HTTP/JSON RPCs" maintainer: "contact@nomadic-labs.com" authors: ["Nomadic Labs" "Ocamlpro"] license: "MIT" homepage: "https://gitlab.com/nomadic-labs/resto" bug-reports: "https://gitlab.com/nomadic-labs/resto/issues" depends: [ "ocaml" {>= "4.08"} "dune" {>= "1.11"} "uri" {>= "1.9.0"} "resto" {= version} "resto-json" {= version} "lwt" {with-test} "base-unix" {with-test} "cohttp" {>= "4.0.0" & with-test} "cohttp-lwt" {>= "4.0.0" & with-test} "cohttp-lwt-unix" {>= "4.0.0" & with-test} "ezjsonm" {>= "1.3.0" & with-test} "json-data-encoding" {>= "0.9.1"} "json-data-encoding-bson" {>= "0.9.1" & with-test} "conduit-lwt-unix" {>= "4.0.2" & with-test} ] build: ["dune" "build" "-p" name "-j" jobs] dev-repo: "git+https://gitlab.com/nomadic-labs/resto" ### opam-version: "2.0" synopsis: "Access Control Lists for Resto" maintainer: "contact@nomadic-labs.com" authors: "Nomadic Labs" license: "MIT" homepage: "https://gitlab.com/nomadic-labs/resto" bug-reports: "https://gitlab.com/nomadic-labs/resto/issues" depends: [ "ocaml" {>= "4.08"} "dune" {>= "1.11"} "uri" {>= "1.9.0"} "resto" {= version} "cohttp" {>= "4.0.0" & with-test} "cohttp-lwt" {>= "4.0.0" & with-test} "cohttp-lwt-unix" {>= "4.0.0" & with-test} "ezjsonm" {>= "1.3.0" & with-test} "json-data-encoding" {>= "0.9.1" & with-test} "json-data-encoding-bson" {>= "0.9.1" & with-test} "lwt" {>= "5.5.0" & with-test} "conduit-lwt-unix" {>= "4.0.2" & with-test} ] build: ["dune" "build" "-p" name "-j" jobs] dev-repo: "git+https://gitlab.com/nomadic-labs/resto" ### opam-version: "2.0" synopsis: "A generic resto client" maintainer: "contact@nomadic-labs.com" authors: ["Nomadic Labs" "Ocamlpro"] license: "MIT" homepage: "https://gitlab.com/nomadic-labs/resto" bug-reports: "https://gitlab.com/nomadic-labs/resto/issues" depends: [ "ocaml" {>= "4.08"} "dune" {>= "1.11"} "uri" {>= "1.9.0"} "resto" {= version} "resto-directory" {= version} "resto-cohttp" {= version} "resto-server" {= version} "cohttp" {>= "4.0.0"} "cohttp-lwt" {>= "4.0.0" & with-test} "cohttp-lwt-unix" {>= "4.0.0" & with-test} "ezjsonm" {>= "1.3.0" & with-test} "json-data-encoding" {>= "0.9.1" & with-test} "json-data-encoding-bson" {>= "0.9.1" & with-test} "lwt" {>= "5.5.0" & with-test} "conduit-lwt-unix" {>= "4.0.2" & with-test} ] build: ["dune" "build" "-p" name "-j" jobs] dev-repo: "git+https://gitlab.com/nomadic-labs/resto" ### opam-version: "2.0" synopsis: "A minimal OCaml library for type-safe HTTP/JSON RPCs" maintainer: "contact@nomadic-labs.com" authors: ["Nomadic Labs" "Ocamlpro"] license: "MIT" homepage: "https://gitlab.com/nomadic-labs/resto" bug-reports: "https://gitlab.com/nomadic-labs/resto/issues" depends: [ "ocaml" {>= "4.08"} "dune" {>= "1.11"} "uri" {>= "1.9.0"} "resto" {= version} "resto-lwt" {= version} "resto-directory" {= version} "resto-cohttp" {= version} "resto-client" {= version} "resto-cohttp-server" {= version} "cohttp-lwt" {>= "1.0.0"} "lwt" {>= "3.0.0" & < "6.0.0"} "cohttp" {>= "4.0.0"} "cohttp-lwt-unix" {>= "4.0.0" & with-test} "ezjsonm" {>= "1.3.0" & with-test} "json-data-encoding" {>= "0.9.1" & with-test} "json-data-encoding-bson" {>= "0.9.1" & with-test} "conduit-lwt-unix" {>= "5.0.0" & with-test} ] build: ["dune" "build" "-p" name "-j" jobs] dev-repo: "git+https://gitlab.com/nomadic-labs/resto" ### opam-version: "2.0" synopsis: "A minimal OCaml library for type-safe HTTP/JSON RPCs" maintainer: "contact@nomadic-labs.com" authors: ["Nomadic Labs" "Ocamlpro"] license: "MIT" homepage: "https://gitlab.com/nomadic-labs/resto" bug-reports: "https://gitlab.com/nomadic-labs/resto/issues" depends: [ "ocaml" {>= "4.08"} "dune" {>= "1.11"} "resto-directory" {= version} "cohttp-lwt" {>= "1.0.0" & with-test} "cohttp" {>= "4.0.0"} "cohttp-lwt-unix" {>= "4.0.0" & with-test} "ezjsonm" {>= "1.3.0" & with-test} "json-data-encoding" {>= "0.9.1" & with-test} "json-data-encoding-bson" {>= "0.9.1" & with-test} "lwt" {>= "5.5.0" & with-test} "conduit-lwt-unix" {>= "4.0.2" & with-test} "uri" {>= "4.2.0" & with-test} ] build: ["dune" "build" "-p" name "-j" jobs] dev-repo: "git+https://gitlab.com/nomadic-labs/resto" ### opam-version: "2.0" synopsis: "A minimal OCaml library for type-safe HTTP/JSON RPCs" maintainer: "contact@nomadic-labs.com" authors: "Nomadic Labs" license: "MIT" homepage: "https://gitlab.com/nomadic-labs/resto" bug-reports: "https://gitlab.com/nomadic-labs/resto/issues" depends: [ "ocaml" {>= "4.08"} "dune" {>= "1.11"} "uri" {>= "1.9.0"} "resto" {= version} "resto-lwt" {= version} "resto-acl" {= version} "resto-directory" {= version} "resto-cohttp" {= version} "resto-cohttp-client" {= version} "resto-cohttp-server" {= version} "resto-self-serving-client" {= version} "cohttp-lwt" {>= "1.0.0"} "lwt" {>= "3.0.0" & < "6.0.0"} "cohttp" {>= "4.0.0" & with-test} "cohttp-lwt-unix" {>= "4.0.0" & with-test} "ezjsonm" {>= "1.3.0" & with-test} "json-data-encoding" {>= "0.9.1" & with-test} "json-data-encoding-bson" {>= "0.9.1" & with-test} "conduit-lwt-unix" {>= "5.0.0" & with-test} ] build: ["dune" "build" "-p" name "-j" jobs] dev-repo: "git+https://gitlab.com/nomadic-labs/resto" ### opam-version: "2.0" synopsis: "A minimal OCaml library for type-safe HTTP/JSON RPCs - server library" maintainer: "contact@nomadic-labs.com" authors: ["Nomadic Labs" "Ocamlpro"] license: "MIT" homepage: "https://gitlab.com/nomadic-labs/resto" bug-reports: "https://gitlab.com/nomadic-labs/resto/issues" depends: [ "ocaml" {>= "4.08"} "dune" {>= "1.11"} "resto" {>= version } "resto-lwt" {>= version } "resto-server" {= version} "resto-directory" {= version} "resto-cohttp" {= version} "resto-acl" {= version} "cohttp-lwt-unix" {>= "4.0.0"} "conduit-lwt-unix" {>= "5.0.0"} "lwt" {>= "3.0.0" & < "6.0.0"} "cohttp" {>= "4.0.0"} "cohttp-lwt" {>= "4.0.0"} "ezjsonm" {>= "1.3.0" & with-test} "json-data-encoding" {>= "0.9.1" & with-test} "json-data-encoding-bson" {>= "0.9.1" & with-test} "result" {>= "1.5"} "uri" {>= "4.2.0" & with-test} ] build: ["dune" "build" "-p" name "-j" jobs] dev-repo: "git+https://gitlab.com/nomadic-labs/resto" ### opam-version: "2.0" synopsis: "A minimal OCaml library for type-safe HTTP/JSON RPCs" maintainer: "contact@nomadic-labs.com" authors: ["Nomadic Labs" "Ocamlpro"] license: "MIT" homepage: "https://gitlab.com/nomadic-labs/resto" bug-reports: "https://gitlab.com/nomadic-labs/resto/issues" depends: [ "ocaml" {>= "4.08"} "dune" {>= "1.11"} "resto" {= version} "resto-json" {= version & with-test} "cohttp" {>= "4.0.0" & with-test} "cohttp-lwt" {>= "4.0.0" & with-test} "cohttp-lwt-unix" {>= "4.0.0" & with-test} "ezjsonm" {>= "1.3.0" & with-test} "json-data-encoding" {>= "0.9.1" & with-test} "json-data-encoding-bson" {>= "0.9.1" & with-test} "lwt" {>= "5.5.0" & with-test} "conduit-lwt-unix" {>= "4.0.2" & with-test} "uri" {>= "4.2.0" & with-test} ] build: ["dune" "build" "-p" name "-j" jobs] dev-repo: "git+https://gitlab.com/nomadic-labs/resto" ### opam-version: "2.0" synopsis: "A minimal OCaml library for type-safe HTTP/JSON RPCs" maintainer: "contact@nomadic-labs.com" authors: ["Nomadic Labs" "Ocamlpro"] license: "MIT" homepage: "https://gitlab.com/nomadic-labs/resto" bug-reports: "https://gitlab.com/nomadic-labs/resto/issues" depends: [ "ocaml" {>= "4.08"} "dune" {>= "1.11"} "resto" {= version} "json-data-encoding" {>= "0.9.1"} "json-data-encoding-bson" {>= "0.9.1"} "cohttp" {>= "4.0.0" & with-test} "cohttp-lwt" {>= "4.0.0" & with-test} "cohttp-lwt-unix" {>= "4.0.0" & with-test} "ezjsonm" {>= "1.3.0" & with-test} "lwt" {>= "5.5.0" & with-test} "conduit-lwt-unix" {>= "5.0.0" & with-test} "uri" {>= "4.2.0" & with-test} ] build: ["dune" "build" "-p" name "-j" jobs] dev-repo: "git+https://gitlab.com/nomadic-labs/resto" ### opam-version: "2.0" synopsis: "A minimal OCaml library for type-safe HTTP/JSON RPCs" maintainer: "contact@nomadic-labs.com" authors: ["Nomadic Labs" "Ocamlpro"] license: "MIT" homepage: "https://gitlab.com/nomadic-labs/resto" bug-reports: "https://gitlab.com/nomadic-labs/resto/issues" depends: [ "ocaml" {>= "4.08"} "dune" {>= "1.11"} "uri" {>= "1.9.0" & with-test} "resto" {= version} "json-data-encoding" {>= "0.9.1" & with-test} "json-data-encoding-bson" {>= "0.9.1" & with-test} "ezjsonm" {with-test} "lwt" "base-unix" {with-test} "cohttp-lwt" {>= "4.0.0"} "cohttp-lwt-unix" {>= "4.0.0"} "conduit-lwt-unix" {>= "5.0.0"} "cohttp" {>= "4.0.0"} "result" {>= "1.5"} ] build: ["dune" "build" "-p" name "-j" jobs] dev-repo: "git+https://gitlab.com/nomadic-labs/resto" ### opam-version: "2.0" synopsis: "A minimal OCaml library for type-safe HTTP/JSON RPCs" maintainer: "contact@nomadic-labs.com" authors: ["Nomadic Labs" "Ocamlpro"] license: "MIT" homepage: "https://gitlab.com/nomadic-labs/resto" bug-reports: "https://gitlab.com/nomadic-labs/resto/issues" depends: [ "ocaml" {>= "4.08"} "dune" {>= "1.11"} "uri" {>= "1.9.0"} "json-data-encoding" {= "0.9.1" & with-test} "json-data-encoding-bson" {= "0.9.1" & with-test} "ezjsonm" {with-test} "lwt" {with-test} "base-unix" {with-test} "cohttp" {>= "4.0.0"} "cohttp-lwt" {>= "4.0.0" & with-test} "cohttp-lwt-unix" {>= "4.0.0" & with-test} "result" {>= "1.5"} "conduit-lwt-unix" {>= "4.0.2" & with-test} ] build: ["dune" "build" "-p" name "-j" jobs] dev-repo: "git+https://gitlab.com/nomadic-labs/resto" ### opam-version: "2.0" synopsis: "A minimal OCaml library for type-safe HTTP/JSON RPCs" maintainer: "contact@nomadic-labs.com" authors: "Nomadic Labs" license: "MIT" homepage: "https://gitlab.com/nomadic-labs/resto" bug-reports: "https://gitlab.com/nomadic-labs/resto/issues" depends: [ "ocaml" {>= "4.08"} "dune" {>= "1.11"} "uri" {>= "1.9.0"} "resto" {= version} "resto-acl" {= version} "resto-cohttp" {= version} "resto-client" {= version} "resto-server" {= version} "resto-directory" {= version} "cohttp" {>= "4.0.0"} "cohttp-lwt" {>= "4.0.0" & with-test} "cohttp-lwt-unix" {>= "4.0.0" & with-test} "ezjsonm" {>= "1.3.0" & with-test} "json-data-encoding" {>= "0.9.1" & with-test} "json-data-encoding-bson" {>= "0.9.1" & with-test} "lwt" {>= "5.5.0" & with-test} "conduit-lwt-unix" {>= "5.0.0" & with-test} ] build: ["dune" "build" "-p" name "-j" jobs] dev-repo: "git+https://gitlab.com/nomadic-labs/resto" ### opam-version: "2.0" synopsis: "A generic resto server" maintainer: "contact@nomadic-labs.com" authors: ["Nomadic Labs" "Ocamlpro"] license: "MIT" homepage: "https://gitlab.com/nomadic-labs/resto" bug-reports: "https://gitlab.com/nomadic-labs/resto/issues" depends: [ "ocaml" {>= "4.08"} "dune" {>= "1.11"} "resto" {= version} "resto-acl" {= version} "resto-cohttp" {= version} "resto-directory" {= version} "cohttp" "cohttp-lwt" {>= "4.0.0" & with-test} "cohttp-lwt-unix" {>= "4.0.0" & with-test} "ezjsonm" {>= "1.3.0" & with-test} "json-data-encoding" {>= "0.9.1" & with-test} "json-data-encoding-bson" {>= "0.9.1" & with-test} "lwt" {>= "5.5.0" & with-test} "uri" {>= "4.2.0"} "conduit-lwt-unix" {>= "5.0.0" & with-test} ] build: ["dune" "build" "-p" name "-j" jobs] dev-repo: "git+https://gitlab.com/nomadic-labs/resto" ### opam switch create default 4.12.0 --fake | unordered <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml-base-compiler" {= "4.12.0"} | "ocaml-system" {= "4.12.0"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-base-compiler.4.12.0 Faking installation of ocaml-config.2 Faking installation of ocaml.4.12.0 Faking installation of ocaml-options-vanilla.1 Done. ### OPAMVAR_os=linux opam pin resto/ --with-version=0.6.1 --show --yes | unordered This will pin the following packages: ezresto-directory, ezresto, resto-acl, resto-client, resto-cohttp-client, resto-cohttp-self-serving-client, resto-cohttp-server, resto-cohttp, resto-directory, resto-json, resto-lwt, resto-self-serving-client, resto-server, resto. Continue? [Y/n] y ezresto-directory is now pinned to file://${BASEDIR}/resto (version 0.6.1) ezresto is now pinned to file://${BASEDIR}/resto (version 0.6.1) resto-acl is now pinned to file://${BASEDIR}/resto (version 0.6.1) Package resto-client does not exist, create as a NEW package? [Y/n] y resto-client is now pinned to file://${BASEDIR}/resto (version 0.6.1) resto-cohttp-client is now pinned to file://${BASEDIR}/resto (version 0.6.1) resto-cohttp-self-serving-client is now pinned to file://${BASEDIR}/resto (version 0.6.1) resto-cohttp-server is now pinned to file://${BASEDIR}/resto (version 0.6.1) resto-cohttp is now pinned to file://${BASEDIR}/resto (version 0.6.1) resto-directory is now pinned to file://${BASEDIR}/resto (version 0.6.1) resto-json is now pinned to file://${BASEDIR}/resto (version 0.6.1) Package resto-lwt does not exist, create as a NEW package? [Y/n] y resto-lwt is now pinned to file://${BASEDIR}/resto (version 0.6.1) Package resto-self-serving-client does not exist, create as a NEW package? [Y/n] y resto-self-serving-client is now pinned to file://${BASEDIR}/resto (version 0.6.1) Package resto-server does not exist, create as a NEW package? [Y/n] y resto-server is now pinned to file://${BASEDIR}/resto (version 0.6.1) resto is now pinned to file://${BASEDIR}/resto (version 0.6.1) [ERROR] Package conflict! * No agreement on the version of conduit-lwt-unix: - resto-lwt -> cohttp-lwt-unix >= 4.0.0 -> conduit-lwt-unix < 5.0.0 - resto-lwt -> conduit-lwt-unix >= 5.0.0 [NOTE] Pinning command successful, but your installed packages may be out of sync. # Return code 20 # ### : Minimal repro case ### opam-version: "2.0" ### opam-version: "2.0" ### opam-version: "2.0" ### opam-version: "2.0" depends: "a" {< "2"} ### opam-version: "2.0" conflicts: "a" {< "2"} ### opam repo add repo ./REPO [repo] Initialised [NOTE] Repository repo has been added to the selections of switch default only. Run `opam repository add repo --all-switches|--set-default' to use it in all existing switches, or in newly created switches, respectively. ### opam install b c --show [ERROR] Package conflict! * Incompatible packages: - b -> a < 2 - c No solution found, exiting # Return code 20 # opam-2.1.5/tests/reftests/conflict-core.test0000644000175000017500000000250714427463453020154 0ustar stephstephf372039d ### OPAMVAR_arch=x86_64 OPAMVAR_os=linux OPAMVAR_os_family=arch OPAMVAR_os_distribution=archarm ### opam switch create ocaml-base-compiler.4.08.0 --fake <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml-base-compiler" {= "4.08.0"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-base-compiler.4.08.0 Faking installation of ocaml-config.1 Faking installation of ocaml.4.08.0 Done. ### opam install 'core_bench.112.17.00' 'core<112.17.00' --show [ERROR] Package conflict! * No agreement on the version of ocaml: - (invariant) -> ocaml-base-compiler >= 4.08.0 -> ocaml = 4.08.0 - core < 112.17.00 -> ocaml < 4.00.1 You can temporarily relax the switch invariant with `--update-invariant' * No agreement on the version of ocaml-base-compiler: - (invariant) -> ocaml-base-compiler >= 4.08.0 - core < 112.17.00 -> ocaml < 4.00.1 -> ocaml-base-compiler = 3.08.4 * Missing dependency: - core < 112.17.00 -> ocaml < 4.00.1 -> ocaml-variants >= 3.11.1 -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' No solution found, exiting # Return code 20 # opam-2.1.5/tests/reftests/empty-conflicts-003.test0000644000175000017500000001233014427463453021040 0ustar stephsteph3235916 ### OPAMYES=1 OPAMSTRICT=0 ### OPAMVAR_arch=arm64 OPAMVAR_os=linux OPAMVAR_os_family=arch OPAMVAR_os_distribution=archarm ### opam switch create test ocaml-base-compiler.4.14.0 --fake <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml-base-compiler" {= "4.14.0"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-base-compiler.4.14.0 Faking installation of ocaml-config.2 Faking installation of ocaml.4.14.0 Faking installation of ocaml-options-vanilla.1 Done. ### opam install --show disml [ERROR] Package conflict! * No agreement on the version of yojson: - disml -> ppx_deriving_yojson >= 3.3 -> yojson >= 1.6.0 - disml -> yojson < 1.6.0 * No agreement on the version of ocaml: - (invariant) -> ocaml-base-compiler = 4.14.0 -> ocaml = 4.14.0 - disml -> ppx_deriving_yojson >= 3.3 -> ppxlib < 0.14.0 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.12 You can temporarily relax the switch invariant with `--update-invariant' * Missing dependency: - disml -> ppx_deriving_yojson >= 3.3 -> ppxlib < 0.14.0 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.06.0 -> ocaml-base-compiler < 3.07+1 | ocaml-system < 3.07+1 | ocaml-variants < 3.8~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions: 'sys-ocaml-version = "3.07"' no matching version * Missing dependency: - disml -> ppx_deriving_yojson >= 3.3 -> ppxlib < 0.14.0 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.06.0 -> ocaml-base-compiler = 3.07+1 | ocaml-system = 3.07+1 | ocaml-variants < 3.8~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions: 'sys-ocaml-version = "3.07+1"' no matching version * Missing dependency: - disml -> ppx_deriving_yojson >= 3.3 -> ppxlib < 0.14.0 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.06.0 -> ocaml-base-compiler = 3.07+2 | ocaml-system = 3.07+2 | ocaml-variants < 3.8~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions: 'sys-ocaml-version = "3.07+2"' no matching version * Missing dependency: - disml -> ppx_deriving_yojson >= 3.3 -> ppxlib < 0.14.0 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.06.0 -> ocaml-base-compiler = 3.08.0 | ocaml-system < 3.08.1~ | ocaml-variants < 3.08.1~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions, e.g. 'sys-ocaml-version = "3.08.0"' no matching version * Missing dependency: - disml -> ppx_deriving_yojson >= 3.3 -> ppxlib < 0.14.0 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.06.0 -> ocaml-base-compiler = 3.08.1 | ocaml-system < 3.08.2~ | ocaml-variants < 3.08.2~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions, e.g. 'sys-ocaml-version = "3.08.1"' no matching version * Missing dependency: - disml -> ppx_deriving_yojson >= 3.3 -> ppxlib < 0.14.0 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.06.0 -> ocaml-base-compiler = 3.08.2 | ocaml-system < 3.08.3~ | ocaml-variants < 3.08.3~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions, e.g. 'sys-ocaml-version = "3.08.2"' no matching version * Missing dependency: - disml -> ppx_deriving_yojson >= 3.3 -> ppxlib < 0.14.0 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.06.0 -> ocaml-base-compiler = 3.08.3 | ocaml-system < 3.08.4~ | ocaml-variants < 3.08.4~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions, e.g. 'sys-ocaml-version = "3.08.3"' no matching version * Missing dependency: - disml -> ppx_deriving_yojson >= 3.3 -> ppxlib < 0.14.0 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.06.0 -> ocaml-base-compiler = 3.08.4 | ocaml-system < 3.08.5~ | ocaml-variants < 3.08.5~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions, e.g. 'sys-ocaml-version = "3.08.4"' no matching version * Missing dependency: - disml -> ppx_deriving_yojson >= 3.3 -> ppxlib < 0.14.0 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.06.0 -> ocaml-base-compiler = 3.09.0 | ocaml-system < 3.09.1~ | ocaml-variants < 3.09.1~ unmet availability conditions: 'arch != "arm64" & arch != "arm32" & arch != "ppc64"' unmet availability conditions, e.g. 'sys-ocaml-version = "3.09.0"' no matching version * Missing dependency: - disml -> ppx_deriving_yojson >= 3.3 -> ppxlib < 0.14.0 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml-variants = 4.08.0+beta2 -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' * Missing dependency: - disml -> ppx_deriving_yojson >= 3.3 -> ppxlib < 0.14.0 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml-variants = 4.08.0+beta3 -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' No solution found, exiting # Return code 20 # opam-2.1.5/tests/reftests/avoid-version.test0000644000175000017500000000765014427463453020216 0ustar stephstephN0REP0 ### opam-version: "2.0" flags: avoid-version ### opam switch create default --empty ### OPAMFAKE=1 ### OPAMYES=1 ### opam install a --show The following actions would be faked: - install a 2 ### opam-version: "2.0" ### opam install a The following actions will be faked: - install a 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of a.1 Done. ### opam upgrade a Everything as up-to-date as possible (run with --verbose to show unavailable upgrades). The following packages are not being upgraded because the new versions conflict with other installed packages: - a.2 However, you may "opam upgrade" these packages explicitly, which will ask permission to downgrade or uninstall the conflicting packages. Nothing to do. ### opam-version: "2.0" ### opam upgrade a The following actions will be faked: - upgrade a 1 to 1.1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of a.1.1 Done. ### opam-version: "2.0" ### opam upgrade a The following actions will be faked: - upgrade a 1.1 to 3 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of a.3 Done. ### opam install a.2 The following actions will be faked: - downgrade a 3 to 2 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of a.2 Done. ### opam upgrade a The following actions will be faked: - upgrade a 2 to 3 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of a.3 Done. ### opam-version: "2.0" depends: "a" ### opam-version: "2.0" depends: "a" {= "2"} ### opam install b The following actions will be faked: - install b 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of b.1 Done. ### opam upgrade Everything as up-to-date as possible (run with --verbose to show unavailable upgrades). The following packages are not being upgraded because the new versions conflict with other installed packages: - b.2 However, you may "opam upgrade" these packages explicitly, which will ask permission to downgrade or uninstall the conflicting packages. Nothing to do. ### opam upgrade b The following actions will be faked: - downgrade a 3 to 2 [required by b] - upgrade b 1 to 2 ===== 1 to upgrade | 1 to downgrade ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of a.2 Faking installation of b.2 Done. ### opam upgrade Everything as up-to-date as possible (run with --verbose to show unavailable upgrades). The following packages are not being upgraded because the new versions conflict with other installed packages: - a.3 -- b.2 is installed and requires a = 2 However, you may "opam upgrade" these packages explicitly, which will ask permission to downgrade or uninstall the conflicting packages. Nothing to do. ### opam-version: "2.0" flags: avoid-version ### opam-version: "2.0" flags: avoid-version ### opam upgrade Everything as up-to-date as possible (run with --verbose to show unavailable upgrades). The following packages are not being upgraded because the new versions conflict with other installed packages: - a.4 - b.3 However, you may "opam upgrade" these packages explicitly, which will ask permission to downgrade or uninstall the conflicting packages. Nothing to do. ### opam upgrade b.3 The following actions will be faked: - upgrade b 2 to 3 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of b.3 Done. ### opam install a.2 [NOTE] Package a is already installed (current version is 2). ### opam upgrade The following actions will be faked: - upgrade a 2 to 4 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of a.4 Done. opam-2.1.5/tests/reftests/gen.ml0000644000175000017500000000651614427463453015633 0ustar stephstephlet first_line ~path = let ic = open_in path in let s = input_line ic in close_in ic; s let null_hash= "N0REP0" let default_repo = "opam-repo-"^null_hash let diff_rule base_name ~condition = Format.sprintf {| (alias (name reftest-%s)%s (action (diff %s.test %s.out))) (alias (name reftest)%s (deps (alias reftest-%s))) |} base_name condition base_name base_name condition base_name let tgz_name ~archive_hash = Printf.sprintf "opam-archive-%s.tar.gz" archive_hash let repo_directory ~archive_hash = Printf.sprintf "opam-repo-%s" archive_hash let opamroot_directory ~archive_hash = Printf.sprintf "root-%s" archive_hash let run_rule ~base_name ~archive_hash ~condition = Format.sprintf {| (rule (targets %s) (deps %s)%s (action (with-stdout-to %%{targets} (run ./run.exe %%{bin:opam} %%{dep:%s.test} %%{read-lines:testing-env})))) |} (base_name^".out") (opamroot_directory ~archive_hash) condition base_name let archive_download_rule archive_hash = Format.sprintf {| (rule (targets %s) (action (run wget --quiet -O %%{targets} https://github.com/ocaml/opam-repository/archive/%s.tar.gz))) |} (tgz_name ~archive_hash) archive_hash let default_repo_rule = Format.sprintf {| (rule (targets %s) (action (progn (run mkdir -p %%{targets}/packages) (write-file repo "opam-version:\"2.0\"") (run cp repo %%{targets}/repo)))) |} default_repo (* XXX this fails if the directory already exists ?! *) let archive_unpack_rule archive_hash = Format.sprintf {| (rule (targets %s) (action (progn (run mkdir -p %%{targets}) (run tar -C %%{targets} -xzf %%{dep:%s} --strip-components=1)))) |} (repo_directory ~archive_hash) (tgz_name ~archive_hash) let opam_init_rule archive_hash = Format.sprintf {| (rule (targets %s) (action (progn (ignore-stdout (run %%{bin:opam} init --root=%%{targets} --no-setup --bypass-checks --no-opamrc --bare file://%%{dep:%s}))))) |} (opamroot_directory ~archive_hash) (repo_directory ~archive_hash) module StringSet = Set.Make(String) let () = let () = set_binary_mode_out stdout true in let contents = Sys.readdir "." |> Array.to_list |> List.sort String.compare in let process archive_hashes filename = let base_name = OpamStd.String.remove_suffix ~suffix:".test" filename in let condition = match Filename.extension base_name with | "" -> "" | os -> Printf.sprintf "\n (enabled_if (= %%{os_type} %S))" String.(capitalize_ascii (sub os 1 (length os - 1))) in if base_name = filename then archive_hashes else (print_string (diff_rule base_name ~condition); let archive_hash = first_line ~path:filename in if archive_hash = null_hash then (print_string (run_rule ~base_name ~archive_hash:null_hash ~condition); archive_hashes) else (print_string (run_rule ~base_name ~archive_hash ~condition); StringSet.add archive_hash archive_hashes)) in let archive_hashes = List.fold_left process StringSet.empty contents in print_string default_repo_rule; print_string (opam_init_rule null_hash); StringSet.iter (fun archive_hash -> print_string (archive_download_rule archive_hash); print_string (archive_unpack_rule archive_hash); print_string (opam_init_rule archive_hash) ) archive_hashes opam-2.1.5/tests/reftests/init.test0000644000175000017500000002434514427463453016374 0ustar stephsteph009e00fa ### OPAMYES=1 ### tar xzf ${OPAMROOT}/repo/default.tar.gz ### rm -rf ${OPAMROOT} ### eval-variables: [ sys-ocaml-version ["false"] "no system compiler" ] ### opam init --no-setup --bypass-checks default default/ --fake --config opamrc Configuring from ${BASEDIR}/opamrc and then from built-in defaults. <><> Fetching repository information ><><><><><><><><><><><><><><><><><><><><><> [default] Initialised <><> Creating initial switch 'default' (invariant ["ocaml" {>= "4.05.0"}] - initially with ocaml-base-compiler) <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml" {>= "4.05.0"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-base-compiler.4.10.0 Faking installation of ocaml-config.1 Faking installation of ocaml.4.10.0 Done. ### opam switch invariant ["ocaml" {>= "4.05.0"}] ### rm -rf ${OPAMROOT} ### eval-variables: [ sys-ocaml-version ["echo" "4.02.3"] "old system compiler" ] ### opam init --no-setup --bypass-checks default default/ --fake --config opamrc Configuring from ${BASEDIR}/opamrc and then from built-in defaults. <><> Fetching repository information ><><><><><><><><><><><><><><><><><><><><><> [default] Initialised <><> Creating initial switch 'default' (invariant ["ocaml" {>= "4.05.0"}] - initially with ocaml-base-compiler) <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml" {>= "4.05.0"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-base-compiler.4.10.0 Faking installation of ocaml-config.1 Faking installation of ocaml.4.10.0 Done. ### opam switch invariant ["ocaml" {>= "4.05.0"}] ### rm -rf ${OPAMROOT} ### eval-variables: [ sys-ocaml-version ["echo" "4.07.0"] "new system compiler" ] ### opam init --no-setup --bypass-checks default default/ --fake --config opamrc Configuring from ${BASEDIR}/opamrc and then from built-in defaults. <><> Fetching repository information ><><><><><><><><><><><><><><><><><><><><><> [default] Initialised <><> Creating initial switch 'default' (invariant ["ocaml" {>= "4.05.0"}] - initially with ocaml-system) <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml" {>= "4.05.0"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-system.4.07.0 Faking installation of ocaml-config.1 Faking installation of ocaml.4.07.0 Done. ### opam switch invariant ["ocaml" {>= "4.05.0"}] ### opam upgrade --fake Everything as up-to-date as possible (run with --verbose to show unavailable upgrades). However, you may "opam upgrade" these packages explicitly, which will ask permission to downgrade or uninstall the conflicting packages. Nothing to do. ### opam upgrade ocaml --fake The following actions will be faked: - remove ocaml-system 4.07.0 [conflicts with ocaml] - install ocaml-base-compiler 4.10.0 [required by ocaml] - recompile ocaml-config 1 [uses ocaml-system] - upgrade ocaml 4.07.0 to 4.10.0 ===== 1 to install | 1 to recompile | 1 to upgrade | 1 to remove ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of ocaml-base-compiler.4.10.0 Faking installation of ocaml-config.1 Faking installation of ocaml.4.10.0 Done. ### : Init with config file : ### opam-version: "2.0" ### opam-version: "2.0" ### :: default setup :: ### rm -rf $OPAMROOT ### opam init --bypass-checks --bare --no-setup default REPO/ No configuration file found, using built-in defaults. <><> Fetching repository information ><><><><><><><><><><><><><><><><><><><><><> [default] Initialised ### opam-cat $OPAMROOT/config default-compiler: ["ocaml-system" "ocaml-base-compiler"] default-invariant: ["ocaml" {>= "4.05.0"}] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 3 eval-variables: [[sys-ocaml-version ["ocamlc" "-vnum"] "OCaml version present on your system independently of opam, if any"] [sys-ocaml-arch ["sh" "-c" "ocamlc -config 2>/dev/null | tr -d '/r' | grep '^architecture: ' | sed -e 's/.*: //' -e 's/i386/i686/' -e 's/amd64/x86_64/'"] "Target architecture of the OCaml compiler present on your system"] [sys-ocaml-cc ["sh" "-c" "ocamlc -config 2>/dev/null | tr -d '/r' | grep '^ccomp_type: ' | sed -e 's/.*: //'"] "Host C Compiler type of the OCaml compiler present on your system"] [sys-ocaml-libc ["sh" "-c" "ocamlc -config 2>/dev/null | tr -d '/r' | grep '^os_type: ' | sed -e 's/.*: //' -e 's/Win32/msvc/' -e '/^msvc$/!s/.*/libc/'"] "Host C Runtime Library type of the OCaml compiler present on your system"]] opam-root-version: "2.1" opam-version: "2.0" repositories: "default" wrap-build-commands: ["%{hooks}%/sandbox.sh" "build"] {os = "linux" | os = "macos"} wrap-install-commands: ["%{hooks}%/sandbox.sh" "install"] {os = "linux" | os = "macos"} wrap-remove-commands: ["%{hooks}%/sandbox.sh" "remove"] {os = "linux" | os = "macos"} ### :: full configred opamrc :: ### rm -rf $OPAMROOT ### opam-version: "2.0" repositories: "norepo" {"REPO/"} default-compiler: "comp" default-invariant: "comp" { = "1"} jobs: 9 download-command: "dl-tool" download-jobs: 8 archive-mirrors: "REPO/cache" solver-criteria: "solver-criteri" solver-upgrade-criteria: "upgrade-criteri" solver-fixup-criteria: "fixup-criteri" solver: "a-solver" global-variables: [ GLOB "glob" "Set throught opamrc" ] eval-variables: [ var-to-eval ["true"] "tautology" ] recommended-tools: [ "recommended" ] required-tools: [ "required" { "tautology" } ] init-scripts: [ "a-script.sh" """\ #!/usr/bin/env bash echo "script $1 launched STOP i repeat STOP script $1 launched" """ ] pre-build-commands: ["%{hooks}%/a-script.sh" "pre-build" ] pre-install-commands: ["%{hooks}%/a-script.sh" "pre-install" ] pre-remove-commands: ["%{hooks}%/a-script.sh" "pre-remove" ] pre-session-commands: ["%{hooks}%/a-script.sh" "pre-session" ] wrap-build-commands: ["%{hooks}%/a-script.sh" "wrap-build" ] wrap-install-commands: ["%{hooks}%/a-script.sh" "wrap-install" ] wrap-remove-commands: ["%{hooks}%/a-script.sh" "wrap-remove" ] post-build-commands: ["%{hooks}%/a-script.sh" "post-build" ] post-install-commands: ["%{hooks}%/a-script.sh" "post-install" ] post-remove-commands: ["%{hooks}%/a-script.sh" "post-remove" ] post-session-commands: ["%{hooks}%/a-script.sh" "post-session" ] ### opam init --bypass-checks --bare --no-setup --config opamrc Configuring from ${BASEDIR}/opamrc and then from built-in defaults. <><> Fetching repository information ><><><><><><><><><><><><><><><><><><><><><> [norepo] Initialised ### opam-cat $OPAMROOT/config archive-mirrors: "file://${BASEDIR}/REPO/cache" default-compiler: ["comp"] default-invariant: ["comp" {= "1"}] depext: true depext-cannot-install: false depext-run-installs: true download-command: "dl-tool" download-jobs: 8 eval-variables: [var-to-eval ["true"] "tautology"] global-variables: [GLOB "glob" "Set throught opamrc"] jobs: 9 opam-root-version: "2.1" opam-version: "2.0" post-build-commands: ["%{hooks}%/a-script.sh" "post-build"] post-install-commands: ["%{hooks}%/a-script.sh" "post-install"] post-remove-commands: ["%{hooks}%/a-script.sh" "post-remove"] post-session-commands: ["%{hooks}%/a-script.sh" "post-session"] pre-build-commands: ["%{hooks}%/a-script.sh" "pre-build"] pre-install-commands: ["%{hooks}%/a-script.sh" "pre-install"] pre-remove-commands: ["%{hooks}%/a-script.sh" "pre-remove"] pre-session-commands: ["%{hooks}%/a-script.sh" "pre-session"] repositories: "norepo" solver: "a-solver" solver-criteria: "solver-criteri" solver-fixup-criteria: "fixup-criteri" solver-upgrade-criteria: "upgrade-criteri" wrap-build-commands: ["%{hooks}%/a-script.sh" "wrap-build"] wrap-install-commands: ["%{hooks}%/a-script.sh" "wrap-install"] wrap-remove-commands: ["%{hooks}%/a-script.sh" "wrap-remove"] ### opam-cat $OPAMROOT/repo/repos-config opam-version: "2.0" repositories: "norepo" {"file://${BASEDIR}/REPO"} ### sh $OPAMROOT/opam-init/hooks/a-script.sh test script test launched STOP i repeat STOP script test launched ### :: partially configured opamrc :: ### rm -rf $OPAMROOT ### opam-version: "2.0" repositories: "norepo" {"REPO/"} default-compiler: "comp" download-jobs: 8 archive-mirrors: "REPO/cache" eval-variables: [ var-to-eval ["true"] "tautology" ] required-tools: [ "required" { "tautology" } ] # As fields are overriden, it is needed to recreate sandbox script init-scripts: [ [ "a-script.sh" """\ #!/usr/bin/env bash echo "script $1 launched STOP i repeat STOP script $1 launched" """ ] [ "sandbox.sh" """\ #!/usr/bin/env bash echo "SUCCESS" """ ] ] pre-build-commands: ["%{hooks}%/a-script.sh" "pre-build" ] wrap-install-commands: ["%{hooks}%/a-script.sh" "wrap-install" ] post-session-commands: ["%{hooks}%/a-script.sh" "post-session" ] ### opam init --bypass-checks --bare --no-setup --config opamrc Configuring from ${BASEDIR}/opamrc and then from built-in defaults. <><> Fetching repository information ><><><><><><><><><><><><><><><><><><><><><> [norepo] Initialised ### opam-cat $OPAMROOT/config archive-mirrors: "file://${BASEDIR}/REPO/cache" default-compiler: ["comp"] default-invariant: ["ocaml" {>= "4.05.0"}] depext: true depext-cannot-install: false depext-run-installs: true download-jobs: 8 eval-variables: [var-to-eval ["true"] "tautology"] opam-root-version: "2.1" opam-version: "2.0" post-session-commands: ["%{hooks}%/a-script.sh" "post-session"] pre-build-commands: ["%{hooks}%/a-script.sh" "pre-build"] repositories: "norepo" wrap-build-commands: ["%{hooks}%/sandbox.sh" "build"] {os = "linux" | os = "macos"} wrap-install-commands: ["%{hooks}%/a-script.sh" "wrap-install"] wrap-remove-commands: ["%{hooks}%/sandbox.sh" "remove"] {os = "linux" | os = "macos"} ### opam-cat $OPAMROOT/repo/repos-config opam-version: "2.0" repositories: "norepo" {"file://${BASEDIR}/REPO"} opam-2.1.5/tests/reftests/opamrt-reinstall.test0000644000175000017500000001627214427463453020726 0ustar stephstephN0REP0 ### OPAMYES=true ### : init_u ### opam-version: "2.0" install: [ "mkdir" _:lib ] ### opam-version: "2.0" depends: "a" build: [ "test" "-d" a:lib ] remove: [ "test" "-d" a:lib ] install: [ "mkdir" _:lib ] ### opam-version: "2.0" depends: "b" build: [ "test" "-d" b:lib ] remove: [ "test" "-d" b:lib ] install: [ "mkdir" _:lib ] ### opam-version: "2.0" depends: "c" build: [ "test" "-d" c:lib ] remove: [ "test" "-d" c:lib ] ### opam switch create system --empty ### : 1/ Install d ### opam install d The following actions will be performed: - install a 1 [required by b] - install b 1 [required by c] - install c 1 [required by d] - install d 1 ===== 4 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed a.1 -> installed b.1 -> installed c.1 -> installed d.1 Done. ### opam list -sV a.1 b.1 c.1 d.1 ### opam list -sA --roots d ### : 2/ Reinstall b ### opam reinstall b The following actions will be performed: - recompile b 1 - recompile c 1 [uses b] - recompile d 1 [uses c] ===== 3 to recompile ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed d.1 -> removed c.1 -> removed b.1 -> installed b.1 -> installed c.1 -> installed d.1 Done. ### opam list -sV a.1 b.1 c.1 d.1 ### opam list -sA --roots d ### : 3/ Install d ### opam install d [NOTE] Package d is already installed (current version is 1). ### opam list -sV a.1 b.1 c.1 d.1 ### opam list -sA --roots d ### : 4/ Remove b ### opam remove b The following actions will be performed: - remove d 1 [uses c] - remove c 1 [uses b] - remove b 1 ===== 3 to remove ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed d.1 -> removed c.1 -> removed b.1 Done. ### opam list -sV a.1 ### opam list -sA --roots ### : 5/ Install d ### opam install d The following actions will be performed: - install b 1 [required by c] - install c 1 [required by d] - install d 1 ===== 3 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed b.1 -> installed c.1 -> installed d.1 Done. ### opam list -sV a.1 b.1 c.1 d.1 ### opam list -sA --roots d ### : 6/ Remove b from upstream ### rm -rf REPO/packages/b/b.1 ### opam update <><> Updating package repositories ><><><><><><><><><><><><><><><><><><><><><><> [default] synchronised from file://${BASEDIR}/REPO Now run 'opam upgrade' to apply any package updates. ### : 7/ Upgrade ### opam upgrade The following actions will be performed: - remove d 1 - remove c 1 - remove b 1 ===== 3 to remove ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed d.1 -> removed c.1 -> removed b.1 Done. ### opam list -sV a.1 ### opam list -sA --roots ### : 8/ Attempt to reinstall d ### opam install d [ERROR] Package conflict! * Missing dependency: - b unknown package No solution found, exiting # Return code 20 # ### : 9/ Revert to the state with all packages installed and b removed upstream ### opam-version: "2.0" depends: "a" build: [ "test" "-d" a:lib ] remove: [ "test" "-d" a:lib ] install: [ "mkdir" _:lib ] ### opam install d The following actions will be performed: - install b 1 [required by c] - install c 1 [required by d] - install d 1 ===== 3 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed b.1 -> installed c.1 -> installed d.1 Done. ### rm -rf REPO/packages/b/b.1 ### opam update <><> Updating package repositories ><><><><><><><><><><><><><><><><><><><><><><> [default] synchronised from file://${BASEDIR}/REPO Now run 'opam upgrade' to apply any package updates. ### opam list -sV a.1 b.1 c.1 d.1 ### opam list -sA --roots d ### : 10/ Reinstall c ### opam reinstall c The following actions will be performed: - recompile c 1 - recompile d 1 [uses c] ===== 2 to recompile ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed d.1 -> removed c.1 -> installed c.1 -> installed d.1 Done. ### :TODO: here will need `opam pin b --current` ### opam list -sV a.1 b.1 c.1 d.1 ### opam list -sA --roots d ### : 11/ Add a new version of c, then upgrade ### opam-version: "2.0" depends: "b" build: [ "test" "-d" b:lib ] remove: [ "test" "-d" b:lib ] install: [ "mkdir" _:lib ] ### opam upgrade c The following actions will be performed: - upgrade c 1 to 2 - recompile d 1 [uses c] ===== 1 to recompile | 1 to upgrade ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed d.1 -> removed c.1 -> installed c.2 -> installed d.1 Done. ### opam list -sV a.1 b.1 c.2 d.1 ### opam list -sA --roots d ### : 12/ Try to reinstall b (should work using the cache) ### opam reinstall b The following actions will be performed: - recompile b 1 - recompile c 2 [uses b] - recompile d 1 [uses c] ===== 3 to recompile ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed d.1 -> removed c.2 -> removed b.1 -> installed b.1 -> installed c.2 -> installed d.1 Done. ### opam list -sV a.1 b.1 c.2 d.1 ### opam list -sA --roots d ### : 13/ Try to reinstall a ### opam reinstall a The following actions will be performed: - recompile a 1 - recompile b 1 [uses a] - recompile c 2 [uses b] - recompile d 1 [uses c] ===== 4 to recompile ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed d.1 -> removed c.2 -> removed b.1 -> removed a.1 -> installed a.1 -> installed b.1 -> installed c.2 -> installed d.1 Done. ### opam list -sV a.1 b.1 c.2 d.1 ### opam list -sA --roots d ### : 14/ Add a new version of a and upgrade ### opam-version: "2.0" install: [ "mkdir" _:lib ] ### opam upgrade --show The following actions would be performed: - remove d 1 [uses c] - remove c 2 [uses b] - remove b 1 [conflicts with a] - upgrade a 1 to 2 ===== 1 to upgrade | 3 to remove ===== ### opam unpin b --show [NOTE] b is not pinned. ### opam unpin b --no-action [NOTE] b is not pinned. ### opam upgrade The following actions will be performed: - remove d 1 [uses c] - remove c 2 [uses b] - remove b 1 [conflicts with a] - upgrade a 1 to 2 ===== 1 to upgrade | 3 to remove ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed d.1 -> removed c.2 -> removed b.1 -> removed a.1 -> installed a.2 Done. ### opam list -sV a.2 ### opam list -sA --roots ### : 15/ Remove that new version of a and upgrade ### rm -rf REPO/packages/a/a.2 ### opam update <><> Updating package repositories ><><><><><><><><><><><><><><><><><><><><><><> [default] synchronised from file://${BASEDIR}/REPO Now run 'opam upgrade' to apply any package updates. ### opam upgrade The following actions will be performed: - downgrade a 2 to 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed a.2 -> installed a.1 Done. ### opam list -sV a.1 ### opam list -sA --roots ### : 16/ Upgrade again ### opam upgrade Already up-to-date. Nothing to do. ### opam list -sV a.1 ### opam list -sA --roots opam-2.1.5/tests/reftests/switch-invariant.test0000644000175000017500000000221414427463453020712 0ustar stephstephN0REP0 ### opam-version: "2.0" ### opam-version: "2.0" ### opam-version: "2.0" ### opam repository add --dont-select non-default ./repo2 [non-default] Initialised ### opam update --all <><> Updating package repositories ><><><><><><><><><><><><><><><><><><><><><><> [default] no changes from file://${BASEDIR}/REPO [non-default] no changes from file://${BASEDIR}/repo2 ### opam switch create inv --empty --repo=default,non-default ### opam switch set-invariant foo The switch invariant was set to foo ### opam install foo The following actions will be performed: - install foo 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed foo.1 Done. ### opam switch set-invariant foo [WARNING] Packages foo don't have the 'compiler' flag set. The switch invariant was set to foo ### opam switch set-invariant --package foo [WARNING] Packages foo don't have the 'compiler' flag set. The switch invariant was set to foo ### opam switch set-invariant bar The switch invariant was set to bar ### opam switch set-invariant --package bar The switch invariant was set to bar opam-2.1.5/tests/reftests/empty-conflicts-005.test0000644000175000017500000000533714427463453021053 0ustar stephstephde897adf36c4230dfea812f40c98223b31c4521a ### OPAMYES=1 OPAMSTRICT=0 ### OPAMVAR_arch=arm64 OPAMVAR_os=linux OPAMVAR_os_family=arch OPAMVAR_os_distribution=archarm ### opam switch create test ocaml-variants.4.12.0+trunk --fake <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml-variants" {= "4.12.0+trunk"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-variants.4.12.0+trunk Faking installation of ocaml-config.2 Faking installation of ocaml.4.12.0 Done. ### opam install --show pgocaml_ppx.4.2.2 [ERROR] Package conflict! * No agreement on the version of ocaml: - (invariant) -> ocaml-variants = 4.12.0+trunk -> ocaml = 4.12.0 - pgocaml_ppx >= 4.2.2 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.06.0 You can temporarily relax the switch invariant with `--update-invariant' * No agreement on the version of ocaml-variants: - (invariant) -> ocaml-variants = 4.12.0+trunk - pgocaml_ppx >= 4.2.2 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.06.0 -> ocaml-variants < 3.09.3~ * No agreement on the version of ocaml-migrate-parsetree: - pgocaml_ppx >= 4.2.2 -> ocaml-migrate-parsetree < 2.0.0 - pgocaml_ppx >= 4.2.2 -> ppx_deriving >= 4.0 -> ppxlib >= 0.20.0 -> ocaml-migrate-parsetree >= 2.1.0 * Missing dependency: - pgocaml_ppx >= 4.2.2 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.09.0 -> ocaml-variants < 4.08.1~ -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' * Missing dependency: - pgocaml_ppx >= 4.2.2 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.09.0 -> ocaml-variants < 4.08.2~ -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' * Missing dependency: - pgocaml_ppx >= 4.2.2 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.10 -> ocaml-variants < 4.09.2~ -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' * Missing dependency: - pgocaml_ppx >= 4.2.2 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.11 -> ocaml-variants < 4.10.3~ -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' * Missing dependency: - pgocaml_ppx >= 4.2.2 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.12 -> ocaml-variants < 4.11.1~ -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' * Missing dependency: - pgocaml_ppx >= 4.2.2 -> ocaml-migrate-parsetree < 2.0.0 -> ocaml < 4.12 -> ocaml-variants < 4.11.3~ -> ocaml-beta unmet availability conditions: 'enable-ocaml-beta-repository' No solution found, exiting # Return code 20 # opam-2.1.5/tests/reftests/upgrade-two-point-o.test0000644000175000017500000000336314427463453021247 0ustar stephstephN0REP0 ### opam-version: "2.0" flags: compiler ### opam-version: "2.0" flags: compiler ### OPAMYES=1 ### opam-version: "2.0" repositories: "default" installed-switches: ["pinned-comp"] switch: "pinned-comp" default-compiler: ["i-am-compiler"] ### opam-version: "2.0" compiler: ["i-am-compiler.1"] roots: ["i-am-compiler.1"] installed: ["i-am-compiler.1"] pinned: ["i-am-compiler.1"] ### opam-version: "2.0" synopsis: "switch with pinned compiler" ### OPAMDEBUGSECTIONS=STATE opam upgrade --show-action --debug-level=-1 STATE LOAD-SWITCH-STATE @ pinned-comp STATE Definition missing for installed package i-am-compiler.1, copying from repo STATE Inferred invariant: from base packages { i-am-compiler.1 }, (roots { i-am-compiler.1 }) => ["i-am-compiler" {= "1"}] STATE Switch state loaded in 0.000s STATE Detected changed packages (marked for reinstall): {} Everything as up-to-date as possible (run with --verbose to show unavailable upgrades). However, you may "opam upgrade" these packages explicitly, which will ask permission to downgrade or uninstall the conflicting packages. Nothing to do. ### opam pin remove i-am-compiler Ok, i-am-compiler is no longer pinned locally (version 1) No package build needed. Nothing to do. ### opam upgrade --show-action Everything as up-to-date as possible (run with --verbose to show unavailable upgrades). However, you may "opam upgrade" these packages explicitly, which will ask permission to downgrade or uninstall the conflicting packages. Nothing to do. opam-2.1.5/tests/reftests/opamrt-big-upgrade.test0000644000175000017500000003063614427463453021117 0ustar stephsteph7090735c ### OPAMYES=true ### opam-version: "2.0" roots: [ "async.109.42.00" "async_graphics.0.5.1" "base-bigarray.base" "base-threads.base" "base-unix.base" "cohttp.0.9.11" "core.109.47.00" "core_bench.109.47.00" "core_extended.109.47.00" "cow.0.7.0" "cryptokit.1.9" "ctypes.0.2.2" "github.0.6.1" "lwt.2.4.4" "menhir.20130912" "mirari.0.9.7" "mpp.0.1.3" "omd.0.7.5" "tuntap.0.7.0" "utop.1.8" "yojson.1.1.6" ] installed: [ "async.109.42.00" "async_core.109.47.00" "async_extra.109.47.00" "async_graphics.0.5.1" "async_unix.109.47.00" "atd.1.0.3" "atdgen.1.2.4" "base-bigarray.base" "base-threads.base" "base-unix.base" "bin_prot.109.47.00" "biniou.1.0.6" "camomile.0.8.5" "cmdliner.0.9.2" "cohttp.0.9.11" "comparelib.109.27.00" "core.109.47.00" "core_bench.109.47.00" "core_extended.109.47.00" "core_kernel.109.47.00" "cow.0.7.0" "cppo.0.9.3" "cryptokit.1.9" "cstruct.0.8.1" "ctypes.0.2.2" "custom_printf.109.27.00" "dyntype.0.9.0" "easy-format.1.0.1" "fd-send-recv.1.0.1" "fieldslib.109.20.00" "github.0.6.1" "herelib.109.35.00" "ipaddr.0.2.3" "lambda-term.1.5" "lwt.2.4.4" "menhir.20130912" "mirari.0.9.7" "mpp.0.1.3" "ocamlfind.1.4.0" "ocplib-endian.0.4" "omd.0.7.5" "optcomp.1.4" "ounit.2.0.0" "pa_ounit.109.36.00" "pipebang.109.28.00" "re.1.2.1" "re2.109.45.02" "react.0.9.4" "res.4.0.3" "sexplib.109.47.00" "ssl.0.4.6" "textutils.109.36.00" "tuntap.0.7.0" "type_conv.109.47.00" "ulex.1.1" "uri.1.3.11" "utop.1.8" "variantslib.109.15.00" "xmlm.1.2.0" "yojson.1.1.6" "zed.1.2" ] ### opam switch import init.export --switch test-import --fake | unordered The following actions will be faked: - install base-unix base - install ocaml-base-compiler 4.01.0beta1 [required by ocaml] - install base-bigarray base - install base-threads base - install ocaml 4.01.0beta1 [required by yojson, variantslib, uri, etc.] - install ocamlfind 1.4.0 - install cppo 0.9.3 - install xmlm 1.2.0 - install ulex 1.1 - install type_conv 109.47.00 - install ssl 0.4.6 - install res 4.0.3 - install react 0.9.4 - install re 1.2.1 - install pipebang 109.28.00 - install ounit 2.0.0 - install optcomp 1.4 - install omd 0.7.5 - install mpp 0.1.3 - install menhir 20130912 - install ipaddr 0.2.3 - install herelib 109.35.00 - install fd-send-recv 1.0.1 - install easy-format 1.0.1 - install ctypes 0.2.2 - install cryptokit 1.9 - install cmdliner 0.9.2 - install camomile 0.8.5 - install variantslib 109.15.00 - install sexplib 109.47.00 - install fieldslib 109.20.00 - install dyntype 0.9.0 - install comparelib 109.27.00 - install bin_prot 109.47.00 - install lwt 2.4.4 - install uri 1.3.11 - install pa_ounit 109.36.00 - install ocplib-endian 0.4 - install tuntap 0.7.0 - install biniou 1.0.6 - install atd 1.0.3 - install zed 1.2 - install cow 0.7.0 - install custom_printf 109.27.00 - install core_kernel 109.47.00 - install mirari 0.9.7 - install yojson 1.1.6 - install lambda-term 1.5 - install core 109.47.00 - install atdgen 1.2.4 - install utop 1.8 - install textutils 109.36.00 - install re2 109.45.02 - install async_core 109.47.00 - install core_bench 109.47.00 - install core_extended 109.47.00 - install async_unix 109.47.00 - install async_extra 109.47.00 - install async 109.42.00 - install cstruct 0.8.1 - install async_graphics 0.5.1 - install cohttp 0.9.11 - install github 0.6.1 ===== 63 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-base-compiler.4.01.0beta1 Faking installation of ocaml.4.01.0beta1 Faking installation of cppo.0.9.3 Faking installation of ocamlfind.1.4.0 Faking installation of camomile.0.8.5 Faking installation of cmdliner.0.9.2 Faking installation of cryptokit.1.9 Faking installation of ctypes.0.2.2 Faking installation of easy-format.1.0.1 Faking installation of biniou.1.0.6 Faking installation of fd-send-recv.1.0.1 Faking installation of herelib.109.35.00 Faking installation of ipaddr.0.2.3 Faking installation of menhir.20130912 Faking installation of atd.1.0.3 Faking installation of mpp.0.1.3 Faking installation of omd.0.7.5 Faking installation of optcomp.1.4 Faking installation of ocplib-endian.0.4 Faking installation of ounit.2.0.0 Faking installation of pipebang.109.28.00 Faking installation of re.1.2.1 Faking installation of react.0.9.4 Faking installation of res.4.0.3 Faking installation of ssl.0.4.6 Faking installation of lwt.2.4.4 Faking installation of tuntap.0.7.0 Faking installation of mirari.0.9.7 Faking installation of type_conv.109.47.00 Faking installation of bin_prot.109.47.00 Faking installation of comparelib.109.27.00 Faking installation of dyntype.0.9.0 Faking installation of fieldslib.109.20.00 Faking installation of pa_ounit.109.36.00 Faking installation of sexplib.109.47.00 Faking installation of custom_printf.109.27.00 Faking installation of ulex.1.1 Faking installation of uri.1.3.11 Faking installation of variantslib.109.15.00 Faking installation of core_kernel.109.47.00 Faking installation of core.109.47.00 Faking installation of async_core.109.47.00 Faking installation of async_unix.109.47.00 Faking installation of async_extra.109.47.00 Faking installation of async.109.42.00 Faking installation of async_graphics.0.5.1 Faking installation of cstruct.0.8.1 Faking installation of cohttp.0.9.11 Faking installation of re2.109.45.02 Faking installation of textutils.109.36.00 Faking installation of core_bench.109.47.00 Faking installation of core_extended.109.47.00 Faking installation of xmlm.1.2.0 Faking installation of cow.0.7.0 Faking installation of yojson.1.1.6 Faking installation of atdgen.1.2.4 Faking installation of zed.1.2 Faking installation of lambda-term.1.5 Faking installation of github.0.6.1 Faking installation of utop.1.8 Done. ### opam upgrade --fake The following actions will be faked: - upgrade uri 1.3.11 to 1.3.12 - upgrade mpp 0.1.3 to 0.1.4 - upgrade herelib 109.35.00 to 109.35.02 - upgrade pipebang 109.28.00 to 109.28.02 - upgrade atd 1.0.3 to 1.1.0 - upgrade type_conv 109.47.00 to 109.53.02 - upgrade optcomp 1.4 to 1.5 - upgrade res 4.0.3 to 4.0.4 - upgrade utop 1.8 to 1.10 - upgrade ipaddr 0.2.3 to 1.0.0 - upgrade omd 0.7.5 to 0.9.1 - upgrade atdgen 1.2.4 to 1.3.0 - upgrade variantslib 109.15.00 to 109.15.02 - upgrade sexplib 109.47.00 to 109.55.02 - upgrade pa_ounit 109.36.00 to 109.53.02 - upgrade fieldslib 109.20.00 to 109.20.02 - upgrade comparelib 109.27.00 to 109.27.02 - upgrade bin_prot 109.47.00 to 109.53.02 - recompile dyntype 0.9.0 [uses type_conv] - recompile ocplib-endian 0.4 [uses optcomp] - recompile tuntap 0.7.0 [uses ipaddr] - install pa_bench 109.55.02 [required by core_kernel] - upgrade custom_printf 109.27.00 to 109.27.02 - install typerep 109.55.02 [required by core_kernel] - upgrade cow 0.7.0 to 0.9.1 - recompile mirari 0.9.7 [uses ipaddr] - upgrade core_kernel 109.47.00 to 109.55.02 - install pa_test 109.53.02 [required by core, async_core, core_extended] - upgrade core 109.47.00 to 109.55.02 - upgrade re2 109.45.02 to 109.55.02 - upgrade async_core 109.47.00 to 109.55.02 - upgrade async_unix 109.47.00 to 109.55.02 - upgrade async_extra 109.47.00 to 109.55.02 - upgrade async 109.42.00 to 109.53.02 - upgrade textutils 109.36.00 to 109.53.02 - upgrade cstruct 0.8.1 to 1.0.1 - recompile async_graphics 0.5.1 [uses async] - upgrade core_extended 109.47.00 to 109.55.02 - upgrade core_bench 109.47.00 to 109.55.02 - upgrade cohttp 0.9.11 to 0.9.14 - upgrade github 0.6.1 to 0.7.0 ===== 3 to install | 5 to recompile | 33 to upgrade ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of atd.1.1.0 Faking installation of atdgen.1.3.0 Faking installation of herelib.109.35.02 Faking installation of ipaddr.1.0.0 Faking installation of mpp.0.1.4 Faking installation of omd.0.9.1 Faking installation of optcomp.1.5 Faking installation of ocplib-endian.0.4 Faking installation of pipebang.109.28.02 Faking installation of res.4.0.4 Faking installation of tuntap.0.7.0 Faking installation of mirari.0.9.7 Faking installation of type_conv.109.53.02 Faking installation of bin_prot.109.53.02 Faking installation of comparelib.109.27.02 Faking installation of dyntype.0.9.0 Faking installation of fieldslib.109.20.02 Faking installation of pa_ounit.109.53.02 Faking installation of pa_bench.109.55.02 Faking installation of sexplib.109.55.02 Faking installation of custom_printf.109.27.02 Faking installation of typerep.109.55.02 Faking installation of uri.1.3.12 Faking installation of cow.0.9.1 Faking installation of utop.1.10 Faking installation of variantslib.109.15.02 Faking installation of core_kernel.109.55.02 Faking installation of pa_test.109.53.02 Faking installation of core.109.55.02 Faking installation of async_core.109.55.02 Faking installation of async_unix.109.55.02 Faking installation of async_extra.109.55.02 Faking installation of async.109.53.02 Faking installation of async_graphics.0.5.1 Faking installation of cstruct.1.0.1 Faking installation of cohttp.0.9.14 Faking installation of github.0.7.0 Faking installation of re2.109.55.02 Faking installation of textutils.109.53.02 Faking installation of core_bench.109.55.02 Faking installation of core_extended.109.55.02 Done. ### opam switch export - opam-version: "2.0" compiler: ["ocaml-base-compiler.4.01.0beta1"] roots: [ "async.109.53.02" "async_graphics.0.5.1" "base-bigarray.base" "base-threads.base" "base-unix.base" "cohttp.0.9.14" "core.109.55.02" "core_bench.109.55.02" "core_extended.109.55.02" "cow.0.9.1" "cryptokit.1.9" "ctypes.0.2.2" "github.0.7.0" "lwt.2.4.4" "menhir.20130912" "mirari.0.9.7" "mpp.0.1.4" "omd.0.9.1" "tuntap.0.7.0" "utop.1.10" "yojson.1.1.6" ] installed: [ "async.109.53.02" "async_core.109.55.02" "async_extra.109.55.02" "async_graphics.0.5.1" "async_unix.109.55.02" "atd.1.1.0" "atdgen.1.3.0" "base-bigarray.base" "base-threads.base" "base-unix.base" "bin_prot.109.53.02" "biniou.1.0.6" "camomile.0.8.5" "cmdliner.0.9.2" "cohttp.0.9.14" "comparelib.109.27.02" "core.109.55.02" "core_bench.109.55.02" "core_extended.109.55.02" "core_kernel.109.55.02" "cow.0.9.1" "cppo.0.9.3" "cryptokit.1.9" "cstruct.1.0.1" "ctypes.0.2.2" "custom_printf.109.27.02" "dyntype.0.9.0" "easy-format.1.0.1" "fd-send-recv.1.0.1" "fieldslib.109.20.02" "github.0.7.0" "herelib.109.35.02" "ipaddr.1.0.0" "lambda-term.1.5" "lwt.2.4.4" "menhir.20130912" "mirari.0.9.7" "mpp.0.1.4" "ocaml.4.01.0beta1" "ocaml-base-compiler.4.01.0beta1" "ocamlfind.1.4.0" "ocplib-endian.0.4" "omd.0.9.1" "optcomp.1.5" "ounit.2.0.0" "pa_bench.109.55.02" "pa_ounit.109.53.02" "pa_test.109.53.02" "pipebang.109.28.02" "re.1.2.1" "re2.109.55.02" "react.0.9.4" "res.4.0.4" "sexplib.109.55.02" "ssl.0.4.6" "textutils.109.53.02" "tuntap.0.7.0" "type_conv.109.53.02" "typerep.109.55.02" "ulex.1.1" "uri.1.3.12" "utop.1.10" "variantslib.109.15.02" "xmlm.1.2.0" "yojson.1.1.6" "zed.1.2" ] opam-2.1.5/tests/reftests/conflict-4373.test0000644000175000017500000000105014427463453017614 0ustar stephstephc1d23f0e ### OPAMVAR_enable_ocaml_beta_repository=1 opam switch create --fake 4.12.0 [ERROR] No compiler matching `4.12.0' found, use `opam switch list-available' to see what is available, or use `--packages' to select packages explicitly. # Return code 5 # ### opam install --show expect.0.0.6 [ERROR] No switch is currently set. Please use 'opam switch' to set or install a switch # Return code 50 # ### opam install --show ppx_expect.v0.14.0 [ERROR] No switch is currently set. Please use 'opam switch' to set or install a switch # Return code 50 # opam-2.1.5/tests/reftests/var-option.test0000644000175000017500000006004314427463453017522 0ustar stephstephN0REP0 ### opam-version: "2.0" depends: [ "base" ] available: !(os = "macos" & arch = "arm64") flags: compiler setenv: IGTV_PATH = "%{lib}%/stublibs" ### opam-version: "2.0" ### opam-version: "2.0" ### opam switch create var-option --empty ### opam var user= --switch var-option Removed variable user in switch var-option ### opam var group= --switch var-option Removed variable group in switch var-option ### opam var arch=x86_64 --global Added '[arch "x86_64" "Set through 'opam var'"]' to field global-variables in global configuration ### opam var jobs=7 --global Added '[jobs "7" "Set through 'opam var'"]' to field global-variables in global configuration ### opam var make=make --global Added '[make "make" "Set through 'opam var'"]' to field global-variables in global configuration ### opam var opam-version=68.79 --global Added '[opam-version "68.79" "Set through 'opam var'"]' to field global-variables in global configuration ### opam var os=linux --global Added '[os "linux" "Set through 'opam var'"]' to field global-variables in global configuration ### opam var os-distribution=lorem --global Added '[os-distribution "lorem" "Set through 'opam var'"]' to field global-variables in global configuration ### opam var os-family=ipsum --global Added '[os-family "ipsum" "Set through 'opam var'"]' to field global-variables in global configuration ### opam var os-version=dolor --global Added '[os-version "dolor" "Set through 'opam var'"]' to field global-variables in global configuration ### opam var sys-ocaml-arch= --global Removed variable sys-ocaml-arch in global configuration ### opam var sys-ocaml-cc= --global Removed variable sys-ocaml-cc in global configuration ### opam var sys-ocaml-libc= --global Removed variable sys-ocaml-libc in global configuration ### opam option wrap-build-commands=[] --global Set to '[]' the field wrap-build-commands in global configuration ### opam option wrap-install-commands=[] --global Set to '[]' the field wrap-install-commands in global configuration ### opam option wrap-remove-commands=[] --global Set to '[]' the field wrap-remove-commands in global configuration ### opam install i-got-the-variables --yes The following actions will be performed: - install base 2 [required by i-got-the-variables] - install i-got-the-variables 2.4.6 ===== 2 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed base.2 -> installed i-got-the-variables.2.4.6 Done. ### opam var | " *" -> " " | "[.]exe " -> "" <><> Global opam variables ><><><><><><><><><><><><><><><><><><><><><><><><><><> arch x86_64 # Set through 'opam var' exe # Suffix needed for executable filenames (Windows) jobs 7 # Set through 'opam var' make make # Set through 'opam var' opam-version 68.79 # Set through 'opam var' os linux # Set through 'opam var' os-distribution lorem # Set through 'opam var' os-family ipsum # Set through 'opam var' os-version dolor # Set through 'opam var' root ${BASEDIR}/OPAM # The current opam root directory switch var-option # The identifier of the current switch sys-ocaml-version 4.08.0 # Set through 'opam var' <><> Configuration variables from the current switch ><><><><><><><><><><><><><> prefix ${BASEDIR}/OPAM/var-option lib ${BASEDIR}/OPAM/var-option/lib bin ${BASEDIR}/OPAM/var-option/bin sbin ${BASEDIR}/OPAM/var-option/sbin share ${BASEDIR}/OPAM/var-option/share doc ${BASEDIR}/OPAM/var-option/doc etc ${BASEDIR}/OPAM/var-option/etc man ${BASEDIR}/OPAM/var-option/man toplevel ${BASEDIR}/OPAM/var-option/lib/toplevel stublibs ${BASEDIR}/OPAM/var-option/lib/stublibs <><> Package variables ('opam var --package PKG' to show) <><><><><><><><><><><> PKG:name # Name of the package PKG:version # Version of the package PKG:depends # Resolved direct dependencies of the package PKG:installed # Whether the package is installed PKG:enable # Takes the value "enable" or "disable" depending on whether the package is installed PKG:pinned # Whether the package is pinned PKG:bin # Binary directory for this package PKG:sbin # System binary directory for this package PKG:lib # Library directory for this package PKG:man # Man directory for this package PKG:doc # Doc directory for this package PKG:share # Share directory for this package PKG:etc # Etc directory for this package PKG:build # Directory where the package was built PKG:hash # Hash of the package archive PKG:dev # True if this is a development package PKG:build-id # A hash identifying the precise package version with all its dependencies PKG:opamfile # Path of the curent opam file ### opam var --switch var-option prefix ${BASEDIR}/OPAM/var-option lib ${BASEDIR}/OPAM/var-option/lib bin ${BASEDIR}/OPAM/var-option/bin sbin ${BASEDIR}/OPAM/var-option/sbin share ${BASEDIR}/OPAM/var-option/share doc ${BASEDIR}/OPAM/var-option/doc etc ${BASEDIR}/OPAM/var-option/etc man ${BASEDIR}/OPAM/var-option/man toplevel ${BASEDIR}/OPAM/var-option/lib/toplevel stublibs ${BASEDIR}/OPAM/var-option/lib/stublibs ### opam var --global | " *" -> " " | "[.]exe " -> "" arch x86_64 # Set through 'opam var' exe # Suffix needed for executable filenames (Windows) jobs 7 # Set through 'opam var' make make # Set through 'opam var' opam-version 68.79 # Set through 'opam var' os linux # Set through 'opam var' os-distribution lorem # Set through 'opam var' os-family ipsum # Set through 'opam var' os-version dolor # Set through 'opam var' root ${BASEDIR}/OPAM # The current opam root directory switch var-option # The identifier of the current switch sys-ocaml-version 4.08.0 # Set through 'opam var' ### OPAMDEBUG=-1 OPAMDEBUGSECTIONS="GSTATE STATE" opam var bin GSTATE LOAD-GLOBAL-STATE @ ${BASEDIR}/OPAM ${BASEDIR}/OPAM/var-option/bin ### opam var bin --switch var-option ${BASEDIR}/OPAM/var-option/bin ### opam var bin --global [ERROR] Variable bin not found in global config # Return code 5 # ### opam var bin=global-bin --global Added '[bin "global-bin" "Set through 'opam var'"]' to field global-variables in global configuration ### opam var bin=switch-bin --switch var-option Added 'bin: "switch-bin"' to field variables in switch var-option ### opam var bin ${BASEDIR}/OPAM/var-option/bin ### opam var bin --switch var-option ${BASEDIR}/OPAM/var-option/bin ### opam var bin --global global-bin ### opam var foo=global-foo --global Added '[foo "global-foo" "Set through 'opam var'"]' to field global-variables in global configuration ### opam var foo=switch-foo --switch var-option Added 'foo: "switch-foo"' to field variables in switch var-option ### opam var foo switch-foo ### opam var foo --switch var-option switch-foo ### opam var foo --global global-foo ### opam var ocaml-base-compiler:version [ERROR] Variable ocaml-base-compiler:version not found in switch var-option # Return code 5 # ### opam var ocaml-base-compiler:version --switch var-option [ERROR] Variable ocaml-base-compiler:version not found in switch var-option # Return code 5 # ### opam var --package ocaml | ".*build-id.*" -> '\c' | ".*opamfile.*" -> '\c' | " *" -> " " Fatal error: Not_found # Return code 99 # ### opam var i-got-the-variables:version 2.4.6 ### opam var i-got-the-variables:version --switch var-option 2.4.6 ### opam var --package i-got-the-variables | ".*build-id.*" -> '\c' | ".*opamfile.*" -> '\c' | " *" -> " " i-got-the-variables:name i-got-the-variables # Name of the package i-got-the-variables:version 2.4.6 # Version of the package i-got-the-variables:depends base.2 # Resolved direct dependencies of the package i-got-the-variables:installed true # Whether the package is installed i-got-the-variables:enable enable # Takes the value "enable" or "disable" depending on whether the package is installed i-got-the-variables:pinned false # Whether the package is pinned i-got-the-variables:bin ${BASEDIR}/OPAM/var-option/bin # Binary directory for this package i-got-the-variables:sbin ${BASEDIR}/OPAM/var-option/sbin # System binary directory for this package i-got-the-variables:lib ${BASEDIR}/OPAM/var-option/lib/i-got-the-variables # Library directory for this package i-got-the-variables:man ${BASEDIR}/OPAM/var-option/man # Man directory for this package i-got-the-variables:doc ${BASEDIR}/OPAM/var-option/doc/i-got-the-variables # Doc directory for this package i-got-the-variables:share ${BASEDIR}/OPAM/var-option/share/i-got-the-variables # Share directory for this package i-got-the-variables:etc ${BASEDIR}/OPAM/var-option/etc/i-got-the-variables # Etc directory for this package i-got-the-variables:build ${BASEDIR}/OPAM/var-option/.opam-switch/build/i-got-the-variables.2.4.6 # Directory where the package was built i-got-the-variables:dev false # True if this is a development package ### opam option <><> Global configuration <><><><><><><><><><><><><><><><><><><><><><><><><><><> best-effort-prefix-criteria {} depext true depext-bypass {} depext-cannot-install false depext-run-installs true download-command {} download-jobs 3 jobs {} post-build-commands {} post-install-commands {} post-remove-commands {} post-session-commands {} pre-build-commands {} pre-install-commands {} pre-remove-commands {} pre-session-commands {} repository-validation-command {} solver {} solver-criteria {} solver-fixup-criteria {} solver-upgrade-criteria {} wrap-build-commands {} wrap-install-commands {} wrap-remove-commands {} <><> Switch configuration (var-option) ><><><><><><><><><><><><><><><><><><><><> depext-bypass {} post-build-commands {} post-install-commands {} post-remove-commands {} post-session-commands {} pre-build-commands {} pre-install-commands {} pre-remove-commands {} pre-session-commands {} setenv {} synopsis "var-option" wrap-build-commands {} wrap-install-commands {} wrap-remove-commands {} ### # Check global & switch option setting ### opam option download-jobs 3 ### opam option download-jobs --global 3 ### opam option download-jobs --switch var-option [ERROR] Field or section download-jobs not found # Return code 5 # ### opam option jobs ### opam option jobs --global ### opam option jobs --switch var-option [ERROR] Field or section jobs not found # Return code 5 # ### opam option depext-bypass [] ### opam option depext-bypass --global [] ### opam option depext-bypass --switch var-option [] ### opam option synopsis "var-option" ### opam option 'synopsis="sit amet"' Set to '"sit amet"' the field synopsis in switch var-option ### opam option synopsis "sit amet" ### opam option synopsis --switch var-option "sit amet" ### opam option synopsis --global [ERROR] Field or section synopsis not found # Return code 5 # ### opam option synopsis= Reverted field synopsis in switch var-option ### opam option synopsis "" ### opam option 'synopsis="consectetur adipiscing"' --switch var-option Set to '"consectetur adipiscing"' the field synopsis in switch var-option ### opam option synopsis "consectetur adipiscing" ### opam option synopsis= --switch var-option Reverted field synopsis in switch var-option ### opam option synopsis "" ### opam option download-jobs 3 ### opam option download-jobs=10 Set to '10' the field download-jobs in global configuration ### opam option download-jobs 10 ### opam option download-jobs --switch var-option [ERROR] Field or section download-jobs not found # Return code 5 # ### opam option download-jobs --global 10 ### opam option download-jobs= Reverted field download-jobs in global configuration ### opam option download-jobs 1 ### opam option download-jobs=12 --global Set to '12' the field download-jobs in global configuration ### opam option download-jobs 12 ### opam option download-jobs= --global Reverted field download-jobs in global configuration ### opam option download-jobs 1 ### # Check same option name setting through global & switch ### opam option pre-session-commands [] ### opam option 'pre-session-commands=["elit"]' Set to '["elit"]' the field pre-session-commands in switch var-option ### opam option pre-session-commands "elit" ### opam option pre-session-commands --switch var-option "elit" ### opam option pre-session-commands --global [] ### opam option pre-session-commands= Reverted field pre-session-commands in switch var-option ### opam option pre-session-commands [] ### opam option pre-session-commands --switch var-option [] ### opam option pre-session-commands --global [] ### opam option 'pre-session-commands=["sed"]' --switch var-option Set to '["sed"]' the field pre-session-commands in switch var-option ### opam option pre-session-commands "sed" ### opam option pre-session-commands --switch var-option "sed" ### opam option pre-session-commands --global [] ### opam option pre-session-commands= --switch var-option Reverted field pre-session-commands in switch var-option ### opam option pre-session-commands [] ### opam option pre-session-commands --switch var-option [] ### opam option pre-session-commands --global [] ### opam option 'pre-session-commands=["do"]' --global Set to '["do"]' the field pre-session-commands in global configuration ### opam option pre-session-commands [] ### opam option pre-session-commands --switch var-option [] ### opam option pre-session-commands --global "do" ### opam option pre-session-commands= --global Reverted field pre-session-commands in global configuration ### opam option pre-session-commands [] ### opam option pre-session-commands --switch var-option [] ### opam option pre-session-commands --global [] ### # Check addition & removal on set ### opam option depext-bypass [] ### opam option 'depext-bypass+=["tempor"]' Added '["tempor"]' to field depext-bypass in switch var-option ### opam option 'depext-bypass+=["incididunt"]' Added '["incididunt"]' to field depext-bypass in switch var-option ### opam option depext-bypass ["incididunt" "tempor"] ### opam option 'depext-bypass-=["incididunt"]' Removed '["incididunt"]' from field depext-bypass in switch var-option ### opam option depext-bypass ["tempor"] ### opam option 'depext-bypass=["incididunt" "tempor"]' Set to '["incididunt" "tempor"]' the field depext-bypass in switch var-option ### opam option 'depext-bypass-=["tempor"]' Removed '["tempor"]' from field depext-bypass in switch var-option ### opam option depext-bypass ["incididunt"] ### opam option 'depext-bypass-=["ut"]' No modification in switch var-option ### opam option depext-bypass ["incididunt"] ### opam option 'depext-bypass-=[]' No modification in switch var-option ### opam option depext-bypass ["incididunt"] ### opam option depext-bypass= Reverted field depext-bypass in switch var-option ### opam option 'depext-bypass-=["tempor"]' No modification in switch var-option ### opam option depext-bypass [] ### # Check addition & removal on list ### opam option 'setenv+=lorem="labore"' Added 'lorem="labore"' to field setenv in switch var-option ### opam option 'setenv+=ipsum="dolore"' Added 'ipsum="dolore"' to field setenv in switch var-option ### opam option setenv [[ipsum = "dolore"] [lorem = "labore"]] ### opam option 'setenv-=lorem="labore"' Removed 'lorem="labore"' from field setenv in switch var-option ### opam option setenv ipsum = "dolore" ### opam option 'setenv=[[lorem="labore"] [ipsum="dolore"]]' Set to '[[lorem="labore"] [ipsum="dolore"]]' the field setenv in switch var-option ### opam option 'setenv-=lorem="labore"' Removed 'lorem="labore"' from field setenv in switch var-option ### opam option setenv ipsum = "dolore" ### opam option 'setenv-=lorem="et"' No modification in switch var-option ### opam option setenv ipsum = "dolore" ### opam option setenv= Reverted field setenv in switch var-option ### opam option 'setenv-=lorem="labore"' No modification in switch var-option ### opam option setenv [] ### # Check that eval-variable is removed when a global variable is removed ### opam option global-variables [[foo "global-foo" "Set through 'opam var'"] [bin "global-bin" "Set through 'opam var'"] [os-version "dolor" "Set through 'opam var'"] [os-family "ipsum" "Set through 'opam var'"] [os-distribution "lorem" "Set through 'opam var'"] [os "linux" "Set through 'opam var'"] [opam-version "68.79" "Set through 'opam var'"] [make "make" "Set through 'opam var'"] [jobs "7" "Set through 'opam var'"] [arch "x86_64" "Set through 'opam var'"] [sys-ocaml-version "4.08.0" "Set through 'opam var'"]] ### opam option 'eval-variables=[dolore ["mania"] "alica"]' Set to '[dolore ["mania"] "alica"]' the field eval-variables in global configuration ### opam option eval-variables [dolore ["mania"] "alica"] ### opam var dolore=mania --global Added '[dolore "mania" "Set through 'opam var'"]' to field global-variables in global configuration ### opam var dolore= --global Removed variable dolore in global configuration ### opam option eval-variables [] ### opam option global-variables [[foo "global-foo" "Set through 'opam var'"] [bin "global-bin" "Set through 'opam var'"] [os-version "dolor" "Set through 'opam var'"] [os-family "ipsum" "Set through 'opam var'"] [os-distribution "lorem" "Set through 'opam var'"] [os "linux" "Set through 'opam var'"] [opam-version "68.79" "Set through 'opam var'"] [make "make" "Set through 'opam var'"] [jobs "7" "Set through 'opam var'"] [arch "x86_64" "Set through 'opam var'"] [sys-ocaml-version "4.08.0" "Set through 'opam var'"]] ### # Check uniable operations ### opam option 'variables+={esse: "cillum"}' [ERROR] Field variables can't be directly appended to, use `opam var` instead # Return code 2 # ### opam option 'invariant="inv"' [ERROR] Field invariant is not modifiable # Return code 2 # ### opam option 'jobs+=3' [ERROR] Field jobs can't be appended # Return code 2 # ### opam option 'jobs-=3' [ERROR] Field jobs can't be substracted # Return code 2 # ### opam option bar [ERROR] No option named 'bar' found. Use 'opam option [--global]' to list them # Return code 2 # ### opam option bar --global [ERROR] Field or section bar not found # Return code 5 # ### opam option bar --switch var-option [ERROR] Field or section bar not found # Return code 5 # ### opam option bar=sit [ERROR] No option named 'bar' found. Use 'opam option [--global]' to list them # Return code 2 # ### opam option bar=sit --global [ERROR] There is no option named 'bar'. The allowed options are: jobs download-command download-jobs solver-criteria solver-upgrade-criteria solver-fixup-criteria best-effort-prefix-criteria solver global-variables eval-variables repository-validation-command depext depext-run-installs depext-cannot-install depext-bypass pre-build-commands pre-install-commands pre-remove-commands pre-session-commands wrap-build-commands wrap-install-commands wrap-remove-commands post-build-commands post-install-commands post-remove-commands post-session-commands # Return code 2 # ### opam option bar=sit --switch var-option [ERROR] There is no option named 'bar'. The allowed options are: synopsis setenv depext-bypass pre-build-commands pre-install-commands pre-remove-commands pre-session-commands wrap-build-commands wrap-install-commands wrap-remove-commands post-build-commands post-install-commands post-remove-commands post-session-commands variables # Return code 2 # ### : when no switch is present ### opam switch remove var-option -y Switch var-option and all its packages will be wiped. Are you sure? [Y/n] y ### opam var | ' +#.*' -> '' | " +[.]exe" -> "" <><> Global opam variables ><><><><><><><><><><><><><><><><><><><><><><><><><><> arch x86_64 bin global-bin exe foo global-foo jobs 7 make make opam-version 68.79 os linux os-distribution lorem os-family ipsum os-version dolor root ${BASEDIR}/OPAM switch sys-ocaml-version 4.08.0 <><> Configuration variables from the current switch ><><><><><><><><><><><><><> No switch installed <><> Package variables ('opam var --package PKG' to show) <><><><><><><><><><><> PKG:name PKG:version PKG:depends PKG:installed PKG:enable PKG:pinned PKG:bin PKG:sbin PKG:lib PKG:man PKG:doc PKG:share PKG:etc PKG:build PKG:hash PKG:dev PKG:build-id PKG:opamfile ### opam var --global | ' +#.*' -> '' | " +[.]exe" -> "" arch x86_64 bin global-bin exe foo global-foo jobs 7 make make opam-version 68.79 os linux os-distribution lorem os-family ipsum os-version dolor root ${BASEDIR}/OPAM switch sys-ocaml-version 4.08.0 ### opam var --switch phantom prefix ${BASEDIR}/OPAM/phantom lib ${BASEDIR}/OPAM/phantom/lib bin ${BASEDIR}/OPAM/phantom/bin sbin ${BASEDIR}/OPAM/phantom/sbin share ${BASEDIR}/OPAM/phantom/share doc ${BASEDIR}/OPAM/phantom/doc etc ${BASEDIR}/OPAM/phantom/etc man ${BASEDIR}/OPAM/phantom/man toplevel ${BASEDIR}/OPAM/phantom/lib/toplevel stublibs ${BASEDIR}/OPAM/phantom/lib/stublibs ### opam option <><> Global configuration <><><><><><><><><><><><><><><><><><><><><><><><><><><> best-effort-prefix-criteria {} depext true depext-bypass {} depext-cannot-install false depext-run-installs true download-command {} download-jobs 1 jobs {} post-build-commands {} post-install-commands {} post-remove-commands {} post-session-commands {} pre-build-commands {} pre-install-commands {} pre-remove-commands {} pre-session-commands {} repository-validation-command {} solver {} solver-criteria {} solver-fixup-criteria {} solver-upgrade-criteria {} wrap-build-commands {} wrap-install-commands {} wrap-remove-commands {} <><> Switch configuration <><><><><><><><><><><><><><><><><><><><><><><><><><><> No switch installed ### opam option --global best-effort-prefix-criteria {} depext true depext-bypass {} depext-cannot-install false depext-run-installs true download-command {} download-jobs 1 jobs {} post-build-commands {} post-install-commands {} post-remove-commands {} post-session-commands {} pre-build-commands {} pre-install-commands {} pre-remove-commands {} pre-session-commands {} repository-validation-command {} solver {} solver-criteria {} solver-fixup-criteria {} solver-upgrade-criteria {} wrap-build-commands {} wrap-install-commands {} wrap-remove-commands {} ### opam option --switch phantom [ERROR] switch phantom not found, display default values depext-bypass {} post-build-commands {} post-install-commands {} post-remove-commands {} post-session-commands {} pre-build-commands {} pre-install-commands {} pre-remove-commands {} pre-session-commands {} setenv {} synopsis "" wrap-build-commands {} wrap-install-commands {} wrap-remove-commands {} ### opam var root ${BASEDIR}/OPAM ### opam var root --global ${BASEDIR}/OPAM ### opam option depext true ### opam option depext --global true ### opam var arch="somearch" | '…' -> '...' | '`' -> "'" opam: variable setting needs a scope, use '--global' or '--switch ' Usage: opam var [OPTION]... [VAR[=[VALUE]]] Try 'opam var --help' or 'opam --help' for more information. # Return code 2 # ### opam var arch="somearch" --global Added '[arch "\"somearch\"" "Set through 'opam var'"]' to field global-variables in global configuration ### opam var arch="somearch" --switch phantom [ERROR] The selected switch phantom is not installed # Return code 2 # ### opam option depext-bypass=["pkg"] Set to '["pkg"]' the field depext-bypass in global configuration ### opam option depext-bypass=["otherpkg"] --global Set to '["otherpkg"]' the field depext-bypass in global configuration ### opam option depext-bypass=["yetanotherpkg"] --switch phantom [ERROR] The selected switch phantom is not installed # Return code 2 # opam-2.1.5/tests/reftests/upgrade-format.test0000644000175000017500000002622514427463453020345 0ustar stephsteph009e00fa ### opam-version: "1.2" version: "2.0.7" maintainer: "opam-devel@lists.ocaml.org" authors: [ "Vincent Bernardoff " "Raja Boujbel " "Roberto Di Cosmo " "Thomas Gazagnaire " "Louis Gesbert " "Fabrice Le Fessant " "Anil Madhavapeddy " "Guillem Rieu " "Ralf Treinen " "Frederic Tuong " ] homepage: "https://opam.ocaml.org/" bug-reports: "https://github.com/ocaml/opam/issues" dev-repo: "https://github.com/ocaml/opam.git" build: [ ["./configure" "--disable-checks" "--prefix" prefix] [make "%{name}%.install"] ] depends: [ "base-unix" "base-bigarray" "ocamlgraph" "re" {>= "1.5.0"} "dune" {build & >= "1.2.1"} "cppo" {build} ] conflicts: "extlib-compat" available: ocaml-version >= "4.02.3" ### opam show --raw ./opam-core.opam [WARNING] Failed checks on opam-core package definition from source at file://${BASEDIR}: error 57: Synopsis and description must not be both empty opam-version: "2.0" name: "opam-core" version: "2.0.7" maintainer: "opam-devel@lists.ocaml.org" authors: [ "Vincent Bernardoff " "Raja Boujbel " "Roberto Di Cosmo " "Thomas Gazagnaire " "Louis Gesbert " "Fabrice Le Fessant " "Anil Madhavapeddy " "Guillem Rieu " "Ralf Treinen " "Frederic Tuong " ] homepage: "https://opam.ocaml.org/" bug-reports: "https://github.com/ocaml/opam/issues" depends: [ "ocaml" {>= "4.02.3"} "base-unix" "base-bigarray" "ocamlgraph" "re" {>= "1.5.0"} "dune" {build & >= "1.2.1"} "cppo" {build} ] conflicts: ["extlib-compat"] build: [ ["./configure" "--disable-checks" "--prefix" prefix] [make "%{name}%.install"] ] dev-repo: "git+https://github.com/ocaml/opam.git" ### opam switch create . ocaml-system --fake -y opam-core is now pinned to file://${BASEDIR} (version 2.0.7) <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml-system"] The following actions will be faked: - install base-bigarray base [required by opam-core] - install base-threads base [required by dune] - install base-unix base [required by opam-core] - install ocaml-system 4.08.0 - install conf-m4 1 [required by ocamlfind] - install ocaml-config 1 [required by ocaml] - install ocaml 4.08.0 [required by opam-core] - install seq base [required by re] - install ocamlfind 1.8.1 [required by ocamlgraph] - install dune 2.5.1 [required by opam-core] - install ocamlgraph 1.8.8 [required by opam-core] - install re 1.9.0 [required by opam-core] - install cppo 1.6.6 [required by opam-core] - install opam-core 2.0.7* ===== 14 to install ===== <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of conf-m4.1 Faking installation of ocaml-system.4.08.0 Faking installation of ocaml-config.1 Faking installation of ocaml.4.08.0 Faking installation of dune.2.5.1 Faking installation of cppo.1.6.6 Faking installation of ocamlfind.1.8.1 Faking installation of ocamlgraph.1.8.8 Faking installation of seq.base Faking installation of re.1.9.0 Faking installation of opam-core.2.0.7 Done. ### opam pin add git+https://github.com/ocaml/opam.git#59a71e3cf1 -yn This will pin the following packages: opam-client, opam-core, opam-devel, opam-format, opam-installer, opam-repository, opam-solver, opam-state. Continue? [Y/n] y opam-client is now pinned to git+https://github.com/ocaml/opam.git#59a71e3cf1 (version 2.1.0~beta3) [NOTE] Package opam-core is currently pinned to file://${BASEDIR} (version 2.0.7). opam-core is now pinned to git+https://github.com/ocaml/opam.git#59a71e3cf1 (version 2.1.0~beta3) opam-devel is now pinned to git+https://github.com/ocaml/opam.git#59a71e3cf1 (version 2.1.0~beta3) opam-format is now pinned to git+https://github.com/ocaml/opam.git#59a71e3cf1 (version 2.1.0~beta3) opam-installer is now pinned to git+https://github.com/ocaml/opam.git#59a71e3cf1 (version 2.1.0~beta3) opam-repository is now pinned to git+https://github.com/ocaml/opam.git#59a71e3cf1 (version 2.1.0~beta3) opam-solver is now pinned to git+https://github.com/ocaml/opam.git#59a71e3cf1 (version 2.1.0~beta3) opam-state is now pinned to git+https://github.com/ocaml/opam.git#59a71e3cf1 (version 2.1.0~beta3) ### opam install opam-format --show <><> Synchronising pinned packages ><><><><><><><><><><><><><><><><><><><><><><> [opam-format.2.1.0~beta3] synchronised (no changes) The following actions would be performed: - upgrade opam-core 2.0.7 to 2.1.0~beta3* [required by opam-format] - install opam-file-format 2.0.0 [required by opam-format] - install opam-format 2.1.0~beta3* ===== 2 to install | 1 to upgrade ===== ### : Testing preserved format with upgrade : ### opam-version: "2.0" build: ["opam"] #comment depends: ["config" "ocaml" "base"] #comment #comment flags: compiler ### #comment opam-version: "2.0" #comment build: ["opam"] #comment depends: [ # comment "config" #comment "ocaml" #comment "base" #comment #comment ] #comment flags: compiler ### #comment opam-version: "2.0" #comment flags: compiler #comment depends: [ #comment "config" #comment "ocaml" #comment "base" #comment #comment ] #comment build: ["opam" "var" "prefix" "--safe"] license: "MIT" #comment ### # taken from repository/packages/ocamlbuild/ocamlbuild.0.9.0/opam at 437319f58e opam-version: "1.2" name: "ocamlbuild" maintainer: "Gabriel Scherer " version: "1" authors: [ "Nicolas Pouillard" "Berke Durak" ] license: "LGPL-2 with OCaml linking exception" dev-repo: "https://github.com/ocaml/ocamlbuild.git" homepage: "https://github.com/ocaml/ocamlbuild/" bug-reports: "https://github.com/ocaml/ocamlbuild/issues" doc: "https://github.com/ocaml/ocamlbuild/blob/master/manual/manual.adoc" build: [ [make "-f" "configure.make" "Makefile.config" "src/ocamlbuild_config.ml" "OCAMLBUILD_PREFIX=%{prefix}%" "OCAMLBUILD_BINDIR=%{bin}%" "OCAMLBUILD_LIBDIR=%{lib}%" "OCAML_NATIVE=%{ocaml-native}%" "OCAML_NATIVE_TOOLS=%{ocaml-native}%"] [make "check-if-preinstalled" "all" "opam-install"] ] available: [ocaml-version >= "4.03" & ocaml-version < "4.04"] depends: [ ] conflicts: [ "base-ocamlbuild" "ocamlfind" {< "1.6.2"} ] ### opam admin upgrade Updated ${BASEDIR}/packages/ocamlbuild/ocamlbuild.1/opam ### cat packages/ocamlbuild/ocamlbuild.1/opam # taken from repository/packages/ocamlbuild/ocamlbuild.0.9.0/opam at 437319f58e opam-version: "2.0" name: "ocamlbuild" maintainer: "Gabriel Scherer " version: "1" authors: [ "Nicolas Pouillard" "Berke Durak" ] license: "LGPL-2 with OCaml linking exception" dev-repo: "git+https://github.com/ocaml/ocamlbuild.git" homepage: "https://github.com/ocaml/ocamlbuild/" bug-reports: "https://github.com/ocaml/ocamlbuild/issues" doc: "https://github.com/ocaml/ocamlbuild/blob/master/manual/manual.adoc" build: [ [ make "-f" "configure.make" "Makefile.config" "src/ocamlbuild_config.ml" "OCAMLBUILD_PREFIX=%{prefix}%" "OCAMLBUILD_BINDIR=%{bin}%" "OCAMLBUILD_LIBDIR=%{lib}%" "OCAML_NATIVE=%{ocaml:native}%" "OCAML_NATIVE_TOOLS=%{ocaml:native}%" ] [make "check-if-preinstalled" "all" "opam-install"] ] depends: [ "ocaml" {>= "4.03" & < "4.04"} ] conflicts: [ "base-ocamlbuild" "ocamlfind" {< "1.6.2"} ] ### opam admin add-constraint "ocaml<4.03.5" ### cat packages/ocamlbuild/ocamlbuild.1/opam # taken from repository/packages/ocamlbuild/ocamlbuild.0.9.0/opam at 437319f58e opam-version: "2.0" name: "ocamlbuild" maintainer: "Gabriel Scherer " version: "1" authors: [ "Nicolas Pouillard" "Berke Durak" ] license: "LGPL-2 with OCaml linking exception" dev-repo: "git+https://github.com/ocaml/ocamlbuild.git" homepage: "https://github.com/ocaml/ocamlbuild/" bug-reports: "https://github.com/ocaml/ocamlbuild/issues" doc: "https://github.com/ocaml/ocamlbuild/blob/master/manual/manual.adoc" build: [ [ make "-f" "configure.make" "Makefile.config" "src/ocamlbuild_config.ml" "OCAMLBUILD_PREFIX=%{prefix}%" "OCAMLBUILD_BINDIR=%{bin}%" "OCAMLBUILD_LIBDIR=%{lib}%" "OCAML_NATIVE=%{ocaml:native}%" "OCAML_NATIVE_TOOLS=%{ocaml:native}%" ] [make "check-if-preinstalled" "all" "opam-install"] ] depends: [ "ocaml" {>= "4.03" & < "4.03.5"} ] conflicts: [ "base-ocamlbuild" "ocamlfind" {< "1.6.2"} ] ### cat packages/foo/foo.1/opam opam-version: "2.0" build: ["opam"] #comment depends: ["config" "ocaml" {< "4.03.5"} "base"] #comment #comment flags: compiler ### cat packages/bar/bar.1/opam #comment opam-version: "2.0" #comment build: ["opam"] #comment depends: [ # comment "config" #comment "ocaml" {< "4.03.5"} #comment "base" #comment #comment ] #comment flags: compiler ### cat packages/baz/baz.1/opam #comment opam-version: "2.0" #comment flags: compiler #comment depends: [ #comment "config" #comment "ocaml" {< "4.03.5"} #comment "base" #comment #comment ] #comment build: ["opam" "var" "prefix" "--safe"] license: "MIT" #comment ### opam admin add-constraint "config<1" ### cat packages/foo/foo.1/opam opam-version: "2.0" build: ["opam"] #comment depends: ["config" {< "1"} "ocaml" {< "4.03.5"} "base"] #comment #comment flags: compiler ### cat packages/bar/bar.1/opam #comment opam-version: "2.0" #comment build: ["opam"] #comment depends: [ # comment "config" {< "1"} #comment "ocaml" {< "4.03.5"} #comment "base" #comment #comment ] #comment flags: compiler ### cat packages/baz/baz.1/opam #comment opam-version: "2.0" #comment flags: compiler #comment depends: [ #comment "config" {< "1"} #comment "ocaml" {< "4.03.5"} #comment "base" #comment #comment ] #comment build: ["opam" "var" "prefix" "--safe"] license: "MIT" #comment ### opam admin add-constraint "base>1" ### cat packages/foo/foo.1/opam opam-version: "2.0" build: ["opam"] #comment depends: ["config" {< "1"} "ocaml" {< "4.03.5"} "base" {> "1"}] #comment #comment flags: compiler ### cat packages/bar/bar.1/opam #comment opam-version: "2.0" #comment build: ["opam"] #comment depends: [ # comment "config" {< "1"} #comment "ocaml" {< "4.03.5"} #comment "base" {> "1"} #comment #comment ] #comment flags: compiler ### cat packages/baz/baz.1/opam #comment opam-version: "2.0" #comment flags: compiler #comment depends: [ #comment "config" {< "1"} #comment "ocaml" {< "4.03.5"} #comment "base" {> "1"} #comment #comment ] #comment build: ["opam" "var" "prefix" "--safe"] license: "MIT" #comment opam-2.1.5/tests/reftests/conflict-3819.test.disabled0000644000175000017500000000574414427463453021404 0ustar stephsteph40265f4 ### opam sw cr 4.03.0 --fake <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml-base-compiler" {= "4.03.0"} | "ocaml-system" {= "4.03.0"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-base-compiler.4.03.0 Faking installation of ocaml-config.1 Faking installation of ocaml.4.03.0 Done. ### opam install mirage-dns.2.0.0 --show [ERROR] Package conflict! * No agreement on the version of cstruct: - mirage-dns < 2.5.0 -> cstruct >= 1.0.0 * No agreement on the version of dns: - mirage-dns < 2.5.0 -> dns * No agreement on the version of cstruct: - mirage-dns < 2.5.0 -> cstruct >= 1.0.0 - mirage-dns < 2.5.0 -> dns -> cstruct < 0.6.0 * No agreement on the version of cstruct: - mirage-dns < 2.5.0 -> cstruct >= 1.0.0 - mirage-dns < 2.5.0 -> dns -> cstruct < 1.0.0 * No agreement on the version of cstruct: - mirage-dns < 2.5.0 -> dns -> cstruct < 1.0.0 * No agreement on the version of io-page: - mirage-dns < 2.5.0 -> dns -> io-page < 1.3.0 - mirage-dns < 2.5.0 -> mirage-types-lwt < 3.0.0 -> io-page >= 1.4.0 * No agreement on the version of ipaddr: - mirage-dns < 2.5.0 -> dns -> ipaddr - mirage-dns < 2.5.0 -> dns -> ipaddr < 2.0.0 * No agreement on the version of ipaddr: - mirage-dns < 2.5.0 -> dns -> ipaddr < 2.0.0 - mirage-dns < 2.5.0 -> dns -> ipaddr < 2.8.0 * No agreement on the version of ipaddr: - mirage-dns < 2.5.0 -> dns -> ipaddr < 2.8.0 * No agreement on the version of ipaddr: - mirage-dns < 2.5.0 -> dns -> ipaddr - mirage-dns < 2.5.0 -> dns -> ipaddr < 2.8.0 * No agreement on the version of mirage-types: - mirage-dns < 2.5.0 -> mirage-types-lwt < 3.0.0 -> mirage-types * Incompatible packages: - mirage-dns < 2.5.0 -> dns - mirage-dns < 2.5.0 -> mirage-types-lwt < 3.0.0 * Incompatible packages: - mirage-dns < 2.5.0 -> dns - mirage-dns < 2.5.0 -> mirage-types-lwt < 3.0.0 -> io-page >= 1.4.0 * Incompatible packages: - mirage-dns < 2.5.0 -> dns - mirage-dns < 2.5.0 -> mirage-types-lwt < 3.0.0 -> mirage-types * Incompatible packages: - mirage-dns < 2.5.0 -> dns -> ipaddr < 2.0.0 - mirage-dns < 2.5.0 -> mirage-types-lwt < 3.0.0 -> mirage-types No solution found, exiting ### opam install tftp.0.1.4 --show [ERROR] Package conflict! * No agreement on the version of cstruct: - tftp -> cstruct * No agreement on the version of mirage: - tftp -> mirage * No agreement on the version of ocaml: - (invariant) -> ocaml-base-compiler = 4.03.0 -> ocaml = 4.03.0 - tftp -> mirage -> mirage-types-lwt < 3.0.0 -> sexplib < 113.01.00 -> ocaml < 4.03.0 You can temporarily relax the switch invariant with `--update-invariant' * Incompatible packages: - tftp -> cstruct - tftp -> mirage No solution found, exiting opam-2.1.5/tests/reftests/conflict-solo5.test0000644000175000017500000000203414427463453020260 0ustar stephstephf372039d ### opam switch create --fake ocaml-base-compiler.4.02.3 <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["ocaml-base-compiler" {= "4.02.3"}] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Faking installation of base-bigarray.base Faking installation of base-threads.base Faking installation of base-unix.base Faking installation of ocaml-base-compiler.4.02.3 Faking installation of ocaml-config.1 Faking installation of ocaml.4.02.3 Faking installation of base-ocamlbuild.base Done. ### opam var arch=x86_64 --global Added '[arch "x86_64" "Set through 'opam var'"]' to field global-variables in global configuration ### opam var os=linux --global Added '[os "linux" "Set through 'opam var'"]' to field global-variables in global configuration ### opam install --show solo5-kernel-virtio solo5-kernel-ukvm [ERROR] Package conflict! * Incompatible packages: - solo5-kernel-ukvm - solo5-kernel-virtio No solution found, exiting # Return code 20 # opam-2.1.5/tests/reftests/run.ml0000644000175000017500000006030114427463453015656 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2021 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (* Simple CRAM-like test framework for opam tests. Features and format: - first line is * the git hash of the opam repository to use, an opamroot is already initialised with that repo as "default" * or N0REP0 for no dependency on opam repository, and an opamroot is already initialised with an empty `default` repository in `./REPO` directory, that you need to populate - 'opam' is automatically redirected to the correct binary - the command prefix is `### ` - use `### `, then the contents below to create a file verbatim - use `### `, then the contents of an opam file below to add this package to `default` repository in `./REPO` - use `### `, then the contents below to add this file as a extra-file of the given package in the `default` repository, and implicitely run `opam update default` - use `### `, then the contents below to create a minimal opam file, it is extended by template defined fields to pin it without lint errors - `### FOO=x BAR=y` to export variables for subsequent commands - shell-like command handling: * **NO pattern expansion, shell pipes, sequences or redirections** * `FOO=x BAR=y command` * Arguments can be quoted: eg `"foo\"bar"`, `'foo\bar'`, but not combined (`foo'bar'` is not translated to `foobar`) * Variable expansion in arguments (`$FOO` or `${FOO}`). Undefined variables are left as-is * rewrites: `| 'REGEXP' -> 'STR'` (can be repeated; set `STR` to `\c` to clear the line) * `| grep REGEXP` * `| grep -v REGEXP` * `| unordered` compares lines without considering their ordering * variables from command outputs: `cmd args >$ VAR` * `### : comment` * opam-cat: prints a nromalised opam file - if you need more shell power, create a script using then run it. Or just use `sh -c`... but beware for compatibility. The opam roots are generated using dynamically generated dune rules (see gen.ml and dune.inc), then the tests are run using this script. *) type test = { repo_hash: string; commands: (string * string list) list; } let cmd_prompt = "### " let no_opam_repo = "N0REP0" let default_repo = "REPO" let is_prefix pfx s = String.length s >= String.length pfx && String.sub s 0 (String.length pfx) = pfx let rem_prefix pfx s = if not (is_prefix pfx s) || s = pfx then invalid_arg "rem_prefix" else String.sub s (String.length pfx) (String.length s - String.length pfx) (* Test file format: {v REPO_HASH ### opam command output line 1 output... ### contents... ### opam command output... ### ENV_VAR=x opam command output... v}*) let load_test f = let ic = open_in f in let repo_hash = try input_line ic with | End_of_file -> failwith "Malformed test file" in let commands = let rec aux commands = match input_line ic, commands with | s, commands when is_prefix cmd_prompt s -> aux ((rem_prefix cmd_prompt s, []) :: commands) | s, ((cmd,out) :: commands) -> aux ((cmd, s::out) :: commands) | exception End_of_file -> List.rev_map (fun (cmd, out) -> cmd, List.rev out) commands | _ -> failwith "Malformed test file" in aux [] in close_in ic; { repo_hash; commands } let base_env = let propagate v = try [v, Sys.getenv v] with Not_found -> [] in propagate "PATH" @ propagate "HOME" @ propagate "COMSPEC" @ propagate "LIB" @ propagate "SYSTEMROOT" @ propagate "TMPDIR" @ propagate "TMP" @ propagate "TEMP" @ [ "OPAMKEEPBUILDDIR", "1"; "OPAMCOLOR", "never"; "OPAMUTF8", "never"; "OPAMNOENVNOTICE", "1"; "OPAMNODEPEXTS", "1"; "OPAMDOWNLOADJOBS", "1"; ] (* See [opamprocess.safe_wait] *) let rec waitpid pid = match Unix.waitpid [] pid with | exception Unix.Unix_error (Unix.EINTR,_,_) -> waitpid pid | exception Unix.Unix_error (Unix.ECHILD,_,_) -> 256 | _, Unix.WSTOPPED _ -> waitpid pid | _, Unix.WEXITED n -> n | _, Unix.WSIGNALED _ -> failwith "signal" exception Command_failure of int * string * string type filt_sort = | Sed of string | Grep | GrepV let escape_regexps s = let buf = Buffer.create (String.length s * 2) in String.iter (function | ('|' | '(' | ')' | '*' | '+' | '?' | '[' | '.' | '^' | '$' | '{' | '\\') as c -> Buffer.add_char buf '\\'; Buffer.add_char buf c | c -> Buffer.add_char buf c ) s; Buffer.contents buf let str_replace_path ?escape whichway filters s = let s = match escape with | Some `Unescape -> Re.(replace_string (compile @@ str "\\\\") ~by:"\\" s) | Some (`Backslashes | `Regexps) | None -> s in let escape_backslashes = match escape with | Some (`Backslashes | `Regexps) -> Re.(replace_string (compile @@ char '\\') ~by:"\\\\") | Some `Unescape | None -> fun s -> s in let escape_regexps = match escape with | Some `Regexps -> escape_regexps | Some `Backslashes -> escape_backslashes | Some `Unescape | None -> fun s -> s in List.fold_left (fun s (re, by) -> let re_path = Re.( seq [re; group (rep (diff any (alt [set ":;$\"'"; space])))] ) in match by with | Sed by -> Re.replace (Re.compile re_path) s ~f:(fun g -> escape_regexps by ^ escape_backslashes (whichway (Re.Group.(get g (nb_groups g - 1))))) | Grep | GrepV -> if (by = Grep) = Re.execp (Re.compile re) s then s else "\\c") s filters let filters_of_var = List.map (fun (v, x) -> Re.(alt [seq [str "${"; str v; str "}"]; seq [char '$'; str v; eow]];), Sed x) let command ?(allowed_codes = [0]) ?(vars=[]) ?(silent=false) ?(filter=[]) cmd args = let env = Array.of_list @@ List.map (fun (var, value) -> Printf.sprintf "%s=%s" var value) @@ (base_env @ vars) in let input, stdout = Unix.pipe () in Unix.set_close_on_exec input; let ic = Unix.in_channel_of_descr input in set_binary_mode_in ic false; let cmd, orig_cmd = let maybe_resolved_cmd = if Sys.win32 then OpamStd.Option.default cmd @@ OpamSystem.resolve_command cmd else cmd in maybe_resolved_cmd, cmd in let args = if orig_cmd = "tar" || orig_cmd = "tar.exe" then List.map (Lazy.force (OpamSystem.get_cygpath_function ~command:cmd)) args else args in let pid = OpamProcess.create_process_env cmd (Array.of_list (cmd::args)) env Unix.stdin stdout stdout in Unix.close stdout; let out_buf = Buffer.create 273 in let rec filter_output ?(first=true) ic = match input_line ic with | s -> let s = str_replace_path ~escape:`Unescape OpamSystem.back_to_forward filter s in if s = "\\c" then filter_output ~first ic else (if not first then Buffer.add_char out_buf '\n'; Buffer.add_string out_buf s; if not silent then print_endline s; filter_output ~first:false ic) | exception End_of_file -> () in filter_output ic; let ret = waitpid pid in close_in ic; let out = Buffer.contents out_buf in if not (List.mem ret allowed_codes) then raise (Command_failure (ret, String.concat " " (cmd :: args), out)) else out let finally f x k = match f x with | r -> k (); r | exception e -> (* When we're at least 4.05+ let bt = Printexc.get_raw_backtrace () in*) (try k () with _ -> ()); (*Printexc.raise_with_backtrace e bt*) raise e (* Borrowed from ocamltest_stdlib.ml *) let rec mkdir_p dir = if Sys.file_exists dir then () else let () = mkdir_p (Filename.dirname dir) in if not (Sys.file_exists dir) then Unix.mkdir dir 0o777 else () let erase_file path = try Sys.remove path with Sys_error _ when Sys.win32 -> (* Deal with read-only attribute on Windows. Ignore any error from chmod so that the message always come from Sys.remove *) let () = try Unix.chmod path 0o666 with Sys_error _ -> () in Sys.remove path let rm_rf path = let rec erase path = if Sys.file_exists path && Sys.is_directory path then begin Array.iter (fun entry -> erase (Filename.concat path entry)) (Sys.readdir path); Unix.rmdir path end else erase_file path in try if Sys.file_exists path then erase path with Sys_error err -> raise (Sys_error (Printf.sprintf "Failed to remove %S (%s)" path err)) let rec with_temp_dir f = let s = Filename.concat (Filename.get_temp_dir_name ()) (Printf.sprintf "opam-reftest-%06x" (Random.int 0xffffff)) in if Sys.file_exists s then with_temp_dir f else (mkdir_p s; finally f s @@ fun () -> rm_rf s) type command = | File_contents of string | Repo_pkg_file_contents of string | Pin_file_content of string | Cat of { files: string list; filter: (Re.t * filt_sort) list; } | Run of { env: (string * string) list; cmd: string; args: string list; (* still escaped *) filter: (Re.t * filt_sort) list; output: string option; unordered: bool; } | Export of (string * string) list | Comment of string module Parse = struct open Re let re_str_atom = alt [ seq [char '"'; rep @@ alt [diff any (set "\"\\"); seq [char '\\'; any]]; char '"']; seq [char '\''; rep @@ diff any (char '\''); char '\'']; seq [diff any (set "\"' "); rep @@ alt [diff any (set "\\ "); seq [char '\\'; any]]]; ] let get_str s = let unescape = replace (compile @@ seq [char '\\'; group any]) ~f:(fun g -> Group.get g 1) in let trim s = String.sub s 1 (String.length s - 2) in if s = "" then "" else match s.[0] with | '"' -> unescape (trim s) | '\'' -> trim s | _ -> unescape s let re_varbind = seq [ group @@ seq [alpha; rep (alt [alnum; set "_-"])]; char '='; group @@ re_str_atom; rep space; ] let re_package = seq [ str "' ] let command ?(vars=[]) str = if str.[0] = '<' && str.[String.length str - 1] = '>' then if String.length str > 4 && String.sub str 1 4 = "pin:" then Pin_file_content (String.sub str 5 (String.length str - 6)) else try let grs = exec (compile re_package) str in let name = Group.get grs 1 in let version = Group.get grs 2 in Repo_pkg_file_contents (try let files = Group.get grs 3 in Printf.sprintf "%s/packages/%s/%s.%s/files/%s" default_repo name name version files with Not_found -> Printf.sprintf "%s/packages/%s/%s.%s/opam" default_repo name name version) with Not_found -> File_contents (String.sub str 1 (String.length str - 2)) else if str.[0] = ':' || str.[0] = '#' then Comment str else let varbinds, pos = let gr = exec (compile @@ rep re_varbind) str in List.map (fun gr -> Group.get gr 1, get_str (Group.get gr 2)) (all (compile @@ re_varbind) (Group.get gr 0)), Group.stop gr 0 in let cmd, pos = try let gr = exec ~pos (compile re_str_atom) str in Some (get_str (Group.get gr 0)), Group.stop gr 0 with Not_found -> None, pos in let args = let grs = all ~pos (compile re_str_atom) str in List.map (fun gr -> Group.get gr 0) grs in let get_str ?escape s = str_replace_path ?escape OpamSystem.back_to_forward (filters_of_var vars) (get_str s) in let posix_re re = try Posix.re (get_str ~escape:`Regexps re) with Posix.Parse_error -> failwith (Printf.sprintf "Bad POSIX regexp: %s" re) in let rec get_args_rewr acc = function | [] -> List.rev acc, false, [], None | ("|"|">$") :: _ as rewr -> let rec get_rewr (unordered, acc) = function | "|" :: re :: "->" :: str :: r -> get_rewr (unordered, (posix_re re, Sed (get_str str)) :: acc) r | "|" :: "grep" :: "-v" :: re :: r -> get_rewr (unordered, (posix_re re, GrepV) :: acc) r | "|" :: "grep" :: re :: r -> get_rewr (unordered, (posix_re re, Grep) :: acc) r | "|" :: "unordered" :: r -> get_rewr (true, acc) r | ">$" :: output :: [] -> unordered, List.rev acc, Some (get_str output) | [] -> unordered, List.rev acc, None | r -> Printf.printf "Bad rewrite %S, expecting '| RE -> STR' or '>$ VAR'\n%!" (String.concat " " r); unordered, List.rev acc, None in let unordered, rewr, out = get_rewr (false, []) rewr in List.rev acc, unordered, rewr, out | arg :: r -> get_args_rewr (arg :: acc) r in let args, unordered, rewr, output = get_args_rewr [] args in match cmd with | Some "opam-cat" -> Cat { files = args; filter = rewr; } | Some cmd -> Run { env = varbinds; cmd; args; filter = rewr; output; unordered; } | None -> Export varbinds end let parse_command = Parse.command let common_filters ?opam dir = let tmpdir = Filename.get_temp_dir_name () in let open Re in [ seq [ bol; alt [ str "#=== ERROR"; seq [ str "# "; alt @@ List.map str [ "context"; "path"; "command"; "exit-code"; "env-file"; "output-file"]]]], GrepV; seq [bol; str cmd_prompt], Sed "##% "; alt [str dir; str (OpamSystem.back_to_forward dir)], Sed "${BASEDIR}"; seq [opt (str "/private"); alt [str tmpdir; str (OpamSystem.back_to_forward tmpdir)]; rep (set "/\\"); str "opam-"; rep1 (alt [xdigit; char '-'])], Sed "${OPAMTMP}"; ] @ (match opam with | None -> [] | Some opam -> [ str opam, Sed "${OPAM}" ]) let run_cmd ~opam ~dir ?(vars=[]) ?(filter=[]) ?(silent=false) cmd args = let filter = filter @ common_filters ~opam dir in let var_filters = filters_of_var vars in let cmd = if cmd = "opam" then opam else cmd in let args = List.map (fun a -> let expanded = if a <> "" && a.[0] = '\'' then a else str_replace_path ~escape:`Backslashes OpamSystem.forward_to_back var_filters a in Parse.get_str expanded) args in try command ~vars ~filter ~silent cmd args, None with Command_failure (n,_, out) -> out, Some n let write_file ~path ~contents = mkdir_p (Filename.dirname path); let oc = open_out_bin path in output_string oc contents; close_out oc let rec list_remove x = function | [] -> [] | y :: r -> if x = y then r else y :: list_remove x r let print_opamfile file = try let open OpamParserTypes.FullPos in let original = OpamParser.FullPos.file file in let rec mangle item = match item.pelem with | Section s -> {item with pelem = Section {s with section_name = OpamStd.Option.map (fun v -> {v with pelem = mangle_string v.pelem}) s.section_name; section_items = {s.section_items with pelem = List.map mangle s.section_items.pelem}}} | Variable(name, value) -> {item with pelem = Variable(name, mangle_value value)} and mangle_value item = match item.pelem with | String s -> {item with pelem = String(mangle_string s)} | Relop(op, l, r) -> {item with pelem = Relop(op, mangle_value l, mangle_value r)} | Prefix_relop(relop, v) -> {item with pelem = Prefix_relop(relop, mangle_value v)} | Logop(op, l, r) -> {item with pelem = Logop(op, mangle_value l, mangle_value r)} | Pfxop(op, v) -> {item with pelem = Pfxop(op, mangle_value v)} | List l -> {item with pelem = List{l with pelem = List.map mangle_value l.pelem}} | Group l -> {item with pelem = Group{l with pelem = List.map mangle_value l.pelem}} | Option(v, l) -> {item with pelem = Option(mangle_value v, {l with pelem = List.map mangle_value l.pelem})} | Env_binding(name, op, v) -> {item with pelem = Env_binding(name, op, mangle_value v)} | Bool _ | Int _ | Ident _ -> item and mangle_string = String.map (function '\\' -> '/' | c -> c) in let mangled = {original with file_contents = List.map mangle original.file_contents} in OpamPrinter.FullPos.Normalise.opamfile mangled with | Sys_error _ -> Printf.sprintf "# %s not found" file | e -> Printf.sprintf "# Error on file %s: %s" file (Printexc.to_string e) let template_opamfile = OpamParser.FullPos.string {| opam-version: "2.0" synopsis: "A word" description: "Two words." authors: "the testing team" homepage: "egapemoh" maintainer: "maint@tain.er" license: "ISC" dev-repo: "hg+htpps://to@lo.ck" bug-reports: "https://nobug" |} "" let run_test ?(vars=[]) ~opam t = let old_cwd = Sys.getcwd () in let opamroot0 = Filename.concat old_cwd ("root-"^t.repo_hash) in with_temp_dir @@ fun dir -> Sys.chdir dir; let dir = Sys.getcwd () in (* because it may need to be normalised on macOS *) let opamroot = Filename.concat dir "OPAM" in if Sys.win32 then ignore @@ command ~allowed_codes:[0; 1] ~silent:true "robocopy" ["/e"; "/copy:dat"; "/dcopy:dat"; "/sl"; opamroot0; opamroot] else ignore @@ command "cp" ["-PR"; opamroot0; opamroot]; let vars = [ "OPAM", opam; "OPAMROOT", opamroot; "BASEDIR", dir; ] @ vars in if t.repo_hash = no_opam_repo then (mkdir_p (default_repo^"/packages"); write_file ~path:(default_repo^"/repo") ~contents:{|opam-version: "2.0"|}; ignore @@ command opam ~silent:true [ "repository"; "set-url"; "default"; "./"^default_repo; "--root"; opamroot]); ignore @@ command ~silent:true opam ["var"; "--quiet"; "--root"; opamroot; "--global"; "--cli=2.1"; "sys-ocaml-version=4.08.0"]; print_endline t.repo_hash; let _vars = List.fold_left (fun vars (cmd, out) -> print_string cmd_prompt; print_endline cmd; match parse_command ~vars cmd with | Comment _ -> vars | File_contents path -> let contents = String.concat "\n" out ^ "\n" in write_file ~path ~contents; print_string contents; vars | Repo_pkg_file_contents path -> let contents = String.concat "\n" out ^ "\n" in write_file ~path ~contents; print_string contents; ignore @@ run_cmd ~opam ~dir ~vars ~silent:true "opam" ["update"; "default"]; vars | Pin_file_content path -> let open OpamParserTypes.FullPos in let raw_content = (String.concat "\n" out) in let opamfile = OpamParser.FullPos.string raw_content path in let nullify_pos p = {p with pos = { filename = path; start = -1, -1; stop = -1, -1; }} in let test_content, tpl_content = List.fold_left (fun (test_content, tpl_content) item -> match item with | { pelem = Variable (name, _); _} -> let tpl_overwrite, test_content = List.partition (function | { pelem = Variable (n, _); _} -> n.pelem = name.pelem | _ -> false) test_content in let item = match tpl_overwrite with | [ item ] -> item | _ -> item in test_content, item::tpl_content | { pelem = Section _ ; _} -> test_content, item::tpl_content ) (opamfile.file_contents,[]) template_opamfile.file_contents in let file_contents = List.rev_map nullify_pos tpl_content @ List.map nullify_pos test_content in let contents = Printf.sprintf "%s\n" (OpamPrinter.FullPos.opamfile { opamfile with file_contents }) in write_file ~path ~contents; print_string (raw_content ^ "\n"); vars | Export bindings -> List.fold_left (fun vars (v, r) -> let r = str_replace_path ~escape:`Backslashes OpamSystem.forward_to_back (filters_of_var vars) r in (v, r) :: List.filter (fun (w, _) -> not (String.equal v w)) vars) vars bindings | Cat { files; filter } -> let files = List.map (fun s -> Re.(replace_string (compile @@ str "$OPAMROOT") ~by:opamroot s)) files in let s = match files with | [file] -> print_opamfile file | files -> OpamStd.List.concat_map "\n" (fun f -> Printf.sprintf "=> %s <=\n%s" f (print_opamfile f)) files in print_string (str_replace_path OpamSystem.back_to_forward (filter @ common_filters dir) s); vars | Run {env; cmd; args; filter; output; unordered} -> let silent = output <> None || unordered in let r, errcode = run_cmd ~opam ~dir ~vars:(vars @ env) ~filter ~silent cmd args in (if unordered then (* print lines from Result, but respecting order from Expect *) let rec diffl acc r e = let expect_has rl = let matching = List.filter (( = ) rl) in List.length (matching e) > List.length (matching acc) in match r, e with | r, el::e when List.mem el acc -> print_endline el; diffl (list_remove el acc) r e | rl::r, el::e -> if rl = el then (print_endline el; diffl acc r e) else if expect_has rl then diffl (rl::acc) r (el :: e) else (print_endline rl; diffl acc r (el :: e)) | [], _::el -> diffl acc [] el | r, [] -> assert (acc = []); List.iter print_endline r in diffl [] (String.split_on_char '\n' r) out); OpamStd.Option.iter (Printf.printf "# Return code %d #\n") errcode; match output with | None -> vars | Some v -> (v, r) :: List.filter (fun (w,_) -> v <> w) vars) vars t.commands in Sys.chdir old_cwd let () = Random.self_init (); match Array.to_list Sys.argv with | _ :: opam :: input :: env -> let opam = OpamFilename.(to_string (of_string opam)) in let vars = List.map (fun s -> match OpamStd.String.cut_at s '=' with | Some (var, value) -> var, value | None -> failwith "Bad 'var=value' argument") env in load_test input |> run_test ~opam ~vars | _ -> failwith "Expected arguments: opam.exe opam file.test [env-bindings]" opam-2.1.5/tests/reftests/env.test0000644000175000017500000001032214427463453016207 0ustar stephstephN0REP0 ### : Revert env : ### opam-version: "2.0" setenv: [ NV_VARS += "%{_:doc}%:%{_:share}%" ] flags: compiler ### opam switch create setenv nv <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["nv"] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed nv.1 Done. ### opam env | grep "NV_VARS" | ';' -> ':' NV_VARS='${BASEDIR}/OPAM/setenv/doc/nv:${BASEDIR}/OPAM/setenv/share/nv': export NV_VARS: ### opam exec -- opam env --revert | grep "NV_VARS" | ';' -> ':' NV_VARS='': export NV_VARS: ### NV_VARS=/another/path ### opam env | grep "NV_VARS" | ';' -> ':' NV_VARS='${BASEDIR}/OPAM/setenv/doc/nv:${BASEDIR}/OPAM/setenv/share/nv:/another/path': export NV_VARS: ### opam exec -- opam env --revert | grep "NV_VARS" | ';' -> ':' NV_VARS='/another/path': export NV_VARS: ### : package variable available at install stage : ### opam-version: "2.0" setenv: [NV_VARS = "%{_:nv_config}%"] flags: compiler ### opam-version: "2.0" variables { nv_config: "hej!!" } ### opam switch create conffile nv <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["nv"] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed nv.1 Done. ### opam env | grep NV_VARS NV_VARS='hej!!'; export NV_VARS; ### : opam env and its revert : ### opam exec -- opam env | grep "^NV_VARS|^OPAM_SWITCH_PREFIX|${OPAM}" OPAM_SWITCH_PREFIX='${BASEDIR}/OPAM/conffile'; export OPAM_SWITCH_PREFIX; NV_VARS='hej!!'; export NV_VARS; ### opam exec -- opam env --revert | grep "^NV_VARS|^OPAM_SWITCH_PREFIX|${OPAM}" OPAM_SWITCH_PREFIX=''; export OPAM_SWITCH_PREFIX; NV_VARS=''; export NV_VARS; ### opam exec -- env | grep '^NV_VARS|^OPAM_SWITCH_PREFIX|${OPAM}' NV_VARS=hej!! OPAM=${OPAM} OPAM_SWITCH_PREFIX=${BASEDIR}/OPAM/conffile ### : Buil environment variable expansion : ### opam-version: "2.0" build: [ "sh" "-c" "echo V$BDE_VERSION > pkg.version" ] install: [ "cp" "pkg.version" "%{doc}%/pkg.version" ] build-env: [ BDE_VERSION = "%{version}%" ] ### opam switch create build-env --empty ### opam install bde The following actions will be performed: - install bde 1.2.3 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed bde.1.2.3 Done. ### cat $OPAMROOT/build-env/doc/pkg.version V1.2.3 ### : empty environment variables update : ### NV_VARS='' ### opam-version: "2.0" setenv: [ [ NV_VARS += "" ] [ NV_VARS2 := "" ] [ NV_VARS3 := "" ] [ NV_VARS3 := "foo" ] [ NV_VARS4 = "" ] ] flags: compiler ### opam switch create emptyvar nv <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["nv"] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed nv.1 Done. ### opam env | grep "NV_VARS" | ';' -> ':' NV_VARS3='foo:': export NV_VARS3: NV_VARS4='': export NV_VARS4: ### opam exec -- opam env --revert | grep "NV_VARS" | ';' -> ':' NV_VARS3='': export NV_VARS3: NV_VARS4='': export NV_VARS4: ### NV_VARS=/another/path ### NV_VARS2=/another/different/path ### NV_VARS3=/yet/another/different/path ### NV_VARS4=ignored-value ### opam env | grep "NV_VARS" | ';' -> ':' NV_VARS3='foo:/yet/another/different/path': export NV_VARS3: NV_VARS4='': export NV_VARS4: ### opam exec -- opam env --revert | grep "NV_VARS" | ';' -> ':' NV_VARS3='/yet/another/different/path': export NV_VARS3: NV_VARS4='': export NV_VARS4: ### : root and switch with spaces : ### RT="$BASEDIR/root 2" ### SW="switch w spaces" ### OPAMNOENVNOTICE=0 ### opam init -na --bare --bypass-check --disable-sandbox --root "$RT" defaut ./REPO No configuration file found, using built-in defaults. <><> Fetching repository information ><><><><><><><><><><><><><><><><><><><><><> [defaut] Initialised ### opam switch create "./$SW" nv --root "$RT" <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["nv"] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed nv.1 Done. # Run eval $(opam env --root=${BASEDIR}/root 2 --switch=${BASEDIR}/switch w spaces) to update the current shell environment opam-2.1.5/tests/reftests/pat-sub.test0000644000175000017500000000320214427463453016771 0ustar stephstephN0REP0 ### blabla pioupiou bloblob ### --- a/bar 2020-12-02 14:22:55.364620832 +0100 +++ b/bar 2020-12-02 14:23:05.668686881 +0100 @@ -1,3 +1,3 @@ blabla -pioupiou +ploplop bloblob ### blabla pat-sub bloblob ### --- a/baz 2020-12-02 14:22:55.364620832 +0100 +++ b/baz 2020-12-02 14:23:05.668686881 +0100 @@ -1,3 +1,3 @@ blabla -%{name}% +ploplop bloblob ### bla %{name}% blo %{version}% ### opam-version: "2.0" patches: [ "bar-update.patch" "baz-update.patch" ] substs: [ "foo" "baz-update.patch" ] build: [ ["grep" "pat-sub" "foo"] ["grep" "0.1" "foo"] ["grep" "ploplop" "bar"] ["grep" "ploplop" "baz"] ] ### opam switch create sw --empty ### OPAMDEBUGSECTIONS="ACTION" opam install pat-sub -y --debug --debug-level=-1 The following actions will be performed: - install pat-sub 0.1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> ACTION download_package: pat-sub.0.1 ACTION prepare_package_source: pat-sub.0.1 at ${BASEDIR}/OPAM/sw/.opam-switch/build/pat-sub.0.1 ACTION pat-sub: expanding opam variables in baz-update.patch.in, generating baz-update.patch. ACTION pat-sub: applying bar-update.patch. ACTION pat-sub: applying baz-update.patch. ACTION pat-sub: expanding opam variables in foo.in, generating foo. ACTION Installing pat-sub.0.1. -> installed pat-sub.0.1 Done. opam-2.1.5/tests/reftests/switch-creation.test0000644000175000017500000000273314427463453020531 0ustar stephstephN0REP0 ### opam-version: "2.0" build: ["opam" "option" "jobs" "--safe" "--cli=2.1"] flags: compiler ### opam-version: "2.0" build: ["opam" "option" "jobs" "--safe" "--cli=2.1"] ### opam-version: "2.0" flags: compiler build: ["sh" "./prefix"] install: ["cp" "pref" "%{lib}%/prefix"] ### opam var prefix --safe > pref ### # switch not undefined for opam calls in build, on build creation ### opam switch create undef-prefix baz <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["baz"] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed baz.1 Done. ### cat $OPAMROOT/undef-prefix/lib/prefix ${BASEDIR}/OPAM/undef-prefix ### # No deadlock on concurent opam calls in build ### opam switch create nohang foo bar | unordered <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><><><> Switch invariant: ["foo" "bar"] <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed bar.1 -> installed foo.1 Done. ### # switch propagation to opam calls in build ### opam switch create undef-switch --empty ### opam switch nohang ### opam install baz --sw undef-switch The following actions will be performed: - install baz 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed baz.1 Done. ### cat $OPAMROOT/undef-switch/lib/prefix ${BASEDIR}/OPAM/undef-switch opam-2.1.5/tests/reftests/local-cache.test0000644000175000017500000002567514427463453017573 0ustar stephstephN0REP0 ### ::: Setup ::: ### Hi robur! ### tar czf archive.tgz hello ### Trust me, im' a patch! ### openssl md5 archive.tgz | '.*= ' -> '' >$ ARCHIVE_MD5 ### openssl sha256 archive.tgz | '.*= ' -> '' >$ ARCHIVE_SHA256 ### openssl md5 p.patch | '.*= ' -> '' >$ PATCH_MD5 ### openssl sha256 p.patch | '.*= ' -> '' >$ PATCH_SHA256 ### sh -c "echo '$ARCHIVE_MD5' | cut -c 1-2" >$ PRE_MD5 ### echo "$OPAMROOT/download-cache/md5/$PRE_MD5/$ARCHIVE_MD5" >$ ARCHIVE_MD5_PATH ### sh -c "echo '$ARCHIVE_SHA256' | cut -c 1-2" >$ PRE_SHA256 ### echo "$OPAMROOT/download-cache/sha256/$PRE_SHA256/$ARCHIVE_SHA256" >$ ARCHIVE_SHA256_PATH ### set -ue eval "ARCHIVE_MD5_PATH=\"$ARCHIVE_MD5_PATH\"" eval "ARCHIVE_SHA256_PATH=\"$ARCHIVE_SHA256_PATH\"" if command -v cygpath 2> /dev/null > /dev/null ; then ARCHIVE_MD5_PATH=`cygpath -u "$ARCHIVE_MD5_PATH"` ARCHIVE_SHA256_PATH=`cygpath -u "$ARCHIVE_SHA256_PATH"` fi check2sum () { kind=$1 path=$2 hsh=`openssl "$kind" "$path" | cut -f 2 -d ' '` name=`basename "$path"` if [ "$name" = "$hsh" ]; then echo "with matching checksum" else echo "with mismatching checksum" fi } check () { path=$1 if [ -L "$path" ] ; then out="link," realpath=`readlink -f "$path"` || true if [ "$realpath" = "$ARCHIVE_MD5_PATH" ]; then out="$out to md5 archive" elif [ "$realpath" = "$ARCHIVE_SHA256_PATH" ]; then out="$out to sha256 archive" else out="$out to unknown path $realpath" fi elif [ -f "$path" ] ; then out="archive," if echo "$path" | grep -q md5 ; then out="$out `check2sum md5 $path`" elif echo "$path" | grep -q sha256 ; then out="$out `check2sum sha256 $path`" else out="$out no checksum validation" fi else out="not found" fi echo "$out" } md5=$(check "$ARCHIVE_MD5_PATH") sha256=$(check "$ARCHIVE_SHA256_PATH") echo "MD5: $md5" echo "SHA256: $sha256" ### set -ue pkg=$1 kind=$2 hsh=$3 case "$hsh-$kind" in md5-archive) HSH=$ARCHIVE_MD5 break;; sha256-archive) HSH=$ARCHIVE_SHA256 break;; md5-patch) HSH=$PATCH_MD5 break;; sha256-patch) HSH=$PATCH_SHA256 break;; esac pkgpath="REPO/packages/${pkg%.*}/$pkg" sed -i.bak "s/good-$hsh/$HSH/" "$pkgpath/opam" ### opam-version: "2.0" maintainer: "nobody" authors: "nobody neither" homepage: "https://no.bo.dy" bug-reports: "https://still.nobo.dy" dev-repo: "git+https://no.were" license: "MIT" synopsis: "Initially empty" build: [ "test" "-f" "hello" ] url { src: "archive.tgz" checksum: [ "sha256=good-sha256" "md5=good-md5" ] } ### sh update-hash.sh good-sha256-good-md5.1 archive md5 ### sh update-hash.sh good-sha256-good-md5.1 archive sha256 ### opam update <><> Updating package repositories ><><><><><><><><><><><><><><><><><><><><><><> [default] synchronised from file://${BASEDIR}/REPO Now run 'opam upgrade' to apply any package updates. ### opam switch create default --empty ### :I:11: Change archive in cache ### :I:11:a: install with removed md5 frome cache, and kept sha256 ### opam install good-sha256-good-md5 The following actions will be performed: - install good-sha256-good-md5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved good-sha256-good-md5.1 (file://${BASEDIR}/archive.tgz) -> installed good-sha256-good-md5.1 Done. ### sh check-cache.sh MD5: not found SHA256: archive, with matching checksum ### : rm "$ARCHIVE_MD5_PATH" ### opam remove good-sha256-good-md5 The following actions will be performed: - remove good-sha256-good-md5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed good-sha256-good-md5.1 Done. ### sh check-cache.sh MD5: not found SHA256: archive, with matching checksum ### opam install good-sha256-good-md5 The following actions will be performed: - install good-sha256-good-md5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved good-sha256-good-md5.1 (cached) -> installed good-sha256-good-md5.1 Done. ### sh check-cache.sh MD5: not found SHA256: archive, with matching checksum ### :I:11:b: install with removed sha256 frome cache, and kept md5 ### opam clean --download-cache Clearing cache of downloaded files ### opam reinstall good-sha256-good-md5 The following actions will be performed: - recompile good-sha256-good-md5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved good-sha256-good-md5.1 (file://${BASEDIR}/archive.tgz) -> removed good-sha256-good-md5.1 -> installed good-sha256-good-md5.1 Done. ### sh check-cache.sh MD5: not found SHA256: archive, with matching checksum ### rm "$ARCHIVE_SHA256_PATH" ### opam remove good-sha256-good-md5 The following actions will be performed: - remove good-sha256-good-md5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed good-sha256-good-md5.1 Done. ### sh check-cache.sh MD5: not found SHA256: not found ### opam install good-sha256-good-md5 The following actions will be performed: - install good-sha256-good-md5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved good-sha256-good-md5.1 (file://${BASEDIR}/archive.tgz) -> installed good-sha256-good-md5.1 Done. ### sh check-cache.sh MD5: not found SHA256: archive, with matching checksum ### :I:11:c: corrupt md5 archive in cache ### sh check-cache.sh MD5: not found SHA256: archive, with matching checksum ### opam remove good-sha256-good-md5 The following actions will be performed: - remove good-sha256-good-md5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed good-sha256-good-md5.1 Done. ### : rm "$ARCHIVE_MD5_PATH" ### : tar czf "$ARCHIVE_MD5_PATH" p.patch ### sh check-cache.sh MD5: not found SHA256: archive, with matching checksum ### # it's only sha256 that is checked, as it is good, it doesn't check other cache files ### opam install good-sha256-good-md5 The following actions will be performed: - install good-sha256-good-md5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved good-sha256-good-md5.1 (cached) -> installed good-sha256-good-md5.1 Done. ### sh check-cache.sh MD5: not found SHA256: archive, with matching checksum ### :I:11:d: corrupt sha256 archive in cache ### sh check-cache.sh MD5: not found SHA256: archive, with matching checksum ### opam remove good-sha256-good-md5 The following actions will be performed: - remove good-sha256-good-md5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed good-sha256-good-md5.1 Done. ### : cp archive.tgz "$ARCHIVE_MD5_PATH" ### rm "$ARCHIVE_SHA256_PATH" ### tar czf "$ARCHIVE_SHA256_PATH" p.patch ### sh check-cache.sh MD5: not found SHA256: archive, with mismatching checksum ### # what happens here is that sha256 is checked first, there is a mismatch on sha256 archive (checking its sha256 & md5), so it is remove, returns file not available, and then it downloads the archive from url ### opam install good-sha256-good-md5 | '[0-9a-z]{32,64}' -> 'hash' The following actions will be performed: - install good-sha256-good-md5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> [ERROR] Conflicting file hashes, or broken or compromised cache! - sha256=hash (MISMATCH) - md5=hash (MISMATCH) -> retrieved good-sha256-good-md5.1 (file://${BASEDIR}/archive.tgz) -> installed good-sha256-good-md5.1 Done. ### sh check-cache.sh MD5: not found SHA256: archive, with matching checksum ### :I:11:e: Both corrupted ### opam remove good-sha256-good-md5 The following actions will be performed: - remove good-sha256-good-md5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed good-sha256-good-md5.1 Done. ### rm "$ARCHIVE_SHA256_PATH" ### tar czf "$ARCHIVE_SHA256_PATH" p.patch ### : rm "$ARCHIVE_MD5_PATH" ### : tar czf "$ARCHIVE_MD5_PATH" p.patch ### sh check-cache.sh MD5: not found SHA256: archive, with mismatching checksum ### opam install good-sha256-good-md5 | '[0-9a-z]{32,64}' -> 'hash' The following actions will be performed: - install good-sha256-good-md5 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> [ERROR] Conflicting file hashes, or broken or compromised cache! - sha256=hash (MISMATCH) - md5=hash (MISMATCH) -> retrieved good-sha256-good-md5.1 (file://${BASEDIR}/archive.tgz) -> installed good-sha256-good-md5.1 Done. ### sh check-cache.sh MD5: not found SHA256: archive, with matching checksum ### opam-version: "2.0" maintainer: "nobody" authors: "nobody neither" homepage: "https://no.bo.dy" bug-reports: "https://still.nobo.dy" dev-repo: "git+https://no.were" license: "MIT" synopsis: "Initially empty" build: [ "test" "-f" "hello" ] url { src: "archive.tgz" checksum: [ "sha256=good-sha256" ] } ### sh update-hash.sh good-sha256.1 archive sha256 ### opam update <><> Updating package repositories ><><><><><><><><><><><><><><><><><><><><><><> [default] synchronised from file://${BASEDIR}/REPO Now run 'opam upgrade' to apply any package updates. ### sh check-cache.sh MD5: not found SHA256: archive, with matching checksum ### opam install good-sha256.1 The following actions will be performed: - install good-sha256 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved good-sha256.1 (cached) -> installed good-sha256.1 Done. ### sh check-cache.sh MD5: not found SHA256: archive, with matching checksum ### opam remove good-sha256.1 The following actions will be performed: - remove good-sha256 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed good-sha256.1 Done. ### rm "$ARCHIVE_SHA256_PATH" ### opam install good-sha256.1 The following actions will be performed: - install good-sha256 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> retrieved good-sha256.1 (file://${BASEDIR}/archive.tgz) -> installed good-sha256.1 Done. ### sh check-cache.sh MD5: not found SHA256: archive, with matching checksum ### opam remove good-sha256.1 The following actions will be performed: - remove good-sha256 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> removed good-sha256.1 Done. ### rm "$ARCHIVE_SHA256_PATH" ### tar czf "$ARCHIVE_SHA256_PATH" p.patch ### sh check-cache.sh MD5: not found SHA256: archive, with mismatching checksum ### opam install good-sha256.1 | '[0-9a-z]{32,64}' -> 'hash' The following actions will be performed: - install good-sha256 1 <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> [ERROR] Conflicting file hashes, or broken or compromised cache! - sha256=hash (MISMATCH) -> retrieved good-sha256.1 (file://${BASEDIR}/archive.tgz) -> installed good-sha256.1 Done. ### sh check-cache.sh MD5: not found SHA256: archive, with matching checksum opam-2.1.5/tests/dune0000644000175000017500000000011314427463453013532 0ustar stephsteph(test (name patcher) (modules patcher) (libraries opam-core)) opam-2.1.5/tests/patcher.expected0000644000175000017500000000555114427463453016040 0ustar stephstephPATCH No CRLF adaptation necessary for b/always-crlf PATCH No CRLF adaptation necessary for b/always-lf PATCH CRLF adaptation skipped for b/no-eol-at-all PATCH No CRLF adaptation necessary for b/no-eol-at-eof PATCH CRLF adaptation skipped for b/null-file PATCH No CRLF adaptation necessary for b/test1 PATCH No CRLF adaptation necessary for b/test2 PATCH No CRLF adaptation necessary for b/test3 PATCH No CRLF adaptation necessary for b/will-null-file Before patch state of c: ./always-crlf: CRLF ./always-lf: LF ./no-eol-at-all: mixed (no eol-at-eof) ./no-eol-at-eof: LF (no eol-at-eof) ./null-file: mixed (no eol-at-eof) ./test1: LF ./test2: LF ./test3: LF ./will-null-file: LF patching file always-crlf patching file always-lf patching file no-eol-at-all patching file no-eol-at-eof patching file null-file patching file test1 patching file test2 patching file test3 patching file will-null-file After patch state of c: ./always-crlf: CRLF ./always-lf: LF ./no-eol-at-all: mixed (no eol-at-eof) ./no-eol-at-eof: LF (no eol-at-eof) ./null-file: LF ./test1: LF ./test2: LF ./will-null-file: mixed (no eol-at-eof) PATCH No CRLF adaptation necessary for b/always-crlf PATCH No CRLF adaptation necessary for b/always-lf PATCH CRLF adaptation skipped for b/no-eol-at-all PATCH Adding \r to patch chunks for b/no-eol-at-eof PATCH CRLF adaptation skipped for b/null-file PATCH No CRLF adaptation necessary for b/test1 PATCH Adding \r to patch chunks for b/test2 PATCH No CRLF adaptation necessary for b/test3 PATCH Adding \r to patch chunks for b/will-null-file PATCH Transform 32-36 +\r PATCH Transform 62-67 +\r PATCH Transform 82-87 +\r Before patch state of c: ./always-crlf: CRLF ./always-lf: LF ./no-eol-at-all: mixed (no eol-at-eof) ./no-eol-at-eof: CRLF (no eol-at-eof) ./null-file: mixed (no eol-at-eof) ./test1: LF ./test2: CRLF ./test3: LF ./will-null-file: CRLF patching file always-crlf patching file always-lf patching file no-eol-at-all patching file no-eol-at-eof patching file null-file patching file test1 patching file test2 patching file test3 patching file will-null-file After patch state of c: ./always-crlf: CRLF ./always-lf: LF ./no-eol-at-all: mixed (no eol-at-eof) ./no-eol-at-eof: CRLF (no eol-at-eof) ./null-file: LF ./test1: LF ./test2: CRLF ./will-null-file: mixed (no eol-at-eof) opam-2.1.5/tests/patcher.ml0000644000175000017500000000733414427463453014650 0ustar stephstephlet set_debug_level n sections = let debug_sections = List.fold_left (fun map elt -> OpamStd.String.Map.add elt None map) OpamStd.String.Map.empty sections in OpamCoreConfig.(update ~noop:()) ~debug_level:n ~debug_sections () let test_dir = "patcher-test" let write_file ~dir ~name use_crlf ?(eol_at_eof = true) pattern = let ch = open_out_bin (Filename.concat dir name) in let eol = if use_crlf then "\r\n" else "\n" in List.fold_left (fun a (n, s) -> for i = a to a + n - 1 do Printf.fprintf ch "Line %d%s" i eol done; a + n + s) 1 pattern |> ignore; output_string ch "End of file"; if eol_at_eof then output_string ch eol; close_out ch let write_single_line ~dir ~name line = let ch = open_out_bin (Filename.concat dir name) in output_string ch line; close_out ch let touch ~dir name = close_out (open_out_bin (Filename.concat dir name)) let setup_directory ~dir = OpamSystem.remove dir; OpamSystem.mkdir dir; OpamSystem.chdir dir; List.iter OpamSystem.mkdir ["a"; "b"; "c"] let pattern1 ?(test1 = false) ?(test2 = false) ?(test3 = false) ?(test4 = false) ?(eoleof_cr = false) dir = write_file ~dir ~name:"always-lf" false [(5, 0)]; write_file ~dir ~name:"always-crlf" true [(5, 0)]; write_file ~dir ~name:"no-eol-at-eof" eoleof_cr ~eol_at_eof:false [(5, 0)]; write_single_line ~dir ~name:"no-eol-at-all" "Original line"; write_file ~dir ~name:"test1" test1 [(5, 0)]; write_file ~dir ~name:"test2" test2 [(5, 0)]; write_file ~dir ~name:"test3" test3 [(5, 0)]; touch ~dir "null-file"; write_file ~dir ~name:"will-null-file" test4 [(5, 0)] let pattern2 dir = write_file ~dir ~name:"always-lf" false [(3, 1); (1, 0)]; write_file ~dir ~name:"always-crlf" true [(6, 0)]; write_file ~dir ~name:"no-eol-at-eof" false ~eol_at_eof:false [(3, 1); (1, 0)]; write_single_line ~dir ~name:"no-eol-at-all" "Patched line"; write_file ~dir ~name:"test1" false [(6, 0)]; write_file ~dir ~name:"test2" false [(1, 1); (1, 1); (1, 0)]; write_file ~dir ~name:"null-file" false [(5, 0)]; touch ~dir "will-null-file" let eol_style ch fn = let s = match OpamSystem.get_eol_encoding fn with | None -> "mixed" | Some true -> "CRLF" | Some false -> "LF" in let s = let ch = open_in_bin fn in let l = in_channel_length ch in let r = if l = 0 || (seek_in ch (l - 1); input_char ch <> '\n') then s ^ " (no eol-at-eof)" else s in close_in ch; r in output_string ch s let print_directory dir = List.iter (fun fn -> Printf.eprintf " %s: %a\n%!" (OpamSystem.back_to_forward fn) eol_style fn) (OpamSystem.ls dir) let generate_patch () = flush stderr; flush stdout; if Sys.command "diff -Naur a b > input.patch" <> 1 then (Printf.eprintf "patch generation failed\n%!"; exit 2); set_debug_level (-3) ["PATCH"]; OpamSystem.translate_patch ~dir:"c" "input.patch" "output.patch"; set_debug_level 0 []; OpamSystem.chdir "c"; Printf.eprintf "Before patch state of c:\n"; print_directory "."; flush stdout; if Sys.command "patch -p1 -i ../output.patch" <> 0 then (Printf.eprintf "patch application failed\n%!"; exit 2); Printf.eprintf "After patch state of c:\n"; print_directory "."; OpamSystem.chdir Filename.parent_dir_name let tests () = set_debug_level 0 []; let cwd = Sys.getcwd () in setup_directory ~dir:test_dir; pattern1 "a"; pattern2 "b"; pattern1 "c"; generate_patch (); pattern1 ~test2:true ~test4:true ~eoleof_cr:true "c"; generate_patch (); OpamSystem.chdir cwd; OpamSystem.remove test_dir let () = (* This causes Windows to use LF endings instead of CRLF, which simplifies the comparison with the reference file *) Unix.putenv "LC_ALL" "C"; set_binary_mode_out stdout true; Unix.dup2 Unix.stdout Unix.stderr; tests () opam-2.1.5/tests/bin/0002755000175000017500000000000014427463453013433 5ustar stephstephopam-2.1.5/tests/bin/dune0000644000175000017500000000020714427463453014306 0ustar stephsteph(rule (targets ocamlc) (action (copy %{ocamlc} %{targets}))) (rule (targets ocamlopt) (action (copy %{ocamlopt} %{targets}))) opam-2.1.5/LICENSE0000644000175000017500000006451714427463453012541 0ustar stephstephOpam is distributed under the terms of the GNU Lesser General Public License (LGPL) version 2.1 (included below). As a special exception to the GNU Lesser General Public License, you may link, statically or dynamically, a "work that uses opam" with a publicly distributed version of opam to produce an executable file containing portions of opam, and distribute that executable file under terms of your choice, without any of the additional requirements listed in clause 6 of the GNU Lesser General Public License. By "a publicly distributed version of opam", we mean either the unmodified opam as distributed by OCamlPro, or a modified version of the opam that is distributed under the conditions defined in clause 2 of the GNU Lesser General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU Lesser General Public License. ---------------------------------------------------------------------- GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. one line to give the library's name and an idea of what it does. Copyright (C) year name of author This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. signature of Ty Coon, 1 April 1990 Ty Coon, President of Vice That's all there is to it! -------------------------------------------------- opam-2.1.5/opam.opam0000644000175000017500000000143214427463453013331 0ustar stephstephopam-version: "2.0" version: "2.1.5" synopsis: "Meta-package for Dune" maintainer: "opam-devel@lists.ocaml.org" authors: [ "Vincent Bernardoff " "Raja Boujbel " "Roberto Di Cosmo " "Thomas Gazagnaire " "Louis Gesbert " "Fabrice Le Fessant " "Anil Madhavapeddy " "Guillem Rieu " "Ralf Treinen " "Frederic Tuong " ] homepage: "https://opam.ocaml.org/" bug-reports: "https://github.com/ocaml/opam/issues" license: "LGPL-2.1-only WITH OCaml-LGPL-linking-exception" depends: [ "dune" {>= "1.11.0"} "opam-client" {= version} ] opam-2.1.5/.gitattributes0000644000175000017500000000114214427463453014410 0ustar stephsteph# Default behaviour, for if core.autocrlf isn't set * text=auto # Shell scripts, autoconf, etc. must have LF endings, even on Windows *.sh text eol=lf configure text eol=lf -diff linguist-generated configure.ac text eol=lf msvs-detect text eol=lf check_linker text eol=lf *.m4 text eol=lf changelog_checker text eol=lf *.cmd text eol=crlf # For diffing simplicity, the patch re-write test uses LF endings on Windows tests/patcher-test.reference text eol=lf # Don't normalise patch files *.patch -text # Actual binary files *.pdf binary # Avoid conflicts in master_changes.md master_changes.md merge=union opam-2.1.5/appveyor_build.cmd0000644000175000017500000002366014427463453015237 0ustar stephsteph@rem *********************************************************************** @rem * * @rem * opam * @rem * * @rem * David Allsopp, OCaml Labs, Cambridge. * @rem * * @rem * Copyright 2018 MetaStack Solutions Ltd. * @rem * * @rem * All rights reserved. This file is distributed under the terms of * @rem * the GNU Lesser General Public License version 2.1, with the * @rem * special exception on linking described in the file LICENSE. * @rem * * @rem *********************************************************************** @rem BE CAREFUL ALTERING THIS FILE TO ENSURE THAT ERRORS PROPAGATE @rem IF A COMMAND SHOULD FAIL IT PROBABLY NEEDS TO END WITH @rem || exit /b 1 @rem BASICALLY, DO THE TESTING IN BASH... @rem Do not call setlocal! @echo off goto %1 goto :EOF :CheckPackage "%CYG_ROOT%\bin\bash.exe" -lc "cygcheck -dc %1" | findstr %1 > nul if %ERRORLEVEL% equ 1 ( echo Cygwin package %1 will be installed set CYGWIN_INSTALL_PACKAGES=%CYGWIN_INSTALL_PACKAGES%,%1 ) goto :EOF :UpgradeCygwin if %CYGWIN_UPGRADE_REQUIRED% equ 1 ( echo Cygwin package upgrade required - please go and drink coffee set CYGWIN_UPGRADE_FLAG=--upgrade-also SET CYGWIN_UPGRADE_REQUIRED=0 ) else ( set CYGWIN_UPGRADE_FLAG= ) if "%CYGWIN_INSTALL_PACKAGES%" neq "" set CYGWIN_INSTALL_PACKAGES=--packages %CYGWIN_INSTALL_PACKAGES:~1% if "%CYGWIN_INSTALL_PACKAGES%%FLAG%" equ "" goto UpgradeCygwin_next pushd %CYG_ROOT% if exist setup-%CYG_ARCH%.exe del setup-%CYG_ARCH%.exe appveyor DownloadFile "https://cygwin.com/setup-%CYG_ARCH%.exe" -FileName "setup-%CYG_ARCH%.exe" || exit /b 1 popd "%CYG_ROOT%\setup-%CYG_ARCH%.exe" --quiet-mode --no-shortcuts --no-startmenu --no-desktop --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" %CYGWIN_INSTALL_PACKAGES% %CYGWIN_UPGRADE_FLAG% > nul set CYGWIN_INSTALL_PACKAGES= :UpgradeCygwin_next if "%CYGWIN_UPGRADE_FLAG%" equ "" for %%P in (%CYGWIN_COMMANDS%) do "%CYG_ROOT%\bin\bash.exe" -lc "%%P --help" > nul || set CYGWIN_UPGRADE_REQUIRED=1 "%CYG_ROOT%\bin\bash.exe" -lc "cygcheck -dc %CYGWIN_PACKAGES%" if "%CYGWIN_UPGRADE_REQUIRED%%CYGWIN_UPGRADE_FLAG%" equ "1" call :UpgradeCygwin goto :EOF :install echo Build Worker Image: %APPVEYOR_BUILD_WORKER_IMAGE% systeminfo 2>nul | findstr /B /C:"OS Name" /C:"OS Version" echo System architecture: %PLATFORM% set CYG_ROOT=C:\%CYG_ROOT% cd "%APPVEYOR_BUILD_FOLDER%" :: if "%OCAML_PORT%" equ "" ( :: rem Need unreleased Cygwin 3.1.7 for bugfix in acl_get_tag_type and acl_get_permset :: appveyor DownloadFile "https://cygwin.com/snapshots/x86/cygwin1-20200710.dll.xz" -FileName "cygwin1.dll.xz" || exit /b 1 :: "%CYG_ROOT%\bin\bash.exe" -lc "cd $APPVEYOR_BUILD_FOLDER ; unxz cygwin1.dll.xz ; chmod +x cygwin1.dll" :: move cygwin1.dll %CYG_ROOT%\bin\cygwin1.dll :: ) rem CYGWIN_PACKAGES is the list of required Cygwin packages (cygwin is included rem in the list just so that the Cygwin version is always displayed on the log). rem CYGWIN_COMMANDS is a corresponding command to run with --version to test rem whether the package works. This is used to verify whether the installation rem needs upgrading. set CYGWIN_PACKAGES=cygwin make patch curl diffutils tar unzip git set CYGWIN_COMMANDS=cygcheck make patch curl diff tar unzip git if "%OCAML_PORT%" equ "mingw" ( set CYGWIN_PACKAGES=%CYGWIN_PACKAGES% mingw64-i686-gcc-g++ set CYGWIN_COMMANDS=%CYGWIN_COMMANDS% i686-w64-mingw32-g++ ) if "%OCAML_PORT%" equ "mingw64" ( set CYGWIN_PACKAGES=%CYGWIN_PACKAGES% mingw64-x86_64-gcc-g++ set CYGWIN_COMMANDS=%CYGWIN_COMMANDS% x86_64-w64-mingw32-g++ ) if "%OCAML_PORT%" equ "" ( set CYGWIN_PACKAGES=%CYGWIN_PACKAGES% gcc-g++ flexdll set CYGWIN_COMMANDS=%CYGWIN_COMMANDS% g++ flexlink ) set CYGWIN_INSTALL_PACKAGES= set CYGWIN_UPGRADE_REQUIRED=0 rem Check that all packages are installed for %%P in (%CYGWIN_PACKAGES%) do call :CheckPackage %%P rem Check that Cygwin is at least 3.1.7 for /f "tokens=2,3,4 delims=-. " %%a in ('%CYG_ROOT%\bin\bash.exe -lc "cygcheck -dc cygwin" ^| findstr cygwin') do ( set CYG_MAJOR=%%a set CYG_MINOR=%%b set CYG_REV=%%c ) set /a CYG_VER=%CYG_MAJOR%*10000+%CYG_MINOR%*100+%CYG_REV% if %CYG_VER% lss 30107 ( if "%OCAML_PORT%" equ "" ( echo Cygwin version %CYG_MAJOR%.%CYG_MINOR%.%CYG_REV% installed; opam requires 3.1.7 or later set CYGWIN_UPGRADE_REQUIRED=1 ) ) rem Upgrade/install packages as necessary call :UpgradeCygwin set INSTALLED_URL= for /f "tokens=3" %%U in ('findstr /C:"URL_ocaml = " src_ext\Makefile') do set OCAML_URL=%%U for /f "tokens=3" %%U in ('findstr /C:"URL_flexdll = " src_ext\Makefile') do set FLEXDLL_URL=%%U if exist bootstrap\ocaml\lib\stdlib.cmxa ( echo Deleting out-of-date bootstrap compiler rd /s/q bootstrap ) if exist bootstrap\installed-tarball for /f "delims=" %%U in ('type bootstrap\installed-tarball') do set INSTALLED_URL=%%U if "%INSTALLED_URL%" neq "%OCAML_URL% %FLEXDLL_URL% %DEP_MODE%" if exist bootstrap\nul ( echo Required: %OCAML_URL% %FLEXDLL_URL% %DEP_MODE% echo Compiled: %INSTALLED_URL% echo Re-building bootstrap compiler rd /s/q bootstrap if exist src_ext\archives\nul rd /s/q src_ext\archives ) if "%DEP_MODE%" equ "lib-pkg" "%CYG_ROOT%\bin\bash.exe" -lc "cd $APPVEYOR_BUILD_FOLDER && make --no-print-directory -C src_ext lib-pkg-urls | head -n -1 | sort | uniq" > current-lib-pkg-list if not exist bootstrap\installed-packages goto SkipCheck fc bootstrap\installed-packages current-lib-pkg-list > nul if %ERRORLEVEL% equ 1 ( echo lib-pkg packages changed: "%CYG_ROOT%\bin\diff.exe" bootstrap/installed-packages current-lib-pkg-list | "%CYG_ROOT%\bin\sed.exe" -ne "s//Add/p" | "%CYG_ROOT%\bin\gawk.exe" "BEGIN{FS="" ""}$2!=k{if(k!="""")print o==f?w:o;w=$0;k=$2;f=o=$2"" ""$3;next}{o=""Switch ""o"" --> ""$3}END{print o==f?w:o}" echo lib-pkg will be re-built "%CYG_ROOT%\bin\bash.exe" -lc "cd $APPVEYOR_BUILD_FOLDER && make --no-print-directory -C src_ext reset-lib-pkg" rd /s/q bootstrap if exist src_ext\archives\nul rd /s/q src_ext\archives ) else ( del current-lib-pkg-list ) :SkipCheck "%CYG_ROOT%\bin\bash.exe" -lc "cd $APPVEYOR_BUILD_FOLDER && make --no-print-directory -C src_ext cache-archives" || exit /b 1 set RECOMPILED=0 if not exist bootstrap\nul ( set RECOMPILED=1 "%CYG_ROOT%\bin\bash.exe" -lc "cd $APPVEYOR_BUILD_FOLDER && make compiler" || exit /b 1 for /f "delims=" %%U in ('type bootstrap\installed-tarball') do echo %%U %DEP_MODE%> bootstrap\installed-tarball if exist bootstrap\ocaml-*.tar.gz del bootstrap\ocaml-*.tar.gz if "%OCAML_PORT%" neq "" if exist bootstrap\flexdll-*.tar.gz del bootstrap\flexdll-*.tar.gz del bootstrap\ocaml\bin\*.byte.exe del bootstrap\ocaml\lib\ocaml\expunge.exe for /f %%D in ('dir /b/ad bootstrap\ocaml-*') do ( rd /s/q bootstrap\%%D rem Directory needs to exist, as the Cygwin bootstraps OCAMLLIB refers to it rem and bootstrap-ocaml.sh assumes it will exist even when regenerating the rem config. md bootstrap\%%D ) ) else ( if not exist bootstrap\installed-packages "%CYG_ROOT%\bin\bash.exe" -lc "cd $APPVEYOR_BUILD_FOLDER && make --no-print-directory -C src_ext reset-lib-pkg" if exist current-lib-pkg-list "%CYG_ROOT%\bin\bash.exe" -lc "cd $APPVEYOR_BUILD_FOLDER && GEN_CONFIG_ONLY=1 shell/bootstrap-ocaml.sh %OCAML_PORT%" || exit /b 1 ) if exist current-lib-pkg-list ( set RECOMPILED=1 "%CYG_ROOT%\bin\bash.exe" -lc "cd $APPVEYOR_BUILD_FOLDER && make lib-pkg" || exit /b 1 move current-lib-pkg-list bootstrap\installed-packages ) goto :EOF :build if "%OCAML_PORT%" equ "" ( rem make install doesn't yet work for the native Windows builds set POST_COMMAND=^&^& make opam-installer install ) set LIB_EXT= if "%DEP_MODE%" equ "lib-ext" set LIB_EXT=^&^& make lib-ext set PRIVATE_RUNTIME= if "%OCAML_PORT:~0,5%" equ "mingw" set PRIVATE_RUNTIME=--with-private-runtime set WITH_MCCS=--with-mccs if "%DEP_MODE%" equ "lib-pkg" set WITH_MCCS= "%CYG_ROOT%\bin\bash.exe" -lc "cd $APPVEYOR_BUILD_FOLDER %LIB_PKG% && ./configure %PRIVATE_RUNTIME% %WITH_MCCS% %LIB_EXT%" || exit /b 1 "%CYG_ROOT%\bin\bash.exe" -lc "cd $APPVEYOR_BUILD_FOLDER && echo DUNE_PROFILE=dev >> Makefile.config" || exit /b 1 "%CYG_ROOT%\bin\bash.exe" -lc "cd $APPVEYOR_BUILD_FOLDER && make opam %POST_COMMAND%" || exit /b 1 goto :EOF :test if %RECOMPILED% equ 1 ( echo Testing skipped for this run to avoid timeout goto :EOF ) rem Configure Git for Windows (for the testsuite, this isn't strictly necessary rem as Git-for-Windows will pick up $HOME/.gitconfig for Cygwin's git) git config --global user.email travis@example.com git config --global user.name Travis rem Configure Cygwin's Git "%CYG_ROOT%\bin\bash.exe" -lc "git config --global user.email travis@example.com" "%CYG_ROOT%\bin\bash.exe" -lc "git config --global user.name Travis" set OPAMCOLOR=always set PATH_SHIM= if "%OCAML_PORT%" neq "" if "%GIT_FOR_WINDOWS%" equ "1" ( set PATH_SHIM=PATH=/cygdrive/c/Program\ Files/Git/cmd:$PATH "C:\Program Files\Git\cmd\git.exe" config --global core.autocrlf "C:\Program Files\Git\cmd\git.exe" config --global core.autocrlf true "C:\Program Files\Git\cmd\git.exe" config --global core.autocrlf ) "%CYG_ROOT%\bin\bash.exe" -lc "%PATH_SHIM% make -C $APPVEYOR_BUILD_FOLDER tests" || exit /b 1 rem Can't yet do an opam init with the native Windows builds if "%OCAML_PORT%" equ "" "%CYG_ROOT%\bin\bash.exe" -lc "make -C $APPVEYOR_BUILD_FOLDER run-appveyor-test" || exit /b 1 goto :EOF opam-2.1.5/process.sed0000644000175000017500000000006114427463453013667 0ustar stephsteph/^[ld][io][bc]:/{ :a N /]/!ba } /[ld][io][bc]:/d opam-2.1.5/configure.ac0000644000175000017500000003724214427463453014015 0ustar stephstephdnl The line below must be formatted AC_INIT(opam,VERSION) with no extra spaces AC_INIT(opam,2.1.5) AC_COPYRIGHT(Copyright 2012-2019 OcamlPro SAS) AC_CONFIG_MACRO_DIR([m4]) # If a bootstrap compiler has been built, always use it PATH_PREPEND= PRE_BOOTSTRAP_PATH="$PATH" AS_IF([ test -x bootstrap/ocaml/bin/ocamlc -o -x bootstrap/ocaml/bin/ocamlopt ],[ echo Bootstrap compiler found -- activating unset OCAMLLIB export PATH_PREPEND=`pwd`/bootstrap/ocaml/bin: export PATH="$PATH_PREPEND$PATH" ]) # XXX This isn't strictly correct for Windows MIN_OCAML_VERSION=4.02.3 AC_PROG_OCAML if test "x$OCAMLC" = "xno"; then AC_MSG_ERROR([You must install the OCaml compiler, at least version $MIN_OCAML_VERSION (or run: make compiler)]) fi AC_CHECK_OCAML_OS_TYPE AS_IF([ test "${OCAML_OS_TYPE}" = "Win32"],[ OCAMLLIB="$(echo "${OCAMLLIB}" | tr -d '\015' | sed -e 's|\\|/|g')" WIN32=1 EXE=.exe ],[ EXE= WIN32=0 ]) AC_SUBST(WIN32) AC_SUBST(EXE) # AC_PREFIX_DEFAULT must be at the top level, which is the reason for the # somewhat convoluted pair of sed expressions... AC_PREFIX_DEFAULT([`echo "os_type: ${OCAML_OS_TYPE}" | sed -e "s;^os_type: Win32;C:/OPAM;" -e "s;^os_type:.*;/usr/local;"`]) AC_ARG_ENABLE([version_check], AS_HELP_STRING([--disable-version-check], [Do not check OCaml version]) ) AC_ARG_ENABLE([checks], AS_HELP_STRING([--disable-checks], [Assume OCaml dependencies are OK without checking]) ) AC_ARG_ENABLE([developer_mode], AC_HELP_STRING([--enable-developer-mode], [Enable developer features]) ) AC_ARG_WITH([mccs], AC_HELP_STRING([--without-mccs], [Compile without a built-in Cudf solver (only works if 'mccs' is not otherwise installed)]),[],[MCCS_DEFAULT=yes] ) AC_ARG_WITH([0install-solver], AC_HELP_STRING([--with-0install-solver], [Compile with the built-in 0install solver (--without-0install-solver only works if 'opam-0install-cudf' is not otherwise installed)]) ) AC_ARG_WITH([libacl], AC_HELP_STRING([--with-libacl], [Compile opam with libacl support]),,[with_libacl=auto]) AC_ARG_WITH([private_runtime], AC_HELP_STRING([--with-private-runtime], [For a mingw-w64 build, manifest the runtime DLLs locally in Opam.Runtime.arch]),,[with_private_runtime=no] ) AC_ARG_ENABLE([cold_check], AC_HELP_STRING([--enable-cold-check], [Fail on some check necessary for make cold]),[COLD_CHECK=yes],[] ) AS_IF([test "x" != "x$LIB_PREFIX"], [ CPATH=$CPATH:$LIB_PREFIX/include LIBRARY_PATH=$LIBRARY_PATH:$LIB_PREFIX/lib export CPATH LIBRARY_PATH ]) AC_SUBST(LIB_PREFIX,$LIB_PREFIX) AC_SUBST(CPATH,$CPATH) AC_SUBST(LIBRARY_PATH,$LIBRARY_PATH) # Check that OCaml version is greater or equal to 4.02.3 # Native Windows builds require at least 4.06.0 for the Unicode runtime. AS_IF([test "x${enable_version_check}" != "xno"], [ AS_IF([ test ${WIN32} -eq 1 ],[MIN_OCAML_VERSION=4.06.0]) AX_COMPARE_VERSION( [$OCAMLVERSION], [lt], [$MIN_OCAML_VERSION], AC_MSG_ERROR([Your version of OCaml: $OCAMLVERSION is not supported])) ]) AC_MSG_CHECKING([for compiler type]) CCOMP_TYPE=`$OCAML shell/print_config.ml ccomp_type 2>/dev/null | fgrep -v "Cannot find" || $OCAMLC -config | tr -d '\r' | sed -n -e "s/ccomp_type: //p"` AS_IF([ test "$?" -eq 0 ],,[AC_MSG_ERROR([failed])] ) AC_MSG_RESULT([$CCOMP_TYPE]) AC_MSG_CHECKING([for compiler architecture]) ARCH=`$OCAML shell/print_config.ml arch 2>/dev/null | fgrep -v "Cannot find" || $OCAMLC -config | tr -d '\r' | sed -n -e "s/architecture: //p"` AS_IF([ test "$?" -eq 0 ],,[AC_MSG_ERROR([failed])] ) AC_MSG_RESULT([$ARCH]) AC_MSG_CHECKING([for compiler system]) SYSTEM=`$OCAML shell/print_config.ml system 2>/dev/null | fgrep -v "Cannot find" || $OCAMLC -config | tr -d '\r' | sed -n -e "s/system: //p"` AC_MSG_RESULT([$SYSTEM]) AC_SUBST(SYSTEM) LIB_PREPEND= INC_PREPEND= # Need the C compiler used for OCaml (important on Windows, as both x86 and x64 are used) AS_IF([test "$OCAMLBEST" = "opt"],[OCAMLBESTCC=$OCAMLOPT],[OCAMLBESTCC=$OCAMLC]) OCAML_CC="$($OCAMLBESTCC -config | sed -n -e "s/native_c_compiler: \(.*\) .*/\1/p")" set dummy ${OCAML_CC}; OCAML_TEST_CC=$2 AS_IF([test ! -x ${OCAML_TEST_CC}],[ AS_IF([test "x${CCOMP_TYPE}" = "xmsvc"],[ AS_IF([test "${ARCH}" = "i386"],[SDK_ARCH=x86],[SDK_ARCH=x64]) AC_MSG_CHECKING([for an installed Microsoft C Compiler for ${SDK_ARCH}]) eval `PATH="$PRE_BOOTSTRAP_PATH" bash ./shell/msvs-detect --arch=$SDK_ARCH; echo RESULT=$?` AS_IF([ test "x$MSVS_NAME" = "x" ], [ AS_IF([ test ${RESULT} -eq 0 ], [ AC_MSG_RESULT([from PATH]) ],[ AC_MSG_ERROR([no]) ]) ],[ AC_MSG_RESULT([from $MSVS_NAME]) export PATH_PREPEND="${MSVS_PATH}${PATH_PREPEND}" # Note that we put ${MSVS_PATH} here NOT ${PATH_PREPEND} so that the bootstrap path isn't repeated export PATH="${MSVS_PATH}$PATH" LIB_PREPEND="${MSVS_LIB}" INC_PREPEND="${MSVS_INC}" export Lib="${MSVS_LIB}$LIB" export Include="${MSVS_INC}$INCLUDE" ]) ]) ]) AC_PROG_CC(["${OCAML_CC}" gcc cc]) AS_IF([test "x${enable_developer_mode}" = "xyes"],[ AC_SUBST(DEVELOPER,true) echo "-D" > src/core/developer echo "DEVELOPER" >> src/core/developer ],[ AC_SUBST(DEVELOPER,false) rm -f src/core/developer ]) AS_IF([test "x${with_mccs}" = "xno"], [AC_SUBST(MCCS_ENABLED,false)], [AC_SUBST(MCCS_ENABLED,true)]) AS_IF([test "x${with_0install_solver}" = "xyes"], [AC_SUBST(OPAM_0INSTALL_SOLVER_ENABLED,true)], [AC_SUBST(OPAM_0INSTALL_SOLVER_ENABLED,false)]) AS_IF([test "x${with_libacl}" != "xno"],[ have_libacl=yes AC_CHECK_HEADER([acl/libacl.h],,[have_libacl=no]) AC_SEARCH_LIBS([acl_get_perm],[acl],,[have_libacl=no]) AS_IF([test "x${SYSTEM}" = "xcygwin"],[ AS_IF([test "x${have_libacl}" = "xno"],[AC_MSG_ERROR([opam on Cygwin requires libacl])],[with_libacl=yes]) ]) AS_IF([test "x${with_libacl}${have_libacl}" = "xyesno"],[AC_MSG_ERROR([libacl not found])]) ]) AS_IF([test "x${with_libacl}" = "xyes"],[ AS_IF([test "x${ac_cv_search_acl_get_perm}" = "xnone required"],[ AC_SUBST(CONF_LIBACL_LINK,[]) ],[ AC_SUBST(CONF_LIBACL_LINK,[${ac_cv_search_acl_get_perm}]) ]) ]) CONF_OCAMLFLAGS="-w -67" AS_IF([test "x${CI}" != "x"], [ CONF_OCAMLFLAGS="${CONF_OCAMLFLAGS} -w -67" ],[]) AS_IF([test "x${CI}" != "x" -o "x${enable_developer_mode}" = "xyes"],[ AS_IF([test "x${CCOMP_TYPE}" = "xmsvc"],[ CONF_CFLAGS="\"/WX\"" ],[ CONF_CFLAGS="-Werror" ]) ],[ CONF_CFLAGS= ]) AC_SUBST(CONF_OCAMLFLAGS) AC_SUBST(CONF_CFLAGS) AS_IF([ test ${WIN32} -eq 1 -a "$GCC" = "yes"],[ # Pre-Visual Studio 2013 Microsoft C compiler adhere to the C89 standard, well # at least the bit of it which requires variable declarations to appear before # statements. Adding this warning to GCC prevents accidentally using C99 and # then getting unexpected C2143 errors from older Microsoft C compilers. I'm # not aware of an equivalent option for the Microsoft C compiler. CC="$CC -Wdeclaration-after-statement" AC_SUBST(CC) ]) AS_IF([ test ${WIN32} -eq 1 ],[ AS_IF([ test "$GCC" = "yes"], [ AS_IF([ test "x${CC64}" = "x" ], [ AS_IF([ test "$ARCH" = "i386" ],[T_CC64=x86_64-w64-mingw32-gcc],[T_CC64=i686-w64-mingw32-gcc])]) AC_CHECK_TOOL(CC64,[${T_CC64}],[no]) AS_IF([ test "x${CC64}" != "xno" ],[ echo "${CC64} -o " > src/stubs/win32/cc64 echo " -Wdeclaration-after-statement " >> src/stubs/win32/cc64 ]) ],[ AC_MSG_CHECKING([whether Microsoft Linker needs a PATH shim]) PREV_PREPEND="$PATH_PREPEND" PATH_PREPEND=$(bash ./shell/check_linker) AS_IF([test "x${PATH_PREPEND}" = "x${PREV_PREPEND}" ],[PATH_PREPEND_RESULT=no],[PATH_PREPEND_RESULT=yes]) PATH_PREPEND=`echo "${PATH_PREPEND}" | sed -e 's/#/\\\\#/g' -e 's/\\$/$$/g'` LIB_PREPEND=`echo ${LIB_PREPEND} | sed -e 's/#/\\\\#/g' -e 's/\\$/$$/g'` INC_PREPEND=`echo ${INC_PREPEND} | sed -e 's/#/\\\\#/g' -e 's/\\$/$$/g'` AC_SUBST(PATH_PREPEND) AC_SUBST(LIB_PREPEND) AC_SUBST(INC_PREPEND) AC_MSG_RESULT([$PATH_PREPEND_RESULT]) AS_IF([ test "$ARCH" = "i386" ],[COMP_ARCH=x64],[COMP_ARCH=x86]) AC_MSG_CHECKING([for a way to invoke an $COMP_ARCH C compiler]) eval `PATH="$PRE_BOOTSTRAP_PATH" bash ./shell/msvs-detect --arch=$COMP_ARCH` AS_IF([ test "x$MSVS_NAME" = "x" ], [ AC_MSG_RESULT([no]) CC64=no ],[ AC_MSG_RESULT([from $MSVS_NAME]) CL_FULL="`PATH="${MSVS_PATH}:${PATH}" which cl | cygpath -f - -w`" MSVS_PATH="`echo "${MSVS_PATH}" | cygpath -f - -wp`" echo "cl /nologo /Fe" > src/stubs/win32/cc64 echo " " >> src/stubs/win32/cc64 echo "PATH" >> src/stubs/win32/cc64 echo "${MSVS_PATH}" >> src/stubs/win32/cc64 echo "LIB" >> src/stubs/win32/cc64 echo "${MSVS_LIB}" >> src/stubs/win32/cc64 echo "INCLUDE" >> src/stubs/win32/cc64 echo "${MSVS_INC}" >> src/stubs/win32/cc64 ]) ]) AS_IF([ test "x${CC64}" = "xno" ],[ AC_MSG_WARN([Complementary C compiler not found - opam-putenv will not be built]) ]) ]) AC_PROG_FINDLIB AC_ARG_ENABLE([certificate_check], AS_HELP_STRING([--disable-certificate-check], [Do not check the certificate of opam's dependency archives])dnl ' ) AS_IF([test "x${enable_certificate_check}" = "xno"], [ curl_certificate_check=--insecure wget_certificate_check=--no-check-certificate ]) AC_CHECK_PROGS(FETCH,[curl wget],no) AC_CHECK_TOOL(DUNE,dune) AC_CHECK_TOOL(CPPO,cppo) AC_CHECK_TOOL(PATCH,patch) AC_CHECK_TOOL(BUNZIP2,bunzip2) AX_COMPARE_VERSION([$OCAMLVERSION], [lt], [4.08.0], [DUNE_SECONDARY=src_ext/secondary/ocaml/bin/ocaml], [DUNE_SECONDARY=]) AC_SUBST([DUNE_SECONDARY]) if test "x${COLD_CHECK}" = "xyes" ; then if test "x$PATCH" = "x" ; then AC_MSG_ERROR([You must have patch installed.]) fi if test "x$BUNZIP2" = "x" ; then AC_MSG_ERROR([You must have bunzip2 installed.]) fi fi AS_IF([test "${OCAML_OS_TYPE}" = "Win32"],[ AC_MSG_CHECKING([for a workable solution for ln -s]) ln -s configure conftestLink AS_IF([test "`cmd /c dir conftestLink 2>/dev/null | fgrep SYMLINK`" = ""],[LN_S="cp -a"],[LN_S="ln -s"]) AC_MSG_RESULT([$LN_S]) ],[ LN_S="ln -s" ]) AC_SUBST(LN_S) if test x"$FETCH" = x"curl" ; then AC_SUBST(fetch, "curl $curl_certificate_check -LSs -o \$(2) \$(1)") elif test x"$FETCH" = x"wget" ; then AC_SUBST(fetch, "wget $wget_certificate_check -O \$(2) \$(1)") elif test x"${enable_checks}" != x"no" ; then if ! ${MAKE:-make} -q -C src_ext has-archives 2>/dev/null ; then AC_MSG_ERROR([You must have either curl or wget installed.]) fi fi AS_IF([test "x${with_private_runtime}" != "xno"],[ AS_IF([test ${WIN32} -eq 1 -a "x${CCOMP_TYPE}" = "xcc"],[ CONF_MANIFEST_O=opam-manifest.o AS_IF([ test "$ARCH" = "i386" ],[ MANIFEST_ARCH=x86 RUNTIME_GCC_S=libgcc_s_sjlj-1 ],[ MANIFEST_ARCH=amd64 RUNTIME_GCC_S=libgcc_s_seh-1 ]) AC_SUBST(MANIFEST_ARCH) AC_SUBST(RUNTIME_GCC_S) ],[ CONF_MANIFEST_O= AC_MSG_WARN([--with-private-runtime ignored (not building on mingw)]) ]) ],[CONF_MANIFEST_O=]) AC_SUBST(CONF_MANIFEST_O) echo AC_CHECK_OCAML_PKG([unix]) AC_CHECK_OCAML_PKG([bigarray]) AC_CHECK_OCAML_PKG([extlib]) AC_CHECK_OCAML_PKG([re]) AC_CHECK_OCAML_PKG([re.glob]) AC_CHECK_OCAML_PKG([cmdliner]) AC_CHECK_OCAML_PKG([ocamlgraph]) AC_CHECK_OCAML_PKG([cudf]) AC_CHECK_OCAML_PKG(dose3.common,dose.common) AC_CHECK_OCAML_PKG(dose3.algo,dose.algo) AC_CHECK_OCAML_PKG([opam-file-format]) AC_CHECK_OCAML_PKG([mccs]) AC_CHECK_OCAML_PKG([opam-0install-cudf]) AS_IF([test "x${with_mccs}" = "xno" && test "x$OCAML_PKG_mccs" != "xno"], [AC_MSG_ERROR([Option --without-mccs is not available without uninstalling the 'mccs' package])]) AS_IF([test "x${with_0install_solver}" = "xno" && test "x$OCAML_PKG_opam_0install_cudf" != "xno"], [AC_MSG_ERROR([Option --without-0install-solver is not available without uninstalling the 'opam-0install-cudf' package])]) dnl -- Enable 0install-solver if the package is available AS_IF([test "x$OCAML_PKG_opam_0install_cudf" != "xno"], [AC_SUBST(OPAM_0INSTALL_SOLVER_ENABLED,true)]) dnl -- that's what we would like to do, but no way to disable mccs in jbuilder dnl -- if it's installed, at the moment dnl AS_IF([test "x${with_mccs}" != "xno"], dnl AC_CHECK_OCAML_PKG([mccs]), dnl [echo "checking for OCaml findlib package mccs... disabled" dnl AC_SUBST(OCAML_PKG_mccs,"no")]) AS_IF([test "x$MCCS_ENABLED" = "xtrue"],[ AS_IF([test "x${CCOMP_TYPE}" != "xmsvc"],[ AC_PROG_CXX # Curiously, CXX=g++ && GXX= seems to be how autoconf "signals" that no C++ # compiler was found. AS_IF([test "x$CXX" = "xg++" -a "x$GXX" != "xyes"],[ AS_IF([test "x$MCCS_DEFAULT" = "xyes"],[ AC_SUBST(MCCS_ENABLED,false) ],[ AS_IF([test "x${enable_checks}" != "xno"],[ AC_MSG_ERROR([A C++ compiler is required to build mccs]) ]) ]) ]) ]) ]) AS_IF([test "x$OPAM_0INSTALL_SOLVER_ENABLED" = "xtrue" -a "x$OCAML_PKG_opam_0install_cudf" = "xno"],[ AX_COMPARE_VERSION([$OCAMLVERSION], [lt], [4.08],[ AC_MSG_ERROR([Your version of OCaml: $OCAMLVERSION does not support the requested 0install-solver. \ You can either re-run the configure script with --without-0install-solver or use make cold]) ]) ]) dnl echo dnl echo "extlib........................ ${OCAML_PKG_extlib}" dnl echo "re............................ ${OCAML_PKG_re}" dnl echo "cmdliner...................... ${OCAML_PKG_cmdliner}" dnl echo "graph......................... ${OCAML_PKG_ocamlgraph}" dnl echo "cudf.......................... ${OCAML_PKG_cudf}" dnl echo "dose3......................... ${OCAML_PKG_dose3}" echo AS_IF([test "x${enable_checks}" != "xno" && { test "x$OCAML_PKG_extlib" = "xno" || test "x$OCAML_PKG_re" = "xno" || test "x$OCAML_PKG_cmdliner" = "xno" || test "x$OCAML_PKG_ocamlgraph" = "xno" || test "x$OCAML_PKG_cudf" = "xno" || test "x$OCAML_PKG_dose3_common" = "xno" || test "x$OCAML_PKG_opam_file_format" = "xno" || test "x$CPPO" = "x" || test "x$OCAML_PKG_mccs$MCCS_ENABLED" = "xnotrue" || test "x$OCAML_PKG_opam_0install_cudf$OPAM_0INSTALL_SOLVER_ENABLED" = "xnotrue";}],[ echo "============================================================================" echo "Some dependencies are missing. If you are just interested in the stand-alone" echo "'opam' binary, run 'make lib-ext' to download and include them." echo "============================================================================" echo AC_SUBST(hasalldeps,"") ],[ AC_SUBST(hasalldeps,"true") ]) if test "x$prefix" = "xNONE"; then prefix=$ac_default_prefix fi AC_CONFIG_FILES( Makefile.config src/ocaml-flags-configure.sexp src/stubs/c-flags.sexp src/stubs/libacl/c-libraries.sexp ) AC_OUTPUT rm -f src/manifest/dune src/manifest/install.inc AS_IF([test "x${with_private_runtime}" != "xno"],[ AS_IF([test ${WIN32} -eq 1 -a "x${CCOMP_TYPE}" = "xcc"],[ cd src/manifest ${LN_S} -f dune-manifest dune ${LN_S} -f install.${ARCH} install.inc cd ../.. ],[ AC_MSG_WARN([--with-private-runtime ignored (not building on mingw)]) ]) ]) rm -f src/stubs/win32/dune AS_IF([ test ${WIN32} -eq 1],[ cd src/stubs/win32 ${LN_S} -f dune-win32 dune cd ../../.. ]) rm -f src/stubs/libacl/dune AS_IF([ test "x${with_libacl}" = "xyes" ],[ cd src/stubs/libacl ${LN_S} -f dune-libacl dune cd ../../.. ]) echo bindir="`eval echo ${bindir}`" bindir="`eval echo ${bindir}`" mandir="`eval echo ${mandir}`" mandir="`eval echo ${mandir}`" AS_IF([test "x$MCCS_ENABLED" = "xfalse" -a "x$OPAM_0INSTALL_SOLVER_ENABLED" = "xfalse"],[ echo "Opam will be built WITHOUT a built-in solver" ],[ echo "Opam will be built WITH a built-in solver" ]) echo echo Executables will be installed in ${bindir} echo Manual pages will be installed in ${mandir} opam-2.1.5/release/0002755000175000017500000000000014427463453013141 5ustar stephstephopam-2.1.5/release/Dockerfile.in0000644000175000017500000000175014427463453015541 0ustar stephstephFROM multiarch/debian-debootstrap:%TARGET_TAG% # May need configuration on the host: # docker run --rm --privileged multiarch/qemu-user-static:register --reset LABEL Description="opam release builds" Vendor="OCamlPro" Version="1.0" RUN apt-get update && apt-get install bzip2 g++ make patch wget libltdl-dev --yes && apt-get clean --yes RUN useradd -U --create-home opam ADD https://caml.inria.fr/pub/distrib/ocaml-4.07/ocaml-4.07.1.tar.gz /root/ WORKDIR /root RUN tar xzf ocaml-4.07.1.tar.gz WORKDIR ocaml-4.07.1 RUN ./configure %CONF% -prefix /usr/local RUN make world opt.opt RUN make install RUN rm -rf /root/ocaml-4.07.1 /root/ocaml-4.07.1.tar.gz ENV PATH /usr/local/bin:/usr/bin:/bin USER opam VOLUME /src WORKDIR /home/opam/ CMD tar xzf /src/opam-full-${VERSION}.tar.gz && \ cd opam-full-${VERSION} && \ echo "(${LINKING})" > src/client/linking.sexp && \ ./configure --with-mccs && \ make lib-ext opam && \ strip opam && \ cp opam /src/opam-${VERSION}-${TARGET} opam-2.1.5/release/release.sh0000755000175000017500000000175314427463453015124 0ustar stephsteph#!/usr/bin/env bash set -uex # This script is expected to run on Linux with docker available, and to have # three remotes "some-osx-x86", "some-osx-arm" and "some-openbsd", with the # corresponding OSes, ocaml deps installed LC_ALL=C DIR=$(dirname $0) cd "$DIR" if [[ $# -eq 0 || "x$1" =~ "x-" ]]; then echo "Usage: $0 TAG [archive|builds]" exit 1 fi TAG="$1"; shift if [[ $# -eq 0 || " $* " =~ " archive " ]]; then make TAG="$TAG" GIT_URL="https://github.com/ocaml/opam.git" "out/opam-full-$TAG.tar.gz" ( cd out && git-upload-release ocaml opam "$TAG" "opam-full-$TAG.tar.gz"; ) fi if [[ $# -eq 0 || " $* " =~ " builds " ]]; then make TAG="$TAG" all & make TAG="$TAG" remote REMOTE=some-osx-x86 REMOTE_DIR=opam-release & make TAG="$TAG" remote REMOTE=some-osx-arm REMOTE_DIR=opam-release & make TAG="$TAG" remote REMOTE=some-openbsd REMOTE_MAKE=gmake REMOTE_DIR=opam-release & wait cd out && for f in opam-$TAG-*; do git-upload-release ocaml opam "$TAG" $f done fi opam-2.1.5/release/readme.md0000644000175000017500000000221514427463453014716 0ustar stephsteph# Steps to follow for each release ## Finalise opam code for release * update version in opam files, configure.ac * run `make configure` to regenerate `./configure` [checked by github actions] * update copyright headers * run `make tests`, `opam-rt` [checked by github actions & appveyor] * update the CHANGE file: take `master_changes.md` content to fil it ## Github release [ once bump version & changes PRs merged ] * tag the release (git tag -a 2.2.0; git push origin 2.2.0) * /!\ Once the tag pushed, it can be updated only in case of severe issue * create a release (or prerelease if intermediate release) draft on github based on your tag (https://github.com/ocaml/opam/releases/new) * generate opam artifacts, using `shell/release.sh`, it requires to have Docker install with several remotes, the different arches * add releases notes (content of `master_changes.md`) in the release * upload signature of artefacts * finalise the release (publish) ## Publish the release * add hashes in `install.sh` (and check signatures) * publish opam packages in opam-repository ## Announce! * a blog entry in opam.ocaml.org * a announcement in discuss.ocaml.org opam-2.1.5/release/Makefile0000644000175000017500000001017514427463453014603 0ustar stephstephTAG = master VERSION = $(shell git describe $(TAG)) OPAM_VERSION = $(subst -,~,$(VERSION)) GIT_URL = .. FULL_ARCHIVE_URL = https://github.com/ocaml/opam/releases/download/$(VERSION)/opam-full-$(VERSION).tar.gz TARGETS = x86_64-linux i686-linux armhf-linux arm64-linux # todo: x86_64-darwin OCAMLV = 4.10.2 # currently hardcoded in Dockerfile.in OCAML_URL = https://caml.inria.fr/pub/distrib/ocaml-$(basename $(OCAMLV))/ocaml-$(OCAMLV).tar.gz HOST_OS = $(shell uname -s | tr A-Z a-z | sed 's/darwin/macos/') HOST = $(shell uname -m | sed 's/amd64/x86_64/')-$(HOST_OS) all: $(patsubst %,out/opam-$(VERSION)-%,$(TARGETS)) out/opam-full-$(VERSION).tar.gz: mkdir -p out cd out && curl -OfL $(FULL_ARCHIVE_URL) || { \ git clone $(GIT_URL) -b $(TAG) --depth 1 opam-full-$(VERSION); \ sed 's/^AC_INIT(opam,.*)/AC_INIT(opam,$(OPAM_VERSION))/' opam-full-$(VERSION)/configure.ac > \ opam-full-$(VERSION)/configure.ac.tmp; \ mv opam-full-$(VERSION)/configure.ac.tmp \ opam-full-$(VERSION)/configure.ac; \ $(MAKE) -C opam-full-$(VERSION) configure download-ext; \ tar cz --exclude-vcs opam-full-$(VERSION) -f $(notdir $@); \ rm -rf opam-full-$(VERSION); \ } build/Dockerfile.x86_64-linux: Dockerfile.in mkdir -p build && sed 's/%TARGET_TAG%/amd64-jessie/g' $^ | sed 's/%CONF%//g' >$@ build/Dockerfile.i686-linux: Dockerfile.in mkdir -p build && sed 's/%TARGET_TAG%/i386-jessie/g' $^ | sed 's/%CONF%/-host i686-linux/g' >$@ build/Dockerfile.armhf-linux: Dockerfile.in mkdir -p build && sed 's/%TARGET_TAG%/armhf-jessie/g' $^ | sed 's/%CONF%//g' >$@ build/Dockerfile.arm64-linux: Dockerfile.in mkdir -p build && sed 's/%TARGET_TAG%/arm64-stretch/g' $^ | sed 's/%CONF%//g' >$@ build/%.image: build/Dockerfile.% docker build -t opam-build-$* -f $^ build touch $@ # Actually, this is for debian 8 jessie, and varies wildly CLINKING_linux = \ -Wl,-Bstatic \ -lunix -lmccs_stubs -lmccs_glpk_stubs \ -lstdc++ \ -Wl,-Bdynamic \ -static-libgcc CLINKING_macos = \ -lunix -lmccs_stubs -lmccs_glpk_stubs \ -lstdc++ CLINKING_openbsd = $(CLINKING_macos) LINKING = (-noautolink $(patsubst %,-cclib %,$(CLINKING_$(1)))) EXPORTS_openbsd = \ CPATH=/usr/local/include: \ LIBRARY_PATH=/usr/local/lib: \ %: opam-$(VERSION)-% opam-$(VERSION)-%: out/opam-$(VERSION)-% ln -sf $^ $@ # host: opam-$(VERSION)-$(HOST) # Build for the local host. Containerised builds, below, are preferred, but not always available build/$(HOST).env: mkdir -p build/$(HOST) cd build/$(HOST) && curl -OL $(OCAML_URL) cd build/$(HOST) && tar xzf ocaml-$(OCAMLV).tar.gz cd build/$(HOST)/ocaml-$(OCAMLV) && \ ./configure -prefix $(shell pwd)/build/$(HOST) && \ $(MAKE) world opt.opt && \ $(MAKE) install rm -rf build/$(HOST)/ocaml-$(OCAMLV) build/$(HOST)/ocaml-$(OCAMLV).tar.gz touch $@ # Actually builds out/opam-$(VERSION)-$(HOST), but we don't want to override the # rule that goes through a container host: out/opam-full-$(VERSION).tar.gz build/$(HOST).env rm -rf build/opam-full-$(VERSION) cd build && tar xzf ../$< ( export \ PATH=$(shell pwd)/build/$(HOST)/bin:$$PATH \ MAKE=$(MAKE) \ $(EXPORTS_$(HOST_OS)); \ cd build/opam-full-$(VERSION) && \ ./configure && \ echo "$(call LINKING,$(HOST_OS))" >src/client/linking.sexp && \ $(MAKE) lib-ext DUNE_ARGS="--root=`pwd`"; \ $(MAKE) opam DUNE_ARGS="--root=`pwd`"; \ ) cp build/opam-full-$(VERSION)/opam out/opam-$(VERSION)-$(HOST) strip out/opam-$(VERSION)-$(HOST) rm -rf build/opam-full-$(VERSION) # Containerised builds out/opam-$(VERSION)-%-linux: build/%-linux.image out/opam-full-$(VERSION).tar.gz docker run --rm -v `pwd`/out:/src \ -e "VERSION=$(VERSION)" \ -e "TARGET=$*-linux" \ -e "LINKING=$(call LINKING,$(HOST_OS))" \ opam-build-$*-linux clean: rm -rf build distclean: clean rm -rf out REMOTE_DIR = /tmp/opam-release REMOTE_MAKE = make remote: out/opam-full-$(VERSION).tar.gz ssh "$(REMOTE)" "mkdir -p $(REMOTE_DIR)/out" scp Makefile "$(REMOTE):$(REMOTE_DIR)/" scp "$^" "$(REMOTE):$(REMOTE_DIR)/$^" ssh "$(REMOTE)" 'sh -c "cd $(REMOTE_DIR) && ulimit -s 8192 && $(REMOTE_MAKE) host TAG=$(TAG) VERSION=$(VERSION) OCAMLV=$(OCAMLV)"' scp "$(REMOTE):$(REMOTE_DIR)/out/opam-$(VERSION)*" out/ opam-2.1.5/dune0000644000175000017500000000003514427463453012373 0ustar stephsteph(dirs :standard \ bootstrap) opam-2.1.5/configure0000755000175000017500000067562714427463453013455 0ustar stephsteph#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for opam 2.1.5. # # # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # # Copyright 2012-2019 OcamlPro SAS ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="as_nop=: if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else $as_nop as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi fi if test "x$CONFIG_SHELL" != x then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='opam' PACKAGE_TARNAME='opam' PACKAGE_VERSION='2.1.5' PACKAGE_STRING='opam 2.1.5' PACKAGE_BUGREPORT='' PACKAGE_URL='' ac_default_prefix=`echo "os_type: ${OCAML_OS_TYPE}" | sed -e "s;^os_type: Win32;C:/OPAM;" -e "s;^os_type:.*;/usr/local;"` # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS hasalldeps ac_ct_CXX CXXFLAGS CXX OCAML_PKG_opam_0install_cudf OCAML_PKG_mccs OCAML_PKG_opam_file_format OCAML_PKG_dose3_algo OCAML_PKG_dose3_common OCAML_PKG_cudf OCAML_PKG_ocamlgraph OCAML_PKG_cmdliner OCAML_PKG_re_glob OCAML_PKG_re OCAML_PKG_extlib OCAML_PKG_bigarray OCAML_PKG_unix CONF_MANIFEST_O RUNTIME_GCC_S MANIFEST_ARCH fetch LN_S DUNE_SECONDARY BUNZIP2 PATCH CPPO DUNE FETCH OCAMLFIND OCAMLOBJINFO INC_PREPEND LIB_PREPEND PATH_PREPEND CC64 CONF_CFLAGS CONF_OCAMLFLAGS CONF_LIBACL_LINK OPAM_0INSTALL_SOLVER_ENABLED MCCS_ENABLED DEVELOPER OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC SYSTEM AWK LIBRARY_PATH CPATH LIB_PREFIX EXE WIN32 OCAML_OS_TYPE OCAMLBUILD OCAMLDOCDOTOPT OCAMLDOC OCAMLMKLIB OCAMLMKTOP OCAMLDEPDOTOPT OCAMLDEP OCAML OCAMLOPTDOTOPT OCAMLCDOTOPT OCAMLBEST OCAMLOPT OCAMLLIB OCAMLVERSION OCAMLC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_version_check enable_checks enable_developer_mode with_mccs with_0install_solver with_libacl with_private_runtime enable_cold_check enable_certificate_check ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CXX CXXFLAGS CCC' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures opam 2.1.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/opam] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of opam 2.1.5:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-version-check Do not check OCaml version --disable-checks Assume OCaml dependencies are OK without checking --enable-developer-mode Enable developer features --enable-cold-check Fail on some check necessary for make cold --disable-certificate-check Do not check the certificate of opam's dependency archives Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --without-mccs Compile without a built-in Cudf solver (only works if 'mccs' is not otherwise installed) --with-0install-solver Compile with the built-in 0install solver (--without-0install-solver only works if 'opam-0install-cudf' is not otherwise installed) --with-libacl Compile opam with libacl support --with-private-runtime For a mingw-w64 build, manifest the runtime DLLs locally in Opam.Runtime.arch Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CXX C++ compiler command CXXFLAGS C++ compiler flags Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF opam configure 2.1.5 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Copyright 2012-2019 OcamlPro SAS _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile ac_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by opam $as_me 2.1.5, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated as an "x". The following induces an error, until -std is added to get proper ANSI mode. Curiously \x00 != x always comes out true, for an array size at least. It is necessary to write \x00 == 0 to get something that is true only with -std. */ int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) '\''x'\'' int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' // Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' // Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" # Test code for whether the C++ compiler supports C++98 (global declarations) ac_cxx_conftest_cxx98_globals=' // Does the compiler advertise C++98 conformance? #if !defined __cplusplus || __cplusplus < 199711L # error "Compiler does not advertise C++98 conformance" #endif // These inclusions are to reject old compilers that // lack the unsuffixed header files. #include #include // and are *not* freestanding headers in C++98. extern void assert (int); namespace std { extern int strcmp (const char *, const char *); } // Namespaces, exceptions, and templates were all added after "C++ 2.0". using std::exception; using std::strcmp; namespace { void test_exception_syntax() { try { throw "test"; } catch (const char *s) { // Extra parentheses suppress a warning when building autoconf itself, // due to lint rules shared with more typical C programs. assert (!(strcmp) (s, "test")); } } template struct test_template { T const val; explicit test_template(T t) : val(t) {} template T add(U u) { return static_cast(u) + val; } }; } // anonymous namespace ' # Test code for whether the C++ compiler supports C++98 (body of main) ac_cxx_conftest_cxx98_main=' assert (argc); assert (! argv[0]); { test_exception_syntax (); test_template tt (2.0); assert (tt.add (4) == 6.0); assert (true && !false); } ' # Test code for whether the C++ compiler supports C++11 (global declarations) ac_cxx_conftest_cxx11_globals=' // Does the compiler advertise C++ 2011 conformance? #if !defined __cplusplus || __cplusplus < 201103L # error "Compiler does not advertise C++11 conformance" #endif namespace cxx11test { constexpr int get_val() { return 20; } struct testinit { int i; double d; }; class delegate { public: delegate(int n) : n(n) {} delegate(): delegate(2354) {} virtual int getval() { return this->n; }; protected: int n; }; class overridden : public delegate { public: overridden(int n): delegate(n) {} virtual int getval() override final { return this->n * 2; } }; class nocopy { public: nocopy(int i): i(i) {} nocopy() = default; nocopy(const nocopy&) = delete; nocopy & operator=(const nocopy&) = delete; private: int i; }; // for testing lambda expressions template Ret eval(Fn f, Ret v) { return f(v); } // for testing variadic templates and trailing return types template auto sum(V first) -> V { return first; } template auto sum(V first, Args... rest) -> V { return first + sum(rest...); } } ' # Test code for whether the C++ compiler supports C++11 (body of main) ac_cxx_conftest_cxx11_main=' { // Test auto and decltype auto a1 = 6538; auto a2 = 48573953.4; auto a3 = "String literal"; int total = 0; for (auto i = a3; *i; ++i) { total += *i; } decltype(a2) a4 = 34895.034; } { // Test constexpr short sa[cxx11test::get_val()] = { 0 }; } { // Test initializer lists cxx11test::testinit il = { 4323, 435234.23544 }; } { // Test range-based for int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; for (auto &x : array) { x += 23; } } { // Test lambda expressions using cxx11test::eval; assert (eval ([](int x) { return x*2; }, 21) == 42); double d = 2.0; assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0); assert (d == 5.0); assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0); assert (d == 5.0); } { // Test use of variadic templates using cxx11test::sum; auto a = sum(1); auto b = sum(1, 2); auto c = sum(1.0, 2.0, 3.0); } { // Test constructor delegation cxx11test::delegate d1; cxx11test::delegate d2(); cxx11test::delegate d3(45); } { // Test override and final cxx11test::overridden o1(55464); } { // Test nullptr char *c = nullptr; } { // Test template brackets test_template<::test_template> v(test_template(12)); } { // Unicode literals char const *utf8 = u8"UTF-8 string \u2500"; char16_t const *utf16 = u"UTF-8 string \u2500"; char32_t const *utf32 = U"UTF-32 string \u2500"; } ' # Test code for whether the C compiler supports C++11 (complete). ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals} ${ac_cxx_conftest_cxx11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_cxx_conftest_cxx98_main} ${ac_cxx_conftest_cxx11_main} return ok; } " # Test code for whether the C compiler supports C++98 (complete). ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals} int main (int argc, char **argv) { int ok = 0; ${ac_cxx_conftest_cxx98_main} return ok; } " # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # If a bootstrap compiler has been built, always use it PATH_PREPEND= PRE_BOOTSTRAP_PATH="$PATH" if test -x bootstrap/ocaml/bin/ocamlc -o -x bootstrap/ocaml/bin/ocamlopt then : echo Bootstrap compiler found -- activating unset OCAMLLIB export PATH_PREPEND=`pwd`/bootstrap/ocaml/bin: export PATH="$PATH_PREPEND$PATH" fi # XXX This isn't strictly correct for Windows MIN_OCAML_VERSION=4.02.3 # checking for ocamlc if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlc", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OCAMLC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OCAMLC"; then ac_cv_prog_OCAMLC="$OCAMLC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLC="${ac_tool_prefix}ocamlc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLC=$ac_cv_prog_OCAMLC if test -n "$OCAMLC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OCAMLC" >&5 printf "%s\n" "$OCAMLC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLC"; then ac_ct_OCAMLC=$OCAMLC # Extract the first word of "ocamlc", so it can be a program name with args. set dummy ocamlc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OCAMLC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OCAMLC"; then ac_cv_prog_ac_ct_OCAMLC="$ac_ct_OCAMLC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLC="ocamlc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLC=$ac_cv_prog_ac_ct_OCAMLC if test -n "$ac_ct_OCAMLC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLC" >&5 printf "%s\n" "$ac_ct_OCAMLC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OCAMLC" = x; then OCAMLC="no" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLC=$ac_ct_OCAMLC fi else OCAMLC="$ac_cv_prog_OCAMLC" fi if test "$OCAMLC" != "no"; then OCAMLVERSION=`$OCAMLC -v | tr -d '\015' | sed -n -e 's|.*version* *\(.*\)$|\1|p'` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: OCaml version is $OCAMLVERSION" >&5 printf "%s\n" "OCaml version is $OCAMLVERSION" >&6; } # If OCAMLLIB is set, use it if test "$OCAMLLIB" = ""; then OCAMLLIB=`$OCAMLC -where 2>/dev/null | tr -d '\015' || $OCAMLC -v|tail -1|cut -d ' ' -f 4` else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: OCAMLLIB previously set; preserving it." >&5 printf "%s\n" "OCAMLLIB previously set; preserving it." >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: OCaml library path is $OCAMLLIB" >&5 printf "%s\n" "OCaml library path is $OCAMLLIB" >&6; } # checking for ocamlopt if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlopt", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlopt; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OCAMLOPT+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OCAMLOPT"; then ac_cv_prog_OCAMLOPT="$OCAMLOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLOPT="${ac_tool_prefix}ocamlopt" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLOPT=$ac_cv_prog_OCAMLOPT if test -n "$OCAMLOPT"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OCAMLOPT" >&5 printf "%s\n" "$OCAMLOPT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLOPT"; then ac_ct_OCAMLOPT=$OCAMLOPT # Extract the first word of "ocamlopt", so it can be a program name with args. set dummy ocamlopt; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OCAMLOPT+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OCAMLOPT"; then ac_cv_prog_ac_ct_OCAMLOPT="$ac_ct_OCAMLOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLOPT="ocamlopt" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLOPT=$ac_cv_prog_ac_ct_OCAMLOPT if test -n "$ac_ct_OCAMLOPT"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLOPT" >&5 printf "%s\n" "$ac_ct_OCAMLOPT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OCAMLOPT" = x; then OCAMLOPT="no" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLOPT=$ac_ct_OCAMLOPT fi else OCAMLOPT="$ac_cv_prog_OCAMLOPT" fi OCAMLBEST=byte if test "$OCAMLOPT" = "no"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find ocamlopt; bytecode compilation only." >&5 printf "%s\n" "$as_me: WARNING: Cannot find ocamlopt; bytecode compilation only." >&2;} else TMPVERSION=`$OCAMLOPT -v | tr -d '\015' | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` if test "$TMPVERSION" != "$OCAMLVERSION" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlopt discarded." >&5 printf "%s\n" "versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlopt discarded." >&6; } OCAMLOPT=no else OCAMLBEST=opt fi fi # checking for ocamlc.opt if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlc.opt", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlc.opt; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OCAMLCDOTOPT+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OCAMLCDOTOPT"; then ac_cv_prog_OCAMLCDOTOPT="$OCAMLCDOTOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLCDOTOPT="${ac_tool_prefix}ocamlc.opt" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLCDOTOPT=$ac_cv_prog_OCAMLCDOTOPT if test -n "$OCAMLCDOTOPT"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OCAMLCDOTOPT" >&5 printf "%s\n" "$OCAMLCDOTOPT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLCDOTOPT"; then ac_ct_OCAMLCDOTOPT=$OCAMLCDOTOPT # Extract the first word of "ocamlc.opt", so it can be a program name with args. set dummy ocamlc.opt; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OCAMLCDOTOPT+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OCAMLCDOTOPT"; then ac_cv_prog_ac_ct_OCAMLCDOTOPT="$ac_ct_OCAMLCDOTOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLCDOTOPT="ocamlc.opt" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLCDOTOPT=$ac_cv_prog_ac_ct_OCAMLCDOTOPT if test -n "$ac_ct_OCAMLCDOTOPT"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLCDOTOPT" >&5 printf "%s\n" "$ac_ct_OCAMLCDOTOPT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OCAMLCDOTOPT" = x; then OCAMLCDOTOPT="no" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLCDOTOPT=$ac_ct_OCAMLCDOTOPT fi else OCAMLCDOTOPT="$ac_cv_prog_OCAMLCDOTOPT" fi if test "$OCAMLCDOTOPT" != "no"; then TMPVERSION=`$OCAMLCDOTOPT -v | tr -d '\015' | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` if test "$TMPVERSION" != "$OCAMLVERSION" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlc.opt discarded." >&5 printf "%s\n" "versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlc.opt discarded." >&6; } else OCAMLC=$OCAMLCDOTOPT fi fi # checking for ocamlopt.opt if test "$OCAMLOPT" != "no" ; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlopt.opt", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlopt.opt; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OCAMLOPTDOTOPT+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OCAMLOPTDOTOPT"; then ac_cv_prog_OCAMLOPTDOTOPT="$OCAMLOPTDOTOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLOPTDOTOPT="${ac_tool_prefix}ocamlopt.opt" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLOPTDOTOPT=$ac_cv_prog_OCAMLOPTDOTOPT if test -n "$OCAMLOPTDOTOPT"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OCAMLOPTDOTOPT" >&5 printf "%s\n" "$OCAMLOPTDOTOPT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLOPTDOTOPT"; then ac_ct_OCAMLOPTDOTOPT=$OCAMLOPTDOTOPT # Extract the first word of "ocamlopt.opt", so it can be a program name with args. set dummy ocamlopt.opt; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OCAMLOPTDOTOPT+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OCAMLOPTDOTOPT"; then ac_cv_prog_ac_ct_OCAMLOPTDOTOPT="$ac_ct_OCAMLOPTDOTOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLOPTDOTOPT="ocamlopt.opt" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLOPTDOTOPT=$ac_cv_prog_ac_ct_OCAMLOPTDOTOPT if test -n "$ac_ct_OCAMLOPTDOTOPT"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLOPTDOTOPT" >&5 printf "%s\n" "$ac_ct_OCAMLOPTDOTOPT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OCAMLOPTDOTOPT" = x; then OCAMLOPTDOTOPT="no" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLOPTDOTOPT=$ac_ct_OCAMLOPTDOTOPT fi else OCAMLOPTDOTOPT="$ac_cv_prog_OCAMLOPTDOTOPT" fi if test "$OCAMLOPTDOTOPT" != "no"; then TMPVERSION=`$OCAMLOPTDOTOPT -v | tr -d '\015' | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` if test "$TMPVERSION" != "$OCAMLVERSION" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlopt.opt discarded." >&5 printf "%s\n" "versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlopt.opt discarded." >&6; } else OCAMLOPT=$OCAMLOPTDOTOPT fi fi fi fi # checking for ocaml toplevel if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocaml", so it can be a program name with args. set dummy ${ac_tool_prefix}ocaml; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OCAML+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OCAML"; then ac_cv_prog_OCAML="$OCAML" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OCAML="${ac_tool_prefix}ocaml" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAML=$ac_cv_prog_OCAML if test -n "$OCAML"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OCAML" >&5 printf "%s\n" "$OCAML" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAML"; then ac_ct_OCAML=$OCAML # Extract the first word of "ocaml", so it can be a program name with args. set dummy ocaml; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OCAML+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OCAML"; then ac_cv_prog_ac_ct_OCAML="$ac_ct_OCAML" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAML="ocaml" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAML=$ac_cv_prog_ac_ct_OCAML if test -n "$ac_ct_OCAML"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAML" >&5 printf "%s\n" "$ac_ct_OCAML" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OCAML" = x; then OCAML="no" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAML=$ac_ct_OCAML fi else OCAML="$ac_cv_prog_OCAML" fi # checking for ocamldep if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamldep", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamldep; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OCAMLDEP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OCAMLDEP"; then ac_cv_prog_OCAMLDEP="$OCAMLDEP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLDEP="${ac_tool_prefix}ocamldep" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLDEP=$ac_cv_prog_OCAMLDEP if test -n "$OCAMLDEP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OCAMLDEP" >&5 printf "%s\n" "$OCAMLDEP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLDEP"; then ac_ct_OCAMLDEP=$OCAMLDEP # Extract the first word of "ocamldep", so it can be a program name with args. set dummy ocamldep; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OCAMLDEP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OCAMLDEP"; then ac_cv_prog_ac_ct_OCAMLDEP="$ac_ct_OCAMLDEP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLDEP="ocamldep" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLDEP=$ac_cv_prog_ac_ct_OCAMLDEP if test -n "$ac_ct_OCAMLDEP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLDEP" >&5 printf "%s\n" "$ac_ct_OCAMLDEP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OCAMLDEP" = x; then OCAMLDEP="no" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLDEP=$ac_ct_OCAMLDEP fi else OCAMLDEP="$ac_cv_prog_OCAMLDEP" fi # checking for ocamldep.opt if test "$OCAMLDEP" != "no" ; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamldep.opt", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamldep.opt; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OCAMLDEPDOTOPT+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OCAMLDEPDOTOPT"; then ac_cv_prog_OCAMLDEPDOTOPT="$OCAMLDEPDOTOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLDEPDOTOPT="${ac_tool_prefix}ocamldep.opt" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLDEPDOTOPT=$ac_cv_prog_OCAMLDEPDOTOPT if test -n "$OCAMLDEPDOTOPT"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OCAMLDEPDOTOPT" >&5 printf "%s\n" "$OCAMLDEPDOTOPT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLDEPDOTOPT"; then ac_ct_OCAMLDEPDOTOPT=$OCAMLDEPDOTOPT # Extract the first word of "ocamldep.opt", so it can be a program name with args. set dummy ocamldep.opt; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OCAMLDEPDOTOPT+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OCAMLDEPDOTOPT"; then ac_cv_prog_ac_ct_OCAMLDEPDOTOPT="$ac_ct_OCAMLDEPDOTOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLDEPDOTOPT="ocamldep.opt" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLDEPDOTOPT=$ac_cv_prog_ac_ct_OCAMLDEPDOTOPT if test -n "$ac_ct_OCAMLDEPDOTOPT"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLDEPDOTOPT" >&5 printf "%s\n" "$ac_ct_OCAMLDEPDOTOPT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OCAMLDEPDOTOPT" = x; then OCAMLDEPDOTOPT="no" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLDEPDOTOPT=$ac_ct_OCAMLDEPDOTOPT fi else OCAMLDEPDOTOPT="$ac_cv_prog_OCAMLDEPDOTOPT" fi if test "$OCAMLDEPDOTOPT" != "no"; then TMPVERSION=`$OCAMLDEPDOTOPT -version | tr -d '\015' | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` if test "$TMPVERSION" != "$OCAMLVERSION" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: version differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamldep.opt discarded." >&5 printf "%s\n" "version differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamldep.opt discarded." >&6; } else OCAMLDEP=$OCAMLDEPDOTOPT fi fi fi # checking for ocamlmktop if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlmktop", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlmktop; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OCAMLMKTOP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OCAMLMKTOP"; then ac_cv_prog_OCAMLMKTOP="$OCAMLMKTOP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLMKTOP="${ac_tool_prefix}ocamlmktop" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLMKTOP=$ac_cv_prog_OCAMLMKTOP if test -n "$OCAMLMKTOP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OCAMLMKTOP" >&5 printf "%s\n" "$OCAMLMKTOP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLMKTOP"; then ac_ct_OCAMLMKTOP=$OCAMLMKTOP # Extract the first word of "ocamlmktop", so it can be a program name with args. set dummy ocamlmktop; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OCAMLMKTOP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OCAMLMKTOP"; then ac_cv_prog_ac_ct_OCAMLMKTOP="$ac_ct_OCAMLMKTOP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLMKTOP="ocamlmktop" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLMKTOP=$ac_cv_prog_ac_ct_OCAMLMKTOP if test -n "$ac_ct_OCAMLMKTOP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLMKTOP" >&5 printf "%s\n" "$ac_ct_OCAMLMKTOP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OCAMLMKTOP" = x; then OCAMLMKTOP="no" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLMKTOP=$ac_ct_OCAMLMKTOP fi else OCAMLMKTOP="$ac_cv_prog_OCAMLMKTOP" fi # checking for ocamlmklib if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlmklib", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlmklib; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OCAMLMKLIB+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OCAMLMKLIB"; then ac_cv_prog_OCAMLMKLIB="$OCAMLMKLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLMKLIB="${ac_tool_prefix}ocamlmklib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLMKLIB=$ac_cv_prog_OCAMLMKLIB if test -n "$OCAMLMKLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OCAMLMKLIB" >&5 printf "%s\n" "$OCAMLMKLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLMKLIB"; then ac_ct_OCAMLMKLIB=$OCAMLMKLIB # Extract the first word of "ocamlmklib", so it can be a program name with args. set dummy ocamlmklib; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OCAMLMKLIB+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OCAMLMKLIB"; then ac_cv_prog_ac_ct_OCAMLMKLIB="$ac_ct_OCAMLMKLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLMKLIB="ocamlmklib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLMKLIB=$ac_cv_prog_ac_ct_OCAMLMKLIB if test -n "$ac_ct_OCAMLMKLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLMKLIB" >&5 printf "%s\n" "$ac_ct_OCAMLMKLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OCAMLMKLIB" = x; then OCAMLMKLIB="no" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLMKLIB=$ac_ct_OCAMLMKLIB fi else OCAMLMKLIB="$ac_cv_prog_OCAMLMKLIB" fi # checking for ocamldoc if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamldoc", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamldoc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OCAMLDOC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OCAMLDOC"; then ac_cv_prog_OCAMLDOC="$OCAMLDOC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLDOC="${ac_tool_prefix}ocamldoc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLDOC=$ac_cv_prog_OCAMLDOC if test -n "$OCAMLDOC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OCAMLDOC" >&5 printf "%s\n" "$OCAMLDOC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLDOC"; then ac_ct_OCAMLDOC=$OCAMLDOC # Extract the first word of "ocamldoc", so it can be a program name with args. set dummy ocamldoc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OCAMLDOC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OCAMLDOC"; then ac_cv_prog_ac_ct_OCAMLDOC="$ac_ct_OCAMLDOC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLDOC="ocamldoc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLDOC=$ac_cv_prog_ac_ct_OCAMLDOC if test -n "$ac_ct_OCAMLDOC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLDOC" >&5 printf "%s\n" "$ac_ct_OCAMLDOC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OCAMLDOC" = x; then OCAMLDOC="no" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLDOC=$ac_ct_OCAMLDOC fi else OCAMLDOC="$ac_cv_prog_OCAMLDOC" fi # checking for ocamldoc.opt if test "$OCAMLDOC" != "no" ; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamldoc.opt", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamldoc.opt; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OCAMLDOCDOTOPT+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OCAMLDOCDOTOPT"; then ac_cv_prog_OCAMLDOCDOTOPT="$OCAMLDOCDOTOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLDOCDOTOPT="${ac_tool_prefix}ocamldoc.opt" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLDOCDOTOPT=$ac_cv_prog_OCAMLDOCDOTOPT if test -n "$OCAMLDOCDOTOPT"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OCAMLDOCDOTOPT" >&5 printf "%s\n" "$OCAMLDOCDOTOPT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLDOCDOTOPT"; then ac_ct_OCAMLDOCDOTOPT=$OCAMLDOCDOTOPT # Extract the first word of "ocamldoc.opt", so it can be a program name with args. set dummy ocamldoc.opt; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OCAMLDOCDOTOPT+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OCAMLDOCDOTOPT"; then ac_cv_prog_ac_ct_OCAMLDOCDOTOPT="$ac_ct_OCAMLDOCDOTOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLDOCDOTOPT="ocamldoc.opt" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLDOCDOTOPT=$ac_cv_prog_ac_ct_OCAMLDOCDOTOPT if test -n "$ac_ct_OCAMLDOCDOTOPT"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLDOCDOTOPT" >&5 printf "%s\n" "$ac_ct_OCAMLDOCDOTOPT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OCAMLDOCDOTOPT" = x; then OCAMLDOCDOTOPT="no" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLDOCDOTOPT=$ac_ct_OCAMLDOCDOTOPT fi else OCAMLDOCDOTOPT="$ac_cv_prog_OCAMLDOCDOTOPT" fi if test "$OCAMLDOCDOTOPT" != "no"; then TMPVERSION=`$OCAMLDOCDOTOPT -version | tr -d '\015'` if test "$TMPVERSION" != "$OCAMLVERSION" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: version differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamldoc.opt discarded." >&5 printf "%s\n" "version differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamldoc.opt discarded." >&6; } else OCAMLDOC=$OCAMLDOCDOTOPT fi fi fi # checking for ocamlbuild if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlbuild", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlbuild; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OCAMLBUILD+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OCAMLBUILD"; then ac_cv_prog_OCAMLBUILD="$OCAMLBUILD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLBUILD="${ac_tool_prefix}ocamlbuild" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLBUILD=$ac_cv_prog_OCAMLBUILD if test -n "$OCAMLBUILD"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OCAMLBUILD" >&5 printf "%s\n" "$OCAMLBUILD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLBUILD"; then ac_ct_OCAMLBUILD=$OCAMLBUILD # Extract the first word of "ocamlbuild", so it can be a program name with args. set dummy ocamlbuild; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OCAMLBUILD+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OCAMLBUILD"; then ac_cv_prog_ac_ct_OCAMLBUILD="$ac_ct_OCAMLBUILD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLBUILD="ocamlbuild" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLBUILD=$ac_cv_prog_ac_ct_OCAMLBUILD if test -n "$ac_ct_OCAMLBUILD"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLBUILD" >&5 printf "%s\n" "$ac_ct_OCAMLBUILD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OCAMLBUILD" = x; then OCAMLBUILD="no" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLBUILD=$ac_ct_OCAMLBUILD fi else OCAMLBUILD="$ac_cv_prog_OCAMLBUILD" fi if test "x$OCAMLC" = "xno"; then as_fn_error $? "You must install the OCaml compiler, at least version $MIN_OCAML_VERSION (or run: make compiler)" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking OCaml Sys.os_type" >&5 printf %s "checking OCaml Sys.os_type... " >&6; } cat > conftest.ml <&5 printf "%s\n" "$OCAML_OS_TYPE" >&6; } if test "${OCAML_OS_TYPE}" = "Win32" then : OCAMLLIB="$(echo "${OCAMLLIB}" | tr -d '\015' | sed -e 's|\\|/|g')" WIN32=1 EXE=.exe else $as_nop EXE= WIN32=0 fi # AC_PREFIX_DEFAULT must be at the top level, which is the reason for the # somewhat convoluted pair of sed expressions... # Check whether --enable-version_check was given. if test ${enable_version_check+y} then : enableval=$enable_version_check; fi # Check whether --enable-checks was given. if test ${enable_checks+y} then : enableval=$enable_checks; fi # Check whether --enable-developer_mode was given. if test ${enable_developer_mode+y} then : enableval=$enable_developer_mode; fi # Check whether --with-mccs was given. if test ${with_mccs+y} then : withval=$with_mccs; else $as_nop MCCS_DEFAULT=yes fi # Check whether --with-0install-solver was given. if test ${with_0install_solver+y} then : withval=$with_0install_solver; fi # Check whether --with-libacl was given. if test ${with_libacl+y} then : withval=$with_libacl; else $as_nop with_libacl=auto fi # Check whether --with-private_runtime was given. if test ${with_private_runtime+y} then : withval=$with_private_runtime; else $as_nop with_private_runtime=no fi # Check whether --enable-cold_check was given. if test ${enable_cold_check+y} then : enableval=$enable_cold_check; COLD_CHECK=yes fi if test "x" != "x$LIB_PREFIX" then : CPATH=$CPATH:$LIB_PREFIX/include LIBRARY_PATH=$LIBRARY_PATH:$LIB_PREFIX/lib export CPATH LIBRARY_PATH fi LIB_PREFIX=$LIB_PREFIX CPATH=$CPATH LIBRARY_PATH=$LIBRARY_PATH # Check that OCaml version is greater or equal to 4.02.3 # Native Windows builds require at least 4.06.0 for the Unicode runtime. for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 printf "%s\n" "$AWK" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AWK" && break done if test "x${enable_version_check}" != "xno" then : if test ${WIN32} -eq 1 then : MIN_OCAML_VERSION=4.06.0 fi # Used to indicate true or false condition ax_compare_version=false # Convert the two version strings to be compared into a format that # allows a simple string comparison. The end result is that a version # string of the form 1.12.5-r617 will be converted to the form # 0001001200050617. In other words, each number is zero padded to four # digits, and non digits are removed. ax_compare_version_A=`echo "$OCAMLVERSION" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/[^0-9]//g'` ax_compare_version_B=`echo "$MIN_OCAML_VERSION" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/[^0-9]//g'` ax_compare_version=`echo "x$ax_compare_version_A x$ax_compare_version_B" | sed 's/^ *//' | sort -r | sed "s/x${ax_compare_version_A}/false/;s/x${ax_compare_version_B}/true/;1q"` if test "$ax_compare_version" = "true" ; then as_fn_error $? "Your version of OCaml: $OCAMLVERSION is not supported" "$LINENO" 5 fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for compiler type" >&5 printf %s "checking for compiler type... " >&6; } CCOMP_TYPE=`$OCAML shell/print_config.ml ccomp_type 2>/dev/null | fgrep -v "Cannot find" || $OCAMLC -config | tr -d '\r' | sed -n -e "s/ccomp_type: //p"` if test "$?" -eq 0 then : else $as_nop as_fn_error $? "failed" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CCOMP_TYPE" >&5 printf "%s\n" "$CCOMP_TYPE" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for compiler architecture" >&5 printf %s "checking for compiler architecture... " >&6; } ARCH=`$OCAML shell/print_config.ml arch 2>/dev/null | fgrep -v "Cannot find" || $OCAMLC -config | tr -d '\r' | sed -n -e "s/architecture: //p"` if test "$?" -eq 0 then : else $as_nop as_fn_error $? "failed" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ARCH" >&5 printf "%s\n" "$ARCH" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for compiler system" >&5 printf %s "checking for compiler system... " >&6; } SYSTEM=`$OCAML shell/print_config.ml system 2>/dev/null | fgrep -v "Cannot find" || $OCAMLC -config | tr -d '\r' | sed -n -e "s/system: //p"` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SYSTEM" >&5 printf "%s\n" "$SYSTEM" >&6; } LIB_PREPEND= INC_PREPEND= # Need the C compiler used for OCaml (important on Windows, as both x86 and x64 are used) if test "$OCAMLBEST" = "opt" then : OCAMLBESTCC=$OCAMLOPT else $as_nop OCAMLBESTCC=$OCAMLC fi OCAML_CC="$($OCAMLBESTCC -config | sed -n -e "s/native_c_compiler: \(.*\) .*/\1/p")" set dummy ${OCAML_CC}; OCAML_TEST_CC=$2 if test ! -x ${OCAML_TEST_CC} then : if test "x${CCOMP_TYPE}" = "xmsvc" then : if test "${ARCH}" = "i386" then : SDK_ARCH=x86 else $as_nop SDK_ARCH=x64 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for an installed Microsoft C Compiler for ${SDK_ARCH}" >&5 printf %s "checking for an installed Microsoft C Compiler for ${SDK_ARCH}... " >&6; } eval `PATH="$PRE_BOOTSTRAP_PATH" bash ./shell/msvs-detect --arch=$SDK_ARCH; echo RESULT=$?` if test "x$MSVS_NAME" = "x" then : if test ${RESULT} -eq 0 then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: from PATH" >&5 printf "%s\n" "from PATH" >&6; } else $as_nop as_fn_error $? "no" "$LINENO" 5 fi else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: from $MSVS_NAME" >&5 printf "%s\n" "from $MSVS_NAME" >&6; } export PATH_PREPEND="${MSVS_PATH}${PATH_PREPEND}" # Note that we put ${MSVS_PATH} here NOT ${PATH_PREPEND} so that the bootstrap path isn't repeated export PATH="${MSVS_PATH}$PATH" LIB_PREPEND="${MSVS_LIB}" INC_PREPEND="${MSVS_INC}" export Lib="${MSVS_LIB}$LIB" export Include="${MSVS_INC}$INCLUDE" fi fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then for ac_prog in "${OCAML_CC}" gcc cc do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in "${OCAML_CC}" gcc cc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else $as_nop ac_file='' fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test "x${enable_developer_mode}" = "xyes" then : DEVELOPER=true echo "-D" > src/core/developer echo "DEVELOPER" >> src/core/developer else $as_nop DEVELOPER=false rm -f src/core/developer fi if test "x${with_mccs}" = "xno" then : MCCS_ENABLED=false else $as_nop MCCS_ENABLED=true fi if test "x${with_0install_solver}" = "xyes" then : OPAM_0INSTALL_SOLVER_ENABLED=true else $as_nop OPAM_0INSTALL_SOLVER_ENABLED=false fi ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi if test "x${with_libacl}" != "xno" then : have_libacl=yes ac_fn_c_check_header_compile "$LINENO" "acl/libacl.h" "ac_cv_header_acl_libacl_h" "$ac_includes_default" if test "x$ac_cv_header_acl_libacl_h" = xyes then : else $as_nop have_libacl=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing acl_get_perm" >&5 printf %s "checking for library containing acl_get_perm... " >&6; } if test ${ac_cv_search_acl_get_perm+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char acl_get_perm (); int main (void) { return acl_get_perm (); ; return 0; } _ACEOF for ac_lib in '' acl do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_acl_get_perm=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_acl_get_perm+y} then : break fi done if test ${ac_cv_search_acl_get_perm+y} then : else $as_nop ac_cv_search_acl_get_perm=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_acl_get_perm" >&5 printf "%s\n" "$ac_cv_search_acl_get_perm" >&6; } ac_res=$ac_cv_search_acl_get_perm if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" else $as_nop have_libacl=no fi if test "x${SYSTEM}" = "xcygwin" then : if test "x${have_libacl}" = "xno" then : as_fn_error $? "opam on Cygwin requires libacl" "$LINENO" 5 else $as_nop with_libacl=yes fi fi if test "x${with_libacl}${have_libacl}" = "xyesno" then : as_fn_error $? "libacl not found" "$LINENO" 5 fi fi if test "x${with_libacl}" = "xyes" then : if test "x${ac_cv_search_acl_get_perm}" = "xnone required" then : else $as_nop CONF_LIBACL_LINK=${ac_cv_search_acl_get_perm} fi fi CONF_OCAMLFLAGS="-w -67" if test "x${CI}" != "x" then : CONF_OCAMLFLAGS="${CONF_OCAMLFLAGS} -w -67" fi if test "x${CI}" != "x" -o "x${enable_developer_mode}" = "xyes" then : if test "x${CCOMP_TYPE}" = "xmsvc" then : CONF_CFLAGS="\"/WX\"" else $as_nop CONF_CFLAGS="-Werror" fi else $as_nop CONF_CFLAGS= fi if test ${WIN32} -eq 1 -a "$GCC" = "yes" then : # Pre-Visual Studio 2013 Microsoft C compiler adhere to the C89 standard, well # at least the bit of it which requires variable declarations to appear before # statements. Adding this warning to GCC prevents accidentally using C99 and # then getting unexpected C2143 errors from older Microsoft C compilers. I'm # not aware of an equivalent option for the Microsoft C compiler. CC="$CC -Wdeclaration-after-statement" fi if test ${WIN32} -eq 1 then : if test "$GCC" = "yes" then : if test "x${CC64}" = "x" then : if test "$ARCH" = "i386" then : T_CC64=x86_64-w64-mingw32-gcc else $as_nop T_CC64=i686-w64-mingw32-gcc fi fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}${T_CC64}", so it can be a program name with args. set dummy ${ac_tool_prefix}${T_CC64}; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC64+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC64"; then ac_cv_prog_CC64="$CC64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC64="${ac_tool_prefix}${T_CC64}" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC64=$ac_cv_prog_CC64 if test -n "$CC64"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC64" >&5 printf "%s\n" "$CC64" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC64"; then ac_ct_CC64=$CC64 # Extract the first word of "${T_CC64}", so it can be a program name with args. set dummy ${T_CC64}; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC64+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC64"; then ac_cv_prog_ac_ct_CC64="$ac_ct_CC64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC64="${T_CC64}" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC64=$ac_cv_prog_ac_ct_CC64 if test -n "$ac_ct_CC64"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC64" >&5 printf "%s\n" "$ac_ct_CC64" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC64" = x; then CC64="no" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC64=$ac_ct_CC64 fi else CC64="$ac_cv_prog_CC64" fi if test "x${CC64}" != "xno" then : echo "${CC64} -o " > src/stubs/win32/cc64 echo " -Wdeclaration-after-statement " >> src/stubs/win32/cc64 fi else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether Microsoft Linker needs a PATH shim" >&5 printf %s "checking whether Microsoft Linker needs a PATH shim... " >&6; } PREV_PREPEND="$PATH_PREPEND" PATH_PREPEND=$(bash ./shell/check_linker) if test "x${PATH_PREPEND}" = "x${PREV_PREPEND}" then : PATH_PREPEND_RESULT=no else $as_nop PATH_PREPEND_RESULT=yes fi PATH_PREPEND=`echo "${PATH_PREPEND}" | sed -e 's/#/\\\\#/g' -e 's/\\$/$$/g'` LIB_PREPEND=`echo ${LIB_PREPEND} | sed -e 's/#/\\\\#/g' -e 's/\\$/$$/g'` INC_PREPEND=`echo ${INC_PREPEND} | sed -e 's/#/\\\\#/g' -e 's/\\$/$$/g'` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PATH_PREPEND_RESULT" >&5 printf "%s\n" "$PATH_PREPEND_RESULT" >&6; } if test "$ARCH" = "i386" then : COMP_ARCH=x64 else $as_nop COMP_ARCH=x86 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a way to invoke an $COMP_ARCH C compiler" >&5 printf %s "checking for a way to invoke an $COMP_ARCH C compiler... " >&6; } eval `PATH="$PRE_BOOTSTRAP_PATH" bash ./shell/msvs-detect --arch=$COMP_ARCH` if test "x$MSVS_NAME" = "x" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } CC64=no else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: from $MSVS_NAME" >&5 printf "%s\n" "from $MSVS_NAME" >&6; } CL_FULL="`PATH="${MSVS_PATH}:${PATH}" which cl | cygpath -f - -w`" MSVS_PATH="`echo "${MSVS_PATH}" | cygpath -f - -wp`" echo "cl /nologo /Fe" > src/stubs/win32/cc64 echo " " >> src/stubs/win32/cc64 echo "PATH" >> src/stubs/win32/cc64 echo "${MSVS_PATH}" >> src/stubs/win32/cc64 echo "LIB" >> src/stubs/win32/cc64 echo "${MSVS_LIB}" >> src/stubs/win32/cc64 echo "INCLUDE" >> src/stubs/win32/cc64 echo "${MSVS_INC}" >> src/stubs/win32/cc64 fi fi if test "x${CC64}" = "xno" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Complementary C compiler not found - opam-putenv will not be built" >&5 printf "%s\n" "$as_me: WARNING: Complementary C compiler not found - opam-putenv will not be built" >&2;} fi fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlobjinfo", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlobjinfo; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OCAMLOBJINFO+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OCAMLOBJINFO"; then ac_cv_prog_OCAMLOBJINFO="$OCAMLOBJINFO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLOBJINFO="${ac_tool_prefix}ocamlobjinfo" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLOBJINFO=$ac_cv_prog_OCAMLOBJINFO if test -n "$OCAMLOBJINFO"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OCAMLOBJINFO" >&5 printf "%s\n" "$OCAMLOBJINFO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLOBJINFO"; then ac_ct_OCAMLOBJINFO=$OCAMLOBJINFO # Extract the first word of "ocamlobjinfo", so it can be a program name with args. set dummy ocamlobjinfo; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OCAMLOBJINFO+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OCAMLOBJINFO"; then ac_cv_prog_ac_ct_OCAMLOBJINFO="$ac_ct_OCAMLOBJINFO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLOBJINFO="ocamlobjinfo" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLOBJINFO=$ac_cv_prog_ac_ct_OCAMLOBJINFO if test -n "$ac_ct_OCAMLOBJINFO"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLOBJINFO" >&5 printf "%s\n" "$ac_ct_OCAMLOBJINFO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OCAMLOBJINFO" = x; then OCAMLOBJINFO="no" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLOBJINFO=$ac_ct_OCAMLOBJINFO fi else OCAMLOBJINFO="$ac_cv_prog_OCAMLOBJINFO" fi # checking for ocamlfind if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlfind", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlfind; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OCAMLFIND+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OCAMLFIND"; then ac_cv_prog_OCAMLFIND="$OCAMLFIND" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLFIND="${ac_tool_prefix}ocamlfind" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLFIND=$ac_cv_prog_OCAMLFIND if test -n "$OCAMLFIND"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OCAMLFIND" >&5 printf "%s\n" "$OCAMLFIND" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLFIND"; then ac_ct_OCAMLFIND=$OCAMLFIND # Extract the first word of "ocamlfind", so it can be a program name with args. set dummy ocamlfind; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OCAMLFIND+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OCAMLFIND"; then ac_cv_prog_ac_ct_OCAMLFIND="$ac_ct_OCAMLFIND" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLFIND="ocamlfind" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLFIND=$ac_cv_prog_ac_ct_OCAMLFIND if test -n "$ac_ct_OCAMLFIND"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLFIND" >&5 printf "%s\n" "$ac_ct_OCAMLFIND" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OCAMLFIND" = x; then OCAMLFIND="no" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLFIND=$ac_ct_OCAMLFIND fi else OCAMLFIND="$ac_cv_prog_OCAMLFIND" fi if test "$OCAMLFIND" != "no" then : if test "$OCAMLOBJINFO" = "no" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: ocamlobjinfo not found; cannot verify ocamlfind" >&5 printf "%s\n" "$as_me: WARNING: ocamlobjinfo not found; cannot verify ocamlfind" >&2;} else $as_nop if ! $OCAMLOBJINFO `$OCAMLFIND query -predicates byte -a-format findlib | tr -d '\015'` > /dev/null 2>&1 then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: site-lib is for a different version of OCaml; ocamlfind discarded." >&5 printf "%s\n" "site-lib is for a different version of OCaml; ocamlfind discarded." >&6; } OCAMLFIND=no fi fi fi # Check whether --enable-certificate_check was given. if test ${enable_certificate_check+y} then : enableval=$enable_certificate_check; fi if test "x${enable_certificate_check}" = "xno" then : curl_certificate_check=--insecure wget_certificate_check=--no-check-certificate fi for ac_prog in curl wget do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_FETCH+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$FETCH"; then ac_cv_prog_FETCH="$FETCH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_FETCH="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi FETCH=$ac_cv_prog_FETCH if test -n "$FETCH"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FETCH" >&5 printf "%s\n" "$FETCH" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$FETCH" && break done test -n "$FETCH" || FETCH="no" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dune", so it can be a program name with args. set dummy ${ac_tool_prefix}dune; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DUNE+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$DUNE"; then ac_cv_prog_DUNE="$DUNE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_DUNE="${ac_tool_prefix}dune" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUNE=$ac_cv_prog_DUNE if test -n "$DUNE"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DUNE" >&5 printf "%s\n" "$DUNE" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_DUNE"; then ac_ct_DUNE=$DUNE # Extract the first word of "dune", so it can be a program name with args. set dummy dune; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DUNE+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_DUNE"; then ac_cv_prog_ac_ct_DUNE="$ac_ct_DUNE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DUNE="dune" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUNE=$ac_cv_prog_ac_ct_DUNE if test -n "$ac_ct_DUNE"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUNE" >&5 printf "%s\n" "$ac_ct_DUNE" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_DUNE" = x; then DUNE="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUNE=$ac_ct_DUNE fi else DUNE="$ac_cv_prog_DUNE" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cppo", so it can be a program name with args. set dummy ${ac_tool_prefix}cppo; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CPPO+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CPPO"; then ac_cv_prog_CPPO="$CPPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CPPO="${ac_tool_prefix}cppo" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CPPO=$ac_cv_prog_CPPO if test -n "$CPPO"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPPO" >&5 printf "%s\n" "$CPPO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CPPO"; then ac_ct_CPPO=$CPPO # Extract the first word of "cppo", so it can be a program name with args. set dummy cppo; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CPPO+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CPPO"; then ac_cv_prog_ac_ct_CPPO="$ac_ct_CPPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CPPO="cppo" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CPPO=$ac_cv_prog_ac_ct_CPPO if test -n "$ac_ct_CPPO"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CPPO" >&5 printf "%s\n" "$ac_ct_CPPO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CPPO" = x; then CPPO="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CPPO=$ac_ct_CPPO fi else CPPO="$ac_cv_prog_CPPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}patch", so it can be a program name with args. set dummy ${ac_tool_prefix}patch; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_PATCH+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$PATCH"; then ac_cv_prog_PATCH="$PATCH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_PATCH="${ac_tool_prefix}patch" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi PATCH=$ac_cv_prog_PATCH if test -n "$PATCH"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PATCH" >&5 printf "%s\n" "$PATCH" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_PATCH"; then ac_ct_PATCH=$PATCH # Extract the first word of "patch", so it can be a program name with args. set dummy patch; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_PATCH+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_PATCH"; then ac_cv_prog_ac_ct_PATCH="$ac_ct_PATCH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_PATCH="patch" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_PATCH=$ac_cv_prog_ac_ct_PATCH if test -n "$ac_ct_PATCH"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_PATCH" >&5 printf "%s\n" "$ac_ct_PATCH" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_PATCH" = x; then PATCH="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PATCH=$ac_ct_PATCH fi else PATCH="$ac_cv_prog_PATCH" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}bunzip2", so it can be a program name with args. set dummy ${ac_tool_prefix}bunzip2; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_BUNZIP2+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$BUNZIP2"; then ac_cv_prog_BUNZIP2="$BUNZIP2" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_BUNZIP2="${ac_tool_prefix}bunzip2" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi BUNZIP2=$ac_cv_prog_BUNZIP2 if test -n "$BUNZIP2"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BUNZIP2" >&5 printf "%s\n" "$BUNZIP2" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_BUNZIP2"; then ac_ct_BUNZIP2=$BUNZIP2 # Extract the first word of "bunzip2", so it can be a program name with args. set dummy bunzip2; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_BUNZIP2+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_BUNZIP2"; then ac_cv_prog_ac_ct_BUNZIP2="$ac_ct_BUNZIP2" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_BUNZIP2="bunzip2" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_BUNZIP2=$ac_cv_prog_ac_ct_BUNZIP2 if test -n "$ac_ct_BUNZIP2"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_BUNZIP2" >&5 printf "%s\n" "$ac_ct_BUNZIP2" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_BUNZIP2" = x; then BUNZIP2="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac BUNZIP2=$ac_ct_BUNZIP2 fi else BUNZIP2="$ac_cv_prog_BUNZIP2" fi # Used to indicate true or false condition ax_compare_version=false # Convert the two version strings to be compared into a format that # allows a simple string comparison. The end result is that a version # string of the form 1.12.5-r617 will be converted to the form # 0001001200050617. In other words, each number is zero padded to four # digits, and non digits are removed. ax_compare_version_A=`echo "$OCAMLVERSION" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/[^0-9]//g'` ax_compare_version_B=`echo "4.08.0" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/[^0-9]//g'` ax_compare_version=`echo "x$ax_compare_version_A x$ax_compare_version_B" | sed 's/^ *//' | sort -r | sed "s/x${ax_compare_version_A}/false/;s/x${ax_compare_version_B}/true/;1q"` if test "$ax_compare_version" = "true" ; then DUNE_SECONDARY=src_ext/secondary/ocaml/bin/ocaml else DUNE_SECONDARY= fi if test "x${COLD_CHECK}" = "xyes" ; then if test "x$PATCH" = "x" ; then as_fn_error $? "You must have patch installed." "$LINENO" 5 fi if test "x$BUNZIP2" = "x" ; then as_fn_error $? "You must have bunzip2 installed." "$LINENO" 5 fi fi if test "${OCAML_OS_TYPE}" = "Win32" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a workable solution for ln -s" >&5 printf %s "checking for a workable solution for ln -s... " >&6; } ln -s configure conftestLink if test "`cmd /c dir conftestLink 2>/dev/null | fgrep SYMLINK`" = "" then : LN_S="cp -a" else $as_nop LN_S="ln -s" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LN_S" >&5 printf "%s\n" "$LN_S" >&6; } else $as_nop LN_S="ln -s" fi if test x"$FETCH" = x"curl" ; then fetch="curl $curl_certificate_check -LSs -o \$(2) \$(1)" elif test x"$FETCH" = x"wget" ; then fetch="wget $wget_certificate_check -O \$(2) \$(1)" elif test x"${enable_checks}" != x"no" ; then if ! ${MAKE:-make} -q -C src_ext has-archives 2>/dev/null ; then as_fn_error $? "You must have either curl or wget installed." "$LINENO" 5 fi fi if test "x${with_private_runtime}" != "xno" then : if test ${WIN32} -eq 1 -a "x${CCOMP_TYPE}" = "xcc" then : CONF_MANIFEST_O=opam-manifest.o if test "$ARCH" = "i386" then : MANIFEST_ARCH=x86 RUNTIME_GCC_S=libgcc_s_sjlj-1 else $as_nop MANIFEST_ARCH=amd64 RUNTIME_GCC_S=libgcc_s_seh-1 fi else $as_nop CONF_MANIFEST_O= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: --with-private-runtime ignored (not building on mingw)" >&5 printf "%s\n" "$as_me: WARNING: --with-private-runtime ignored (not building on mingw)" >&2;} fi else $as_nop CONF_MANIFEST_O= fi echo { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package unix" >&5 printf %s "checking for OCaml findlib package unix... " >&6; } unset found unset pkg found=no for pkg in unix ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 printf "%s\n" "found" >&6; } OCAML_PKG_unix=$pkg found=yes break fi done if test "$found" = "no" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 printf "%s\n" "not found" >&6; } OCAML_PKG_unix=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package bigarray" >&5 printf %s "checking for OCaml findlib package bigarray... " >&6; } unset found unset pkg found=no for pkg in bigarray ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 printf "%s\n" "found" >&6; } OCAML_PKG_bigarray=$pkg found=yes break fi done if test "$found" = "no" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 printf "%s\n" "not found" >&6; } OCAML_PKG_bigarray=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package extlib" >&5 printf %s "checking for OCaml findlib package extlib... " >&6; } unset found unset pkg found=no for pkg in extlib ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 printf "%s\n" "found" >&6; } OCAML_PKG_extlib=$pkg found=yes break fi done if test "$found" = "no" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 printf "%s\n" "not found" >&6; } OCAML_PKG_extlib=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package re" >&5 printf %s "checking for OCaml findlib package re... " >&6; } unset found unset pkg found=no for pkg in re ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 printf "%s\n" "found" >&6; } OCAML_PKG_re=$pkg found=yes break fi done if test "$found" = "no" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 printf "%s\n" "not found" >&6; } OCAML_PKG_re=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package re.glob" >&5 printf %s "checking for OCaml findlib package re.glob... " >&6; } unset found unset pkg found=no for pkg in re.glob ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 printf "%s\n" "found" >&6; } OCAML_PKG_re_glob=$pkg found=yes break fi done if test "$found" = "no" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 printf "%s\n" "not found" >&6; } OCAML_PKG_re_glob=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package cmdliner" >&5 printf %s "checking for OCaml findlib package cmdliner... " >&6; } unset found unset pkg found=no for pkg in cmdliner ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 printf "%s\n" "found" >&6; } OCAML_PKG_cmdliner=$pkg found=yes break fi done if test "$found" = "no" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 printf "%s\n" "not found" >&6; } OCAML_PKG_cmdliner=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package ocamlgraph" >&5 printf %s "checking for OCaml findlib package ocamlgraph... " >&6; } unset found unset pkg found=no for pkg in ocamlgraph ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 printf "%s\n" "found" >&6; } OCAML_PKG_ocamlgraph=$pkg found=yes break fi done if test "$found" = "no" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 printf "%s\n" "not found" >&6; } OCAML_PKG_ocamlgraph=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package cudf" >&5 printf %s "checking for OCaml findlib package cudf... " >&6; } unset found unset pkg found=no for pkg in cudf ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 printf "%s\n" "found" >&6; } OCAML_PKG_cudf=$pkg found=yes break fi done if test "$found" = "no" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 printf "%s\n" "not found" >&6; } OCAML_PKG_cudf=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package dose3.common" >&5 printf %s "checking for OCaml findlib package dose3.common... " >&6; } unset found unset pkg found=no for pkg in dose3.common dose.common ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 printf "%s\n" "found" >&6; } OCAML_PKG_dose3_common=$pkg found=yes break fi done if test "$found" = "no" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 printf "%s\n" "not found" >&6; } OCAML_PKG_dose3_common=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package dose3.algo" >&5 printf %s "checking for OCaml findlib package dose3.algo... " >&6; } unset found unset pkg found=no for pkg in dose3.algo dose.algo ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 printf "%s\n" "found" >&6; } OCAML_PKG_dose3_algo=$pkg found=yes break fi done if test "$found" = "no" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 printf "%s\n" "not found" >&6; } OCAML_PKG_dose3_algo=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package opam-file-format" >&5 printf %s "checking for OCaml findlib package opam-file-format... " >&6; } unset found unset pkg found=no for pkg in opam-file-format ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 printf "%s\n" "found" >&6; } OCAML_PKG_opam_file_format=$pkg found=yes break fi done if test "$found" = "no" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 printf "%s\n" "not found" >&6; } OCAML_PKG_opam_file_format=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package mccs" >&5 printf %s "checking for OCaml findlib package mccs... " >&6; } unset found unset pkg found=no for pkg in mccs ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 printf "%s\n" "found" >&6; } OCAML_PKG_mccs=$pkg found=yes break fi done if test "$found" = "no" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 printf "%s\n" "not found" >&6; } OCAML_PKG_mccs=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package opam-0install-cudf" >&5 printf %s "checking for OCaml findlib package opam-0install-cudf... " >&6; } unset found unset pkg found=no for pkg in opam-0install-cudf ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 printf "%s\n" "found" >&6; } OCAML_PKG_opam_0install_cudf=$pkg found=yes break fi done if test "$found" = "no" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 printf "%s\n" "not found" >&6; } OCAML_PKG_opam_0install_cudf=no fi if test "x${with_mccs}" = "xno" && test "x$OCAML_PKG_mccs" != "xno" then : as_fn_error $? "Option --without-mccs is not available without uninstalling the 'mccs' package" "$LINENO" 5 fi if test "x${with_0install_solver}" = "xno" && test "x$OCAML_PKG_opam_0install_cudf" != "xno" then : as_fn_error $? "Option --without-0install-solver is not available without uninstalling the 'opam-0install-cudf' package" "$LINENO" 5 fi if test "x$OCAML_PKG_opam_0install_cudf" != "xno" then : OPAM_0INSTALL_SOLVER_ENABLED=true fi if test "x$MCCS_ENABLED" = "xtrue" then : if test "x${CCOMP_TYPE}" != "xmsvc" then : ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CXX+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 printf "%s\n" "$CXX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CXX+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 printf "%s\n" "$ac_ct_CXX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5 printf %s "checking whether the compiler supports GNU C++... " >&6; } if test ${ac_cv_cxx_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+y} ac_save_CXXFLAGS=$CXXFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 printf %s "checking whether $CXX accepts -g... " >&6; } if test ${ac_cv_prog_cxx_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_g=yes else $as_nop CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : else $as_nop ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } if test $ac_test_CXXFLAGS; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_prog_cxx_stdcxx=no if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 printf %s "checking for $CXX option to enable C++11 features... " >&6; } if test ${ac_cv_prog_cxx_11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cxx_11=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_cxx_conftest_cxx11_program _ACEOF for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA do CXX="$ac_save_CXX $ac_arg" if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_cxx11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cxx_cxx11" != "xno" && break done rm -f conftest.$ac_ext CXX=$ac_save_CXX fi if test "x$ac_cv_prog_cxx_cxx11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cxx_cxx11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } CXX="$CXX $ac_cv_prog_cxx_cxx11" fi ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 ac_prog_cxx_stdcxx=cxx11 fi fi if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 printf %s "checking for $CXX option to enable C++98 features... " >&6; } if test ${ac_cv_prog_cxx_98+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cxx_98=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_cxx_conftest_cxx98_program _ACEOF for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA do CXX="$ac_save_CXX $ac_arg" if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_cxx98=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cxx_cxx98" != "xno" && break done rm -f conftest.$ac_ext CXX=$ac_save_CXX fi if test "x$ac_cv_prog_cxx_cxx98" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cxx_cxx98" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } CXX="$CXX $ac_cv_prog_cxx_cxx98" fi ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 ac_prog_cxx_stdcxx=cxx98 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Curiously, CXX=g++ && GXX= seems to be how autoconf "signals" that no C++ # compiler was found. if test "x$CXX" = "xg++" -a "x$GXX" != "xyes" then : if test "x$MCCS_DEFAULT" = "xyes" then : MCCS_ENABLED=false else $as_nop if test "x${enable_checks}" != "xno" then : as_fn_error $? "A C++ compiler is required to build mccs" "$LINENO" 5 fi fi fi fi fi if test "x$OPAM_0INSTALL_SOLVER_ENABLED" = "xtrue" -a "x$OCAML_PKG_opam_0install_cudf" = "xno" then : # Used to indicate true or false condition ax_compare_version=false # Convert the two version strings to be compared into a format that # allows a simple string comparison. The end result is that a version # string of the form 1.12.5-r617 will be converted to the form # 0001001200050617. In other words, each number is zero padded to four # digits, and non digits are removed. ax_compare_version_A=`echo "$OCAMLVERSION" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/[^0-9]//g'` ax_compare_version_B=`echo "4.08" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/[^0-9]//g'` ax_compare_version=`echo "x$ax_compare_version_A x$ax_compare_version_B" | sed 's/^ *//' | sort -r | sed "s/x${ax_compare_version_A}/false/;s/x${ax_compare_version_B}/true/;1q"` if test "$ax_compare_version" = "true" ; then as_fn_error $? "Your version of OCaml: $OCAMLVERSION does not support the requested 0install-solver. \ You can either re-run the configure script with --without-0install-solver or use make cold" "$LINENO" 5 fi fi echo if test "x${enable_checks}" != "xno" && { test "x$OCAML_PKG_extlib" = "xno" || test "x$OCAML_PKG_re" = "xno" || test "x$OCAML_PKG_cmdliner" = "xno" || test "x$OCAML_PKG_ocamlgraph" = "xno" || test "x$OCAML_PKG_cudf" = "xno" || test "x$OCAML_PKG_dose3_common" = "xno" || test "x$OCAML_PKG_opam_file_format" = "xno" || test "x$CPPO" = "x" || test "x$OCAML_PKG_mccs$MCCS_ENABLED" = "xnotrue" || test "x$OCAML_PKG_opam_0install_cudf$OPAM_0INSTALL_SOLVER_ENABLED" = "xnotrue";} then : echo "============================================================================" echo "Some dependencies are missing. If you are just interested in the stand-alone" echo "'opam' binary, run 'make lib-ext' to download and include them." echo "============================================================================" echo hasalldeps="" else $as_nop hasalldeps="true" fi if test "x$prefix" = "xNONE"; then prefix=$ac_default_prefix fi ac_config_files="$ac_config_files Makefile.config src/ocaml-flags-configure.sexp src/stubs/c-flags.sexp src/stubs/libacl/c-libraries.sexp" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by opam $as_me 2.1.5, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to the package provider." _ACEOF ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ opam config.status 2.1.5 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile.config") CONFIG_FILES="$CONFIG_FILES Makefile.config" ;; "src/ocaml-flags-configure.sexp") CONFIG_FILES="$CONFIG_FILES src/ocaml-flags-configure.sexp" ;; "src/stubs/c-flags.sexp") CONFIG_FILES="$CONFIG_FILES src/stubs/c-flags.sexp" ;; "src/stubs/libacl/c-libraries.sexp") CONFIG_FILES="$CONFIG_FILES src/stubs/libacl/c-libraries.sexp" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi rm -f src/manifest/dune src/manifest/install.inc if test "x${with_private_runtime}" != "xno" then : if test ${WIN32} -eq 1 -a "x${CCOMP_TYPE}" = "xcc" then : cd src/manifest ${LN_S} -f dune-manifest dune ${LN_S} -f install.${ARCH} install.inc cd ../.. else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: --with-private-runtime ignored (not building on mingw)" >&5 printf "%s\n" "$as_me: WARNING: --with-private-runtime ignored (not building on mingw)" >&2;} fi fi rm -f src/stubs/win32/dune if test ${WIN32} -eq 1 then : cd src/stubs/win32 ${LN_S} -f dune-win32 dune cd ../../.. fi rm -f src/stubs/libacl/dune if test "x${with_libacl}" = "xyes" then : cd src/stubs/libacl ${LN_S} -f dune-libacl dune cd ../../.. fi echo bindir="`eval echo ${bindir}`" bindir="`eval echo ${bindir}`" mandir="`eval echo ${mandir}`" mandir="`eval echo ${mandir}`" if test "x$MCCS_ENABLED" = "xfalse" -a "x$OPAM_0INSTALL_SOLVER_ENABLED" = "xfalse" then : echo "Opam will be built WITHOUT a built-in solver" else $as_nop echo "Opam will be built WITH a built-in solver" fi echo echo Executables will be installed in ${bindir} echo Manual pages will be installed in ${mandir} opam-2.1.5/opam-state.opam0000644000175000017500000000205314427463453014447 0ustar stephstephopam-version: "2.0" version: "2.1.5" synopsis: "State library for opam 2.1" description: """ Handling of the ~/.opam hierarchy, repository and switch states. """ maintainer: "opam-devel@lists.ocaml.org" authors: [ "Vincent Bernardoff " "Raja Boujbel " "Roberto Di Cosmo " "Thomas Gazagnaire " "Louis Gesbert " "Fabrice Le Fessant " "Anil Madhavapeddy " "Guillem Rieu " "Ralf Treinen " "Frederic Tuong " ] homepage: "https://opam.ocaml.org" bug-reports: "https://github.com/ocaml/opam/issues" dev-repo: "git+https://github.com/ocaml/opam.git" license: "LGPL-2.1-only WITH OCaml-LGPL-linking-exception" build: [ ["./configure" "--disable-checks" "--prefix" prefix] ["dune" "build" "-p" name "-j" jobs] ] depends: [ "ocaml" {>= "4.02.3"} "opam-repository" {= version} "dune" {>= "1.11.0"} ] opam-2.1.5/opam-client.opam0000644000175000017500000000231614427463453014607 0ustar stephstephopam-version: "2.0" version: "2.1.5" synopsis: "Client library for opam 2.1" description: """ Actions on the opam root, switches, installations, and front-end. """ maintainer: "opam-devel@lists.ocaml.org" authors: [ "Vincent Bernardoff " "Raja Boujbel " "Roberto Di Cosmo " "Thomas Gazagnaire " "Louis Gesbert " "Fabrice Le Fessant " "Anil Madhavapeddy " "Guillem Rieu " "Ralf Treinen " "Frederic Tuong " ] homepage: "https://opam.ocaml.org" bug-reports: "https://github.com/ocaml/opam/issues" dev-repo: "git+https://github.com/ocaml/opam.git" license: "LGPL-2.1-only WITH OCaml-LGPL-linking-exception" build: [ ["./configure" "--disable-checks" "--prefix" prefix] ["dune" "build" "-p" name "-j" jobs] ] depends: [ "ocaml" {>= "4.02.3"} "opam-state" {= version} "opam-solver" {= version} ("base64" {>= "3.1.0"} | "base64" & "ocaml" {= "4.02.3"}) "opam-repository" {= version} "re" {>= "1.9.0"} "cmdliner" {>= "1.0.0"} "dune" {>= "1.11.0"} ] opam-2.1.5/CHANGES0000644000175000017500000024071114427463453012517 0ustar stephstephChanges prefixed with "(*)" are potentially breaking to scripts or existing repositories (changes that are automatically handled by the format upgrade tools are not marked). Those prefixed with "(+)" are new command/option (since 2.1.0~alpha2). 2.1.5: * [BUG] Variables are now expanded in build-env (as for setenv) [#5352 @dra27] * Correctly handle empty environment variable additions [#5350 @dra27] * Skip empty environment variable additions [#5350 @dra27] * [BUG] Fix passing `archive-mirrors` field from init config file to config [#5315 @hannesm] * git, hg: Use the full SHA1 revision instead of just the 8 first characters [#5342 @reynir] * [BUG] Fix opam installing packages without checking their checksum when the local cache is corrupted in some case [#5538 @kit-ty-kate] 2.1.4: * Add support for OCaml 5.0. Dose3 >= 6.1 and base64 >= 3.1.0 are now required [#5357 @kit-ty-kate @dra27 - fix #5354] * [BUG] Fix all empty conflict explanation messages [#5378 @kit-ty-kate - partial fix #4373] 2.1.3: * [BUG] Fix `opam init` and `opam init --reinit` when the `jobs` variable has been set in the opamrc or the current config. [#5056 @rjbou] * When inferring a 2.1+ switch invariant from 2.0 base packages, don't filter out pinned packages as that causes very wide invariants for pinned compiler packages [#5176 @dra27 - fix #4501] * [BUG] Fix an internal error on repository upgrade from OPAM 1.2 [#4965 @AltGr] * Some optimisations to `opam list --installable` queries combined with other filters [#4882 @AltGr - fix #4311] * Improve performance of some opam list combinations (e.g. `--available`, `--installable`) [#4999 @kit-ty-kate] * Improve performance of `opam list --conflicts-with` when combined with other filters [#4999 @kit-ty-kate] * Improve performance of `opam show` by as much as 300% when the package to show is given explicitly or is unique [#4998 @kit-ty-kate - fix #4997 and partially #4172] * [BUG] `opam var` no longer fails if no switch is set [#5027 @rjbou - fix #5025] * [BUG] Setting a variable with option `--switch ` fails instead of writing an invalid `switch-config` file [#5027 @rjbou] * When a field is defined in switch and global scope, try to determine the scope also by checking switch selection [#5027 @rjbou] * [BUG] Handle external dependencies when updating switch state pin status (all pins), instead as a post pin action (only when called with `opam pin` [#5047 @rjbou - fix #5046] * [BUG] When reinstalling a package that has a dirty source, if uncommitted changes are the same than the ones stored in opam's cache, opam consider that it is up to date and nothing is updated [4879 @rjbou] * Stop Zypper from upgrading packages on updates on OpenSUSE [#4978 @kit-ty-kate] * Clearer error message if a command doesn't exist [#4971 @kit-ty-kat - fix #4112] * [BUG] Remove windows double printing on commands and their output [#4940 @rjbou] * Actually allow multiple state caches to co-exist [#4934 @dra27 - actually fixes #4554] * Update cold compiler to 4.13 to avoid issues with glibc 2.34 on Unix [#5017 @dra27] * Bump opam-file-format to 2.1.4 [#5117 @kit-ty-kate - fix #5116] * Fix some empty conflict explanations [#4982 @kit-ty-kate - partially fix #4373] * Port some tests from master [#4841 #4974 #4861 #4915 #4979 #5004 #5006 #5015 #5024 #5025 #5031 #5131 #5176 @AltGr @dra27 @kit-ty-kate] * Update test engine to allow for additional tests [#4913 #4966 #4979 #5004 #5009 #5024 #5097 @AltGr @kit-ty-kate @rjbou] * Update for git protocol deprecation on GitHub [#5097 @rjbou] * When building opam, do not fail if curl/wget is missing [#5223 #5233 @kit-ty-kate] 2.1.2: * Fallback on dnf if yum does not exist on RHEL-based systems [#4825 @kit-ty-kate] * Use --no-depexts in CLI 2.0 mode [#4908 @dra27] * bootstrap: update ocaml version (fixes the compilation of opam with mingw) [#4927 @kit-ty-kate] 2.1.1: * Fix typo in error message for opam var [#4786 @kit-ty-kate - fix #4785] * Run the sandbox check in the temporary directory [#4787 @dra27 - fix #4783] * OpamSystem: avoid calling Unix.environment at top level [#4789 @hannesm] * Homebrew: Add support for casks and full-names [#4801 @kit-ty-kate] * Fix the cold target in presence of an older OCaml compiler version on macOS [#4802 @kit-ty-kate - fix #4801] * Archlinux: handle virtual package detection [#4833 @rjbou - partial fix #4759] * Disable the detection of available packages on RHEL-based distributions. This fixes an issue on RHEL-based distributions where yum list used to detect available and installed packages would wait for user input without showing any output and/or fail in some cases [#4791 @kit-ty-kate - fixes #4790] * Handle empty environment variable updates - missed cherry-pick from 2.0 [#4840 @dra27] * Fix vendored build on mingw-w64 with g++ 11.2 [#4835 @dra27] * Put back support for switch creation with packages argument and `--packages` option with cli 2.0, and a specific error message for cli 2.1 [#4853 @rjbou - fix #4843] * Fix reverting environment additions to PATH-like variables when several dirs added at once [#4861 @dra27] * Fix dose3 download url since gforge is gone [#4870 @avsm] * Ensure setenv can use package variables defined during the build [#4841 @dra27] * Fix `set-invariant: default repos were loaded instead of switch repos [#4866 @rjbou] 2.1.0: * Set DEBIAN_FRONTEND=noninteractive for unsafe-yes confirmation level [#4735 @dra27 - partially fix #4731] * Fix 2.1~alpha2 to 2.1 format upgrade with reinit [#4750 #4756 @rjbou - fix #4748] * Fix bypass-check handling on reinit [#4750 @rjbou] * fish: fix deprecated redirection syntax `^` [#4736 @vzaliva] * Bump src_exts and fix build compat with Dune 2.9.0 [#4754 @dra27] * Fix depext alpine tagged repositories handling [#4758 @rjbou] 2.1.0~rc2: * Remove OPAMZ3DEBUG evironment variable [#4720 @rjbou - fix #4717] * Fix format upgrade when there is missing local switches in the config file [#4715 @rjbou - fix #4713] * Fix not recorded local switch handling, with format upgrade [#4715 @rjbou] * Set opam root version to 2.1 [#4715 @rjbou] * Improved and extended tests [#4715 @rjbou] 2.1.0~rc: * (*) Environment variables initialised only at opam client launch, no more via libraries [#4606 #4703 @rjbou] * (*) Deprecated `build-doc`, `build-test`, `make` flags [#4581 @rjbou] * (+) Add `--confirm-level` and `OPAMCONFIRMLEVEL` for automatic answering [#4582 @rjbou - fix #4168; #4683 @dra27 - fix #4682; #4691 @rjbou - fix #4682] * (+) Add `--no` [#4582 @rjbou] * (+) Add a `--with-0install-solver` option to the configure script to enable the 'builtin-0install' solver [#4646 @kit-ty-kate] * Add default cli mechanism: deprecated options are accepted (in the major version) if no cli is specified [#4575 @rjbou] * Add `opam config` deprecated subcommands in the default cli [#4575 @rjbou - fix #4503] * Add cli versioning for opam environment variables [#4606 @rjbou] * Add cli versioning for enums of flags with predefined enums [#4606 @rjbou] * Clearer messages about using --cli and OPAMCLI [#4655 @dra27] * The options `--root` and `--switch` are now reflected in environment variables when building packages so that calls to `opam` during build access the correct root and switch [#4668 @LasseBlaauwbroek] * Add cli versioning for enums of flags with predefined enums [#4626 @rjbou] * Preprocess `--confirm-level` for plugins calls/install [#4694 @rjbou] * Ensure the symlink for a plugin is maintained on each invocation [#4621 @dra27 - partially fixes #4619] * Initialise environment variables for plugins call/install [#4582 @rjbou] * Expect plugins to end in .exe on Windows [#4709 @dra27] * Introduce a `default-invariant` config field, restore the 2.0 semantics for `default-compiler` [#4607 @AltGr] * Fix default invariant with no system compiler [#4644 @AltGr - fix #4640] * Perform an hard upgrade on intermediate roots, ie root from `2.1~alpha/beta`, and keep a light upgrade from `2.0` [#4638 @rjbou] * Send the 'opam root layout update' message to stderr [#4692 @AltGr] * If opam root is different from the binary, allow reading it and try to read in best effort mode [#4638 @rjbou - fix #4636] * Don't check opam system dependencies on reinit after a format upgrade [#4638 @rjbou] * Fix `sys-ocaml-cc`, `sys-ocaml-arch` and `sys-ocaml-libc` when no system compiler installed [#4706 @dra27] * Fix `Not_found` (config file) in config report [#4570 @rjbou] * Config report: Print variables of installed compilers and their (installed) dependencies [#4570 @rjbou] * Don't patch twice file [#4529 @rjbou] * With `--deps-only`, set dependencies as root packages [#4964 @rjbou - fix #4502] * Keep global lock only if root format upgrade is performed [#4612 @rjbou - fix #4597] * Improve installation times by only tracking files listed in `.install` instead of the whole switch prefix when there are no `install:` instructions (and no preinstall commands) [#4494 @kit-ty-kate @rjbou; #4667 @dra27 - fix #4422] * Scrub OPAM* environment variables added since 2.0 from package builds to prevent warnings when a package calls opam [#4663 @dra27 - fix #4660] * Correct the message when more than one depext is missing [#4678 @dra27] * Only display one conflict message when they are all owing to identical missing depexts [#4678 @dra27] * Don't exclude base packages from rebuilds (made some sense in opam 2.0 with base packages but doesn't make sense with 2.1 switch invariants) [#4569 @dra27] * Don't refer to base packages in messages any more [#4623 @dra27 - fixes #4572] * Give the correct command when demonstrating switch creation [#4675 @dra27 - fixes #4673] * On switch loading, if invariant is inferred and a write lock required, write the file [#4638 @rjbou] * Don't look for lock files for pin depends [#4511 @rjbou - fix #4505] * Fetch sources when pinning an already pinned package with a different url when using working directory [#4542 @rjbou - fix #4484] * Don't ask for confirmation for pinning base packages (similarly makes no sense with 2.1 switch invariants) [#4571 @dra27] * Fix version pin source retrieving: mustn't error if archive opam file is malformed [#4580 @rjbou] * `opam list --silent` renamed to `--check` [#4595 @dra27 - fix #4323] * Include doc field in opam-show [#4567 @dra27 - partially fix #4565] * Fix `switch` global variable resolving [#4685 @rjbou - fix #4684] * Fix `hash` package variable resolving [#4687 @rjbou] * Lint: Fix W59 & E60 for conf packages (no url required) [#4550 @rjbou - fix #4549] * Lint: Fix W59 & E60 with VCS urls, don't check upstream if url has VCS backend [#4635 @rjbou] * Lint: Add E67 checksum specified with non archive url [#4635 @rjbou] * Lint: Disable subpath warning E63,W64 [#4638 @rjbou] * Lint: Fix manpage listing [#4708 @rjbou] * Don't write lock file with `--read-only', `--safe`, and `--dryrun` [#4562 @rjbou - fix #4320] * Make `opam lock` consistent with `opam install`, on local pin always take last opam file even if uncommitted [#4562 @rjbou - fix #4320] * Opam file: Fix `features` parser [#4507 @rjbou] * Opam file: Rename `hidden-version` to `avoid-version` [#4527 @dra27] * Opam file: Fix rewriting with preserved format empty field error [#4634 @rjbou - fix #4628] * Opam file: Switch config: Defined `invariant` field as an option to differentiate when it is not defined [#4638 @rjbou] * Opam file: Differentiate bad format from bad (opam) version with `Bad_version` exception, raised from `OpamFormat.check_opam_version` [#4638 @rjbou] * Opam file: Always print the `opam-version` field on files [#4638 @rjbou] * Opam file: Config: add `opam-root-version` field as a marker for the whole opam root [#4638 @rjbou - fix #4636] * Opam file: Add `BestEffort` modules with reading functions that don't show errors, given the `opam_file_format` internal field [#4638 @rjbou - fix #4636] * Depext: Handle macport variants [#4509 @rjbou - fix #4297] * Depext: Always upgrade all the installed packages when installing a new package on Archlinux [#4556 @kit-ty-kate] * Depext: Handle some additional environment variables (`OPAMASSUMEDEPEXTS`, `OPAMNODEPEXTS`) [#4587 @AltGr] * Depext: Improve messages to hint that answering `no` doesn't abort installation [#4591 @AltGr] * Depext: Add support for non-interactive mode in macports [#4676 @kit-ty-kate] * Depext: Handling of packages of tagged repositories for alpine [#4700 @rjbou - fix #4670] * Depext: Clarify some `assume-depexts` related messages [#4671 @AltGr - partial fix #4662] * Depext: Warn the user if epel-release is missing and unavailable depexts are detected [#4679 @dra27 fix #4669] * Depext: Ignore config yes automatic answering when asking confirmation to run install commands [#4698 @rjbou - fix #4680] * Sandbox: Fix the conflict with the environment variable name used by dune [#4535 @smorimoto - fix ocaml/dune#4166] * Sandbox: Kill builds on Ctrl-C with bubblewrap [#4530 @kit-ty-kate - fix #4400] * Sandbox: Linux: mount existing TMPDIR read-only, re-bind `$TMPDIR` to a separate tmpfs [#4589 @AltGr] * Sandbox: Fix the sandbox check [#4589 @AltGr] * Sandbox: Fix sandbox script shell mistake that made `PWD` read-write on remove actions [#4589 @AltGr] * Sandbox: Port bwrap improvements to sandbox_exec [#4589 @AltGr] * Sandbox: Fix realpath use for macos, partial revert of #4589 [#4609 @AltGr] * Add missing shell quoting to support space and special shell characters in switch directory path [#4707 @kit-ty-kate] * Rename `state.cache` to include the `OpamVersion.magic()` string. All .cache files are deleted if any cache file is written to, allowing multiple versions of the library to co-exist without constantly regenerating it [#4642 @dra27 - fix #4554] * Fix Cudf preprocessing [#4534 #4627 @AltGr - fix #4624] * Allow to upgrade to a hidden-version package if a hidden-version package is already installed [#4525 @kit-ty-kate] * Add support for a few select criteria useful to CI to the 0install solver: `+count[version-lag,solution]` to always choose the oldest version available, `+removed` to not try to keep installed packages [#4631 @kit-ty-kate] * Fix opam-devel's tests on platforms without openssl, GNU-diff and a system-wide ocaml [#4500 @kit-ty-kate] * Use dune to run reftests [#4376 @emillon] * Restrict `extlib` and `dose` version [#4517 @kit-ty-kate] * Restrict to `opam-file-format.2.1.2` [#4495 @rjbou] * Require `opam-file-format.2.1.3+` in order to enforce `opam-version: "2.1"` as first non-comment line [#4639 @dra27 - fix #4394] * Switch to newer version of MCCS (based on newer GLPK) for src_ext [#4559 @AltGr] * Bump dune version to 2.8.2 [#4592 @AltGr] * Bump the minimal dune requirement to dune 1.11 [#4437 @dra27 @kit-ty-kate] * 4.12 compatibility [#4437 @dra27 @kit-ty-kate] * Cold compiler updated to 4.12 [#4616 @dra27] * Fix build from source when a dune-project file is presented in the parent directory [#4545 @kit-ty-kate] * Fix build from source when a dune-project file is presented in the parent directory [#4545 @kit-ty-kate - fix #4537] * Fix opam-devel.install not to install two files called opam [#4664 @dra27] * Build release tags as non-dev versions, as for release tarballs [#4665 @dra27 - fix #4656] * Disable dev version for tests (needed for format upgrade test) [#4638 @rjbou] * Add a hint for missing `openssl` in `make cold` [#4702 @rjbou] * Remove test field from opam-devel, they need the network [#4702 @rjbou] * Update src_ext for Dune and MCCS [#4704 @dra27] * Release scripts: switch to OCaml 4.10.2 by default, add macos/arm64 builds by default [#4559 @AltGr] * Release scripts: add default cli version check on full archive build [#4575 @rjbou] * Arg: Generalise `mk_tristate_opt` to `mk_state_opt` [#4575 @rjbou] * Arg: Fix `mk_state_opt` and rename to `mk_enum_opt` [#4626 @rjbou] * Arg: Add `mk_enum_opt_all` for state flags that appears more than once [#4582 @rjbou] * Fix `opam exec` on native Windows when calling cygwin executables [#4588 @AltGr] * Fix temporary file with a too long name causing errors on Windows [#4590 @AltGr] * CLI: Add flag deprecation and replacement helper [#4595 @rjbou] * Win32 Console: fix VT100 support [#3897 #4710 @dra27] * Tidied the opam files [#4620 @dra27] * Externalise cli versioning tools from `OpamArg` into `OpamArgTools` [#4606 @rjbou] * Each library defines its own environment variables, that fills the config record [#4606 @rjbou] * Harden cygpath wrapper [#4625 @dra27] * Reset the plugin symlinks when the root is upgraded [#4641 @dra27 - partial fix for #4619] * Formalise opam dev version detection with `OpamVersion.is_dev_version` [#4665 @dra27] * Add `OpamStd.String.is_prefix_of` [#4694 @rjbou @dra27] * Fix `OpamStd.Format.pretty_list`: `last` argument dropped if list contains more than 2 elements [#4694 @rjbou] * Run the shell hooks with closed stdin (bash, zsh) [#4692 @AltGr] * Improved and extended tests [#4376 #4504 #4545 #4612 #4668 #4612 #4634 #4672 #4638 #4702 #4697 #4697 @AltGr @dra27 @emillon @rjbou] * Improve Github Actions [#4593 #4575 #4610 #4610 #4618 #4606 #4695 #4695 @AltGr @dra27 @rjbou] * Improve documentation [#4496 #4506 #4513 #4637 #4681 #4702 @dannywillems @eth-arm @kit-ty-kate @rjbou @UnixJunkie] 2.1.0~beta4: * (*) Implemented CLI version compatibility layer [#4385 @rjbou] * (*) Return code 31 (`Sync_error`) instead of code 40 (`Package_operation_error`) when all failures happend during fetching [#4416 @rjbou - fix #4214] * (+) Add `--download-only` flag [#4071 @Armael @rjbou - fix #4036] * (+) Provide `opam update --depexts` to request an update of the system package manager databases [#4379 @AltGr - fix #4355] * Set OPAMCLI=2.0 during package action commands [#4492 @kit-ty-kate] * Fix sandbox check on first `opam init` [#4370 @rjbou - fix #4368] * Print shell-appropriate eval command on `opam init` [#4427 @freevoid] * Fix init script check in csh [#4482 @gahr] * The stdout of `pre-` and `post-session` hooks is now propagated to the user [#4382 @AltGr - fix #4359] * `post-install` hooks are now allowed to modify or remove installed files [#4388 @lefessan] * Add support for switch-specific pre/post sessions hooks [#4476 @rjbou - fix #4472] * Ensure we don't advertise upgrades to hidden versions [#4477 @AltGr - fix #4432] * Fix `opam remove --autoremove ` to not autoremove unrelated packages [#4369 @AltGr - fix #4250 #4332] * Fix cases where `opam remove -a` could trigger conflicts in the presence of orphan packages [#4369 @AltGr - fix #4250 #4332] * Fix `--update-invariant` when removing or changing package name [#4360 @AltGr - fix #4353] * Fix updates of the invariant with `--update-invariant` [#4431 @AltGr] * Fix cleanup of build dirs for version pinned packages [#4436 @rjbou - fix #4255] * Fix opamfile format upgrade on pinning [#4366 @rjbou - fix #4365] * Fix `pin --show` actually pinning [#4367 @rjbou - fix #4348] * When several pins are needed, do their fetching in parallel [#4399 @rjbou - fix #4315] * Don't cleanup VCS pin source directories [#4399 @rjbou] * Fix `--working-dir` with local switches [#4433 @rjbou] * Add package variable `opamfile-loc`, containing the location of installed package opam file [#4402 @rjbou] * Fix `arch` detection when using 32bit mode on ARM64 [#4462 @kit-ty-kate] * Fix `arch` detection of i486 [#4462 @kit-ty-kate] * Skip loading the switch state for variable lookup when possible [#4428 @rjbou] * Fix package variables display when no config file is found [#4428 @rjbou] * Fix `opam option depext-bypass-=["XXX"]` [#4428 @rjbou] * Lint: add a check that strings in filtered package formula are booleans or variables [#443 @rjbou - fix #4439] * Fix handling of filename-encoded pkgname in opam files [#4401 @AltGr - fix ocaml-opam/opam-publish#107] * Don't recompile when modifying the package flags [#4477 @AltGr] * Add depext support for NetBSD and DragonFlyBSD [#4396 @kit-ty-kate] * Fix depexts on OpenBSD, FreeBSD and Gentoo: Allow short names and full name paths for ports-based systems [#4396 @kit-ty-kate] * Handle the case where `os-family=ubuntu` as `os-family=debian` [#4441 @alan-j-hu] * Update opam's opam files to 2.0 [#4371 @AltGr] * Makefile: Add rule `custom-libinstall` for `opam-custom-install` use [#4401 @AltGr] * Use the archive caches when running `opam admin cache` [#4384 @AltGr - fix #4352] * Fix explosion of `opam admin check --cycles` on repositories with huge cliques [#4392 @AltGr] * Much improved format-preserving printer [#4298 #4302 @rjbou - fix #3993] * Fix missing conflict message when trying to remove required packages [#4362 @AltGr] * Fix the Z3 backend for upgrades [#4393 @AltGr] * Fix cases where opam would wrongly complain about action cycles [#4358 @AltGr - fix #4357] * Fix permission denied fallback for openssl [#4449 @Blaisorblade - fix #4448] * Add debug & verbose log for patch & subst applications [#4464 @rjbou - fix #4453] * Be more robust w.r.t. new caches updates when `--read-only` is not used [#4467 @AltGr - fix #4354] * Improved and extended tests [#4375 #4395 #4428 #4385 #4467 #4475 #4483 @emillon @rjbou @AltGr @freevoid @dra27] * Switched to Github actions [#4463 @rjbou] 2.1.0~beta2: * Reduced startup times, in particular for `opam exec` [#4341 @altgr] * Fixed the sandboxing check on fresh inits [#4342 @altgr] * Fixed cases where `--with-version` was not respected by `opam pin` [#4346 @altgr] * Upgraded the bootstrap OCaml compiler from 4.09.1 to 4.11.1 [#4242 @avsm @dra27 @MisterDA @rjbou] 2.1.0~beta: * (*) `--cli` / `OPAMCLI` option added [#4316 @dra27] * `--help/--version` documented in wrong section for aliases [#4317 @dra27] * `opam lock --help` missing common information {#4317 @dra27] * (+) `--yes` passed to all commands, and plugins [#4316 @dra27] * On init, check availability of sandbox and propose to disable [#4284 @rjbou - fix #4089] * config upgrade: on the fly upgrade if no write lock required [#4313 @rjbou] * (*) Add `pin scan` subcommand to list available pins [#4285 @rjbou] * (*) Add `--normalise` option to print a normalised list when scanning, that can be taken by `opam pin add` [#4285 @rjbou] * (*) Add `with-version` option to set the pinned package version [#4301 @rjbou] * Add error message in case git repo is empty [#4303 @rjbou - fix #3905] * Lock: Support -d as alias of --direct-only (to match plugin) [#4319 @dra27] * Switch: Support -n as an alias of --no-action (to match opam-pin) [#4324 @dra27] * List: form no longer advertised as valid for --columns [#4322 @dra27] * Admin: form no longer advertised as valid for --columns in list [#4322 @dra27] * Solver: Don't penalise packages with more recent 'hidden-versions' [#4312 @AltGr] * `OpamCommand.pin` refactor, including adding `OpamClient.PIN.url_pins` to pin a list of package with url [#4285 #4301 @rjbou] * `OpamPinCommand.source_pin', for new package confirmation, don't check that no opam file is given as argument [#4301 @rjbou] * CLI: Provide all functions in the client library [#4329 @AltGr] * Process: don't display status line if not verbose, and status line disabled [#4285 @rjbou] * Optimise package name comparison [#4328 @AltGr - fix #4245] 2.1.0~alpha3: * Confirmation on non-compiler switch invariant: not on dryrun, Y by default [#4289 @AltGr] * (*) Fix pin kind automatic detection consistency [#4300 @rjbou]: With `opam pin target', when opam file is not versioned and at root, vcs-pin the package instead of path-pin, and with `opam pin add nv target', take opam file even if not versioned. * External dependencies: Fix non-interactive mode on OpenSuse [#4293 @kit-ty-kate] * src-ext: bump topkg to 1.0.2 and dune to 2.6.2, with a second compiler built in case main one is < 4.07.0 (dune restriction) [#4294 @dra27] * Allow Z3 backend to return sub-optimal solutions on timeout, add `OPAMSOLVERALLOWSUBOPTIMAL` environment variable [#4289 @AltGr] * Add an optional solver relying on opam-0install-cudf [#4240 @kit-ty-kate] 2.1.0~alpha2: * Remove m4 from the list of recommended tools [#4184 @kit-ty-kate] * Fix config solver field ignored at init [#4243 @rjbou - fix #4241] * Fix atoms formula restriction with `--all` at upgrade [#4221 @rjbou - fix #4218] * Copy instead of calling rsync when archives are in a local cache [#4270 @kit-ty-kate] * Opam file build using dune, removal of opam-%.install makefile target [#4178 @rjbou #4229 @kit-ty-kate - fix #4173] * Use version var in opam file instead of equal current version number in opamlib dependencies [#4178 @rjbou] * src ext: fix extlib url [#4248 @rjbou] * Add `_build` to rsync exclusion list [#4230 @rjbou - fix #4195] * Recursive opam file lookup: ignore `_build` [#4230 @rjbou] * Assume-built fix & rewriting [#4211 @rjbou] * Fix autoremove env var handling [#4219 @rjbou - fix #4217] * Fix Not_found with `opam switch create . --deps` [#4151 @AltGr] * Package Var: resolve self `name` variable for orphan packages [#4228 @rjbou - fix #4224] * (*) Reject (shell) character on switch names [#4237 @rjbou - fix #4231] * Fix `OPAMSWITCH` empty string setting, consider as unset [#4237 @rjbou] * opam-installer: For paths, remove use of empty switch in favor of a context-less module [#4237 @rjbou] * Add missing depext to unavailable reasons [#4194 @rjbou #4279 @rjbou - fix #4176] * (*) Bump config file version to 2.1 (new depext fields) [#4280 @rjbou - fix #4266] * Add depext handling on new pinned packages [#4194 @rjbou - fix #4189] * Don't keep unpinned package version if it exists in repo [#4073 @rjbou - fix #3630] * Fix path resolving when pinning with `file://` [#4209 @rjbou - fix #4208] * (*) Disable recursive & subpath pinning (only present experimentally in opam 2.1.0~alpha) [#4252 @rjbou] * Add switch depext-bypass as modifiable field [#4194 @rjbou - fix #4177] * Add `--no-depexts` option to disable depexts packages unavailability [#4194 @rjbou - fix #4205] * Warn if packages are not listed because of depexts unavailability [#4194 @rjbou - fix #4205] * (*) Display error message for all not found packages [#4179 @rjbou - fix #4164] * (*) Keep package order given via cli [#4179 @rjbou - fix #4163] * `--sort`` apply to with all options, not only `--just-file` [#4179 @rjbou] * Add scope display to Not found message [#4192 @rjbou] * No scope needed for variable display [#4192 @rjbou - fix #4183] * Fix package variable resolution [#4192 @rjbou - fix #4182] * opam option: Fix messages advertising a command in an obsolete format [#4194 @rjbou] * E65: check that url local paths are absolute [#4209 @rjbou] * Fix arch query depext [#4200 @rjbou] * Add message when adding a package to `depext-bypass` [#4194 @rjbou] * Fix performance issue of depext under Docker/debian [#4165 @AltGr] * Handle debian virtual packages [#4269 @AltGr @rjbou - fix #4251] * Refactor `OpamSysInteract` package status [#4152 #4200 @rjbou] * Add environment variables handling on depext query [#4200 @rjbou] * Add depext Macport support [#4152 @rjbou] * Homebrew/depext: add no auto update env var for install, accept `pkgname` and `pkgname@version` on query [#4200 @rjbou] * Tag packages with missing depexts in Cudf [#4235 @AltGr] * Force LC_ALL=C for depext query commands [#4200 @rjbou] * Put back opam-depext-2.0's behaviour with regards to asking users' consent before installing system packages [#4168 @kit-ty-kate @rjbou] * Add OPAMDEPEXTYES env variable to pass --yes options to system package manager [#4168 @kit-ty-kate @rjbou] * Fix system install command dryrun [#4200 @rjbou] * (+) Add --depext-only to install only external dependencies, regardless of config depext status [#4238 @rjbou] * Move system install confirmation message after opam packages install [#4238 @rjbou] * Error if '--depext-only' is given with '--assume-depexts' or '--no-depexts' [#4238 @rjbou] * Sanddbox: no error when linked directory doesn't exist (e.g. XDG defined) [#4278 @kit-ty-kate] * Sandbox: add quotes to avoid space unwanted behaviors [#4278 @kit-ty-kate] * Fix temp files repository cleaning [#4197 @rjbou] * Fix admin cache synchronisation message [#4193 @rjbou - fix #4167] * Fix mismatching extra files detection [#4198 @rjbou] * Fix Cudf generation for compat with external solvers [#4261 @AltGr] * Check for a solution before calling the solver [#4263 @AltGr] * Add the package flag 'hidden-version' to discourage selection by the solver [#4281 @AltGr] * Tweak the default criteria to handle 'missing-depexts' and 'hidden-version' flags [#4281 @AltGr] * Disable chrono when timestamps are disables [#4206 @rjbou] * Expose some functionality in the `OpamAction`, `OpamPath` and `OpamSwitchState` modules for use without a `switch` value (introduce a functor to permit replicating switch layout in different contexts) [#4147 @timberston] * Std: Add map_reduce to Set and Map [#4263 @AltGr] * Fix regression in command resolution from #4072 (ocaml code for looking up commands in PATH) [#4265 @dra27] * Use OCaml 4.09.1 for the make cold target [#4257 @dra27] * Add show cram test [#4206 @rjbou] * Add envrionnement variable handling on cram test [#4206 @rjbou] 2.1.0~alpha: * Recursive & subpath based pin [#3499 @rjbou @hngrgr - fix #3174 #3477] * Define switch invariants rather than "base packages" [#3894 @AltGr] * Don't warn on switch creation with 'ocaml' as invariant [#4108 @AltGr] * Better error handling on switch creation [#4121 @AltGr] * Integrate lock plugin [#3746 @rjbou - fix #3734 #3769 #3694] * Add configuration modifications as opam config subcommands [#3992 @rjbou] * opam var and opam option outside of opam config [#4116 @rjbou - fix #4119] * Enable option var optimisation switch load [#4138 @rjbou] * Integrate depext plugin [#3975 @rjbou @AltGr - fix #3790 #1519 #2426 #3692] * Enable command/output display only from verbose level 3 [#4141 @rjbou] * Add `opam install --check ` checks that `` dependencies are already installed in the switch. It reports missing ones and exits with 1, 0 otherwise. It is used on a check only purpose, additionally to `--deps-only`. [#3854 @rjbou - fix #3823] * Add `opam install --ignore-conflicts` to use with `--deps-only` in case it is needed to install dependencies without taking conflicts into account. [#3853 @rjbou - fix #3846] * Add `opam show --just-file ` shows information of a given file, without loading the switch state. It can be combined with other options, as field filter `--field`. It deprecates `--file` option. [#3729 @rjbou - fix #3721] * Add `opam show --all-versions ` displays information of all versions of the given package. It can be used in combination of field filter. [#3867 @rjbou - fix #2980] * Add `opam show --sort ` display on stdout a sorted opam file: all fields are alphabetically sorted. [#3866 @rjbou - fix ocaml/opam2web#173] * opam show better error handling. [#4118 @rjbou - fix #3875] * `opam show --field` are no longer required to end with a colon. [#3931 @rjbou] * (*) `opam show --normalise` disable terminal width wrapping. [#3868 @rjbou - fix #3751] * `opam env --check` permit to indicates if an opam environment is synchronized: returns 0 if up-to-date, 1 otherwise. [#4074 @rjbou - fix #3725] * Add `opam switch export --freeze` to record VCS commit hash when a VCS url is specified. [#4055 @hannesm] * Add `opam switch export --full` option, include extra-files in switch export, on import create an overlay directory with the file contents. [#4040 @hannesm] * Optimize repository loading: we store the repository contents as .tar.gz files in ~/.opam/repo instead. [#3752 @AltGr - fix #3721] * Handle failure or interruption of tar during `opam update`. [#3861 @AltGr] * Fallback in case repository archive doesn't exist. [#4008 @rjbou] * In case repository archive is corrupted, delete it and ask to launch an update. [#4075 @rjbou - fix #4053] * When adding a repository, an error is displayed in case of mismatching urls, now both urls are displayed. [#4086 @rjbou - fix #4085] * Handle url backend change to VCS of a package from repository. [#4007 @rjbou - fix #3991] * Allow local compiler switch creation. [#3720 @rjbou - fix #3713] * Switch creation, fix multiple compiler candidate. [#3884 @rjbou - fix #3874] * Make reinstall handling stricter. [#3907 @AltGr] * (*) `opam list --resolve`: restrain test dependencies to direct one instead of listing all test dependencies of queried package(s) [#3923 @rjbou - fix ocaml/opam-depext#121] * Update pin-depends confirmation message to add a skip option. [#3852 @rjbou - fix #3840] * Add OPAMDROPWORKINGDIR environment variable for C. [#3792 @rjbou - fix #3727] * Don't restrain copy to versioned file. [#3759 @rjbou] * Don't fetch sources when working-dir is set. [#4046 @rjbou] * Update in place source copy: [#3948 @rjbou] - review `sync_dirty` on VCS: - use VCS to synchronize, then rsync & remove others files - exclude `_build`, `_opam` & VCS directories - when `--inplace-build` is given, it does a dirty synchronization of the sources, in order to keep tracking package stats (clean, local or dirty). * Fix `working-dir` messages on update command. [#3824 @rjbou] * Working-dir fixes. [#3982 @rjbou] * Update download errors handling during actions processing. [#3811 @AltGr] * Update `ftp` command, to pass url last. [#3910 @hannesm] * Terminate (with double dashes) list of command-line download option. [#3913 @cfcs] * Repository: remove 'file://' prefix for darcs. [#3761 @rjbou] * Opam{Git,Hg}: Fix diffs in presence of binary file. [#3879 @kit-ty-kate] * Set core.autocrlf and core.eol for Git remotes. [#3882 @dra27] * Add a git clean on `reset_tree` to keep source dir clean. [#3948 @rjbou] * Lint W62: Add a lint check for SPDX license. [#3976 @AltGr] * Lint: add result in json output. [#3848 @rjbou - fix #3046] * Add lint codes in manpage. [#3903 @rjbou] * Default configuration file: add `getconf` to required tools. [#3813 @rjbou] * Clarify message in `opam init --yes`. [#3892 @dra27] * Shell setup: don't advice an infinite sourcing loop. [#3832 @rjbou] * Default configuration file: Add compilation target globals, `sys-ocaml-arch, `sys-ocaml-cc`, and `sys-ocaml-libc`. [#3900 @dra27] * Ensure that environment is initialized lazily, not before init functions are called [#4111 @gasche] * Fix OPAMLOGS handling, and logdir `opam_init` argument [#4117 @rjbou - fix #4076] * Include base packages configuration variables in opam config report. [#3798 @dra27] * Determine jobs number at launch (`OpamStateConfig`) [#4004 @rjbou - fix #3986] * Fully test native Windows in the testsuite. [#3260 @dra27] * Allow native Windows to use Cygwin tool. [#3348 @dra27] * Deal with Windows path conventions (backslashes, .exe, etc.) [#3350 @dra27] * Correct display of dir separator on Windows. [#3893 @dra27] * Tested wrong variable in OPAMW_HasGlyp. [#3898 @dra27] * Default use `fetch` on FreeBSD, `ftp` on OpenBSD. [#3904 @hannesm] * Don't overwrite user's sandbow script modification. [#4020 #4092 @rjbou] * Handle `CCACHE_DIR` environment variable in sandbox script. [#4087 @rjbou - fix #4079] * Follow links of `~/.cache` & `~/.cache/dune` for bwrap call. [#4087 @rjbou - fix #4086] * On MacOS sandbox script, always read write mount `/tmp` [#3742 @rjbou - fix ocaml/opam-repository#13339] * Environment file right handling for empty switch. [#3899 @dra27] * Add colon for fish MANPATH fix. [#4084 @rjbou - fix #4078] * Update zsh check interactive terminal [#4095 @OCamlPro-mattiasdrp #4128 @AltGr] * Add package selection to `opam admin add-hashes` [#3787 @rjbou - fix #3767] * Download files (patches, etc.) using a safe filename. [#3900 @dra27] * `opam admin --add-constraints`, add constraint on depopts. [#4002 @rjbou - fix #3994] * Add `format-version` field to all opam files. [#3478 @AltGr] [#3906 @AltGr] * Clarify pin depend parse error. [#3762 @rjbou] * Opam file extensions (`x-` fields) enhancement. [#4049 @hannesm] * Add support for Z3 as a solver backend. [#3845 @AltGr] * Interleave download actions with build/install actions. [#3777 @Armael] [#4083 @rjbou - fix #4080] * Generalization of the job scheduler: provide separate job pools for different subsets of the tasks. [#3778 @AltGr] * Refactor the return types of `OpamSolution.{apply,resolve_and_apply}` [#3781 @Armael] * Use the scheduler pools to respect the download-jobs parameter. [#3791 @AltGr] * Set the right opam file `format-version` field on upgrade. [#4014 @rjbou] * Streamline the output from download action. [#3794 @AltGr] * Use a character that displays better on terminals for download action. [ #3802 @AltGr] * Change symbol for download action. [#3862 @AltGr] * Include the version number in "compilation failed" message. [#4052 @Armael] * Propagate `--force` remove option to directory tracking revert function. [#4094 @rjbou - fix #4091] * Add `OpamDirTack.string_of_changes` [#4107 @rjbou @hannesm] * Introduce state `drop` function to replace `ignore (unlock ..)` for more lock-type-safety. [#3783 @gasche - #3812 @rjbou] * Change `OpamStateTypes.switch_state.conf_files `from package_map` to `name_map` [#3799 @dra27] * Fix handling of availability outside of switches. [#3864 @AltGr] * Sorting formulas function. [#3945 @rjbou] * Sort formula: fix `compare_formula` & add `compare` [#3960 @rjbou] * Patch rewrite test. [#3456 @dra27] * Command errors display: differentiate command not found & permission denied. [#3865 @rjbou] * Factorize option functions in `OpamProcess` [#4016 @nobrakal] * Use ocaml code for looking up commands in `PATH` [#4072 @Armael] * Copy files using OCaml code instead of calling to cp or install [#4064 @Armael] * Sort & clean pkg:depend. [#4060 @rjbou - fix #4057] * Add `of_json` functions & crowbar. [#3776 @gasche] * JSON (de)serialization for OpamParallel graph. [#3786 @gasche] * Url: catch failure & specific exception. [#3946 @rjbou] * Update: don't update installed dev package that is not pinned. [#3947 @rjbou] * Use `OpamArg` helpers for option. [#4059 @rjbou] * Steps towards sudo-enabled make install. [#3522 @dra27] * Port build system to Dune (1.2) [#3618 @dra27] * Update shell/msvs-detect to 0.4.0. [#3869 @dra27] * Sort out repository script mode. [#3963 @dra27] * Preliminary support for Dune 2.0. [#3965 @dra27] * Update mccs.1.1+11 [#4109 #4146 @MisterDA] * Fix developer mode option. [#3646 @rjbou] * Ensure configure generates consistently. [#3935 @dra27] * Documentation [#3542 @0xflotus] [#3571 @hannesm] [#3780 @gasche] [#3944 @tchajed] [#3955 @nbraud] [#4106 @vp2177] [#3863 @dra27] [#3554 @rjbou - fix #3540 #2255c #3612 #3606c] [#4058 @rjbou] [#4114 @rjbou @AltGr] 2.0.7: * opam exec: display command not found message. [#4133 @rjbou - fix #4131] * Escape Windows paths on manpages. [#4129 @AltGr @rjbou - fix #4100] * Fix opam installer opam file. [#4058 @rjbou] * Fix various warnings. [#4132 @rjbou @AltGr - fix #4100] 2.0.6: * Do not fail if `$HOME/.ccache` is missing. [#3957 @mseri - fix https://discuss.ocaml.org/t/dune-1-11-1-compilation-failed/4248] * Add dune cache as rw. [#4019 @rjbou - fix #4012] * Check both size and mtime for dirtrack cached entries. [#4038 @hannesm] * Build man pages with dune. [#3937 @AltGr @dra27] * make cold: fail if patch or bunzip2 missing. [#4006 @rjbou - fix #3842] * Documentation [#3999 @maroneze] 2.0.5: * `opam lint --check-upstream` enables lint checks on archive urls. This option lead to download archives to check their checksum. [#3758 @rjbou] * Lint W59: No url checksum given (if `check-upstream` enabled). [#3758 @rjbou] * Lint E60: Unavailable archive or checksum mismatching (if `check-upstream` enabled). [#3758 @rjbou] * Lint E61: Out-of-scope `with-test` variable in `run-test:` field. [#3763 @rjbou - fix AltGr/Camelus/issues/27] * Lint W58: Restrain warning to filters. [#3871 @rjbou - fix ocaml/opam-repository#14280 (comment)] * Lint E61: Restrain to `run-test:`. [#3860 @rjbou] * Read jobs variable from `OpamStateConfig` [#3881 @dra27] * Fix cppo detection. [#3915 @rjbou] * Documentation [#3809#3891 @dra27] 2.0.4: * Remove mismatching extra-files: sort list before comparing them. [#3744 @rjbou] * Update source of (version) pinned directory. [#3726 @rjbou - fix #3651] * Fix `--ignore-pin-depends` with autopin. [#3736 @AltGr] * Fix pin not installing/upgrading already pinned package. [#3800 @AltGr] * Fix hg opam1.2 url parsing. [#3754 @rjbou] * Use `git -c diff.noprefix=false diff`. [#3788/#3628 @Blaisorblade - fix #3627] * Lint W47: Update warning message. [#3753 @rjbou - fix #3738] * Harmonization of `opam config list` and `opam config var `: resolve variable first with switch state (loading it only for package defined variables), otherwise, global state. [#3723 @rjbou - fix #3717] * Considering the possibility that TMPDIR is unset. [#3597 @herbelin - fix #3576] * Unconditionally display MANPATH when fish version is 2.7 or late. [#3728 @gregory-nisbet] * Fix precise tracking mode: missing `to_hex` conversion. [#3796 @rjbou] * Catch signal to select ones that are really cancelling a blocking state (e.g. waiting for a lock to be released). [#3541 @rjbou] * `opam clean`: ignore errors trying to remove directories. [#3732 @kit-ty-kate] * Documentation [#3731 @MisterDA] 2.0.3: * On init, retrieve `root is ok` from global options instead of initialization. [#3704 @rjbou - fix #3695] * Regenerate missing environment file. [#3691 @rjbou - fix #3690 #3594] * Documentation [#3703 @rjbou - fix #3700] 2.0.2: * Check consistency with opam file when reading lock file to suggest regeneration message [#3680 @rjbou - fix #3654] * Remove pin depends messages. [#3679 @rjbou] * Upgrade pin depends on pinning. [#3684 @rjbou - fix #3508] * To avoid lint warning 57 (description error) on 1.2 opam file pinning, add auxiliary files (descr, url) before linting. [#3687 @rjbou] * Don't check hash with --no-checksum on pull_upstream. [#3658 @rjbou - fix #3652] * Lint E52: Fix `light_uninstall` flag. [#3631 @rjbou - fix #3625] * On init, don't fail if empty compiler given. [#3633 @rjbou - fix #3614] * Sandbox: make `/var` read-only instead of empty and rw. [#3605 @bobot - fix #3604] * Handle symlinks in bwrap sandbox. [#3661 @mroch - fix #3660] * Sandbox: Change one-line conditional to `if` statement which was incompatible with `set -e`. [#3645 @rjbou - fix #3607] * Release use of unix sockets on MacOS. [#3663 @silene - fix #3659] * Fix closure computation in the presence of cycle. [#3670 @AltGr - fix #3662 #3666] * Fix some cases of listing coinstallable package. [#3689 @AltGr] * Extract archived source files of version-pinned packages. [#3610 @rjbou - fix #3600] * Add function to upgrade opam file, including its auxiliary files: descr, url, files/. [#3624 @rjbou] * Set `.out` suffix for `read_command_output` stdout file. [#3644 @rjbou] {2.0.2} * Default opam root is resolved at creation, in order to have the correct linked path. [#3681 @rjbou - fix #3622] * Reinsert and deprecate `alias-of` & `no-autoinstall` option. [#3685 @rjbou - fix #3390] * Updates for OCaml 4.07. [#3474 @dra27] * Documentation [#3656 @rjbou - fix #3634 #3653 #3639] [#3685 @rjbou - fix #3390] 2.0.1: * Add `opam list --silent` to not write in the output, exit with return code 0 if the list is not empty, 1 otherwise. [#3533 @rjbou - fix #3525] * Fix `opam list --external` [#3558 @rjbou - fix #3557 ocaml/opam-repository#12677] * Show command with local opam file returns local file information. Fixes also the non 1.2 conversion to 2.0 format of local files with `opam show --raw`. [#3536 @rjbou - fix #3423] * Show command display string fields printed with quotes, as lists. [#3368 @rjbou - fix #3365] * Pin edit: fix editing an opam file without a name field. [#3535 @rjbou] * Don't execute validation hook if update is empty. [#3490 @hannesm] * Git: fallback, fetch all repository remotes to get SHA1 with git < 2.1. [#3561 @rjbou - fix #3523 #3548] * Lint E57: A description or a synopsis must be present and non empty. [#3581 @rjbou - fix ocaml/opam-repository#12729] * Lint W58: Advise to use `with-test` and `with-doc` variables if `test` and `doc` are present. [#3591 @rjbou - fix #3580 ocaml/opam-repository#12729] * Add `gtar` as OpenBSD required tool, as tar does not support the `J` flag. [#3538 @adamsteen] * Hash: fallback to internal library in case of openssl error. [#3543 @rjbou - fix ocaml/opam-repository#12613] * Respect user's TMPDIR when invoking bwrap sandbox. [#3487 @3noch] * Add a way to mount unusual path in bwrap sandbox: introduction of `OPAM_USER_PATH_RO` environment variable. [#3540 @ErwanGa] * opam admin: handle non http backend on repository upgrade: compute hash only for http or distant rsync backend [#3596 @rjbou - fix #3590] * Upgrade to opam 2.0 format overlay opam files of pinned package. [#3528 @rjbou - fix #3513] * Add compiler file translation to opam 2.0 format function. [#3530 @rjbou - fix ocaml/opam-repository#12523] * Tar extract fail error message: if a tar extract fails, it checks the presence of underlying commands (bzip2, xz, lzma, gzip) to display the error message in verbose mode. [#3502 @rjbou - fix #3497] * Remove link files only if it exists. [#3519 @rjbou - fix ocaml/opam-depext#104] * Remove GNUism from bootstrap-ocaml.sh [#3481 @dra27 - fix #3480] * Avoid sed -i, a GNU sed extension, use mv instead [#3603 @hannesm] * Add patch & bunzip2 check in configure. [#3531 @rjbou - fix #3520] * Not having wget or curl is now only a hard-error if src_ext/archives doesn't contain the archives (i.e. if make -C src_ext cache-archives has not been run) which means that this should no longer be a requirement for building with the "full" tarball. [#3572 @dra27 - fix #3551] * C++ test for MCCS is now moved to the correct place and the message as to whether the solver will be build should work correctly with --disable-checks. Note that not having a C++ compiler is not considered an error if --disable-checks is specified because configure is permitted to believe that the MCCS library exists even if it couldn't detect it. [#3572 @dra27] 2.0.0 * Fixes and documentation * Add `opam admin add-hashes` helper to add more secure hashes to the repository 2.0.0~rc3 * Fixes * Added subcommand `switch link` to link a local switch to a defined one * Added option `--assume-built` to install an already built pinned package * Better Windows support * Obsolete `opam config setup` option 2.0.0~rc2 * Fixes * Much faster CUDF universe loading * Much faster `opam env` and similar commands * Added `opam admin check` for integrity checks on package repositories * Added the ability to setup scripts on `opam init` from `.opamrc` * Setup wrappers to sandbox builds by default, based on `bubblewrap` on Linux and `sandbox-exec` on MacOS * Windows support for many aspects including parallel processes, environment variables setup, color console and utf8 (using specific C stubs) * Better detection of the running shell * Added shell helpers to automatically sync the environment on every prompt * Support for selecting different backends if compiled in the `ocaml-mccs` solver lib 2.0.0~rc * Fixes * Support compiling on OCaml 4.06.0 * `opam env` and `opam exec` no longer set the `OPAMROOT` or `OPAMSWITCH` variables * Allow in-source package metadata to be gathered in an `opam/` directory 2.0.0~beta6 * Small UI fixes * Fixed a rare case of looping while processing actions 2.0.0~beta5 * Added timeout support to the solvers (default 1min) * Added `--unlock-base` to allow changing the compiler of a switch * Added the `{post}` dependency flag for packages to be installed together, but in no specific order. Use it for `base-*` packages. * Fixed issue with OCaml 4.05.0 and installed programs not found (`Unix.execvpe` behaviour changes, https://caml.inria.fr/mantis/view.php?id=7640) * Added a `pin-depends` field for easier development project dependency management and sharing * Some optimisations to repository loading * Fixed --best-effort with the built-in solver * Shorten conflict messages even more * Added `opam admin add-constraint` to amend a set of reverse dependencies in a repository * New format for `depexts:`, easier to understand and more flexible. Depexts for the host can now be inferred by opam * Optimised search criteria for the built-in solver * Added a `build-id` variable to identify package builds * Extend hooks (new variable `installed-files`, new session hooks) * `opam switch create DIR` now installs packages defined in `DIR` * Added system-related variables `arch`, `os`, `os-distribution`, `os-family`, `os-version` * Added support for using `opam.locked` files instead of `opam` ones (`--locked`) * Opam plugins are now made available across switches 2.0.0~beta4 * Building with OCaml < 4.02.3 is no longer supported * Support compilation with a built-in mccs solver (removing run-time dependency to aspcud). Integrated half-working "heuristics" dropped. * Remove jsonm and transitive uutf dependency. * Switch build systems to `jbuilder`, including `lib-ext` support * Allow repeated and or'd arguments to the `list` command * Many code and build system portability fixes (Windows, BSD) * Add `switch export --full` to include package definitions * Add `announce:` and `stamp:` fields to repositories (`repo` files) * Add a global cache of git objects (greatly speeding up multiple cloning) * Allow `opam pin URL` without a package name * Many error handling, messages and corner case fixes * Updated the versions of dependencies * Removed the unused `features:` field, and proposal for a new syntax * More informative exit codes, and documentation thereof 2.0.0~beta3 * (*) Renamed `--soft-request` to `--best-effort` * Fixed and improved speed of the package file tracking mechanism * Added `--ignore-constraints-on` to temporarily bypass version constraints on some dependencies * Fields `build-test:`, `build-doc:` are now deprecated, in favor of specifying conditions on the `with-test` and `with-doc` variables within the `build:` field, and of the new `run-test:` field * (*) The command-line options have been renamed accordingly to `--with-test` and `--with-doc` * Removed the `opam build` command * Allow directories in place of package specifications for the `install`, `remove`, `upgrade`, `reinstall` and `show` commands. `opam` files can also be specified for `install` and `show` * On local switch creation, check for package definitions and choose a compatible compiler if possible * Add `opam install|remove --destdir` to copy the package's installed files somewhere else * Allow `opam init --config=URL` 2.0~beta2 * Fixes (mainly to `opam build`) * Faster coinstallability check 2.0~beta * New, by-hash package archive caching system * Simpler HTTP repository update * Allow specification of multiple checksums per file * Add `opam reinstall --pending`, to handle reinstallations of changed packages * Support for defining trust anchors and repository validation hooks (for use with Conex) * (*) Added `opam install --working-dir`, removed "mixed mode" for pinned packages * Added `opam install --soft-request`, a non-failing "do what can be done" install mode * Simplified, better conflict messages * Added `opam list --coinstallable-with PKG` * Added command `opam clean` * Added `opam upgrade --all PKGS`, to do a full upgrade while guaranteeing `PKGS` are kept installed * Allow `&` in conflict version constraints, e.g. `conflicts: "foo" {>= "3" & < "4"}` * Added an `opam admin` command, with various, better organised repository admin commands, and remove the `opam-admin` tool * Added an `opam build` command, to handle `opam` files found in the current directory * Internally upgrade repositories in 1.2 format automatically to 2.0 (on `init`, `update` or `repo add`) 2.0~alpha5 * Merge stdout and stderr of child processes by default * Fixed regression on solver call times * Added a few shorter command aliases: `opam var` `opam exec`, `opam env` for the corresponding `opam config` commands * (*) Simplified `opam repo` to only use `add` and `remove` in normal use, always meaning the current switch (only) if not specified otherwise * (*) Restrict package names and versions to a reasonable character set * Added support for SHA256 and SHA512 checksums * Separated the opam format lexer/parser/printers into a separate `opam-file-format` library * Reporting on package definition file errors only when the file will be used, and on by default (rather than all-off by default, and optionally all-on) * `opam lint` now accept multiple input files * `opam pin` interface yet improved, allow pinning all at once when a source directory contains multiple packages. `opam unpin ` now allowed to cancel `opam pin ` * Updated version of the dose lib dependency * (*) All patch files used in package definitions are now assumed to apply with `-p1`. 2.0~alpha4 * Added pre and post hooks for package command sections; allowed per-switch configuration * Re-packaged the libraries and opam into 7 individual packages * Convert opam 1.2 files on the fly when pinning * `opam list` can now match patterns on versions * Allow switches to be created below arbitrary directories using `opam switch create `. Automatically select a switch found in `$PWD` * Add `install --reuse-build-dir` to be used together with `--keep-build-dir` and allow incremental recompilations * Add `install --inplace-build` to build locally pinned packages directly in their source directory 2.0~alpha3 * (*) Refactored 'opam switch' command, creation of new switches no longer implicit * (*) Allow per-switch selection of repositories * Better update of the environment variables across switches or opam roots * Add `opam install --restore` to recover packages that got removed due to errors or interruptions * Added `synopsis:` and `description:` fields to integrate package descriptions in a single package definition file * Removed the clever hack to skip downloads when uninstalling packages with `ocamlfind remove`; this now needs to be explicit through the `light-uninstall` flag. * Provide `opam admin upgrade-format` to migrate package repositories to the new format, and create the proper OCaml compiler package wrappers * Allow initialisation parameters from a .opamrc file, possibly completely overriding OCaml and opam.ocaml.org repository defaults 2.0~alpha2 * Extended the `opam lint` command-line options (package descriptions from opam metadata, warnings selection) * Allow to create a new switch with `opam switch import` * (*) Rewritten, much more flexible `opam list` command, with composable filters and output selection * Delay the removals of packages as much as possible, avoiding most cases of mass uninstalled packages after a build failure * Use a specific `opam` user-agent for downloads * Remove globalisation of compiler package variables and support for `available:` constraints depending on those. Rewrite the repository accordingly to use explicit dependencies towards the compiler version. 2.0~alpha * Changed license to LGPL 2.1 with linking exception, like OCaml (#2573) * Track files installed by packages for cleaner removal and listing, add `opam search --owns-file` (#502, #1215) *this requires packages to properly separate build and install*, or unrelated files could get removed on package uninstall. * Allow command wrappers around package build/install/remove commands to be defined in `~/.opam/config`; include sample Linux wrappers to restrict process permissions (e.g. ensure `build:` doesn't install) * (*) Reworked `opam show`, with more fields and the ability to select raw fields from the opam file (#2122) * Dropped ability to compile opam with OCaml earlier than 4.01.0 * Version constraints in `depopts:` allowed again, but with consistent semantics * Allow mixing filters within dependency constraints * More flexible `opam pin` command interface * New internal file-lock handling, less obtrusive and safer * New `switch export` format, now including local (pinned) package definitions * No longer uses insecure arguments of curl/wget (#55, #2006, #2460) * Installed package source and metadata are now handled per-switch, which is more reliable * `opam pin edit` now allows changing version and even URL; better editor handling * Discarded built-in variables based on polling OCaml (they are now defined by the compiler package at installation) * Discarded compiler files, `opam switch` now based on packages with the `compiler` flag set * Extended package configuration files * Allow initialised opam without switch, initialised switch without compiler. Better handling of compiler install failure * (*) Large API rework, switch and repository state now handled separately, used in functional style and avoiding many loads * Git submodules are now automatically fetched by the git backend * (*) Package definition files now prioritize `&` higher than `|`, like is most common * (*) `opam list -a` now lists all available packages, even if they can't be installed (missing depends...), which is much faster (#2370) * Added ability to reprint files with reduced diffs (#2363) * Url and description can now be included within a single package definition `opam` file (#2328) * Internal switch state now all below `/.opam-switch/`, state in a single `switch-state` file (#2340) * Add a `setenv:` field to package definitions, allowing to export environment variables (#2337, #2361) * Built-in support for alternative solver `mccs` (#2333) * `opam upgrade pkg` now prompts to install `pkg` if absent (#2327) * (*) Assume plugin package and exec names start with "opam-" (#2316, #2317) * Reworked, cleaner and bidirectional file manipulation library (kind of lenses) (#2325) * Allow packages to specify extra remote overlay files within their definition files * Heuristic to detect bad solutions and print a hint when no solver is available * (*) Proper URL handling with version-control + transport handling (e.g. `git+https://`) * Allow unescaped strings enclosed between `"""` markers in package definition files * Don't rely on '.zip' extension for downloaded archive handling (#2289) * `opam config` extended with `set`, `unset`, `expand` subcommands, allows variables in `exec` argument (#2268) * `conflict:` field is now handled as a disjunction in all regards (#2267) * Better handling of concurrent removal/build/install actions (#2161, #2266, #2370) * Allow fields `x-fieldname` in package definition files, for use by external tools (#2265) * Extended, more useful JSON output (including full package failure logs) (#2236) * Use the switch paths that are defined in the switch configuration file (#2185) * Allow package definition files to reference the package's own variables through "%{_:varname}%" (#2184) * Initialise number of jobs from host's number of processors (#2180) 1.2.2 * Fixed wrong locks being taken during `switch reinstall` (#2051) * Fixed `config report` that wasn't displaying the external solver (#2059) * Follow glibc standard on detecting an UTF8 locale (#2065) * Fixed issues with fish shell init scripts (#2063) * Restored printing of commands with `--verbose` and `--dry-run` * More concise printing of conflicts, with accurate version numbers * Small improvements to the causes of actions * Fixed issue causing the state cache not to be used on some OSes (OSX) (#2077) * Added numbers to lint checks, and some new checks * Restored the handling of a simple path to an `aspcud`-compatible executable in variable OPAMEXTERNALSOLVER (#2085) * Added package universe output to new PEF format for diagnostics * Prioritise newer versions even when the latest can't be installed (#2109) * Automatically install plugins on `opam plugin-name` (#2092) * Fixed a fd leak on solver calls (#2134) * Accept opam files with errors when no debug or strict options are set, for easier format updates * Add `opam list --resolve` to get dependencies as a consistent set of packages * Provide the expected checksum to download commands * Changed return code of `opam list` when no patterns are supplied and the list is empty 1.2.1 * Non-system compiler definitions without source are now allowed * Better handling of compiler "base" packages allows one to move build instructions from compiler definitions to packages * Rewritten action resolution mechanism to be based on atomic actions. Actions are not aborted anymore on first failure when there is no inter-dependency * Rewritten parallel command execution engine * Better display of actions, lots of improved messages * `opam upgrade pkg` now fails if no new version of `pkg` can be installed * fixed shell configuration for various shells * Updated Dose dependency to 3.3 * Fixed behaviour of `opam switch` and related commands when a switch is locally set in a shell (through `OPAMSWITCH`) * Better behaviour on failed `opam switch` * New pinning mode: when pinning using version-control on a local path and without a branch specified, use current file tree, but limited to version-tracked files * Faster and cleaner handling of downloads * Now compiles with --safe-string on OCaml 4.02, better compatibility handling * `opam unpin` now accepts multiple arguments * `opam pin add . ` is now allowed to specify the advertised version * Fixed bug leading to a bad `CAML_LD_LIBRARY_PATH` when switching from system * Better `opam lint`, reporting warnings and errors, including format errors * `opam config setup` now takes `--shell=` instead of `--sh`, `--csh`, `--fish`, `--zsh` * Provisional feature: dependency flag `dev` is accepted (but does nothing) * Provisional feature: field `features` in opam files implemented (beta), not for use in production * Better definition of the `filter` language within opam files: propagates undefined values, bool-to-string converter syntax * Provisional feature: `verbose` may be specified in package flags * OPAM git-like plugins (commands of the form opam-xxx) are now searched in the correct OPAM path * ~/.opam/config doesn't refer to OPAM's patch-version anymore, to allow downgrading * Recognise .opam files and directories when pinning a package to source * Cleaned up debug and verbose messages, allow more control (`-v` can now be repeated) * Pinning URL can now be explicit in the form `VC+URL`, e.g. `git+ssh://`, `hg+https://`... * New flexible way to specify download and solver commands in `~/.opam/config` or in variables `OPAMFETCH` and `OPAMEXTERNALSOLVER` * Lots of bug-fixes 1.2.0 * Handle locally installed self-upgrade opam binary (#1257) * Added `opam list --depends-on` to show reverse dependencies (#693) * More consistent checks on user-specified packages (#1241) * Handle version constraints from the command line (`package>=version`) (#380) * Output clear and concise messages on non solvable requests (#595, #1238) * Much better internal parser. File locations in error messages (#1260, #1222) * Removed dependency on camlp4 (#917) * Fixed orphan packages handling (installed packages with no upstream) (#1198) * Solver: optimize default preferences, depending on the solver version. New --criteria option (#1208) * Better PATH modifications handling, add 'opam config env --inplace-path' (#1189, #1749) * Specify variable overrides with environment OPAMVAR_name (#1153) * Much better overall failsafe behaviour. Error reports on interruption (#1202, #1125, #1188...) * Better action processing, with downloads first (#984) * Much improved and faster interface with the Cudf solver (#1185, #1179) * Ask the user to confirm actions whenever non-trivial (#1165) * Added option --show-actions, made --dry-run simulate actions (#1142) * Now prints meaningful causes explaining the actions (#1174) * Fixed the stats displayed after update (#1161) * Added variables to query ocaml native tools and arch (#979) * Enable packagers to specify mirrors in url files (#807) * Cleaned up the command-line interface (#1250, #1170, #1472). Incompatible changes: - 'opam config exec': takes command args directly rather than as a string (use -- for command arguments) - 'opam switch import|export': now have a mandatory FILE argument. '-f' no longer accepted. - 'opam pin' now takes a subcommand 'add', 'remove', 'list' or 'edit'. - 'opam config -env': no longer accepted for 'opam config env' - '--no-aspcud' is now '--use-internal-solver'. - Removed unused `opam config -I`, `opam config {asm,byte}{comp,link}` - '-r' isn't accepted anymore for '--root' * Much extended pinning features, with the ability to use opam files from the source, pin packages that don't exist in a repository, fill a local opam file from a template, etc. * Improved the internal solver to handle much larger problems (#1358) * Use Unix.lockf for more reliable internal repository locks (#1299) * Large performance improvements (#1363) * Upgraded external dependencies to dose 3.2.2, ocamlgraph 1.8.5, cmdliner 0.9.4, cudf 0.7 * Switch export file now include pinning data. Pinned package restored through 'opam switch import' (#1393) * Meaningful messages explaining why packages aren't available (#1419, #1398) * More informative 'opam config list', more complete 'opam config var' * Added 'opam config cudf-universe' for use in external tools * opam files: added a 'dev-repo' field, and the experimental 'flags' field (#1217, #1472) * Generate an opam-admin.top to easily apply scripts on a package repository (#1454). Provide scripts to ease adding new metadata ('dev-repo', etc.) * Added 'opam upgrade --fixup' to save the day if your installed package set gets inconsistent. * Fixed some return codes * Added option to query (recursive) (reverse) dependencies and external dependencies to 'opam list * Fixed opam init for some shells * OPAM search now includes the 'syntax' and 'libs' fields in the search, as well as 'findlib' files * 'opam source' command to get the package archive or upstream source easily * Added an 'install' field in opam files, to separate from build * Added the 'build', 'test' and 'doc' dependency flags to limit the scope of some dependencies * Added Check for common dependencies at init time * Pinning to a local git directory pins as path, but advertises pinning as git will now automatically select the pin kind to 'git' (#1555) * Fixed init scripts for fish and csh (#952) * More reliable and faster usage of git branches in the git backend * Friendlier env variable handling (true/1/yes or false/0/no/"" for true and false) (#1608) * Specify what is not rather than 'already up-to-date' when some packages couldn't be upgradedd (#1645) * Override Make variables in sub-processes (#1617) * 'opam update' no longer needed after 'opam repo add' * Attempt to read files in 'permissive mode' when they claim a newer OPAM version (#1662) * Fixed ignore of SIGPIPE in sub-processes (#1681) * New shell completion scripts * Added 'opam lint' to perform checks on opam files * Use the published version of jsonm rather than include it (#1574) * Changed findlib package name from 'opam' to 'opam-lib' * Hundreds of smaller fixes and UI improvements 1.1.2 * Rewritten, more compatible build system based on Makefiles (#1362, #1424) 1.1.1 * Fix `opam-admin make -r` (#990) * Explicitly prettyprint list of lists, to fix `opam-admin depexts` (#997) * Tell the user which fields is invalid in a configuration file (#1016) * Add `OpamSolver.empty_universe` for flexible universe instantiation (#1033) * Add `OpamFormula.eval_relop` and `OpamFormula.check_relop` (#1042) * Change `OpamCompiler.compare` to match `Pervasives.compare` (#1042) * Add `OpamCompiler.eval_relop` (#1042) * Add `OpamPackage.Name.compare` (#1046) * Add types `version_constraint` and `version_formula` to `OpamFormula` (#1046) * Clearer command aliases. Made `info` an alias for `show` and added the alias `uninstall` (#944) * Fixed `opam init --root=` (#1047) * Display OS constraints in `opam info` (#1052) * Add a new 'opam-installer' script to make `.install` files usable outside of opam (#1026) * Add a `--resolve` option to `opam-admin make` that builds just the archives you need for a specific installation (#1031) * Fixed handling of spaces in filenames in internal files (#1014) * Replace calls to `which` by a more portable call (#1061) * Fixed generation of the init scripts in some cases (#1011) * Better reports on package patch errors (#987, #988) * More accurate warnings for unknown package dependencies (#1079) * Added `opam config report` to help with bug reports (#1034) * Do not reinstall dev packages with `opam upgrade ` (#1001) * Be more careful with `opam init` to a non-empty root directory (#974) * Cleanup build-dir after successful compiler installation to save on space (#1006) * Improved OSX compatibility in the external solver tools (#1074) * Fixed messages printed on update that were plain wrong (#1030) * Improved detection of meaningful changes from upstream packages to trigger recompilation 1.1.0 [Oct 2013] * Fix update of dev packages (#962) * Add support for zip source archives (#958) * Add `OPAMCURL` environment variable to control invocation of curl (#960) * Ensure repository redirects only happen for http remotes (#955) * Turn malformed package files into warnings instead of hard errors (#957) * Improve robustness of pinned package update (#949) * Finish conversion of default repository to (#948) * Fix regression in handling archives with no extension (treat them as tar again) (#972) * Fixed stale archives causing packages to be marked as NEW when they weren't (#945) 1.1.0RC1 [Oct 2013] * Add `make cold` target to build OPAM without a system OCaml installed (#910) * More informative error messages from `curl` (#905) * Document use of `OPAMCOLOR` for optional ANSI coloring * Add `opam-admin depexts` utility to rewrite OPAM files with external dependencies * Added `repo` files for repository meta-information * Added support for repo redirections * Added scripts for automated testing in Travis * Fixed bug in opam-admin that could keep not up-to-date archives * Added an `opam-admin depexts` script to ease handling of external dependencies * Added the `--deps-only` option to `opam install` * Fixed upgrade with corner-cases of orphan packages * Added a `note` display form * Better handling of external solver failures, and added a `--no-aspcud` option * Fixed unpinning of some installed packages * Fixed upgrade of metadata from 1.0 when there are orphan custom compilers 1.1.0-beta [Sept 2013] * Automatic backup before any operation which might alter the list of installed packages * Support for arbitrary sub-directories for metadata repositories * Lots of colors * New option `opam update -u` equivalent to `opam update && opam upgrade --yes` * New `opam-admin` tool, bundling the features of `opam-mk-repo` and `opam-repo-check` + new 'opam-admin stats' tool * New `available`: field in opam files, superseding `ocaml-version` and `os` fields * Package names specified on the command-line are now understood case-insensitively (#705) * Fixed parsing of malformed opam files (#696) * Fixed recompilation of a package when uninstalling its optional dependencies (#692) * Added conditional post-messages support, to help users when a package fails to install for a known reason (#662) * Rewrite the code which updates pin et dev packages to be quicker and more reliable * Add {opam,url,desc,files/} overlay for all packages * `opam config env` now detects the current shell and outputs a sensible default if no override is provided. * Improve `opam pin` stability and start display information about dev revisions * Add a new `man` field in `.install` files * Support hierarchical installation in `.install` files * Add a new `stublibs` field in `.install` files * OPAM works even when the current directory has been deleted * speed-up invocation of `opam config var VARIABLE` when variable is simple (eg. `prefix`, `lib`, ...) * `opam list` now display only the installed packages. Use `opam list -a` to get the previous behavior. * Inverse the depext tag selection (useful for `ocamlot`) * Add a `--sexp` option to `opam config env` to load the configuration under emacs * Purge `~/.opam/log` on each invocation of OPAM * System compiler with versions such as `version+patches` are now handled as if this was simply `version` * New `OpamVCS` functor to generate OPAM backends * More efficient `opam update` * Switch license to LGPL with linking exception * `opam search` now also searches through the tags * minor API chanages for `API.list` and `API.SWITCH.list` * Improve the syntax of filters * Add a `messages` field * Add a `--jobs` command line option and add `%{jobs}%` to be used in OPAM files * Various improvements in the solver heuristics * By default, turn-on checking of certificates for downloaded dependency archives: use `./configure --disable-certificate-check` to go back to the previous behavior * Check the md5sum of downloaded archives when compiling OPAM * Improved `opam info` command (more information, non-zero error code when no patterns match) * Display OS and OPAM version on internal errors to ease error reporting * Fix `opam reinstall` when reinstalling a package which is a dependency of installed packages (regression introduced in 0.9.5) * Export and read `OPAMSWITCH` to be able to call OPAM in different switches * `opam-client` can now be used in a toplevel * `-n` now means `--no-setup` and not `--no-checksums` anymore * Fix support for FreeBSD * Fix installation of local compilers with local paths endings with `.../ocaml/` * Fix the contents of `~/.opam/opam-init/variable.sh` after a switch 1.0.0 [Mar 2013] * Improve the lexer performance (thx to @oandrieu) * Fix various typos (thx to @chaudhuri) * Fix build issue (thx to @avsm) 0.9.6 [Mar 2013] * Fix installation of pinned packages on BSD (thx to @smondet) * Fix configuration for zsh users (thx to @AltGr) * Fix loading of `~/.profile` when using dash (eg. in Debian/Ubuntu) * Fix installation of packages with symbolic links (regression introduced in 0.9.5) 0.9.5 [Mar 2013] * If necessary, apply patches and substitute files before removing a package * Fix `opam remove --keep-build-dir` keeps the folder if a source archive is extracted * Add build and install rules using ocamlbuild to help distro packagers * Support arbitrary level of nested subdirectories in packages repositories * Add `opam config exec "CMD ARG1 ... ARGn" --switch=SWITCH` to execute a command in a subshell * Improve the behaviour of `opam update` wrt. pinned packages * Change the default external solver criteria (only useful if you have aspcud installed on your machine) * Add support for global and user configuration for OPAM (`opam config setup`) * Stop yelling when OPAM is not up-to-date * Update or generate `~/.ocamlinit` when running `opam init` * Fix tests on *BSD (thx Arnaud Degroote) * Fix compilation for the source archive 0.9.4 [Feb 2013] * Disable auto-removal of unused dependencies. This can now be enabled on-demand using `-a` * Fix compilation and basic usage on Cygwin * Fix BSD support (use `type` instead of `which` to detect existing commands) * Add a way to tag external dependencies in OPAM files * Better error messages when trying to upgrade pinned packages * Display `depends` and `depopts` fields in `opam info` * `opam info pkg.version` shows the metadata for this given package version * Add missing `doc` fields in `.install` files * `opam list` now only shows installable packages 0.9.3 [Feb 2013] * Add system compiler constraints in OPAM files * Better error messages in case of conflicts * Cleaner API to install/uninstall packages * On upgrade, OPAM now perform all the remove action first * Use a cache for main storing OPAM metadata: this greatly speed-up OPAM invocations * after an upgrade, propose to reinstall a pinned package only if there were some changes * improvements to the solver heuristics * better error messages on cyclic dependencies 0.9.2 [Jan 2013] * Install all the API files * Fix `opam repo remove repo-name` * speed-up `opam config env` * support for `opam-foo` scripts (which can be called using `opam foo`) * 'opam update pinned-package' works * Fix 'opam-mk-repo -a' * Fix 'opam-mk-repo -i' * clean-up pinned cache dir when a pinned package fails to install 0.9.1 [Jan 2013] * Use ocaml-re 1.2.0 0.9.0 [Jan 2013] * add a new `--fake` option to simulate build and installation of packages. Use this option this care, it can easily corrupt the state of OPAM. * Better messages in case of error * OPAM proposes better solutions to the user * support for installed roots and auto-clean of unused packages * rename `--cores` to `--jobs` * better error messages for wrong argument of 'opam init' * show the root causes of actions done by OPAM * opam import and export now uses -f to specify the filename, and uses stdin and stdout if no filename is specified * Fix environment initialisation for some corner-cases * Add a way to specify how to run tests and build documentation for the packages * Display homepage, authors, doc link, license with 'opam info' * Improve `opam remove` efficiency when using `ocamlfind` command(s) only * Git pinning now works with commits/tags/branches * `opam init` works without preinstalled compiler * Support for DARCS backends * Each global command-line flag `xxx` as can be set using the `OPAMxxx` environment variable instead * Better display of compiler switch (+ read compiler descriptions) * Clearer error message when trying to pin a non-existing package * Fix issue with pinning to version number * Add a `shared` location to be used in OPAM files * Improve (but break) the command-line interface by using cmdliner 0.8.2 [Dec 2012] * Fix an issue with `opam reinstall` where packages were reinstalled in reverse order 0.8.1 [Nov 2012] * Simplify string substitution in OPAM files * Recompile the installed packages when the system compiler is upgraded * Fix various regressions in pinned and dev packages introduced in 0.8.0 0.8.0 [Nov 2012] * Improvements in the solver interface and API * The solver now use an external SAT-solver (aspcud) if found in the path * More expressive constraints in optional dependencies * Clean-up the build directory when build succeeds 0.7.7 [Oct 2012] * Add an `--alias` global command-line argument to overwrite the default alias value * Allow more concurrency between no conflicting opam commands * Upgrade to the latest version of DOSE and CUDF (solver libraries) * Add repository priorities * Create the default directories (`bin/`, `lib/` ...) when installing a new compiler 0.7.6 [Oct 2012] * major internal API refactoring * repositories are now versionned, and we try to auto-update when possible * more expressive compiler constraints in opam files 0.7.5 [Oct 2012] * dependencies can now be expressed by any formula (instead of just CNF) * It's easier to compose the value of environment variable (ie. to write `%{lwt+ssl:enable}%`) * Fix regression on init for rsync repositories 0.7.4 [Oct 2012] * improve `opam pin`: the code is more robust and it is now possible to pin a package to a git repository * add support for patches per package * add `opam switch -import file` and `opam switch -export file` 0.7.3 [Sep 2012] * Better user-message when no solution is found * Improve the minimality of installed packages 0.7.2 [Sep 2012] * Fix regression in init introcuced in 0.7.0 * Fix regression in update introduced in 0.7.0 0.7.1 [Sep 2012] * Remove forgotten debug statement 0.7.0 [Sep 2012] * report upgrade statistic on update * do no ask y/n when installing compiler's base packages * improve opam-mk-repo * fix `opam search` to be caseless * ability to filter some commands (depending on some predicates) in opam file * improvements when packages disappear upstream * check for ocaml 3.12.1 on configure * tell the user to unset some potentially dangerous variables when running opam * fix few git backend issues 0.6.0 [Sep 2012] * semantics changes in `opam switch` * solver improvements in case of install and remove * better error reporting * fix caching of package archives * fix `~/.opam/repo/index` priorities 0.5.0 [Sep 2012] * add opam search * add opam reinstall * ability to upgrade only a subset of packages * lot of bug fixes in the rsync and curl backend * better `--help` messages * better information displayed to the user 0.4.0 [Aug 2012] * better layout of repository files * (partial) possibility to specify archive checksums * if the archive is not on ocamlpro.com, download it upstream * suffix +opam to the versions of archives available on ocamlpro.com * prompt the user to evaluate `opam config -env` more often * changes in meta-data aren't picked up by the CURL backen * more modulare repository system: the 'kind' of repository is no more linked to the kind of package archives 0.3.2 [Aug 2012] * fix regression for `opam switch` introduced in 0.3 * fix deletion of optional dependencies * support for pinned packages * fix compilation for ocaml 4.00 * fix compilation for *BSD 0.3.1 [Jul 2012] * fix regression for `opam install` introduced in 0.3 0.3.0 [Jul 2012] * improve parallel compilation of packages * better recovery on compilation/installation errors * first draft of version pinnig * fix`'opam config -env` for old shells * install the latest version of packages when possible * more robust `opam update` (ie. old files are gc-ed) * add a (more or less) generic way to install and use topfind 0.2.0 [Jul 2012] * more robust switch command * more robust parallel build (not yet activated by default) * support for compiler-constraints in packages * new solver heuristics * improved performance on init with the rsync backend 0.1.0 [Jun 2012] * Initial version opam-2.1.5/.ocamlinit0000644000175000017500000000107014427463453013475 0ustar stephsteph#use "topfind";; #use "down.top";; #require "opam-client";; OpamClientConfig.opam_init ();; let gt = OpamGlobalState.load `Lock_none;; OpamConsole.msg "Opam global state for %s loaded in 'gt'\n" OpamStateConfig.(OpamFilename.Dir.to_string !r.root_dir);; let rt = OpamRepositoryState.load `Lock_none gt;; OpamConsole.msg "Opam repository state loaded in 'rt'\n";; let st = OpamSwitchState.load `Lock_none gt rt (OpamStateConfig.get_switch ());; OpamConsole.msg "Opam switch state of '%s' loaded in 'st'\n" (OpamSwitch.to_string (OpamStateConfig.get_switch ()));; opam-2.1.5/CONTRIBUTING.md0000644000175000017500000000100614427463453013745 0ustar stephstephBug reports and feature requests for **the opam tool** should be reported on: * http://github.com/ocaml/opam/issues (please include the output of `opam config report` whenever possible) **Packaging issues** or requests for a new package should be reported on: * http://github.com/ocaml/opam-repository/issues **General queries** can be addressed at: * http://lists.ocaml.org/listinfo/platform (for the both the tool & packages) * http://lists.ocaml.org/listinfo/opam-devel (for the tool and its evolution) opam-2.1.5/opam-admin.opam0000644000175000017500000000144314427463453014421 0ustar stephstephopam-version: "2.0" synopsis: "Meta-package for Dune" maintainer: "opam-devel@lists.ocaml.org" authors: [ "Vincent Bernardoff " "Raja Boujbel " "Roberto Di Cosmo " "Thomas Gazagnaire " "Louis Gesbert " "Fabrice Le Fessant " "Anil Madhavapeddy " "Guillem Rieu " "Ralf Treinen " "Frederic Tuong " ] homepage: "https://opam.ocaml.org/" bug-reports: "https://github.com/ocaml/opam/issues" license: "LGPL-2.1-only WITH OCaml-LGPL-linking-exception" depends: [ "dune" {>= "1.11.0"} "re" {>= "1.9.0"} "opam-file-format" {>= "2.1.4"} ] opam-2.1.5/.github/0002755000175000017500000000000014427463453013061 5ustar stephstephopam-2.1.5/.github/workflows/0002755000175000017500000000000014427463453015116 5ustar stephstephopam-2.1.5/.github/workflows/ci.yml0000644000175000017500000002254614427463453016243 0ustar stephstephname: Builds, tests & co on: [ push, pull_request ] env: OPAMBSVERSION: 2.1.0-beta4 OPAMBSROOT: ~/.cache/.opam.cached OPAM12CACHE: ~/.cache/opam1.2/cache # This should be identical to the value in appveyor.yml OPAM_TEST_REPO_SHA: 3d6779beedc761067596bf5c3f5c25ab57a7e3e7 OPAM_REPO_SHA: 3d6779beedc761067596bf5c3f5c25ab57a7e3e7 # Default ocaml version for some jobs OCAML_VERSION: 4.12.0 ## variables for cache paths GH_OCAML_CACHE: ~/.cache/ocaml-local/** SOLVER: defaults: run: shell: bash jobs: #### # Caches #### # ocaml-cache: # runs-on: ${{ matrix.os }} # strategy: # matrix: # os: [ ubuntu-latest ] # ocamlv: [ 4.02.3, 4.03.0, 4.04.2, 4.05.0, 4.06.1, 4.07.1, 4.08.1, 4.09.1, 4.10.2, 4.11.2 ] # include: # - os: macos-latest # ocamlv: 4.11.2 # fail-fast: false # steps: # - uses: actions/checkout@v2 # - name: ocaml ${{ matrix.ocamlv }} cache # id: ocaml-cache # uses: actions/cache@v2 # with: # path: ${{ env.GH_OCAML_CACHE }} # key: ${{ runner.os }}-ocaml-${{ matrix.ocamlv }}-${{ hashFiles ('.github/scripts/ocaml-cache.sh', '.github/scripts/preamble.sh') }} # - name: Building ocaml ${{ matrix.ocamlv }} cache # if: steps.ocaml-cache.outputs.cache-hit != 'true' # env: # OCAML_VERSION: ${{ matrix.ocamlv }} # run: bash -exu .github/scripts/ocaml-cache.sh ocaml archives-cache: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: src ext archives cache id: archives uses: actions/cache@v2 with: path: src_ext/archives key: archives-${{ hashFiles('src_ext/Makefile.sources', 'src_ext/Makefile') }} - name: Retrieve archives if: steps.archives.outputs.cache-hit != 'true' run: |#bash -exu .github/scripts/caches.sh archives rm -rf src_ext/archives export PATH=~/.cache/ocaml-local/bin:$PATH which ocaml && export OCAML=`which ocaml` || true make -C src_ext cache-archives ls src_ext/archives -al #### # Build #### build: runs-on: ${{ matrix.os }} strategy: matrix: os: [ ubuntu-latest ] ocamlv: [ 4.02.3, 4.03.0, 4.04.2, 4.05.0, 4.06.1, 4.07.1, 4.08.1, 4.09.1, 4.10.2, 4.11.2, 4.12.1, 4.13.1, 4.14.0, 5.0.0~beta2 ] include: - os: macos-latest ocamlv: 4.12.0 # Intentionnaly fail fast, no need to run all build if there is a # problem in a given version; usually it is functions not defined in lower # versions of caml # fail-fast: false steps: - name: install deps if: ${{ matrix.os == 'ubuntu-latest' }} run: sudo apt install bubblewrap - uses: actions/checkout@v2 - name: ocaml ${{ matrix.ocamlv }} cache id: ocaml-cache uses: actions/cache@v2 with: path: ${{ env.GH_OCAML_CACHE }} key: ${{ runner.os }}-ocaml-${{ matrix.ocamlv }}-${{ hashFiles ('.github/scripts/ocaml-cache.sh', '.github/scripts/preamble.sh') }} - name: Building ocaml ${{ matrix.ocamlv }} cache if: steps.ocaml-cache.outputs.cache-hit != 'true' env: OCAML_VERSION: ${{ matrix.ocamlv }} run: bash -exu .github/scripts/ocaml-cache.sh ocaml - name: Build env: OCAML_VERSION: ${{ matrix.ocamlv }} run: bash -exu .github/scripts/main.sh #### # Opam tests #### test: needs: [ build, archives-cache ] runs-on: ${{ matrix.os }} strategy: matrix: os: [ ubuntu-latest, macos-latest ] ocamlv: [ 4.12.0 ] fail-fast: false env: OPAM_TEST: 1 steps: - uses: actions/checkout@v2 - name: install deps if: ${{ matrix.os == 'ubuntu-latest' }} run: sudo apt install bubblewrap - name: ocaml ${{ matrix.ocamlv }} cache - test id: ocaml-cache-test uses: actions/cache@v2 with: path: ${{ env.GH_OCAML_CACHE }} key: ${{ runner.os }}-ocaml-${{ matrix.ocamlv }}-${{ hashFiles ('.github/scripts/ocaml-cache.sh', '.github/scripts/preamble.sh') }}-test - name: Building ocaml ${{ env.OCAML_VERSION }} cache - test if: steps.ocaml-cache-test.outputs.cache-hit != 'true' env: OCAML_VERSION: ${{ matrix.ocamlv }} run: bash -exu .github/scripts/ocaml-cache.sh ocaml - name: opam bootstrap cache id: opam-bootstrap uses: actions/cache@v2 with: path: | ${{ env.OPAMBSROOT }}/** ~/.cache/opam-local/bin/** key: opam-${{ runner.os }}-${{ env.OPAMBSVERSION }}-${{ matrix.ocamlv }}-${{ env.OPAM_REPO_SHA }}-${{ hashFiles ('.github/scripts/opam-bs-cache.sh', '.github/scripts/preamble.sh') }} - name: opam root cache if: steps.opam-bootstrap.outputs.cache-hit != 'true' run: bash -exu .github/scripts/opam-bs-cache.sh - name: opam-rt cache id: opam-rt uses: actions/cache@v2 with: path: ~/.cache/opam-rt/** key: ${{ runner.os }}-opam-rt-${{ matrix.ocamlv }} - name: Test env: OCAML_VERSION: ${{ matrix.ocamlv }} run: bash -exu .github/scripts/main.sh #### # Opam cold #### cold: needs: [ build, archives-cache ] runs-on: ${{ matrix.os }} strategy: matrix: # os: [ ubuntu-latest, macos-latest ] os: [ ubuntu-latest ] ocamlv: [ 4.12.0 ] fail-fast: false steps: - name: install deps if: ${{ matrix.os == 'ubuntu-latest' }} run: sudo apt install bubblewrap - uses: actions/checkout@v2 - name: src ext archives cache uses: actions/cache@v2 with: path: src_ext/archives key: archives-${{ hashFiles('src_ext/Makefile.sources', 'src_ext/Makefile') }} - name: Cold env: OCAML_VERSION: ${{ matrix.ocamlv }} OPAM_COLD: 1 run: | make compiler make lib-pkg bash -exu .github/scripts/main.sh #### # Compile solver backends #### solvers: needs: [ build ] runs-on: ${{ matrix.os }} strategy: matrix: os: [ ubuntu-latest, macos-latest ] ocamlv: [ 4.12.0 ] solver: [ z3, 0install ] fail-fast: false env: SOLVER: ${{ matrix.solver }} OPAM_REPO_SHA: 3d6779beedc761067596bf5c3f5c25ab57a7e3e7 OPAMBSROOT: ~/.cache/opam.${{ matrix.solver }}.cached steps: - uses: actions/checkout@v2 - name: install deps if: ${{ matrix.os == 'ubuntu-latest' }} run: sudo apt install bubblewrap - name: ocaml ${{ matrix.ocamlv }} cache - test id: ocaml-cache-test uses: actions/cache@v2 with: path: ${{ env.GH_OCAML_CACHE }} key: ${{ runner.os }}-ocaml-${{ matrix.ocamlv }}-${{ matrix.solver }}-${{ hashFiles ('.github/scripts/ocaml-cache.sh', '.github/scripts/preamble.sh') }}-test - name: Building ocaml ${{ env.OCAML_VERSION }} cache - test if: steps.ocaml-cache-test.outputs.cache-hit != 'true' env: OCAML_VERSION: ${{ matrix.ocamlv }} run: bash -exu .github/scripts/ocaml-cache.sh ocaml - name: opam bootstrap cache id: opam-bootstrap uses: actions/cache@v2 with: path: | ~/.cache/opam.${{ matrix.solver }}.cached ~/.cache/opam-local/bin/** key: opam-${{ matrix.solver }}-${{ runner.os }}-${{ env.OPAMBSVERSION }}-${{ matrix.ocamlv }}-${{ hashFiles ('.github/scripts/opam-bs-cache.sh', '.github/scripts/preamble.sh') }} - name: opam root cache env: OPAMBSROOT: ~/.cache/opam.${{ matrix.solver }}.cached if: steps.opam-bootstrap.outputs.cache-hit != 'true' run: bash -exu .github/scripts/opam-bs-cache.sh - name: Compile env: OCAML_VERSION: ${{ matrix.ocamlv }} run: bash -exu .github/scripts/solvers.sh #### # Upgrade from 1.2 to current #### upgrade: needs: [ build ] runs-on: ${{ matrix.os }} strategy: matrix: os: [ ubuntu-latest, macos-latest ] ocamlv: [ 4.12.0 ] fail-fast: false steps: - name: install deps if: ${{ matrix.os == 'ubuntu-latest' }} run: sudo apt install bubblewrap - uses: actions/checkout@v2 - name: opam 1.2 root cache uses: actions/cache@v2 with: path: ${{ env.OPAM12CACHE }} key: ${{ runner.os }}-opam1.2-root - name: ocaml ${{ matrix.ocamlv }} cache id: ocaml-cache uses: actions/cache@v2 with: path: ${{ env.GH_OCAML_CACHE }} key: ${{ runner.os }}-ocaml-${{ matrix.ocamlv }}-${{ hashFiles ('.github/scripts/ocaml-cache.sh', '.github/scripts/preamble.sh') }} - name: Building ocaml ${{ matrix.ocamlv }} cache if: steps.ocaml-cache.outputs.cache-hit != 'true' env: OCAML_VERSION: ${{ matrix.ocamlv }} run: bash -exu .github/scripts/ocaml-cache.sh ocaml - name: Upgrade env: OCAML_VERSION: ${{ matrix.ocamlv }} OPAM_UPGRADE: 1 run: bash -exu .github/scripts/main.sh #### # Around opam tests ### hygiene: needs: [ archives-cache ] runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: src ext archives cache uses: actions/cache@v2 with: path: src_ext/archives key: archives-${{ hashFiles('src_ext/Makefile.sources', 'src_ext/Makefile') }} - name: Hygiene env: # Defined only on pull request jobs BASE_REF_SHA: ${{ github.event.pull_request.base.sha }} PR_REF_SHA: ${{ github.event.pull_request.head.sha }} run: bash -exu .github/scripts/hygiene.sh opam-2.1.5/.github/workflows/changelog_check.yml0000644000175000017500000000030714427463453020723 0ustar stephstephname: Changelog check on: pull_request: branches: master jobs: diff: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - run: bash .github/scripts/changelog_checker opam-2.1.5/.github/pull_request_template.md0000644000175000017500000000007214427463453020017 0ustar stephstephPlease update `master_changes.md` file with your changes. opam-2.1.5/.github/issue_template.md0000644000175000017500000000044414427463453016426 0ustar stephsteph> If your issue concerns a package not building, please report to > https://github.com/ocaml/opam-repository/issues or to the package maintainer > unless you are confident it is an issue in the opam tool itself. ``` ``` opam-2.1.5/.github/scripts/0002755000175000017500000000000014427463453014550 5ustar stephstephopam-2.1.5/.github/scripts/changelog_checker0000644000175000017500000000231314427463453020103 0ustar stephsteph# This script check that the current master changelog has been updated by PR, # ignoring some internal files. # It is used byt the changelog_check github action. # (c) Copyright Raja Boujbel OCamlPro 2020 set -ue IGNORE=" .gitattributes .github .gitignore .ocamlinit .ocp-indent .ocplint .travis-ci.sh .travis.yml AUTHORS CONTRIBUTING.md README.md appveyor.patch appveyor.yml appveyor_build.cmd appveyor_test.sh master_changes.md shell/install.sh " changelog=master_changes.md diffile=/tmp/diff git fetch origin $GITHUB_BASE_REF --depth=1 --quiet echo "> base commit" git show origin/$GITHUB_BASE_REF --format=oneline -s git diff origin/$GITHUB_BASE_REF --name-only --diff-filter=AMRCX > $diffile updated=0 grep -sq $changelog $diffile || updated=1 echo "> all changes" cat $diffile for ign in $IGNORE ; do sed -i "/^${ign//\//\\\/}/d" $diffile done echo "> kept changes" cat $diffile num_changes=`wc -l $diffile | cut -f 1 -d ' '` if [ $num_changes -ne 0 ] ; then if [ $updated -eq 0 ] ; then echo -e "\033[32mChangelog updated\033[m" else echo -e "\033[31mPlease update changelog in master_changes.md\033[m" exit 1 fi else echo -e "\033[33mCommitted files not concerned by changelog\033[m" fi opam-2.1.5/.github/scripts/preamble.sh0000644000175000017500000000306614427463453016676 0ustar stephsteph CWD=$PWD CACHE=~/.cache CACHE=`eval echo $CACHE` echo "Cache -> $CACHE" OCAML_LOCAL=$CACHE/ocaml-local OPAM_LOCAL=$CACHE/opam-local PATH=$OPAM_LOCAL/bin:$OCAML_LOCAL/bin:$PATH; export PATH OPAM_COLD=${OPAM_COLD:-0} OPAM_TEST=${OPAM_TEST:-0} OPAM_UPGRADE=${OPAM_UPGRADE:-0} OPAM12CACHE=`eval echo $OPAM12CACHE` OPAMBSROOT=`eval echo $OPAMBSROOT` OPAMBSSWITCH=opam-build case $GITHUB_EVENT_NAME in pull_request) BRANCH=$GITHUB_HEAD_REF ;; push) BRANCH=${GITHUB_REF##*/} ;; *) echo -e "Not handled event" BRANCH=master esac git config --global user.email "gha@example.com" git config --global user.name "Github Actions CI" git config --global gc.autoDetach false # used only for TEST jobs init-bootstrap () { if [ "$OPAM_TEST" = "1" ] || [ -n "$SOLVER" ]; then set -e export OPAMROOT=$OPAMBSROOT # The system compiler will be picked up opam init --yes --no-setup git+https://github.com/ocaml/opam-repository#$OPAM_REPO_SHA cat >> $OPAMROOT/config <.cached export OPAMROOT=$OPAMBSROOT echo $OPAMROOT case "$SOLVER" in z3) PKGS=$SOLVER ;; 0install) PKGS="$SOLVER opam-0install-cudf" ;; *) echo -e "\e[31mSolver $SOLVER not handled\e[0m"; exit 3 ;; esac opam switch create $SOLVER ocaml-system || true opam install $PKGS opam install . --deps opam clean --logs --switch-cleanup eval $(opam env) ./configure make opam-2.1.5/.github/scripts/hygiene.sh0000644000175000017500000001151614427463453016536 0ustar stephsteph#!/bin/bash -xue . .github/scripts/preamble.sh if [ "$GITHUB_EVENT_NAME" = "pull_request" ] && [ "x" = "x$BASE_REF_SHA$PR_REF_SHA" ] ; then echo "Variables BASE_REF_SHA and PR_REF_SHA must be defined in a pull request job" exit 2 fi # Don't use BASE_REF_SHA and PR_REF_SHA on non pull request jobs, they are not # defined. See .github/workflows/ci.yml hygiene job. if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then # needed for git diffs and rev-list # we need to get history from base ref to head ref for check configure depth=10 set +e git cat-file -e $BASE_REF_SHA r=$? while [ $r -ne 0 ] ; do git fetch origin $GITHUB_REF --depth=$depth depth=$(( $depth + 10 )) git cat-file -e $BASE_REF_SHA r=$? done set -e fi CheckConfigure () { GIT_INDEX_FILE=tmp-index git read-tree --reset -i "$1" git diff-tree --diff-filter=d --no-commit-id --name-only -r "$1" \ | (while IFS= read -r path do case "$path" in configure|configure.ac|m4/*) touch CHECK_CONFIGURE;; esac done) rm -f tmp-index if [[ -e CHECK_CONFIGURE ]] ; then echo "configure generation altered in $1" echo 'Verifying that configure.ac generates configure' git clean -dfx git checkout -f "$1" mv configure configure.ref make configure if ! diff -q configure configure.ref >/dev/null ; then echo -e "[\e[31mERROR\e[0m] configure.ac in $1 doesn't generate configure, \ please run make configure and fixup the commit" ERROR=1 else echo "configure ok for $1" fi fi } set +x ERROR=0 ### # Check configure ### (set +x ; echo -en "::group::check configure\r") 2>/dev/null case $GITHUB_EVENT_NAME in push) CheckConfigure "$GITHUB_SHA" ;; pull_request) CheckConfigure "$PR_REF_SHA" ;; #git rev-list $BASE_REF_SHA...$PR_REF_SHA --reverse #for commit in $(git rev-list $BASE_REF_SHA...$PR_REF_SHA --reverse) #do # echo "check configure for $commit" # CheckConfigure "$commit" #done #;; *) echo "no configure to check for unknown event" ;; esac (set +x ; echo -en "::endgroup::check configure\r") 2>/dev/null ### # Check install.sh ### if [ "$GITHUB_EVENT_NAME" = "pull_request" ] ; then (set +x ; echo -en "::group::check install.sh\r") 2>/dev/null if ! git diff "$BASE_REF_SHA..$PR_REF_SHA" --name-only --exit-code -- shell/install.sh > /dev/null ; then echo "shell/install.sh updated - checking it" eval $(grep '^\(OPAM_BIN_URL_BASE\|DEV_VERSION\|VERSION\)=' shell/install.sh) echo "OPAM_BIN_URL_BASE=$OPAM_BIN_URL_BASE" echo "VERSION = $VERSION" echo "DEV_VERSION = $DEV_VERSION" for VERSION in $DEV_VERSION $VERSION; do eval $(grep '^TAG=' shell/install.sh) echo "TAG = $TAG" ARCHES=0 while read -r key sha do ARCHES=1 URL="$OPAM_BIN_URL_BASE$TAG/opam-$TAG-$key" echo "Checking $URL" check=$(curl -Ls "$URL" | sha512sum | cut -d' ' -f1) if [ "$check" = "$sha" ] ; then echo "Checksum as expected ($sha)" else echo -e "[\e[31mERROR\e[0m] Checksum downloaded: $check" echo -e "[\e[31mERROR\e[0m] Checksum install.sh: $sha" ERROR=1 fi done < <(sed -ne "s/.*opam-$TAG-\([^)]*\).*\"\([^\"]*\)\".*/\1 \2/p" shell/install.sh) done if [ $ARCHES -eq 0 ] ; then echo "[\e[31mERROR\e[0m] No sha512 checksums were detected in shell/install.sh" echo "That can't be right..." ERROR=1 fi else echo "No changes in install.sh" fi (set +x ; echo -en "::endgroup::check install.sh\r") 2>/dev/null fi ### # Check src_ext patches ### (set +x ; echo -en "::group::check src_ext patches\r") 2>/dev/null # Check that the lib-ext/lib-pkg patches are "simple" make -C src_ext PATCH="busybox patch" clone make -C src_ext PATCH="busybox patch" clone-pkg # Check that the lib-ext/lib-pkg patches have been re-packaged cd src_ext ../shell/re-patch.sh if [[ $(find patches -name \*.old | wc -l) -ne 0 ]] ; then echo -e "[\e[31mERROR\e[0m] ../shell/re-patch.sh should be run from src_ext before CI check" git diff ERROR=1 fi cd .. (set +x ; echo -en "::endgroup::check src_ext patches\r") 2>/dev/null ### # Default cli version check ### if [ "$GITHUB_EVENT_NAME" = "push" ] && [ "$BRANCH" = "master" ]; then (set +x ; echo -en "::group::check default cli\r") 2>/dev/null CURRENT_MAJOR="`sed -n "s/^AC_INIT(opam,\([0-9]\+\)[^0-9]*.*)$/\1/p" configure.ac`" DEFAULT_CLI_MAJOR="`sed -n "/let *default *=/s/.*(\([0-9]*\)[^0-9]*.*/\1/p" src/client/opamCLIVersion.ml`" if [ $CURRENT_MAJOR -eq $DEFAULT_CLI_MAJOR ]; then echo "Major viersion is default cli one: $CURRENT_MAJOR" else echo -e "[\e[31mERROR\e[0m] Major version $CURRENT_MAJOR and default cli version $DEFAULT_CLI_MAJOR mismatches" (set +x ; echo -en "::endgroup::check default cli\r") 2>/dev/null ERROR=1 fi fi exit $ERROR opam-2.1.5/.github/scripts/main.sh0000644000175000017500000001107114427463453016026 0ustar stephsteph#!/bin/bash -xue . .github/scripts/preamble.sh unset-dev-version () { # disable git versioning to allow OPAMYES use for upgrade touch src/client/no-git-version } export OPAMYES=1 export OCAMLRUNPARAM=b ( # Run subshell in bootstrap root env to build (set +x ; echo -en "::group::build opam\r") 2>/dev/null if [[ $OPAM_TEST -eq 1 ]] ; then export OPAMROOT=$OPAMBSROOT # If the cached root is newer, regenerate a binary compatible root opam env || { rm -rf $OPAMBSROOT; init-bootstrap; } eval $(opam env) fi ./configure --prefix ~/local --with-mccs if [ "$OPAM_TEST" != "1" ]; then echo 'DUNE_PROFILE=dev' >> Makefile.config fi if [[ $OPAM_TEST$OPAM_COLD -eq 0 ]] ; then make lib-ext fi if [ $OPAM_UPGRADE -eq 1 ]; then unset-dev-version fi make all admin rm -f ~/local/bin/opam make install (set +x ; echo -en "::endgroup::build opam\r") 2>/dev/null export PATH=~/local/bin:$PATH opam config report if [ "$OPAM_TEST" = "1" ]; then # test if an upgrade is needed set +e opam list 2> /dev/null rcode=$? if [ $rcode -eq 10 ]; then echo "Recompiling for an opam root upgrade" (set +x ; echo -en "::group::rebuild opam\r") 2>/dev/null unset-dev-version make all admin rm -f ~/local/bin/opam make install opam list 2> /dev/null rcode=$? set -e if [ $rcode -ne 10 ]; then echo -e "\e[31mBad return code $rcode, should be 10\e[0m"; exit $rcode fi (set +x ; echo -en "::endgroup::rebuild opam\r") 2>/dev/null fi set -e # Note: these tests require a "system" compiler and will use the one in $OPAMBSROOT make tests make distclean # Compile and run opam-rt (set +x ; echo -en "::group::opam-rt\r") 2>/dev/null opamrt_url="https://github.com/ocaml-opam/opam-rt" if [ ! -d $CACHE/opam-rt ]; then git clone $opamrt_url $CACHE/opam-rt fi cd $CACHE/opam-rt git fetch origin if git ls-remote --exit-code origin $BRANCH ; then if git branch | grep -q $BRANCH; then git checkout $BRANCH git reset --hard origin/$BRANCH else git checkout -b $BRANCH origin/$BRANCH fi else git checkout master git reset --hard origin/master fi test -d _opam || opam switch create . --no-install --formula '"ocaml-system"' eval $(opam env) opam pin $GITHUB_WORKSPACE -yn --with-version to-test # opam lib pins defined in opam-rt are ignored as there is a local pin opam pin . -yn --ignore-pin-depends opam install opam-rt --deps-only opam-devel.to-test make || { opam reinstall opam-client -y; make; } (set +x ; echo -en "::endgroup::opam-rt\r") 2>/dev/null fi ) export PATH=~/local/bin:$PATH if [ $OPAM_UPGRADE -eq 1 ]; then OPAM12=$OPAM12CACHE/bin/opam if [[ ! -f $OPAM12 ]]; then mkdir -p $OPAM12CACHE/bin os="Linux" if [ "$RUNNER_OS" = "macOS" ]; then os="Darwin" fi wget "https://github.com/ocaml/opam/releases/download/1.2.2/opam-1.2.2-x86_64-$os" -O $OPAM12 chmod +x $OPAM12 fi export OPAMROOT=/tmp/opamroot rm -rf $OPAMROOT if [[ ! -d $OPAM12CACHE/root ]]; then $OPAM12 init cp -r /tmp/opamroot/ $OPAM12CACHE/root else cp -r $OPAM12CACHE/root /tmp/opamroot fi set +e $OPAM12 --version opam --version opam update rcode=$? if [ $rcode -ne 10 ]; then echo "Bad return code $rcode, should be 10"; exit $rcode fi opam_version=$(sed -ne 's/opam-version: *//p' $OPAMROOT/config) if [ "$opam_version" = '"1.2"' ]; then echo -e "\e[31mUpgrade failed, opam-root is still 1.2\e[0m"; cat $OPAMROOT/config exit 2 fi exit 0 fi ( # Finally run the tests, in a clean environment export OPAMKEEPLOGS=1 if [[ $OPAM_TEST -eq 1 ]] ; then cd $CACHE/opam-rt make KINDS="local git" run else if [[ $OPAM_COLD -eq 1 ]] ; then export PATH=$PWD/bootstrap/ocaml/bin:$PATH fi # Test basic actions # The SHA is fixed so that upstream changes shouldn't affect CI. The SHA needs # to be moved forwards when a new version of OCaml is added to ensure that the # ocaml-system package is available at the correct version. if [ "$OCAML_VERSION" != '5.0.0~beta2' ]; then opam init --bare default git+https://github.com/ocaml/opam-repository#$OPAM_TEST_REPO_SHA cat >> $(opam var root --global 2>/dev/null)/config <= 4.02.3 (or see [below](#compiling-without-ocaml)) - A C++ compiler (unless building without a solver, see `./configure --without-mccs`) * Run `./configure` * Run `make lib-ext` as advertised by `./configure` if you don't have the dependencies installed. This will locally take care of all OCaml dependencies for you (downloading them, unless you used the inclusive archive we provide for each release). * Run `make` * Run `make install` This is all you need for installing and using opam, but if you want to use the `opam-lib` (to work on opam-related tools), you need to link it to installed libraries, rather than use `make lib-ext` which would cause conflicts. It's easier to already have a working opam installation in this case, so you can do it as a second step. * Make sure to have ocamlfind, ocamlgraph, cmdliner >= 0.9.8, cudf >= 0.7, dose3 >= 6.1, re >= 1.5.0, opam-file-format installed. Or run `opam install . --deps-only` if you already have a working instance. Re-run `./configure` once done * Run `make libinstall` at the end _Note_: If you install on your system (without changing the prefix), you will need to install as root (`sudo`). As sudo do not propagate environment variables, there wil be some errors. You can use `sudo -E "PATH=$PATH" in order to be sure to have the good environment for install. ## Developer mode If you are developing OPAM, you may enable developer features by including the `--enable-developer-mode` parameter with `./configure`. ## Compiling on Native Windows ``` BUILDING ON WINDOWS IS A WORK-IN-PROGRESS AND THESE INSTRUCTIONS WILL EVOLVE! ``` Cygwin (https://www.cygwin.com/setup-x86_64.exe) is always required to build opam on Windows. Both the 64-bit and 32-bit versions of Cygwin may be used (you can build 32-bit opam using 64-bit Cygwin and vice versa though note that you must be running 64-bit Windows in order to build the 64-bit version). The following Cygwin packages are required: * From Devel - `make` * From Devel - `patch` (not required if OCaml and all required packages are pre-installed) * From Interpreters - `m4` (unless required packages are pre-installed or built using `make lib-ext` rather than `make lib-pkg` - `m4` is required by findlib's build system) * From Devel - `mingw64-i686-gcc-core` & `mingw64-x86_64-gcc-core` (not required if building with MSVC) Alternatively, having downloaded Cygwin's setup program, Cygwin can be installed using the following command line: `setup-x86_64 --root=C:\cygwin64 --quiet-mode --no-desktop --no-startmenu --packages=make,mingw64-i686-gcc-core,mingw64-x86_64-gcc-core,m4,patch` The `--no-desktop` and `--no-startmenu` switches may be omitted in order to create shortcuts on the Desktop and Start Menu respectively. Executed this way, setup will still be interactive, but the packages will have been pre-selected. To make setup fully unattended, choose a mirror URL from https://cygwin.com/mirrors.lst and add the --site switch to the command line (e.g. `--site=http://www.mirrorservice.org/sites/sourceware.org/pub/cygwin/`). It is recommended that you set the `CYGWIN` environment variable to `nodosfilewarning winsymlinks:native`. Cygwin is started either from a shortcut or by running: ``` C:\cygwin64\bin\mintty - ``` It is recommended that opam be built outside Cygwin's root (so in `/cygdrive/c/...`). From an elevated Cygwin shell, edit `/etc/fstab` and ensure that the file's content is exactly: ``` none /cygdrive cygdrive noacl,binary,posix=0,user 0 0 ``` The change is the addition of the `noacl` option to the mount instructions for `/cygdrive` and this stops from Cygwin from attempting to emulate POSIX permissions over NTFS (which can result in strange and unnecessary permissions showing up in Windows Explorer). It is necessary to close and restart all Cygwin terminal windows after changing `/etc/fstab`. opam is able to be built **without** a pre-installed OCaml compiler. For the MSVC ports of OCaml, the Microsoft Windows SDK 7 or later or Microsoft Visual Studio is required (https://www.microsoft.com/en-gb/download/details.aspx?id=8442 - either x86 or x64 may be installed, as appropriate to your system). It is not necessary to modify PATH, INCLUDE or LIB - opam's build system will automatically detect the required changes. If OCaml is not pre-installed, run: ``` make compiler [OCAML_PORT=mingw64|mingw|msvc64|msvc|auto] ``` The `OCAML_PORT` variable determines which flavour of Windows OCaml is compiled - `auto` will attempt to guess. As long as `gcc` is **not** installed in Cygwin (i.e. the native C compiler *for Cygwin*), `OCAML_PORT` does not need to be specified and `auto` will be assumed. Once the compiler is built, you may run: ``` make lib-pkg ``` to install the dependencies as findlib packages to the compiler. Building `lib-pkg` requires the ability to create native symbolic links (and the `CYGWIN` variable *must* include `winsymlinks:native`) - this means that either Cygwin must be run elevated from an account with administrative privileges or your user account must be granted the SeCreateSymbolicLinkPrivilege either by enabling Developer mode on Windows 10, or using Local Security Policy on earlier versions of Windows. Alternatively, you may run `configure` and use `make lib-ext`, as advised. You can then `configure` and build opam as above. ## Compiling without OCaml `make cold` is provided as a facility to compile OCaml, then bootstrap opam. You don't need need to run `./configure` in that case, but you may specify `CONFIGURE_ARGS` if needed, e.g.: ``` make cold CONFIGURE_ARGS="--prefix ~/local" make cold-install ``` NOTE: You'll still need GNU make. ## Bug tracker Have a bug or a feature request ? Please open an issue on [our bug-tracker](https://github.com/ocaml/opam/issues). Please search for existing issues before posting, and include the output of `opam config report` and any details that may help track down the issue. ## Documentation #### User Manual The main documentation entry point to opam is the user manual, available using `opam --help`. To get help for a specific command, use `opam --help`. #### Guides and Tutorials A collection of guides and tutorials is available [online](http://opam.ocaml.org/doc/Usage.html). They are generated from the files in [doc/pages](https://github.com/ocaml/opam/tree/master/doc/pages). #### API, Code Documentation and Developer Manual A more thorough technical document describing opam and specifying the package description format is available in the [developer manual](http://opam.ocaml.org/doc/manual/dev-manual.html). `make doc` will otherwise make the API documentation available under `doc/`. ## Community Keep track of development and community news. * Have a question that's not a feature request or bug report? [Ask on the mailing list](http://lists.ocaml.org/listinfo/infrastructure). * Chat with fellow opamers on IRC. On the `irc.freenode.net` server, in the `#ocaml` or the `#opam` channel. ## Contributing We welcome contributions ! Please use Github's pull-request mechanism against the master branch of the [opam repository](https://github.com/ocaml/opam). If that's not an option for you, you can use `git format-patch` and email us. ## Versioning The release cycle respects [Semantic Versioning](http://semver.org/). ## Related repositories - [ocaml/opam-repository](https://github.com/ocaml/opam-repository) is the official repository for opam packages and compilers. A number of non-official repositories are also available on the interwebs, for instance on [Github](https://github.com/search?q=opam-repo&type=Repositories). - [opam2web](https://github.com/ocaml/opam2web) generates a collection of browsable HTML files for a given repository. It is used to generate http://opam.ocaml.org. - [opam-rt](https://github.com/ocaml/opam-rt) is the regression framework for opam. - [opam-publish](https://github.com/AltGr/opam-publish) is a tool to facilitate the creation, update and publication of opam packages. ## Copyright and license The version comparison function in `src/core/opamVersionCompare.ml` is part of the Dose library and Copyright 2011 Ralf Treinen. All other code is: Copyright 2012-2020 OCamlPro Copyright 2012 INRIA All rights reserved. Opam is distributed under the terms of the GNU Lesser General Public License version 2.1, with the special exception on linking described in the file LICENSE. Opam is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. opam-2.1.5/src/0002755000175000017500000000000014427463453012310 5ustar stephstephopam-2.1.5/src/tools/0002755000175000017500000000000014427463453013450 5ustar stephstephopam-2.1.5/src/tools/opam_admin_top.mli0000644000175000017500000000367614427463453017153 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Small lib for writing opam-repo admin scripts *) (** The current repo (taken from CWD!) *) val repo : OpamTypes.dirname (** All defined packages in the current repo *) val packages : OpamPackage.Set.t open OpamFile type 'a action = [`Update of 'a | `Remove | `Keep ] (** Maps on the files of every package. Only changed files are written back to disk. *) val iter_packages_gen: ?quiet:bool -> (OpamPackage.t -> prefix:string option -> opam:OPAM.t -> descr:Descr.t option -> url:URL.t option -> dot_install:Dot_install.t option -> OPAM.t * Descr.t action * URL.t action * Dot_install.t action) -> unit (** Turn a list of glob patterns into a proper filtering function on package names. *) val filter_packages: string list -> (OpamPackage.t -> bool) (** Quicker interface when considering a single type of file *) val iter_packages: ?quiet:bool -> ?filter:(OpamPackage.t -> bool) -> ?f:(OpamPackage.t -> string option -> OPAM.t -> unit) -> ?opam:(OpamPackage.t -> OPAM.t -> OPAM.t) -> ?descr:(OpamPackage.t -> Descr.t -> Descr.t) -> ?url:(OpamPackage.t -> URL.t -> URL.t) -> ?dot_install:(OpamPackage.t -> Dot_install.t -> Dot_install.t) -> unit -> unit opam-2.1.5/src/tools/dune0000644000175000017500000000220414427463453014322 0ustar stephsteph(library (name opam_admin_top) (public_name opam-admin.top) (synopsis "OCaml Package Manager admin toplevel") (modules opam_admin_top) (libraries opam-client opam-file-format compiler-libs.toplevel re) (wrapped false)) (executable (name opam_admin_topstart) (public_name opam-admin.top) (package opam-admin) (modes byte) (modules opam_admin_topstart) (libraries opam-admin.top) (ocamlc_flags (:standard (:include ../ocaml-flags-standard.sexp) (:include ../ocaml-flags-configure.sexp) (:include ../ocaml-context-flags.sexp) -linkall))) (rule (with-stdout-to opam_admin_topstart.ml (echo "include Opam_admin_top\n\nlet _ = Topmain.main ()"))) (executable (name opam_installer) (package opam-installer) (public_name opam-installer) (modules opam_installer) (libraries opam-format cmdliner) (flags (:standard (:include ../ocaml-flags-standard.sexp) (:include ../ocaml-flags-configure.sexp) (:include ../ocaml-context-flags.sexp)))) opam-2.1.5/src/tools/opam_admin_top.ml0000644000175000017500000001103314427463453016764 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2014-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (* To be used for quick repo scripts using the toplevel *) open OpamFilename.Op open OpamStd.Op let identity _ x = x let true_ _ = true let repo = OpamFilename.cwd () let packages = OpamRepository.packages repo let wopt w f = function | None -> OpamFilename.remove (OpamFile.filename f) | Some contents -> w f contents let apply f x prefix y = match f with | None -> () | Some f -> f x prefix y type 'a action = [`Update of 'a | `Remove | `Keep] let to_action f x y = match f with | None -> `Keep | Some f -> match y with | None -> `Keep | Some y -> `Update (f x y) let of_action o = function | `Keep -> o | `Update x -> Some x | `Remove -> None let iter_packages_gen ?(quiet=false) f = let packages = OpamRepository.packages_with_prefixes repo in let changed_pkgs = ref 0 in let changed_files = ref 0 in (* packages *) OpamPackage.Map.iter (fun package prefix -> if not quiet then OpamConsole.msg "Processing package %s... " (OpamPackage.to_string package); let opam_file = OpamRepositoryPath.opam repo prefix package in let opam = OpamFile.OPAM.read opam_file in let descr_file = OpamRepositoryPath.descr repo prefix package in let descr = OpamFile.Descr.read_opt descr_file in let url_file = OpamRepositoryPath.url repo prefix package in let url = OpamFile.URL.read_opt url_file in let dot_install_file : OpamFile.Dot_install.t OpamFile.t = OpamFile.make (OpamRepositoryPath.files repo prefix package // (OpamPackage.Name.to_string (OpamPackage.name package) ^ ".install")) in let dot_install = OpamFile.Dot_install.read_opt dot_install_file in let opam2, descr2, url2, dot_install2 = f package ~prefix ~opam ~descr ~url ~dot_install in let descr2 = of_action descr descr2 in let url2 = of_action url url2 in let dot_install2 = of_action dot_install dot_install2 in let changed = ref false in let upd () = changed := true; incr changed_files in if opam <> opam2 then (upd (); OpamFile.OPAM.write_with_preserved_format opam_file opam2); if descr <> descr2 then (upd (); wopt OpamFile.Descr.write descr_file descr2); if url <> url2 then (upd (); wopt OpamFile.URL.write url_file url2); if dot_install <> dot_install2 then (upd (); wopt OpamFile.Dot_install.write dot_install_file dot_install2); if !changed then (incr changed_pkgs; if not quiet then begin OpamConsole.carriage_delete (); OpamConsole.msg "Updated %s\n" (OpamPackage.to_string package) end) else if not quiet then OpamConsole.carriage_delete (); ) packages; if not quiet then OpamConsole.msg "Done. Updated %d files in %d packages.\n" !changed_files !changed_pkgs let iter_packages ?quiet ?(filter=true_) ?f ?(opam=identity) ?descr ?url ?dot_install () = iter_packages_gen ?quiet (fun p ~prefix ~opam:o ~descr:d ~url:u ~dot_install:i -> if filter p then ( apply f p prefix o; opam p o, to_action descr p d , to_action url p u, to_action dot_install p i ) else o, `Keep, `Keep, `Keep) let regexps_of_patterns patterns = let contains_dot str = let len = String.length str in let rec aux = function | -1 -> false | i -> str.[i] = '.' || aux (i-1) in aux (len-1) in List.map (fun pattern -> if contains_dot pattern then pattern else pattern ^ ".*" ) patterns |> List.map (fun pattern -> Re.compile (Re.Glob.globx pattern)) let filter fn patterns = let regexps = regexps_of_patterns patterns in fun t -> match regexps with | [] -> true | _ -> let str = fn t in List.exists (fun re -> OpamStd.String.exact_match re str) regexps let filter_packages = filter OpamPackage.to_string opam-2.1.5/src/tools/opam_installer.ml0000644000175000017500000003542414427463453017021 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2013-2018 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open Cmdliner type options = { file: OpamFile.Dot_install.t OpamFile.t; pkgname: OpamPackage.Name.t; prefix: OpamFilename.Dir.t; script: bool; mandir: OpamFilename.Dir.t option; libdir: OpamFilename.Dir.t option; stubsdir: OpamFilename.Dir.t option; topdir: OpamFilename.Dir.t option; docdir: OpamFilename.Dir.t option; } (* A wrapper on top of commands to either proceed, or output a script *) type commands = { mkdir: OpamFilename.Dir.t -> unit; rmdir: opt:bool -> OpamFilename.Dir.t -> unit; cp: ?exec:bool -> opt:bool -> src:OpamFilename.t -> dst:OpamFilename.t -> unit -> unit; rm: opt:bool -> OpamFilename.t -> unit; confirm: string -> (unit -> unit) -> unit; } let do_commands project_root = let mkdir d = if not (OpamFilename.exists_dir d) then (OpamConsole.msg "Creating directory %s\n" (OpamFilename.Dir.to_string d); OpamFilename.mkdir d) in let rec rmdir ~opt d = if not (OpamFilename.exists_dir d) then () else if Sys.readdir (OpamFilename.Dir.to_string d) = [||] then (OpamConsole.msg "Removing empty dir %S\n" (OpamFilename.Dir.to_string d); OpamFilename.rmdir d; let parent = OpamFilename.dirname_dir d in if parent <> d then rmdir ~opt:true parent) else if not opt then OpamConsole.warning "Directory %S is not empty\n" (OpamFilename.Dir.to_string d) in let do_cp ?exec ~opt ~src ~dst () = if OpamFilename.exists src then (mkdir (OpamFilename.dirname dst); OpamConsole.msg "%-32s => %s\n" (OpamFilename.remove_prefix project_root src) (OpamFilename.to_string dst); OpamFilename.install ?exec ~src ~dst ()) else if not opt then OpamConsole.error "Could not find %S" (OpamFilename.to_string src) in let cp = if Sys.win32 then fun ?exec ~opt ~src ~dst -> let (src, dst) = if not (OpamFilename.exists src) then let test = OpamFilename.add_extension src "exe" in if OpamFilename.exists test then begin let dst = OpamFilename.add_extension dst "exe" in OpamConsole.warning "Adding .exe for %s" (OpamFilename.to_string test); (test, dst) end else (src, dst) else (src, dst) in do_cp ?exec ~opt ~src ~dst else do_cp in let do_rm ~opt f = if OpamFilename.exists f then (OpamConsole.msg "Removing %s\n" (OpamFilename.to_string f); OpamFilename.remove f) else if not opt then OpamConsole.warning "%S doesn't exist" (OpamFilename.to_string f) in let rm = if Sys.win32 then fun ~opt f -> let f = if OpamFilename.exists f then f else let test = OpamFilename.add_extension f "exe" in if OpamFilename.exists test then begin OpamConsole.warning "Removing %s instead of %s" (OpamFilename.to_string test) (OpamFilename.to_string f); test end else f in do_rm ~opt f else do_rm in let confirm s f = if OpamConsole.confirm "%s" s then f () in { mkdir; rmdir; cp; rm; confirm } let script_commands project_root ochan = let made_dirs = ref [] in Printf.fprintf ochan "#!/bin/sh\n"; let mkdir d = if not (List.mem d !made_dirs) then ( Printf.fprintf ochan "mkdir -p %S\n" (OpamFilename.Dir.to_string d); made_dirs := d :: !made_dirs ) in let rmdir ~opt d = let f = OpamFilename.Dir.to_string d in Printf.fprintf ochan "if [ -d %S ]\n" f; Printf.fprintf ochan "then rmdir -p %S 2>/dev/null" f; if not opt then Printf.fprintf ochan " ||\n echo \"Warning: could not remove directory %s\"" f; Printf.fprintf ochan "\nfi\n" in let cp ?exec ~opt ~src ~dst () = mkdir (OpamFilename.dirname dst); let mode = match exec with | Some true -> "-m 0755" | Some false -> "-m 0644" | None -> "" in let src = OpamFilename.remove_prefix project_root src in let dst = OpamFilename.to_string dst in Printf.fprintf ochan "if [ -e %S ]\n" src; Printf.fprintf ochan "then install %s %S %S\n" mode src dst; if not opt then Printf.fprintf ochan "else echo \"Error: %s doesn't exist\"\n" src; Printf.fprintf ochan "fi\n" in let rm ~opt file = let f = OpamFilename.to_string file in Printf.fprintf ochan "if [ -e %S ]; then rm -f %S\n" f f; if not opt then Printf.fprintf ochan "else echo \"Warning: %s doesn't exist\"\n" f; Printf.fprintf ochan "fi\n" in let confirm msg f = Printf.fprintf ochan "read -p %S' [y/n] ' -n 1 -r; echo; if [ \"$REPLY\" = 'y' ]; then\n" msg; f (); Printf.fprintf ochan "fi\n"; in { mkdir; rmdir; cp; rm; confirm } (* [f (dest, file_list, is_exec)] should take care of the processing, where [dest src dst] returns the destination of a file with a ["src" {"dst"}] line in the .install *) let iter_install f instfile o = let open OpamFilename.Op in let module D = struct include OpamPath.Switch.DefaultF (struct type ctx = unit let root d _ = d let lib_dir t a = root t a / "lib" end) end in let module S = OpamFile.Dot_install in let dest ?fix dir = let dir = OpamStd.Option.default dir fix in fun src dst -> OpamFilename.create dir (OpamStd.Option.default (OpamFilename.basename src) dst) in let dest_global ?fix instdir_f = dest ?fix (instdir_f o.prefix ()) in let dest_pkg ?fix instdir_f = let fix = OpamStd.Option.map (fun d -> d / OpamPackage.Name.to_string o.pkgname) fix in dest ?fix (instdir_f o.prefix () o.pkgname) in List.iter f [ dest_global D.bin, S.bin instfile, true; dest_global D.sbin, S.sbin instfile, true; dest_pkg ?fix:o.libdir D.lib, S.lib instfile, false; dest_pkg ?fix:o.libdir D.lib, S.libexec instfile, true; dest_global ?fix:o.libdir D.lib_dir, S.lib_root instfile, false; dest_global ?fix:o.libdir D.lib_dir, S.libexec_root instfile, true; dest_global ?fix:o.topdir D.toplevel, S.toplevel instfile, false; dest_global ?fix:o.stubsdir D.stublibs, S.stublibs instfile, true; dest_global ?fix:o.mandir D.man_dir, S.man instfile, false; dest_pkg D.share, S.share instfile, false; dest_global D.share_dir,S.share_root instfile, false; dest_pkg D.etc, S.etc instfile, false; dest_pkg ?fix:o.docdir D.doc, S.doc instfile, false; ] let install options = let instfile = OpamFile.Dot_install.safe_read options.file in let project_root = OpamFilename.cwd () in let cmd = if options.script then script_commands project_root stdout else do_commands project_root in let install_files (dest, files, exec) = List.iter (fun (base, dst) -> let src_file = OpamFilename.create project_root base.c in let dst_file = dest src_file dst in cmd.cp ~exec ~opt:base.optional ~src:src_file ~dst:dst_file ()) files in iter_install install_files instfile options; List.iter (fun (src, dst) -> let src_file = OpamFilename.create (OpamFilename.cwd ()) src.c in cmd.confirm (Printf.sprintf "Do you want to install %s to %s?" (OpamFilename.Base.to_string src.c) (OpamFilename.to_string dst)) (fun () -> cmd.cp ~opt:false ~src:src_file ~dst ()) ) (OpamFile.Dot_install.misc instfile) let uninstall options = let instfile = OpamFile.Dot_install.safe_read options.file in let project_root = OpamFilename.cwd () in let cmd = if options.script then script_commands project_root stdout else do_commands project_root in let dirs_to_remove = ref OpamFilename.Dir.Set.empty in let remove_files (dest, files, _) = List.iter (fun (base, dst) -> let src_file = OpamFilename.create project_root base.c in let dst_file = dest src_file dst in cmd.rm ~opt:base.optional dst_file; dirs_to_remove := OpamFilename.Dir.Set.add (OpamFilename.dirname dst_file) !dirs_to_remove) files in iter_install remove_files instfile options; List.iter (cmd.rmdir ~opt:true) (List.rev (OpamFilename.Dir.Set.elements !dirs_to_remove)); List.iter (fun df -> cmd.rmdir ~opt:false (df options.prefix (OpamSwitch.of_string "") options.pkgname)) OpamPath.Switch.Default.([ lib; share; etc; doc ]); List.iter (fun (_src, dst) -> cmd.confirm (Printf.sprintf "Remove %s?" (OpamFilename.to_string dst)) (fun () -> cmd.rm ~opt:false dst)) (OpamFile.Dot_install.misc instfile) let options = let file = let doc = "The opam .install file to read for installation instructions" in Arg.(value & pos 0 (some string) None & info ~docv:"PKG.install" ~doc []) in let prefix = let doc = "The prefix to install to. You can use eg '\\$PREFIX' to output a \ relocatable script" in Arg.(value & opt string "/usr/local" & info ~docv:"PREFIX" ~doc ["prefix"]) in let script = let doc = "Don't execute the commands, but output a shell-script \ (experimental)" in Arg.(value & flag & info ~doc ["script"]) in let pkgname = let doc = "Specify the package name. Used to set install directory under \ `share/', etc. \ By default, basename of the .install file" in Arg.(value & opt (some string) None & info ~docv:"NAME" ~doc ["name"]) in let mandir = let doc = "Manpages dir. Relative to $(b,prefix) or absolute. \ By default $(i,\\$prefix/man)." in Arg.(value & opt (some string) None & info ~docv:"PATH" ~doc ["mandir"]) in let libdir = let doc = "OCaml lib dir. Relative to $(b,prefix) or absolute. \ By default $(i,\\$prefix/lib) ; sometimes setting this to \ $(i,\\$(ocamlc -where)) is preferable." in Arg.(value & opt (some string) None & info ~docv:"PATH" ~doc ["libdir"]) in let stubsdir = let doc = "Stubs installation dir. Relative to $(b,prefix) or absolute. \ By default $(i,\\$libdir/stublibs)." in Arg.(value & opt (some string) None & info ~docv:"PATH" ~doc ["stubsdir"]) in let topdir = let doc = "Toplevel install dir. Relative to $(b,prefix) or absolute. \ By default $(i,\\$libdir/toplevel)." in Arg.(value & opt (some string) None & info ~docv:"PATH" ~doc ["topdir"]) in let docdir = let doc = "Documentation dir. Relative to $(b,prefix) or absolute. \ By default $(i,\\$prefix/doc)." in Arg.(value & opt (some string) None & info ~docv:"PATH" ~doc ["docdir"]) in let make_options file prefix script name mandir libdir stubsdir topdir docdir = let file = match file with | Some file -> let f = OpamFilename.of_string (file ^ ".install") in if OpamFilename.exists f then f else let f = OpamFilename.of_string file in if OpamFilename.exists f then f else raise (Invalid_argument ("File not found: " ^ file)) | None -> let candidates = OpamFilename.files (OpamFilename.cwd ()) in match List.filter (fun f -> OpamFilename.check_suffix f ".install") candidates with | [f] -> f | [] -> raise (Invalid_argument "No .install file found") | files -> let msg = Printf.sprintf "Please specify a .install file, %s found in current dir" (OpamStd.Format.pretty_list (List.map (fun f -> OpamFilename.(Base.to_string (basename f))) files)) in raise (Invalid_argument msg) in let file = (OpamFile.make file: OpamFile.Dot_install.t OpamFile.t) in let prefix = OpamFilename.Dir.of_string prefix in let pkgname = match name with | Some n -> OpamPackage.Name.of_string n | None when OpamFilename.check_suffix (OpamFile.filename file) ".install" -> OpamPackage.Name.of_string (OpamFilename.Base.to_string (OpamFilename.basename (OpamFilename.chop_extension (OpamFile.filename file)))) | None -> raise (Invalid_argument "Could not guess the package name, please specify `--name'") in let mk_dir = function | None -> None | Some d when Filename.is_relative d -> Some OpamFilename.Op.(prefix / d) | Some d -> Some (OpamFilename.Dir.of_string d) in let mandir = mk_dir mandir in let libdir = mk_dir libdir in let stubsdir = match mk_dir stubsdir, libdir with | None, Some d -> Some OpamFilename.Op.(d / "stublibs") | d, None | (Some _ as d), _ -> d in let topdir = match mk_dir topdir, libdir with | None, Some d -> Some OpamFilename.Op.(d / "toplevel") | d, None | (Some _ as d), _ -> d in let docdir = mk_dir docdir in { file; prefix; script; pkgname; mandir; libdir; stubsdir; topdir; docdir } in Term.(const make_options $ file $ prefix $ script $ pkgname $ mandir $ libdir $ stubsdir $ topdir $ docdir) let command = let remove = Arg.(value & vflag false & [ false, Arg.info ["i";"install"] ~doc:"Install the package (the default)"; true, Arg.info ["u";"uninstall";"remove"] ~doc:"Remove the package"; ]) in Term.( const (fun options remove -> if remove then uninstall options else install options) $ options $ remove) let info = let doc = "Handles (un)installation of package files following instructions from \ opam *.install files." in Term.info "opam-installer" ~version:OpamVersion.(to_string current) ~doc let () = OpamSystem.init (); OpamCoreConfig.init (); try match Term.eval ~catch:false (command,info) with | `Error _ -> exit 2 | _ -> exit 0 with | Invalid_argument s -> OpamConsole.error "%s" s; exit 2 | OpamStd.Sys.Exit i -> exit i | e -> OpamConsole.error "Failure during install"; OpamConsole.errmsg "%s\n" (Printexc.to_string e); exit 1 opam-2.1.5/src/dune0000644000175000017500000000033614427463453013166 0ustar stephsteph(rule (targets ocaml-flags-configure.sexp) (mode fallback) (action (with-stdout-to %{targets} (echo "()")))) (rule (with-stdout-to ocaml-context-flags.sexp (run ocaml %{dep:../shell/context_flags.ml} flags))) opam-2.1.5/src/state/0002755000175000017500000000000014427463453013430 5ustar stephstephopam-2.1.5/src/state/opamStateTypes.mli0000644000175000017500000001477514427463453017131 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Defines the types holding global, repository and switch states *) open OpamTypes (** Client state *) (** Phantom types to indicate the locking state of a state, and allow or not on-disk operations. Note that each state load is itself locking enough to return a consistent state: a read lock is only needed when the consistency of the actions depend on the fact that the given state doesn't change during the run (e.g. an update that depends on it). In particular, all query commands don't need a read lock. Subtyping is by guarantees given on the operations allowed, [rw] giving the most and being the smallest type, so that it is safe to coerce [(rw t :> ro t)]. *) (** Phantom type for readwrite-locked state (ensures that there are no concurrent reads or writes) *) type rw = [ `Lock_write ] (** Type for read-locked state (ensures that there are no concurrent writes) *) type ro = [ `Lock_read | rw ] (** Type for unlocked state (single file reads should still be ok) *) type unlocked = [ `Lock_none | ro ] (** The super-type for all lock types *) type +'a lock = [< unlocked > `Lock_write ] as 'a (** Global state corresponding to an opam root and its configuration *) type +'lock global_state = { global_lock: OpamSystem.lock; root: OpamPath.t; (** The global OPAM root path (caution: this is stored here but some code may rely on OpamStateConfig.root_dir ; in other words, multiple root handling isn't really supported at the moment) *) config: OpamFile.Config.t; (** The main configuration file. A note of caution: this corresponds to the configuration as loaded from the file: to get the current options, which may be overridden through the command-line or environment, see OpamStateConfig *) global_variables: (variable_contents option Lazy.t * string) OpamVariable.Map.t; (** A map of variables that have been defined globally, e.g. through `.opam/config`. They may need evaluation so are stored as lazy values. The extra string is the supplied variable documentation *) } constraint 'lock = 'lock lock (** State corresponding to the repo/ subdir: all available packages and metadata, for each repository. *) type +'lock repos_state = { repos_lock: OpamSystem.lock; repos_global: unlocked global_state; repositories: repository repository_name_map; (** The list of repositories *) repos_definitions: OpamFile.Repo.t repository_name_map; (** The contents of each repo's [repo] file *) repo_opams: OpamFile.OPAM.t package_map repository_name_map; (** All opam files that can be found in the configured repositories *) repos_tmp: (OpamRepositoryName.t, OpamFilename.Dir.t Lazy.t) Hashtbl.t; (** Temporary directories containing the uncompressed contents of the repositories *) } constraint 'lock = 'lock lock (** State of a given switch: options, available and installed packages, etc.*) type +'lock switch_state = { switch_lock: OpamSystem.lock; switch_global: unlocked global_state; switch_repos: unlocked repos_state; switch: switch; (** The current active switch *) switch_invariant: formula; (** Defines the "base" of the switch, e.g. what compiler is desired *) compiler_packages: package_set; (** The packages that form the base of the current compiler. Normally equal to the subset of installed packages matching the invariant defined in switch_config *) switch_config: OpamFile.Switch_config.t; (** The configuration file for this switch *) repos_package_index: OpamFile.OPAM.t package_map; (** Metadata of all packages that could be found in the configured repositories (ignoring installed or pinned packages) *) opams: OpamFile.OPAM.t package_map; (** The metadata of all packages, gathered from repo, local cache and pinning overlays. This includes URL and descr data (even if they were originally in separate files), as well as the original metadata directory (that can be used to retrieve the files/ subdir) *) conf_files: OpamFile.Dot_config.t name_map; (** The opam-config of installed packages (from ".opam-switch/config/pkgname.config") *) packages: package_set; (** The set of all known packages *) sys_packages: sys_pkg_status package_map Lazy.t; (** Map of package and their system dependencies packages status. Only initialised for otherwise available packages *) available_packages: package_set Lazy.t; (** The set of available packages, filtered by their [available:] field *) pinned: package_set; (** The set of pinned packages (their metadata, including pinning target, is in [opams]) *) installed: package_set; (** The set of all installed packages *) installed_opams: OpamFile.OPAM.t package_map; (** The cached metadata of installed packages (may differ from the metadata that is in [opams] for updated packages) *) installed_roots: package_set; (** The set of packages explicitly installed by the user. Some of them may happen not to be installed at some point, but this indicates that the user would like them installed. *) reinstall: package_set Lazy.t; (** The set of packages which need to be reinstalled *) invalidated: package_set Lazy.t; (** The set of packages which are installed but no longer valid, e.g. because of removed system dependencies. Only packages which are unavailable end up in this set, they are otherwise put in [reinstall]. *) (* Missing: a cache for - switch-global and package variables - the solver universe? *) } constraint 'lock = 'lock lock (** Command-line setting provenance *) type provenance = [ `Env (** Environment variable *) | `Command_line (** Command line *) | `Default (** Default value *) ] opam-2.1.5/src/state/opamScript.mli0000644000175000017500000000202314427463453016247 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2018 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** (generated) Shell config scripts as OCaml strings *) val complete : string val complete_zsh : string val prompt : string val bwrap : string val sandbox_exec : string val env_hook : string val env_hook_zsh : string val env_hook_csh : string val env_hook_fish : string opam-2.1.5/src/state/opamFileTools.ml0000644000175000017500000013002614427463453016537 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamParserTypes.FullPos open OpamTypes open OpamTypesBase let log ?level fmt = OpamConsole.log "opam-file" ?level fmt open OpamFile.OPAM let is_valid_license_id s = let memplus s = let s = OpamStd.String.remove_suffix ~suffix:"+" s in OpamStd.String.Set.mem s OpamSpdxList.licenses in match OpamStd.String.split (String.lowercase_ascii s) ' ' with | [s] -> memplus s | [s; "with"; e] -> memplus s && OpamStd.String.Set.mem e OpamSpdxList.exceptions | _ -> false (** manipulation utilities *) let names_of_formula flag f = OpamPackageVar.filter_depends_formula ~build:true ~post:true ~dev:true ~test:flag ~doc:flag ~default:false ~env:OpamStd.Option.none f |> OpamFormula.atoms |> List.map fst |> OpamPackage.Name.Set.of_list let all_commands t = t.build @ t.install @ t.remove @ t.run_test @ t.deprecated_build_doc let all_urls t = let urlf_urls uf = OpamFile.URL.url uf :: OpamFile.URL.mirrors uf in (match t.url with Some uf -> urlf_urls uf | None -> []) @ (match t.dev_repo with Some u -> [u] | None -> []) @ List.fold_left (fun acc (_, uf) -> urlf_urls uf @ acc) [] t.extra_sources @ List.map snd t.pin_depends let filters_of_formula f = OpamFormula.fold_left (fun acc (_, f) -> OpamFormula.fold_left (fun acc -> function | Constraint (_,f) -> f :: acc | Filter f -> f :: acc) acc f) [] f (* Doesn't include filters in commands *) let all_filters ?(exclude_post=false) t = OpamStd.List.filter_map snd t.patches @ OpamStd.List.filter_map snd t.messages @ (if exclude_post then [] else OpamStd.List.filter_map snd t.post_messages) @ List.map snd t.depexts @ OpamStd.List.filter_map snd t.libraries @ OpamStd.List.filter_map snd t.syntax @ [t.available] @ filters_of_formula (OpamFormula.ands (t.depends :: t.depopts :: t.conflicts :: List.map (fun (_,f,_) -> f) t.features)) let map_all_filters f t = let mapsnd x = List.map (fun (x, ft) -> x, f ft) x in let mapsndopt x = List.map (function | (x, Some ft) -> x, Some (f ft) | nf -> nf) x in let map_commands = List.map (fun (args, filter) -> List.map (function | s, Some ft -> s, Some (f ft) | nf -> nf) args, OpamStd.Option.map f filter) in let map_filtered_formula = OpamFormula.map (fun (name, fc) -> let fc = OpamFormula.map (function | Filter flt -> Atom (Filter (f flt)) | Constraint (relop, flt) -> Atom (Constraint (relop, (f flt)))) fc in Atom (name, fc)) in let map_features = List.map (fun (var, fformula, doc) -> var, map_filtered_formula fformula, doc) in t |> with_patches (mapsndopt t.patches) |> with_messages (mapsndopt t.messages) |> with_post_messages (mapsndopt t.post_messages) |> with_depexts (mapsnd t.depexts) |> with_libraries (mapsndopt t.libraries) |> with_syntax (mapsndopt t.syntax) |> with_available (f t.available) |> with_depends (map_filtered_formula t.depends) |> with_depopts (map_filtered_formula t.depopts) |> with_conflicts (map_filtered_formula t.conflicts) |> with_features (map_features t.features) |> with_build (map_commands t.build) |> with_run_test (map_commands t.run_test) |> with_install (map_commands t.install) |> with_remove (map_commands t.remove) |> with_deprecated_build_test (map_commands t.deprecated_build_test) |> with_deprecated_build_doc (map_commands t.deprecated_build_doc) (* Returns all variables from all commands (or on given [command]) and all filters *) let all_variables ?exclude_post ?command t = let commands = match command with | Some cmd -> cmd | None -> all_commands t in OpamFilter.commands_variables commands @ List.fold_left (fun acc f -> OpamFilter.variables f @ acc) [] (all_filters ?exclude_post t) let map_all_variables f t = let map_fld (x, flt) = x, OpamFilter.map_variables f flt in let map_optfld = function | x, Some flt -> x, Some (OpamFilter.map_variables f flt) | _, None as optfld -> optfld in let map_commands = let map_args = List.map (fun (s, filter) -> (match s with | CString s -> CString (OpamFilter.map_variables_in_string f s) | CIdent id -> let id = try filter_ident_of_string id |> OpamFilter.map_variables_in_fident f |> string_of_filter_ident with Failure _ -> id in CIdent id), OpamStd.Option.Op.(filter >>| OpamFilter.map_variables f)) in List.map (fun (args, filter) -> map_args args, OpamStd.Option.Op.(filter >>| OpamFilter.map_variables f)) in let map_filtered_formula = OpamFormula.map (fun (name, fc) -> let fc = OpamFormula.map (function | Filter flt -> Atom (Filter (OpamFilter.map_variables f flt)) | Constraint (relop, flt) -> Atom (Constraint (relop, (OpamFilter.map_variables f flt)))) fc in Atom (name, fc) ) in let map_features = List.map (fun (var, fformula, doc) -> var, map_filtered_formula fformula, doc) in t |> with_patches (List.map map_optfld t.patches) |> with_messages (List.map map_optfld t.messages) |> with_post_messages (List.map map_optfld t.post_messages) |> with_depexts (List.map map_fld t.depexts) |> with_libraries (List.map map_optfld t.libraries) |> with_syntax (List.map map_optfld t.syntax) |> with_build (map_commands t.build) |> with_run_test (map_commands t.run_test) |> with_install (map_commands t.install) |> with_remove (map_commands t.remove) |> with_depends (map_filtered_formula t.depends) |> with_depopts (map_filtered_formula t.depopts) |> with_conflicts (map_filtered_formula t.conflicts) |> with_available (OpamFilter.map_variables f t.available) |> with_features (map_features t.features) |> with_deprecated_build_test (map_commands t.deprecated_build_test) |> with_deprecated_build_doc (map_commands t.deprecated_build_doc) let all_expanded_strings t = List.map fst t.messages @ List.map fst t.post_messages @ List.fold_left (fun acc (args, _) -> List.fold_left (fun acc -> function CString s, _ -> s :: acc | _ -> acc) acc args) [] (all_commands t) @ List.fold_left (OpamFilter.fold_down_left (fun acc -> function FString s -> s :: acc | _ -> acc)) [] (all_filters t) let all_depends t = OpamPackage.Name.Set.union (names_of_formula true t.depends) (names_of_formula true t.depopts) (* Templating & linting *) let template nv = let maintainer = let from_git = try match OpamSystem.read_command_output ["git"; "config"; "--get"; "user.name"], OpamSystem.read_command_output ["git"; "config"; "--get"; "user.email"] with | [name], [email] -> Some [Printf.sprintf "%s <%s>" name email] | _ -> raise Not_found with e -> OpamStd.Exn.fatal e; None in match from_git with | Some u -> u | None -> let email = try Some (Sys.getenv "EMAIL") with Not_found -> None in try let open Unix in let pw = getpwuid (getuid ()) in let email = match email with | Some e -> e | None -> pw.pw_name^"@"^gethostname () in match OpamStd.String.split pw.pw_gecos ',' with | name::_ -> [Printf.sprintf "%s <%s>" name email] | _ -> [email] with Not_found -> match email with | Some e -> [e] | None -> [] in create nv |> with_name_opt None |> with_maintainer maintainer |> with_build [[CString "./configure", None; CString "--prefix=%{prefix}%", None], None; [CIdent "make", None], None] |> with_install [[CIdent "make", None; CString "install", None], None] |> with_depends (Atom (OpamPackage.Name.of_string "specify-dependencies-here", (Atom (Constraint (`Geq, FString "optional-version"))))) |> with_author maintainer |> with_homepage [""] |> with_license [""] |> with_dev_repo (OpamUrl.of_string "git+https://") |> with_bug_reports [""] |> with_synopsis "" let t_lint ?check_extra_files ?(check_upstream=false) ?(all=false) t = let format_errors = List.map (fun (field, (pos, msg)) -> 3, `Error, Printf.sprintf "File format error in '%s'%s: %s" field (match pos with | Some {start=li,col; _} when li >= 0 && col >= 0 -> Printf.sprintf " at line %d, column %d" li col | _ -> "") msg) (OpamFile.OPAM.format_errors t) in let cond num level msg ?detail cd = if all then Some (num, level, msg) else if cd then let msg = match detail with | None | Some [] -> msg | Some d -> Printf.sprintf "%s: \"%s\"" msg (String.concat "\", \"" d) in Some (num, level, msg) else None in let all_commands = all_commands t in let all_expanded_strings = all_expanded_strings t in let all_depends = all_depends t in (* Upstream is checked only if it is an archive and non vcs backend *) let url_is_archive = let open OpamStd.Option.Op in t.url >>| OpamFile.URL.url >>| (fun u -> match u.OpamUrl.backend with | #OpamUrl.version_control -> false | _ -> OpamSystem.is_archive (OpamUrl.base_url u)) in let check_upstream = check_upstream && not (OpamFile.OPAM.has_flag Pkgflag_Conf t) && url_is_archive = Some true in let warnings = [ cond 20 `Warning "Field 'opam-version' refers to the patch version of opam, it \ should be of the form MAJOR.MINOR" ~detail:[OpamVersion.to_string t.opam_version] (OpamVersion.nopatch t.opam_version <> t.opam_version); cond 21 `Error "Field 'opam-version' doesn't match the current version, \ validation may not be accurate" ~detail:[OpamVersion.to_string t.opam_version] (OpamVersion.compare t.opam_version OpamFile.OPAM.format_version <> 0); (* cond (t.name = None) "Missing field 'name' or directory in the form 'name.version'"; cond (t.version = None) "Missing field 'version' or directory in the form 'name.version'"; *) (let empty_fields = OpamStd.List.filter_map (function n,[""] -> Some n | _ -> None) ["maintainer", t.maintainer; "homepage", t.homepage; "author", t.author; "license", t.license; "doc", t.doc; "tags", t.tags; "bug_reports", t.bug_reports] in cond 22 `Error "Some fields are present but empty; remove or fill them" ~detail:empty_fields (empty_fields <> [])); cond 23 `Error "Missing field 'maintainer'" (t.maintainer = []); cond 24 `Error "Field 'maintainer' has the old default value" (List.mem "contact@ocamlpro.com" t.maintainer && not (List.mem "org:ocamlpro" t.tags)); cond 25 `Warning "Missing field 'authors'" (t.author = []); cond 26 `Warning "No field 'install', but a field 'remove': install instructions \ probably part of 'build'. Use the 'install' field or a .install \ file" (t.install = [] && t.build <> [] && t.remove <> []); (* cond 27 `Warning "No field 'remove' while a field 'install' is present, uncomplete \ uninstallation suspected" (t.install <> [] && t.remove = []); *) (let unk_flags = OpamStd.List.filter_map (function | Pkgflag_Unknown s -> Some s | _ -> None) t.flags in cond 28 `Error "Unknown package flags found" ~detail:unk_flags (unk_flags <> [])); (let filtered_vars = OpamFilter.variables_of_filtered_formula t.depends @ OpamFilter.variables_of_filtered_formula t.depopts |> List.filter (fun v -> not (OpamVariable.Full.is_global v)) |> List.map OpamVariable.Full.to_string in cond 29 `Error "Package dependencies mention package variables" ~detail:filtered_vars (filtered_vars <> [])); (* cond 30 `Error "Field 'depopts' is not a pure disjunction" (List.exists (function | OpamFormula.Atom _ -> false | _ -> true) (OpamFormula.ors_to_list t.depopts)); *) (let dup_depends = OpamPackage.Name.Set.inter (names_of_formula false t.depends) (names_of_formula true t.depopts) in cond 31 `Error "Fields 'depends' and 'depopts' refer to the same package names" ~detail:OpamPackage.Name. (List.map to_string (Set.elements dup_depends)) (not (OpamPackage.Name.Set.is_empty dup_depends))); cond 32 `Error "Field 'ocaml-version:' and variable 'ocaml-version' are deprecated, use \ a dependency towards the 'ocaml' package instead for availability, and \ the 'ocaml:version' package variable for scripts" (t.ocaml_version <> None || List.mem (OpamVariable.Full.of_string "ocaml-version") (all_variables t)); cond 33 `Error "Field 'os' is deprecated, use 'available' and the 'os' variable \ instead" (t.os <> Empty); (let pkg_vars = List.filter (fun v -> not (OpamVariable.Full.is_global v)) (OpamFilter.variables t.available) in cond 34 `Error "Field 'available:' contains references to package-local variables. \ It should only be determined from global configuration variables" ~detail:(List.map OpamVariable.Full.to_string pkg_vars) (pkg_vars <> [])); cond 35 `Warning "Missing field 'homepage'" (t.homepage = []); (* cond (t.doc = []) *) (* "Missing field 'doc'"; *) cond 36 `Warning "Missing field 'bug-reports'" (t.bug_reports = []); cond 37 `Warning "Missing field 'dev-repo'" (t.dev_repo = None && t.url <> None); (* cond 38 `Warning "Package declares 'depexts', but has no 'post-messages' to help \ the user out when they are missing" (t.depexts <> None && t.post_messages = []); *) cond 39 `Error "Command 'make' called directly, use the built-in variable \ instead" (List.exists (function | (CString "make", _)::_, _ -> true | _ -> false ) all_commands); (* cond 40 `Warning "Field 'features' is still experimental and not yet to be used on \ the official repo" (t.features <> []); (let alpha_flags = OpamStd.List.filter_map (function | Pkgflag_LightUninstall | Pkgflag_Unknown _ -> None | f -> if List.exists (fun tag -> flag_of_tag tag = Some f) t.tags then None else Some (string_of_pkg_flag f)) t.flags in cond 40 `Warning "Package uses flags that aren't recognised by earlier versions in \ OPAM 1.2 branch. At the moment, you should use a tag \"flags:foo\" \ instead for compatibility" ~detail:alpha_flags (alpha_flags <> [])); *) (let undep_pkgs = List.fold_left (fun acc v -> match OpamVariable.Full.package v with | Some n when t.OpamFile.OPAM.name <> Some n && not (OpamPackage.Name.Set.mem n all_depends) && OpamVariable.(Full.variable v <> of_string "installed") -> OpamPackage.Name.Set.add n acc | _ -> acc) OpamPackage.Name.Set.empty (all_variables ~exclude_post:true t) in cond 41 `Warning "Some packages are mentioned in package scripts or features, but \ there is no dependency or depopt toward them" ~detail:OpamPackage.Name. (List.map to_string (Set.elements undep_pkgs)) (not (OpamPackage.Name.Set.is_empty undep_pkgs))); cond 42 `Error "The 'dev-repo:' field doesn't use version control. You should use \ URLs of the form \"git://\", \"git+https://\", \"hg+https://\"..." (match t.dev_repo with | None -> false | Some { OpamUrl.backend = #OpamUrl.version_control; _ } -> false | Some _ -> true); cond 43 `Error "Conjunction used in 'conflicts:' field. Only '|' is allowed" (OpamVersion.compare t.opam_version (OpamVersion.of_string "1.3") >= 0 && let rec ors_only_constraint = function | Atom _ | Empty -> true | Or (a, b) -> ors_only_constraint a && ors_only_constraint b | And (a, Atom (Filter _)) | And (Atom (Filter _), a) | Block a -> ors_only_constraint a | And _ -> false in let rec check = function | Atom (_, c) -> ors_only_constraint c | Empty -> true | Or (a, b) -> check a && check b | Block a -> check a | And _ -> false in not (check t.conflicts)); cond 44 `Warning "The 'plugin' package flag is set but the package name doesn't \ begin with 'opam-'" (OpamVersion.compare t.opam_version (OpamVersion.of_string "1.3") >= 0 && List.mem Pkgflag_Plugin t.flags && match t.OpamFile.OPAM.name with | None -> false | Some name -> not (OpamStd.String.starts_with ~prefix:OpamPath.plugin_prefix (OpamPackage.Name.to_string name))); (let unclosed = List.fold_left (fun acc s -> List.rev_append (OpamFilter.unclosed_expansions s) acc) [] all_expanded_strings in cond 45 `Error "Unclosed variable interpolations in strings" ~detail:(List.map snd unclosed) (unclosed <> [])); cond 46 `Error "Package is flagged \"conf\" but has source, install or remove \ instructions" (has_flag Pkgflag_Conf t && (t.install <> [] || t.remove <> [] || t.url <> None || t.extra_sources <> [])); cond 47 `Warning "Synopsis (or description first line) should start with a capital and \ not end with a dot" (let valid_re = Re.(compile (seq [bos; diff any (alt [blank; lower]); rep any; diff any (alt [blank; char '.']); eos])) in match t.descr with None -> false | Some d -> not (Re.execp valid_re (OpamFile.Descr.synopsis d))); cond 48 `Warning "The fields 'build-test:' and 'build-doc:' are deprecated, and should be \ replaced by uses of the 'with-test' and 'with-doc' filter variables in \ the 'build:' and 'install:' fields, and by the newer 'run-test:' \ field" (t.deprecated_build_test <> [] || t.deprecated_build_doc <> []); (let suspicious_urls = List.filter (fun u -> OpamUrl.parse_opt ~handle_suffix:true (OpamUrl.to_string u) <> Some u) (all_urls t) in cond 49 `Warning "The following URLs don't use version control but look like version \ control URLs" ~detail:(List.map OpamUrl.to_string suspicious_urls) (suspicious_urls <> [])); cond 50 `Warning "The 'post' flag doesn't make sense with build or optional \ dependencies" (List.mem (OpamVariable.Full.of_string "post") (List.flatten (List.map OpamFilter.variables (filters_of_formula t.depopts))) || OpamFormula.fold_left (fun acc (_, f) -> acc || let vars = OpamFormula.fold_left (fun vars f -> match f with | Constraint _ -> vars | Filter fi -> OpamFilter.variables fi @ vars) [] f in List.mem (OpamVariable.Full.of_string "build") vars && List.mem (OpamVariable.Full.of_string "post") vars) false t.depends); cond 51 `Error "The behaviour for negated dependency flags 'build' or 'post' is \ unspecified" (OpamFormula.fold_left (fun acc (_, f) -> acc || OpamFormula.fold_left (fun acc f -> acc || match f with | Filter fi -> OpamFilter.fold_down_left (fun acc fi -> acc || match fi with | FNot (FIdent ([], var, None)) -> (match OpamVariable.to_string var with | "build" | "post" -> true | _ -> false) | _ -> false) false (OpamFilter.distribute_negations fi) | _ -> false) false f) false (OpamFormula.ands [t.depends; t.depopts])); cond 52 `Error "Package is needlessly flagged \"light-uninstall\", since it has no \ remove instructions" (has_flag Pkgflag_LightUninstall t && t.remove = []); (let mismatching_extra_files = match t.extra_files, check_extra_files with | None, _ | _, None -> [] | Some fs, Some [] -> List.map fst fs | Some efiles, Some ffiles -> OpamStd.List.filter_map (fun (n, _) -> if List.mem_assoc n ffiles then None else Some n) efiles @ OpamStd.List.filter_map (fun (n, check_f) -> try if check_f (List.assoc n efiles) then None else Some n with Not_found -> Some n) ffiles in cond 53 `Error "Mismatching 'extra-files:' field" ~detail:(List.map OpamFilename.Base.to_string mismatching_extra_files) (mismatching_extra_files <> [])); (let spaced_depexts = List.concat (List.map (fun (dl,_) -> OpamStd.List.filter_map (fun s -> let d = OpamSysPkg.to_string s in if String.contains d ' ' || String.length d = 0 then Some d else None) (OpamSysPkg.Set.elements dl)) t.depexts) in cond 54 `Warning "External dependencies should not contain spaces nor empty string" ~detail:spaced_depexts (spaced_depexts <> [])); (let bad_os_arch_values = List.fold_left (OpamFilter.fold_down_left (fun acc -> function | FOp (FIdent ([],vname,None), _, FString value) | FOp (FString value, _, FIdent ([],vname,None)) -> (match OpamVariable.to_string vname with | "os" -> let norm = OpamSysPoll.normalise_os value in if value <> norm then (value, norm)::acc else acc | "arch" -> let norm = OpamSysPoll.normalise_arch value in if value <> norm then (value, norm)::acc else acc | _ -> acc) | _ -> acc)) [] (all_filters t) in cond 55 `Error "Non-normalised OS or arch string being tested" ~detail:(List.map (fun (used,norm) -> Printf.sprintf "%s (use %s instead)" used norm) bad_os_arch_values) (bad_os_arch_values <> [])); cond 56 `Warning "It is discouraged for non-compiler packages to use 'setenv:'" (t.env <> [] && not (has_flag Pkgflag_Compiler t)); cond 57 `Error "Synopsis and description must not be both empty" (t.descr = None || t.descr = Some OpamFile.Descr.empty); (let vars = all_variables ~exclude_post:false ~command:[] t in let exists svar = List.exists (fun v -> v = OpamVariable.Full.of_string svar) vars in let rem_test = exists "test" in let rem_doc = exists "doc" in cond 58 `Warning (let var, s_, nvar = match rem_test, rem_doc with | true, true -> "`test` and `doc`", "s", "s are `with-test` and `with-doc`" | true, false -> "`test`", "", " is `with-test`" | false, true -> "`doc`", "", " is `with-doc`" | _ -> "","","" in Printf.sprintf "Found %s variable%s, predefined one%s" var s_ nvar) (rem_test || rem_doc)); cond 59 `Warning "url doesn't contain a checksum" (check_upstream && OpamStd.Option.map OpamFile.URL.checksum t.url = Some []); (let upstream_error = if not check_upstream then None else match t.url with | None -> Some "No url defined" | Some urlf -> let open OpamProcess.Job.Op in let check_checksum f = match OpamFile.URL.checksum urlf with | [] -> None | chks -> let not_corresponding = OpamStd.List.filter_map (fun chk -> match OpamHash.mismatch (OpamFilename.to_string f) chk with | Some m -> Some (m, chk) | None -> None) chks in if not_corresponding = [] then None else let msg = let is_singular = function [_] -> true | _ -> false in Printf.sprintf "The archive doesn't match checksum%s:\n%s." (if is_singular not_corresponding then "" else "s") (OpamStd.Format.itemize (fun (good, bad) -> Printf.sprintf "archive: %s, in opam file: %s" (OpamHash.to_string good) (OpamHash.to_string bad)) not_corresponding) in Some msg in let url = OpamFile.URL.url urlf in OpamProcess.Job.run @@ OpamFilename.with_tmp_dir_job @@ fun dir -> match url.backend with | #OpamUrl.version_control -> Done None (* shouldn't happen *) | `http -> OpamProcess.Job.catch (function | Failure msg -> Done (Some msg) | OpamDownload.Download_fail (s,l) -> Done (Some (OpamStd.Option.default l s)) | e -> Done (Some (Printexc.to_string e))) @@ fun () -> OpamDownload.download ~overwrite:false url dir @@| check_checksum | `rsync -> let filename = let open OpamStd.Option.Op in (OpamFile.OPAM.name_opt t >>| OpamPackage.Name.to_string) +! "lint-check-upstream" |> OpamFilename.Base.of_string |> OpamFilename.create dir in OpamLocal.rsync_file url filename @@| function | Up_to_date f | Result f -> check_checksum f | Not_available (_,src) -> Some ("Source not found: "^src) in cond 60 `Error "Upstream check failed" ~detail:(OpamStd.Option.to_list upstream_error) (upstream_error <> None)); (let with_test = List.exists ((=) (OpamVariable.Full.of_string "with-test")) (OpamFilter.commands_variables t.run_test) in cond 61 `Warning "`with-test` variable in `run-test` is out of scope, it will be ignored" with_test); (let bad_licenses = List.filter (fun s -> not (is_valid_license_id s)) t.license in cond 62 `Warning "License doesn't adhere to the SPDX standard, see https://spdx.org/licenses/" ~detail:bad_licenses (bad_licenses <> [])); (* (let subpath = match OpamStd.String.Map.find_opt "x-subpath" (extensions t) with | Some {pelem = String _; _} -> true | _ -> false in let opam_restriction = OpamFilter.fold_down_left (fun acc filter -> acc || match filter with | FOp (FIdent (_, var, _), op, FString version) when OpamVariable.to_string var = "opam-version" -> OpamFormula.simplify_version_formula (OpamFormula.ands [ Atom (`Lt, OpamPackage.Version.of_string "2.1"); Atom (op, OpamPackage.Version.of_string version) ]) = None | _ -> false) false t.available in cond 63 `Error "`subpath` field need `opam-version = 2.1` restriction" (subpath && not opam_restriction)); (let subpath_string = match OpamStd.String.Map.find_opt "x-subpath" (extensions t) with | Some {pelem = String _; _} | None -> false | _ -> true in cond 64 `Warning "`x-subpath` must be a simple string to be considered as a subpath`" subpath_string); *) (let relative = let open OpamUrl in List.filter (fun u -> (* OpamUrl.local_dir is not used because it checks the existence of the directory *) (match u.backend, u.transport with | (#version_control | `rsync), ("file" | "path" | "local" | "rsync") -> true | _, _ -> false) && (Filename.is_relative u.path || OpamStd.String.contains ~sub:".." u.path)) (all_urls t) in cond 65 `Error "URLs must be absolute" ~detail:(List.map (fun u -> u.OpamUrl.path) relative) (relative <> [])); (let maybe_bool = (* Regexp from [OpamFilter.string_interp_regexp] *) let re = let open Re in let notclose = rep @@ alt [ diff notnl @@ set "}"; seq [char '}'; alt [diff notnl @@ set "%"; stop] ] ] in compile @@ seq [ bos; alt [ str "true"; str "false"; str "%%"; seq [str "%{"; greedy notclose; opt @@ str "}%"]; ]; eos] in fun s -> try let _ = Re.exec re s in true with Not_found -> false in let check_strings = let rec aux acc oped = function | FString s -> if oped || maybe_bool s then acc else s::acc | FIdent _ | FBool _ -> acc | FOp (fl,_,fr) -> (aux acc true fl) @ aux acc true fr | FAnd (fl, fr) | FOr (fl, fr) -> (aux acc false fl) @ aux acc false fr | FNot f | FDefined f | FUndef f -> aux acc false f in aux [] false in let check_formula = OpamFormula.fold_left (fun acc (_, form as ff) -> match OpamFormula.fold_left (fun acc fc -> match fc with | Filter f -> check_strings f @ acc | Constraint _ -> acc) [] form with | [] -> acc | strs -> (ff, List.rev strs)::acc ) in let not_bool_strings = List.fold_left check_formula [] (t.depends :: t.depopts :: t.conflicts :: List.map (fun (_,f,_) -> f) t.features) in cond 66 `Warning "String that can't be resolved to bool in filtered package formula" ~detail:(List.map (fun (f, strs) -> Printf.sprintf "%s in '%s'" (OpamStd.Format.pretty_list (List.map (Printf.sprintf "%S") strs)) (OpamFilter.string_of_filtered_formula (Atom f))) not_bool_strings) (not_bool_strings <> [])); cond 67 `Error "Checksum specified with a non archive url" ?detail:(OpamStd.Option.map (fun url -> [Printf.sprintf "%s - %s" (OpamFile.URL.url url |> OpamUrl.to_string) (OpamFile.URL.checksum url |> List.map OpamHash.to_string |> OpamStd.Format.pretty_list)]) t.url) (match t.url with | None -> false | Some urlf -> (OpamFile.URL.checksum urlf <> []) && url_is_archive <> Some true); ] in format_errors @ OpamStd.List.filter_map (fun x -> x) warnings let lint = t_lint ~all:false let extra_files_default filename = let dir = OpamFilename.Op.(OpamFilename.dirname (OpamFile.filename filename) / "files") in List.map (fun f -> OpamFilename.Base.of_string (OpamFilename.remove_prefix dir f), OpamHash.check_file (OpamFilename.to_string f)) (OpamFilename.rec_files dir) let lint_gen ?check_extra_files ?check_upstream ?(handle_dirname=false) reader filename = let warnings, t = let warn_of_bad_format (pos, msg) = 2, `Error, Printf.sprintf "File format error%s: %s" (match pos with | Some {start=li,col; _} when li >= 0 && col >= 0 -> Printf.sprintf " at line %d, column %d" li col | _ -> "") msg in try let f = reader filename in let _, t = OpamPp.parse ~pos:(pos_file (OpamFile.filename filename)) (OpamFormat.I.map_file OpamFile.OPAM.pp_raw_fields) f in let t, warnings = if handle_dirname = false then t, [] else match OpamPackage.of_filename (OpamFile.filename filename) with | None -> t, [] | Some nv -> let fname = nv.OpamPackage.name in let fversion = nv.OpamPackage.version in let t, name_warn = match t.OpamFile.OPAM.name with | Some tname -> if tname = fname then t, [] else t, [ 4, `Warning, Printf.sprintf "Field 'name: %S' while the directory name or pinning \ implied %S" (OpamPackage.Name.to_string tname) (OpamPackage.Name.to_string fname) ] | None -> OpamFile.OPAM.with_name fname t, [] in let t, version_warn = match t.OpamFile.OPAM.version with | Some tversion -> if tversion = fversion then t, [] else t, [ 4, `Warning, Printf.sprintf "Field 'version: %S' while the directory name or pinning \ implied %S" (OpamPackage.Version.to_string tversion) (OpamPackage.Version.to_string fversion) ] | None -> OpamFile.OPAM.with_version fversion t, [] in t, name_warn @ version_warn in warnings, Some (OpamFile.OPAM.with_metadata_dir (Some (None, OpamFilename.Dir.to_string (OpamFilename.dirname (OpamFile.filename filename)))) t) with | OpamSystem.File_not_found _ -> OpamConsole.error "%s not found" (OpamFile.to_string filename); [0, `Error, "File does not exist"], None | OpamLexer.Error _ | Parsing.Parse_error -> [1, `Error, "File does not parse"], None | OpamPp.Bad_version bf | OpamPp.Bad_format bf -> [warn_of_bad_format bf], None | OpamPp.Bad_format_list bfl -> List.map warn_of_bad_format bfl, None in let check_extra_files = match check_extra_files with | None -> extra_files_default filename | Some f -> f in warnings @ (match t with Some t -> lint ~check_extra_files ?check_upstream t | None -> []), t let lint_file ?check_extra_files ?check_upstream ?handle_dirname filename = let reader filename = try let ic = OpamFilename.open_in (OpamFile.filename filename) in try let f = OpamFile.Syntax.of_channel filename ic in close_in ic; f with e -> close_in ic; raise e with OpamSystem.File_not_found _ -> OpamConsole.error_and_exit `Bad_arguments "File %s not found" (OpamFile.to_string filename) in lint_gen ?check_extra_files ?check_upstream ?handle_dirname reader filename let lint_channel ?check_extra_files ?check_upstream ?handle_dirname filename ic = let reader filename = OpamFile.Syntax.of_channel filename ic in lint_gen ?check_extra_files ?check_upstream ?handle_dirname reader filename let lint_string ?check_extra_files ?check_upstream ?handle_dirname filename string = let reader filename = OpamFile.Syntax.of_string filename string in lint_gen ?check_extra_files ?check_upstream ?handle_dirname reader filename let all_lint_warnings () = t_lint ~all:true OpamFile.OPAM.empty let warns_to_string ws = OpamStd.List.concat_map "\n" (fun (n, w, s) -> let ws = match w with | `Warning -> OpamConsole.colorise `yellow "warning" | `Error -> OpamConsole.colorise `red "error" in OpamStd.Format.reformat ~indent:14 (Printf.sprintf " %16s %2d: %s" ws n s)) ws let warns_to_json ?filename ws = let filename = match filename with | Some f -> f | None -> "stdout" in let warn, err = List.fold_left (fun (w,e) (n,we,s) -> let arr = `O [ "id", `Float (float_of_int n); "message", `String s] in match we with | `Warning -> arr::w, e | `Error -> w, arr::e) ([],[]) ws in let result = match warn,err with | [],[] -> "passed" | _, _::_ -> "error" | _::_, [] -> "warning" in `O [ "file", `String filename; "result", `String result; "warnings", `A warn; "errors", `A err ] (* Package definition loading *) open OpamFilename.Op open OpamStd.Option.Op let try_read rd f = try rd f, None with | (OpamSystem.Internal_error _ | Not_found) as exc -> if OpamFormatConfig.(!r.strict) then OpamConsole.error_and_exit `File_error "Could not read file %s: %s.\nAborting (strict mode)." (OpamFile.to_string f) (Printexc.to_string exc); None, let f = OpamFile.filename f in Some (OpamFilename.(Base.to_string (basename f)), (Some (pos_file f), Printexc.to_string exc)) | OpamPp.Bad_format bf as exc -> if OpamFormatConfig.(!r.strict) then OpamConsole.error_and_exit `File_error "Errors while parsing %s: %s.\nAborting (strict mode)." (OpamFile.to_string f) (Printexc.to_string exc); None, let f = OpamFile.filename f in Some (OpamFilename.(Base.to_string (basename f)), bf) let add_aux_files ?dir ~files_subdir_hashes opam = let dir = match dir with | None -> OpamFile.OPAM.get_metadata_dir ~repos_roots:(fun r -> failwith ("Repository "^OpamRepositoryName.to_string r^ " not registered for add_aux_files!")) opam | some -> some in match dir with | None -> opam | Some dir -> let (url_file: OpamFile.URL.t OpamFile.t) = OpamFile.make (dir // "url") in let (descr_file: OpamFile.Descr.t OpamFile.t) = OpamFile.make (dir // "descr") in let files_dir = OpamFilename.Op.(dir / "files") in let opam = match OpamFile.OPAM.url opam, try_read OpamFile.URL.read_opt url_file with | None, (Some url, None) -> OpamFile.OPAM.with_url url opam | Some opam_url, (Some url, errs) -> if url = opam_url && errs = None then log "Duplicate definition of url in '%s' and opam file" (OpamFile.to_string url_file) else OpamConsole.warning "File '%s' ignored (conflicting url already specified in the \ 'opam' file)" (OpamFile.to_string url_file); opam | _, (_, Some err) -> OpamFile.OPAM.with_format_errors (err :: opam.format_errors) opam | _, (None, None) -> opam in let opam = match OpamFile.OPAM.descr opam, try_read OpamFile.Descr.read_opt descr_file with | None, (Some descr, None) -> OpamFile.OPAM.with_descr descr opam | Some _, (Some _, _) -> log "Duplicate descr in '%s' and opam file" (OpamFile.to_string descr_file); opam | _, (_, Some err) -> OpamFile.OPAM.with_format_errors (err :: opam.format_errors) opam | _, (None, None) -> opam in let opam = if not files_subdir_hashes then opam else let extra_files = OpamFilename.opt_dir files_dir >>| fun dir -> OpamFilename.rec_files dir |> List.map (fun file -> file, OpamFilename.Base.of_string (OpamFilename.remove_prefix dir file)) in match OpamFile.OPAM.extra_files opam, extra_files with | None, None -> opam | None, Some ef -> log ~level:2 "Missing extra-files field for %s, adding them." (OpamStd.List.concat_map ", " (fun (_,f) -> OpamFilename.Base.to_string f) ef); let ef = List.map (fun (file, basename) -> basename, OpamHash.compute (OpamFilename.to_string file)) ef in OpamFile.OPAM.with_extra_files ef opam | Some ef, None -> log "Missing expected extra files %s at %s/files" (OpamStd.List.concat_map ", " (fun (f,_) -> OpamFilename.Base.to_string f) ef) (OpamFilename.Dir.to_string dir); opam | Some oef, Some ef -> let wr_check, nf_opam, rest = List.fold_left (fun (wr_check, nf_opam, rest) (file, basename) -> match OpamStd.List.pick_assoc basename rest with | None, rest -> wr_check, (basename::nf_opam), rest | Some ohash, rest -> (if OpamHash.check_file (OpamFilename.to_string file) ohash then wr_check else basename::wr_check), nf_opam, rest ) ([], [], oef) ef in let nf_file = List.map fst rest in if nf_file <> [] || wr_check <> [] || nf_opam <> [] then log "Mismatching extra-files at %s: %s" (OpamFilename.Dir.to_string dir) ((if nf_file = [] then None else Some (Printf.sprintf "missing from 'files' directory (%d)" (List.length nf_file))) :: (if nf_opam = [] then None else Some (Printf.sprintf "missing from opam file (%d)" (List.length nf_opam))) :: (if wr_check = [] then None else Some (Printf.sprintf "wrong checksum (%d)" (List.length wr_check))) :: [] |> OpamStd.List.filter_some |> OpamStd.Format.pretty_list); opam in opam let read_opam dir = let (opam_file: OpamFile.OPAM.t OpamFile.t) = OpamFile.make (dir // "opam") in match try_read OpamFile.OPAM.read_opt opam_file with | Some opam, None -> Some (add_aux_files ~dir ~files_subdir_hashes:true opam) | _, Some err -> OpamConsole.warning "Could not read file %s. skipping:\n%s" (OpamFile.to_string opam_file) (OpamPp.string_of_bad_format (OpamPp.Bad_format (snd err))); None | None, None -> None let read_repo_opam ~repo_name ~repo_root dir = let open OpamStd.Option.Op in read_opam dir >>| OpamFile.OPAM.with_metadata_dir (Some (Some repo_name, OpamFilename.remove_prefix_dir repo_root dir)) let dep_formula_to_string f = let pp = OpamFormat.V.(package_formula `Conj (constraints version)) in OpamPrinter.FullPos.value (OpamPp.print pp f) let sort_opam opam = log "sorting %s" (OpamPackage.to_string (package opam)); let sort_ff = let compare_filters filter filter' = let get_vars = function | Constraint _ -> [] | Filter filter -> List.sort compare (OpamFilter.variables filter) in match get_vars filter, get_vars filter' with | v::_, v'::_ -> compare v v' | [], _::_ -> 1 | _::_, [] -> -1 | [],[] -> 0 in OpamFilter.sort_filtered_formula (fun (n,filter) (n',filter') -> let cmp = OpamFormula.compare_formula compare_filters filter filter' in if cmp <> 0 then cmp else OpamPackage.Name.compare n n') in let fst_sort ?comp = let comp = OpamStd.Option.default compare comp in fun l -> List.sort (fun (e,_) (e',_) -> comp e e') l in opam |> with_author @@ List.sort compare opam.author |> with_tags @@ List.sort compare opam.tags |> with_depends @@ sort_ff opam.depends |> with_depopts @@ sort_ff opam.depopts |> with_depexts @@ fst_sort opam.depexts |> with_conflicts @@ sort_ff opam.conflicts |> with_pin_depends @@ fst_sort ~comp:OpamPackage.compare opam.pin_depends |> with_extra_files_opt @@ OpamStd.Option.map fst_sort opam.extra_files |> with_extra_sources @@ fst_sort opam.extra_sources opam-2.1.5/src/state/opamSwitchAction.mli0000644000175000017500000000663414427463453017416 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Switch-related actions and changes *) open OpamTypes open OpamStateTypes (** Initialises a new switch with the given name in the given opam root, registers it in the global config and returns the updated global state *) val create_empty_switch: rw global_state -> ?synopsis:string -> ?repos:repository_name list -> ?invariant:formula -> switch -> rw global_state (** Writes the current state file to disk (installed, pinned, root packages etc.). Unless [OpamStateConfig.(!r.dryrun)] *) val write_selections: rw switch_state -> unit (** Updates the global default switch to the one corresponding to the given state; fails and exits with a message if the switch is external *) val set_current_switch: rw global_state -> 'a switch_state -> 'a switch_state (** Create the default global_config structure for a switch, including default prefix *) val gen_switch_config: dirname -> ?synopsis:string -> ?repos:repository_name list -> ?invariant:formula -> switch -> OpamFile.Switch_config.t (** (Re-)install the configuration for a given root and switch *) val install_switch_config: dirname -> switch -> OpamFile.Switch_config.t -> unit (** Add the package metadata to the switch-local cache of installed packages *) val install_metadata: rw switch_state -> package -> unit (** Remove the metadata of the package from the switch-local cache of installed packages *) val remove_metadata: rw switch_state -> package_set -> unit (** Update the on-disk set of packages marked to reinstall on the current switch (excepting compiler packages, and pinned packages if [unpinned_only] is set) *) val add_to_reinstall: rw switch_state -> unpinned_only:bool -> package_set -> rw switch_state (** Updates the package selections and switch config to take into account the given newly installed package. The updated state is written to disk unless [OpamStateConfig.(!r.dry_run)] and returned. *) val add_to_installed: rw switch_state -> ?root:bool -> package -> rw switch_state (** Updates the package selections and switch config to take into account the removed package. The updated state is written to disk unless [OpamStateConfig.(!r.dry_run)], and returned. If [keep_as_root], the package isn't removed from the switch state [installed_roots] set. *) val remove_from_installed: ?keep_as_root:bool -> rw switch_state -> package -> rw switch_state (** Update the switch selections with the supplied optional arguments. Changes are written to disk and returned *) val update_switch_state: ?installed: package_set -> ?installed_roots: package_set -> ?reinstall: package_set -> ?pinned: package_set -> rw switch_state -> rw switch_state opam-2.1.5/src/state/opamStateConfig.mli0000644000175000017500000001263314427463453017221 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2015-2020 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Configuration options for the state lib (record, global reference, setter, initialisation) *) open OpamTypes open OpamStateTypes module E : sig type OpamStd.Config.E.t += | BUILDDOC of bool option | BUILDTEST of bool option | DOWNLOADJOBS of int option | DRYRUN of bool option | IGNORECONSTRAINTS of string option | JOBS of int option | LOCKED of string option | MAKECMD of string option | NODEPEXTS of bool option | NOENVNOTICE of bool option | ROOT of string option | SWITCH of string option | UNLOCKBASE of bool option | WITHDOC of bool option | WITHTEST of bool option val root: unit -> string option val switch: unit -> string option end type t = private { root_dir: OpamFilename.Dir.t; current_switch: OpamSwitch.t option; switch_from: provenance; jobs: int Lazy.t; dl_jobs: int; build_test: bool; build_doc: bool; dryrun: bool; makecmd: string Lazy.t; ignore_constraints_on: name_set; unlock_base: bool; no_env_notice: bool; locked: string option; no_depexts : bool; } type 'a options_fun = ?root_dir:OpamFilename.Dir.t -> ?current_switch:OpamSwitch.t -> ?switch_from:provenance -> ?jobs:(int Lazy.t) -> ?dl_jobs:int -> ?build_test:bool -> ?build_doc:bool -> ?dryrun:bool -> ?makecmd:string Lazy.t -> ?ignore_constraints_on:name_set -> ?unlock_base:bool -> ?no_env_notice:bool -> ?locked:string option -> ?no_depexts: bool -> 'a include OpamStd.Config.Sig with type t := t and type 'a options_fun := 'a options_fun (** Get the initial opam root value (from default, env or optional argument). This allows one to get it before doing the init, which is useful to get the configuration file used to fill some options to init() *) val opamroot: ?root_dir:dirname -> unit -> dirname (** Loads the global configuration file, protecting against concurrent writes *) val load: ?lock_kind: 'a lock -> dirname -> OpamFile.Config.t option val safe_load: ?lock_kind: 'a lock -> dirname -> OpamFile.Config.t (** Loads the config file from the OPAM root and updates default values for all related OpamXxxConfig modules. Doesn't read the env yet, the [init] functions should still be called afterwards. OpamFormat should be initialised beforehand, as it may impact the config file loading. Returns the config file that was found, if any *) val load_defaults: ?lock_kind:'a lock -> OpamFilename.Dir.t -> OpamFile.Config.t option (** Returns the current switch, failing with an error message is none is set. *) val get_switch: unit -> switch (** Returns the current switch, if any is set. *) val get_switch_opt: unit -> switch option (** The function used to locate an external switch from parents of the current directory. Takes the opam root as parameter, and rejects any external switch configured with a different root *) val get_current_switch_from_cwd: OpamFilename.Dir.t -> switch option (** Checks if a local switch exists and is configurade for the given root *) val local_switch_exists: OpamFilename.Dir.t -> switch -> bool (** Resolves the switch if it is a link to a global switch in the given root (return unchanged otherwise) *) val resolve_local_switch: OpamFilename.Dir.t -> switch -> switch (** Given the required lock, returns [true] if the opam root is newer than the binary, so that it can only be loaded read-only by the current binary. *) val is_newer_than_self: ?lock_kind:'a lock -> 'b global_state -> bool (** Check config root version regarding self-defined one *) val is_newer: OpamFile.Config.t -> bool val load_config_root: ?lock_kind:'a lock -> ((OpamFile.Config.t OpamFile.t -> 'b) * (OpamFile.Config.t OpamFile.t -> 'b)) -> dirname -> 'b module Switch : sig val safe_load_t: ?lock_kind: 'a lock -> dirname -> switch -> OpamFile.Switch_config.t val safe_load: ?lock_kind: 'a lock -> 'b global_state -> switch -> OpamFile.Switch_config.t val safe_read_selections: ?lock_kind: 'a lock -> 'b global_state -> switch -> switch_selections val read_opt: ?lock_kind: 'a lock -> 'b global_state -> switch -> OpamFile.Switch_config.t option end module Repos : sig val safe_read: ?lock_kind: 'a lock -> 'b global_state -> OpamFile.Repos_config.t end (* Raw read an switch config to downgrade its [opam-version] from 2.1 to 2.0. It is necessary to handle opam root and switch upgrade from 2.1 intermediates roots to 2.1: this allows a workaround for a bug in versions 2.1~alpha which wrongly updated the declared switch versions, requiring that we fix it during [OpamFormatUpgrade] from these specific intermediate versions, and at switch loading for that specific case. *) val downgrade_2_1_switch: OpamFile.Switch_config.t OpamFile.t -> OpamFile.Switch_config.t option opam-2.1.5/src/state/opamPackageVar.mli0000644000175000017500000000620114427463453017011 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2017 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Resolution and handling of opam variables + filters *) open OpamTypes open OpamStateTypes (** Lists of available switch-global variables and their description *) val global_variable_names: (string * string) list (** Lists of predefined package variables and their description *) val package_variable_names: (string * string) list (** Variables that are pre-defined in the dependency filtered-formula scope, and which resolution is delayed to after the universe is computed (these are the only ones allowed in the universe, and resolved by [OpamFilter.filter_deps]) *) val predefined_depends_variables: full_variable list (** Resolves globally available variables only *) val resolve_global: 'a global_state -> full_variable -> variable_contents option (** Resolves global variables within the context of a switch. If a package is specified, "name" and "version" as taken to exclusively resolve to the current package name and version. *) val resolve_switch: ?package:package -> 'a switch_state -> full_variable -> variable_contents option (** Resolves filter variables, including global, switch and package variables ; a map of locally defined variables can be supplied, as well as the opam file of origin, which is used to resolve self-references (implicit ["%{bin}%"] or explicit ["%{_:bin}%"] *) val resolve: 'a switch_state -> ?opam:OpamFile.OPAM.t -> ?local:OpamVariable.variable_contents option OpamVariable.Map.t -> OpamFilter.env (** Like [resolve_switch], but takes more specific parameters so that it can be used before the switch state is fully loaded *) val resolve_switch_raw: ?package:package -> 'a global_state -> switch -> OpamFile.Switch_config.t -> full_variable -> variable_contents option val is_dev_package: 'a switch_state -> OpamFile.OPAM.t -> bool (** The defaults are [true] for [build], false for [dev] and [post], and defined by OpamStateConfig for [test] and [bool]. *) val filter_depends_formula: ?build:bool -> ?post:bool -> ?test:bool -> ?doc:bool -> ?dev:bool -> ?default:bool -> env:OpamFilter.env -> filtered_formula -> formula (** Assumes [filter_default=false] by default, i.e. dependencies with undefined filters are discarded. *) val all_depends: ?build:bool -> ?post:bool -> ?test:bool -> ?doc:bool -> ?dev:bool -> ?filter_default:bool -> ?depopts:bool -> 'a switch_state -> OpamFile.OPAM.t -> formula opam-2.1.5/src/state/opamPinned.ml0000644000175000017500000002244714427463453016063 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamStateTypes open OpamFilename.Op let log fmt = OpamConsole.log "PIN" fmt let package st name = OpamPackage.package_of_name st.pinned name let package_opt st name = try Some (package st name) with Not_found -> None let version st name = (package st name).version let packages st = st.pinned let possible_definition_filenames dir name = [ dir / (OpamPackage.Name.to_string name ^ ".opam") // "opam"; dir // (OpamPackage.Name.to_string name ^ ".opam"); dir / "opam" / (OpamPackage.Name.to_string name ^ ".opam") // "opam"; dir / "opam" // (OpamPackage.Name.to_string name ^ ".opam"); dir / "opam" // "opam"; dir // "opam" ] let check_locked ?subpath default = (* we keep the check, but this function shouldn't be called if the package is not asked as locked *) match OpamStateConfig.(!r.locked) with | None -> default | Some ext -> let flo = match subpath with | Some s -> OpamFilename.(Op.(Dir.of_string s // to_string default)) | None -> default in let fl = OpamFilename.add_extension flo ext in if not (OpamFilename.exists fl) then default else (log "Lock file found %s" (OpamFilename.to_string flo); let base_depends = OpamFile.make flo |> OpamFile.OPAM.read |> OpamFile.OPAM.depends in let lock_depends = OpamFile.make fl |> OpamFile.OPAM.read |> OpamFile.OPAM.depends in let ldep_names = OpamFormula.fold_left (fun acc (n,_) -> OpamPackage.Name.Set.add n acc) OpamPackage.Name.Set.empty lock_depends in let base_formula = OpamFilter.filter_deps ~build:true ~post:true ~test:false ~doc:false ~dev:false base_depends in let lock_formula = OpamFilter.filter_deps ~build:true ~post:true ~test:false ~doc:false ~dev:false lock_depends in let lpkg_f = lock_formula |> OpamFormula.atoms |> OpamPackage.Name.Map.of_list in (* Check consistency between them. It is based on the fact that locked file dependencies are an and list with precise version, i.e., pkg { =v0.1}. Construction of a two list: missing dependencies and inconsistent ones (version mismatch) *) let (@) = List.rev_append in let rec fold formula = List.fold_left cross ([],[]) (OpamFormula.ands_to_list formula) and cross (cont,cons) formula = match formula with | Atom (bn, bvf) -> ( let cont = if OpamPackage.Name.Set.mem bn ldep_names then cont else bn::cont in let cons = match OpamPackage.Name.Map.find_opt bn lpkg_f with | Some (Some (`Eq, lv)) -> if OpamFormula.check_version_formula bvf lv then cons else (bn, lv, bvf)::cons | _ -> cons in (cont,cons)) | Or (or1, or2) -> let or1_cont, or1_cons = fold or1 in let or2_cont, or2_cons = fold or2 in let cont = if or1_cont = [] || or2_cont = [] then cont else or1_cont @ or2_cont @ cont in let cons = if or1_cons = [] || or2_cons = [] then cons else or1_cons @ or2_cons @ cons in (cont,cons) | And (and1, and2) -> let and1_cont, and1_cons = fold and1 in let and2_cont, and2_cons = fold and2 in ((and1_cont @ and2_cont @ cont), (and1_cons @ and2_cons @ cons)) | Block f -> cross (cont,cons) f | Empty -> (cont,cons) in let contains, consistent = fold base_formula in if contains <> [] || consistent <> [] then (OpamConsole.warning "Lock file %s is outdated, you may want to re-run opam lock:\n%s" (OpamConsole.colorise `underline (OpamFilename.Base.to_string (OpamFilename.basename fl))) ((if contains <> [] then Printf.sprintf "Dependencies present in opam file not in lock file:\n%s" (OpamStd.Format.itemize OpamPackage.Name.to_string contains) else "") ^ (if consistent <> [] then Printf.sprintf "Dependencies in lock file not consistent wit opam file filter:\n%s" (OpamStd.Format.itemize (fun (n,lv,(bv: OpamFormula.version_formula)) -> Printf.sprintf "%s: %s in not contained in {%s}" (OpamPackage.Name.to_string n) (OpamPackage.Version.to_string lv) (OpamFormula.string_of_formula (fun (op, vc) -> Printf.sprintf "%s %s" (OpamPrinter.FullPos.relop_kind op) (OpamPackage.Version.to_string vc)) bv)) consistent) else ""))); OpamFilename.add_extension default ext) let find_opam_file_in_source ?(locked=false) name dir = let opt = OpamStd.List.find_opt OpamFilename.exists (possible_definition_filenames dir name) in (match opt with | Some base when locked -> Some (check_locked base) | _ -> opt) |> OpamStd.Option.map OpamFile.make let name_of_opam_filename dir file = let open OpamStd.Option.Op in let suffix = ".opam" in let get_name s = if Filename.check_suffix s suffix then Some Filename.(chop_suffix (basename s) suffix) else None in let rel = OpamFilename.remove_prefix dir file in let rel = match OpamStateConfig.(!r.locked) with | None -> rel | Some suf -> let ext = "."^suf in if OpamStd.String.ends_with ~suffix:(suffix^ext) rel then OpamStd.String.remove_suffix ~suffix:ext rel else rel in (get_name (Filename.basename rel) >>+ fun () -> get_name (Filename.dirname rel)) >>= fun name -> try Some (OpamPackage.Name.of_string name) with Failure _ -> None let files_in_source ?(recurse=false) ?subpath d = let baseopam = OpamFilename.Base.of_string "opam" in let files = let rec files_aux acc base d = let acc = OpamStd.List.filter_map (fun f -> if OpamFilename.basename f = baseopam || OpamFilename.check_suffix f ".opam" then let base = match base, subpath with | Some b, Some sp -> Some (Filename.concat sp b) | Some b, _ | _, Some b -> Some b | None, None -> None in Some (f, base) else None) (OpamFilename.files d) @ acc in List.fold_left (fun acc d -> if OpamFilename.(basename_dir d = Base.of_string "opam") || OpamStd.String.ends_with ~suffix:".opam" (OpamFilename.Dir.to_string d) then match OpamFilename.opt_file OpamFilename.Op.(d//"opam") with | None -> acc | Some f -> (f, base) :: acc else let base_dir = OpamFilename.basename_dir d in let basename = OpamFilename.Base.to_string base_dir in if recurse && not (base_dir = OpamFilename.Base.of_string OpamSwitch.external_dirname || base_dir = OpamFilename.Base.of_string "_build" || OpamStd.String.starts_with ~prefix:"." basename) then let base = match base with | None -> Some basename | Some base -> Some (Filename.concat base basename) in files_aux acc base d else acc) acc (OpamFilename.dirs d) in files_aux [] None in let d = (OpamStd.Option.map_default (fun sp -> OpamFilename.Op.(d / sp)) d subpath) in files d @ files (d / "opam") |> List.map (fun (f,s) -> (check_locked ?subpath:s f), s) |> OpamStd.List.filter_map (fun (f, subpath) -> try (* Ignore empty files *) if (Unix.stat (OpamFilename.to_string f)).Unix.st_size = 0 then None else Some (name_of_opam_filename d f, OpamFile.make f, subpath) with Unix.Unix_error _ -> OpamConsole.error "Can not read %s, ignored." (OpamFilename.to_string f); None) let orig_opam_file st name opam = let open OpamStd.Option.Op in OpamFile.OPAM.get_metadata_dir ~repos_roots:(OpamRepositoryState.get_root st.switch_repos) opam >>= fun dir -> OpamStd.List.find_opt OpamFilename.exists [ dir // (OpamPackage.Name.to_string name ^ ".opam"); dir // "opam" ] >>| OpamFile.make opam-2.1.5/src/state/opamRepositoryState.ml0000644000175000017500000002557214427463453020030 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamStd.Op open OpamStateTypes let log fmt = OpamConsole.log "RSTATE" fmt let slog = OpamConsole.slog module Cache = struct type t = { cached_repofiles: (repository_name * OpamFile.Repo.t) list; cached_opams: (repository_name * OpamFile.OPAM.t OpamPackage.Map.t) list; } module C = OpamCached.Make (struct type nonrec t = t let name = "repository" end) let remove () = let root = OpamStateConfig.(!r.root_dir) in let cache_dir = OpamPath.state_cache_dir root in let remove_cache_file file = if OpamFilename.check_suffix file ".cache" then OpamFilename.remove file in List.iter remove_cache_file (OpamFilename.files cache_dir) let marshall rt = (* Repository without remote are not cached, they are intended to be manually edited *) let filter_out_nourl repos_map = OpamRepositoryName.Map.filter (fun name _ -> try (OpamRepositoryName.Map.find name rt.repositories).repo_url <> OpamUrl.empty with Not_found -> false) repos_map in { cached_repofiles = OpamRepositoryName.Map.bindings (filter_out_nourl rt.repos_definitions); cached_opams = OpamRepositoryName.Map.bindings (filter_out_nourl rt.repo_opams); } let file rt = OpamPath.state_cache rt.repos_global.root let save rt = remove (); C.save (file rt) (marshall rt) let save_new rt = C.save (file rt) (marshall rt) let load root = let file = OpamPath.state_cache root in match C.load file with | Some cache -> Some (OpamRepositoryName.Map.of_list cache.cached_repofiles, OpamRepositoryName.Map.of_list cache.cached_opams) | None -> None end let load_opams_from_dir repo_name repo_root = (* FIXME: why is this different from OpamPackage.list ? *) let rec aux r dir = if OpamFilename.exists_dir dir then let fnames = Sys.readdir (OpamFilename.Dir.to_string dir) in if Array.fold_left (fun a f -> a || f = "opam") false fnames then match OpamFileTools.read_repo_opam ~repo_name ~repo_root dir with | Some opam -> (try let nv = OpamPackage.of_string OpamFilename.(Base.to_string (basename_dir dir)) in OpamPackage.Map.add nv opam r with Failure _ -> log "ERR: directory name not a valid package: ignored %s" OpamFilename.(to_string Op.(dir // "opam")); r) | None -> log "ERR: Could not load %s, ignored" OpamFilename.(to_string Op.(dir // "opam")); r else Array.fold_left (fun r name -> aux r OpamFilename.Op.(dir / name)) r fnames else r in aux OpamPackage.Map.empty (OpamRepositoryPath.packages_dir repo_root) let load_repo repo repo_root = let t = OpamConsole.timer () in let repo_def = OpamFile.Repo.safe_read (OpamRepositoryPath.repo repo_root) |> OpamFile.Repo.with_root_url repo.repo_url in let opams = load_opams_from_dir repo.repo_name repo_root in log "loaded opam files from repo %s in %.3fs" (OpamRepositoryName.to_string repo.repo_name) (t ()); repo_def, opams (* Cleaning directories follows the repo path pattern: TMPDIR/opam-tmp-dir/repo-dir, defined in [load]. *) let clean_repo_tmp tmp_dir = if Lazy.is_val tmp_dir then (let dir = Lazy.force tmp_dir in OpamFilename.rmdir dir; let parent = OpamFilename.dirname_dir dir in if OpamFilename.dir_is_empty parent then OpamFilename.rmdir parent) let remove_from_repos_tmp rt name = try clean_repo_tmp (Hashtbl.find rt.repos_tmp name); Hashtbl.remove rt.repos_tmp name with Not_found -> () let cleanup rt = Hashtbl.iter (fun _ tmp_dir -> clean_repo_tmp tmp_dir) rt.repos_tmp; Hashtbl.clear rt.repos_tmp let get_root_raw root repos_tmp name = match Hashtbl.find repos_tmp name with | lazy repo_root -> repo_root | exception Not_found -> OpamRepositoryPath.root root name let get_root rt name = get_root_raw rt.repos_global.root rt.repos_tmp name let get_repo_root rt repo = get_root_raw rt.repos_global.root rt.repos_tmp repo.repo_name let load lock_kind gt = log "LOAD-REPOSITORY-STATE %@ %a" (slog OpamFilename.Dir.to_string) gt.root; let lock = OpamFilename.flock lock_kind (OpamPath.repos_lock gt.root) in let repos_map = OpamStateConfig.Repos.safe_read ~lock_kind gt in if OpamStateConfig.is_newer_than_self gt then log "root version (%s) is greater than running binary's (%s); \ load with best-effort (read-only)" (OpamVersion.to_string (OpamFile.Config.opam_root_version gt.config)) (OpamVersion.to_string (OpamFile.Config.root_version)); let mk_repo name url_opt = { repo_name = name; repo_url = OpamStd.Option.Op.((url_opt >>| fst) +! OpamUrl.empty); repo_trust = OpamStd.Option.Op.(url_opt >>= snd); } in let uncached = (* Don't cache repositories without remote, as they should be editable in-place *) OpamRepositoryName.Map.filter (fun _ url -> url = None) repos_map in let repositories = OpamRepositoryName.Map.mapi mk_repo repos_map in let repos_tmp_root = lazy (OpamFilename.mk_tmp_dir ()) in let repos_tmp = Hashtbl.create 23 in OpamRepositoryName.Map.iter (fun name repo -> let uncompressed_root = OpamRepositoryPath.root gt.root repo.repo_name in let tar = OpamRepositoryPath.tar gt.root repo.repo_name in if not (OpamFilename.exists_dir uncompressed_root) && OpamFilename.exists tar then let tmp = lazy ( let tmp_root = Lazy.force repos_tmp_root in try (* We rely on this path pattern to clean the repo. cf. [clean_repo_tmp] *) OpamFilename.extract_in tar tmp_root; OpamFilename.Op.(tmp_root / OpamRepositoryName.to_string name) with Failure s -> OpamFilename.remove tar; OpamConsole.error_and_exit `Aborted "%s.\nRun `opam update --repositories %s` to fix the issue" s (OpamRepositoryName.to_string name); ) in Hashtbl.add repos_tmp name tmp ) repositories; let make_rt repos_definitions opams = let rt = { repos_global = (gt :> unlocked global_state); repos_lock = lock; repos_tmp; repositories; repos_definitions; repo_opams = opams; } in OpamStd.Sys.at_exit (fun () -> cleanup rt); rt in match Cache.load gt.root with | Some (repofiles, opams) when OpamRepositoryName.Map.is_empty uncached -> log "Cache found"; make_rt repofiles opams | Some (repofiles, opams) -> log "Cache found, loading repositories without remote only"; OpamFilename.with_flock_upgrade `Lock_read lock @@ fun _ -> let repofiles, opams = OpamRepositoryName.Map.fold (fun name url (defs, opams) -> let repo = mk_repo name url in let repo_def, repo_opams = load_repo repo (get_root_raw gt.root repos_tmp name) in OpamRepositoryName.Map.add name repo_def defs, OpamRepositoryName.Map.add name repo_opams opams) uncached (repofiles, opams) in make_rt repofiles opams | None -> log "No cache found"; OpamFilename.with_flock_upgrade `Lock_read lock @@ fun _ -> let repofiles, opams = OpamRepositoryName.Map.fold (fun name url (defs, opams) -> let repo = mk_repo name url in let repo_def, repo_opams = load_repo repo (get_root_raw gt.root repos_tmp name) in OpamRepositoryName.Map.add name repo_def defs, OpamRepositoryName.Map.add name repo_opams opams) repos_map (OpamRepositoryName.Map.empty, OpamRepositoryName.Map.empty) in let rt = make_rt repofiles opams in Cache.save_new rt; rt let find_package_opt rt repo_list nv = List.fold_left (function | None -> fun repo_name -> OpamStd.Option.Op.( OpamRepositoryName.Map.find_opt repo_name rt.repo_opams >>= OpamPackage.Map.find_opt nv >>| fun opam -> repo_name, opam ) | some -> fun _ -> some) None repo_list let build_index rt repo_list = List.fold_left (fun acc repo_name -> try let repo_opams = OpamRepositoryName.Map.find repo_name rt.repo_opams in OpamPackage.Map.union (fun a _ -> a) acc repo_opams with Not_found -> (* A repo is unavailable, error should have been already reported *) acc) OpamPackage.Map.empty repo_list let get_repo rt name = OpamRepositoryName.Map.find name rt.repositories let unlock ?cleanup:(cln=true) rt = if cln then cleanup rt; OpamSystem.funlock rt.repos_lock; (rt :> unlocked repos_state) let drop ?cleanup rt = let _ = unlock ?cleanup rt in () let with_write_lock ?dontblock rt f = if OpamStateConfig.is_newer_than_self rt.repos_global then OpamConsole.error_and_exit `Locked "The opam root has been upgraded by a newer version of opam-state \ and cannot be written to"; let ret, rt = OpamFilename.with_flock_upgrade `Lock_write ?dontblock rt.repos_lock @@ fun _ -> f ({ rt with repos_lock = rt.repos_lock } : rw repos_state) (* We don't actually change the field value, but this makes restricting the phantom lock type possible *) in ret, { rt with repos_lock = rt.repos_lock } let with_ lock gt f = let rt = load lock gt in OpamStd.Exn.finally (fun () -> drop rt) (fun () -> f rt) let write_config rt = OpamFile.Repos_config.write (OpamPath.repos_config rt.repos_global.root) (OpamRepositoryName.Map.map (fun r -> if r.repo_url = OpamUrl.empty then None else Some (r.repo_url, r.repo_trust)) rt.repositories) let check_last_update () = if OpamCoreConfig.(!r.debug_level) < 0 then () else let last_update = OpamFilename.written_since (OpamPath.state_cache (OpamStateConfig.(!r.root_dir))) in if last_update > float_of_int (3600*24*21) then OpamConsole.note "It seems you have not updated your repositories \ for a while. Consider updating them with:\n%s\n" (OpamConsole.colorise `bold "opam update"); opam-2.1.5/src/state/dune0000644000175000017500000000416414427463453014311 0ustar stephsteph(library (name opam_state) (public_name opam-state) (libraries opam-repository) (synopsis "OCaml Package Manager instance management library") (modules_without_implementation OpamStateTypes) (modules :standard \ flags) (flags (:standard (:include ../ocaml-flags-standard.sexp) (:include ../ocaml-flags-configure.sexp) (:include ../ocaml-context-flags.sexp) (:include flags.sexp))) (wrapped false)) (rule (targets opamScript.ml) (deps ../../shell/crunch.ml (glob_files shellscripts/*.*sh)) (action (with-stdout-to %{targets} (run ocaml %{deps})))) ;; These rules are here to document and for easy (re-)generation of the module, ;; but relying on the checked-in file should be OK (we don't want to rely on ;; either `jq` or a network download). Hence the `(mode fallback)`. (rule (targets opamSpdxList.ml) (mode fallback) (action (with-stdout-to %{targets} (progn (echo "(* THIS FILE IS GENERATED. See dune file *)\n\n") (echo "open OpamCompat\n") (echo "let licenses = OpamStd.String.Set.of_list @@ List.map String.lowercase_ascii @@ [\n") (cat spdx-license-list) (echo "]\n") (echo "let exceptions = OpamStd.String.Set.of_list @@ List.map String.lowercase_ascii @@ [\n") (cat spdx-license-exn-list) (echo "]\n"))))) (rule (targets spdx-license-list) (action (with-stdout-to %{targets} (system "curl https://raw.githubusercontent.com/spdx/license-list-data/master/json/licenses.json | jq -rc '.licenses | map(\" \\\"\" + .licenseId + \"\\\";\") | join(\"\\n\")'")))) (rule (targets spdx-license-exn-list) (action (with-stdout-to %{targets} (system "curl https://raw.githubusercontent.com/spdx/license-list-data/master/json/exceptions.json | jq -rc '.exceptions | map(\" \\\"\" + .licenseExceptionId + \"\\\";\") | join(\"\\n\")'")))) (rule (with-stdout-to flags.ml (echo "print_string (if String.sub Sys.ocaml_version 0 5 = \"4.02.\" then \"(-w -50)\" else \"()\")"))) (rule (with-stdout-to flags.sexp (run ocaml %{dep:flags.ml}))) opam-2.1.5/src/state/opamPinned.mli0000644000175000017500000000474714427463453016237 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Specific query and handling of pinned packages *) open OpamTypes open OpamStateTypes (** Returns the version the package is pinned to. @raise Not_found when appropriate *) val version: 'a switch_state -> name -> version (** Returns the package with the pinned-to version from a pinned package name. @raise Not_found when appropriate *) val package: 'a switch_state -> name -> package (** Returns the package with the pinned-to version from a package name, if pinned *) val package_opt: 'a switch_state -> name -> package option (** The set of all pinned packages with their pinning versions *) val packages: 'a switch_state -> package_set (** Looks up an 'opam' file for the given named package in a source directory. if [locked] is true, look for a locked file. *) val find_opam_file_in_source: ?locked:bool -> name -> dirname -> OpamFile.OPAM.t OpamFile.t option (** Finds all package definition files in a given source dir [opam], [pkgname.opam/opam], etc. This is affected by [OpamStateConfig.(!r.locked)] *) val files_in_source: ?recurse:bool -> ?subpath:string -> dirname -> (name option * OpamFile.OPAM.t OpamFile.t * string option) list (** From an opam file location, sitting below the given project directory, find the corresponding package name if specified ([.opam] or [.opam/opam]). This function doesn't check the project directory name itself, or the package name that might be specified within the file. *) val name_of_opam_filename: dirname -> filename -> name option (** Finds back the location of the opam file this package definition was loaded from *) val orig_opam_file: 'a switch_state -> OpamPackage.Name.t -> OpamFile.OPAM.t -> OpamFile.OPAM.t OpamFile.t option opam-2.1.5/src/state/opamStateConfig.ml0000644000175000017500000003054514427463453017052 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2015-2020 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamStateTypes module E = struct type OpamStd.Config.E.t += | BUILDDOC of bool option | BUILDTEST of bool option | DOWNLOADJOBS of int option | DRYRUN of bool option | IGNORECONSTRAINTS of string option | JOBS of int option | LOCKED of string option | MAKECMD of string option | NODEPEXTS of bool option | NOENVNOTICE of bool option | ROOT of string option | SWITCH of string option | UNLOCKBASE of bool option | WITHDOC of bool option | WITHTEST of bool option open OpamStd.Config.E let builddoc = value (function BUILDDOC b -> b | _ -> None) let buildtest = value (function BUILDTEST b -> b | _ -> None) let downloadjobs = value (function DOWNLOADJOBS i -> i | _ -> None) let dryrun = value (function DRYRUN b -> b | _ -> None) let ignoreconstraints = value (function IGNORECONSTRAINTS s -> s | _ -> None) let jobs = value (function JOBS i -> i | _ -> None) let locked = value (function LOCKED s -> s | _ -> None) let makecmd = value (function MAKECMD s -> s | _ -> None) let nodepexts = value (function NODEPEXTS b -> b | _ -> None) let noenvnotice = value (function NOENVNOTICE b -> b | _ -> None) let root = value (function ROOT s -> s | _ -> None) let switch = value (function SWITCH s -> s | _ -> None) let unlockbase = value (function UNLOCKBASE b -> b | _ -> None) let withdoc = value (function WITHDOC b -> b | _ -> None) let withtest = value (function WITHTEST b -> b | _ -> None) end type t = { root_dir: OpamFilename.Dir.t; current_switch: OpamSwitch.t option; switch_from: provenance; jobs: int Lazy.t; dl_jobs: int; build_test: bool; build_doc: bool; dryrun: bool; makecmd: string Lazy.t; ignore_constraints_on: name_set; unlock_base: bool; no_env_notice: bool; locked: string option; no_depexts: bool; } let default = { root_dir = OpamFilename.( concat_and_resolve (Dir.of_string (OpamStd.Sys.home ())) ".opam" ); current_switch = None; switch_from = `Default; jobs = lazy (max 1 (OpamSysPoll.cores () - 1)); dl_jobs = 3; build_test = false; build_doc = false; dryrun = false; makecmd = lazy OpamStd.Sys.( match os () with | FreeBSD | OpenBSD | NetBSD | DragonFly -> "gmake" | _ -> "make" ); ignore_constraints_on = OpamPackage.Name.Set.empty; unlock_base = false; no_env_notice = false; locked = None; no_depexts = false; } type 'a options_fun = ?root_dir:OpamFilename.Dir.t -> ?current_switch:OpamSwitch.t -> ?switch_from:provenance -> ?jobs:(int Lazy.t) -> ?dl_jobs:int -> ?build_test:bool -> ?build_doc:bool -> ?dryrun:bool -> ?makecmd:string Lazy.t -> ?ignore_constraints_on:name_set -> ?unlock_base:bool -> ?no_env_notice:bool -> ?locked:string option -> ?no_depexts: bool -> 'a let setk k t ?root_dir ?current_switch ?switch_from ?jobs ?dl_jobs ?build_test ?build_doc ?dryrun ?makecmd ?ignore_constraints_on ?unlock_base ?no_env_notice ?locked ?no_depexts = let (+) x opt = match opt with Some x -> x | None -> x in k { root_dir = t.root_dir + root_dir; current_switch = (match current_switch with None -> t.current_switch | s -> s); switch_from = t.switch_from + switch_from; jobs = t.jobs + jobs; dl_jobs = t.dl_jobs + dl_jobs; build_test = t.build_test + build_test; build_doc = t.build_doc + build_doc; dryrun = t.dryrun + dryrun; makecmd = t.makecmd + makecmd; ignore_constraints_on = t.ignore_constraints_on + ignore_constraints_on; unlock_base = t.unlock_base + unlock_base; no_env_notice = t.no_env_notice + no_env_notice; locked = t.locked + locked; no_depexts = t.no_depexts + no_depexts; } let set t = setk (fun x () -> x) t let r = ref default let update ?noop:_ = setk (fun cfg () -> r := cfg) !r let initk k = let open OpamStd.Option.Op in let current_switch, switch_from = match E.switch () with | Some "" | None -> None, None | Some s -> Some (OpamSwitch.of_string s), Some `Env in setk (setk (fun c -> r := c; k)) !r ?root_dir:(E.root () >>| OpamFilename.Dir.of_string) ?current_switch ?switch_from ?jobs:(E.jobs () >>| fun s -> lazy s) ?dl_jobs:(E.downloadjobs ()) ?build_test:(E.withtest () ++ E.buildtest ()) ?build_doc:(E.withdoc () ++ E.builddoc ()) ?dryrun:(E.dryrun ()) ?makecmd:(E.makecmd () >>| fun s -> lazy s) ?ignore_constraints_on: (E.ignoreconstraints () >>| fun s -> OpamStd.String.split s ',' |> List.map OpamPackage.Name.of_string |> OpamPackage.Name.Set.of_list) ?unlock_base:(E.unlockbase ()) ?no_env_notice:(E.noenvnotice ()) ?locked:(E.locked () >>| function "" -> None | s -> Some s) ?no_depexts:(E.nodepexts ()) let init ?noop:_ = initk (fun () -> ()) let opamroot ?root_dir () = let open OpamStd.Option.Op in (root_dir >>+ fun () -> OpamStd.Env.getopt "OPAMROOT" >>| OpamFilename.Dir.of_string) +! default.root_dir let is_newer_raw = function | Some v -> OpamVersion.compare v OpamFile.Config.root_version > 0 | None -> false let is_newer config = is_newer_raw (Some (OpamFile.Config.opam_root_version config)) (** none -> shouldn't load (write attempt in readonly) Some true -> everything is fine normal read Some false -> readonly accorded, load with best effort *) let is_readonly_opamroot_raw ?(lock_kind=`Lock_write) version = let newer = is_newer_raw version in let write = lock_kind = `Lock_write in if newer && write then None else Some (newer && not write) let is_readonly_opamroot_t ?lock_kind gt = is_readonly_opamroot_raw ?lock_kind (Some (OpamFile.Config.opam_root_version gt.config)) let is_newer_than_self ?lock_kind gt = is_readonly_opamroot_t ?lock_kind gt <> Some false let load_if_possible_raw ?lock_kind root version (read,read_wo_err) f = match is_readonly_opamroot_raw ?lock_kind version with | None -> OpamConsole.error_and_exit `Locked "Refusing write access to %s, which is more recent than this version of \ opam (%s > %s), aborting." (OpamFilename.Dir.to_string root) (OpamStd.Option.to_string OpamVersion.to_string version) OpamVersion.(to_string OpamFile.Config.root_version) | Some true -> read_wo_err f | Some false -> read f let load_if_possible_t ?lock_kind opamroot config readf f = load_if_possible_raw ?lock_kind opamroot (Some (OpamFile.Config.opam_root_version config)) readf f let load_if_possible ?lock_kind gt = load_if_possible_t ?lock_kind gt.root gt.config let load_config_root ?lock_kind readf opamroot = let f = OpamPath.config opamroot in load_if_possible_raw ?lock_kind opamroot (OpamFile.Config.raw_root_version f) readf f let safe read read' default = let safe r f = OpamStd.Option.default default @@ r f in safe read, safe read' let safe_load ?lock_kind opamroot = load_config_root ?lock_kind OpamFile.Config.(safe read_opt BestEffort.read_opt empty) opamroot let load ?lock_kind opamroot = load_config_root ?lock_kind OpamFile.Config.(read_opt, BestEffort.read_opt) opamroot (* switches *) module Switch = struct let load_raw ?lock_kind root config readf switch = load_if_possible_t ?lock_kind root config readf (OpamPath.Switch.switch_config root switch) let safe_load_t ?lock_kind root switch = let config = safe_load ~lock_kind:`Lock_read root in load_raw ?lock_kind root config OpamFile.Switch_config.(safe read_opt BestEffort.read_opt empty) switch let load ?lock_kind gt readf switch = load_raw ?lock_kind gt.root gt.config readf switch let safe_load ?lock_kind gt switch = load ?lock_kind gt OpamFile.Switch_config.(safe read_opt BestEffort.read_opt empty) switch let read_opt ?lock_kind gt switch = load ?lock_kind gt OpamFile.Switch_config.(read_opt, BestEffort.read_opt) switch let safe_read_selections ?lock_kind gt switch = load_if_possible ?lock_kind gt OpamFile.SwitchSelections.(safe read_opt BestEffort.read_opt empty) (OpamPath.Switch.selections gt.root switch) end (* repos *) module Repos = struct let safe_read ?lock_kind gt = load_if_possible ?lock_kind gt OpamFile.Repos_config.(safe read_opt BestEffort.read_opt empty) (OpamPath.repos_config gt.root) end let downgrade_2_1_switch f = let filename = OpamFile.filename f in let str_f = OpamFilename.to_string filename in let opamfile = OpamParser.FullPos.file str_f in let opamfile' = let open OpamParserTypes.FullPos in { opamfile with file_contents = List.map (fun item -> match item.pelem with | Variable (({pelem = "opam-version"; _} as opam_v), ({pelem = String "2.1"; _} as v)) -> { item with pelem = Variable ({opam_v with pelem = "opam-version"}, {v with pelem = String "2.0"})} | _ -> item) opamfile.file_contents} in if opamfile' = opamfile then None else Some (opamfile' |> OpamPrinter.FullPos.opamfile |> OpamFile.Switch_config.read_from_string) let local_switch_exists root switch = (* we don't use safe loading function to avoid errors displaying *) let f = OpamPath.Switch.switch_config root switch in match OpamFile.Switch_config.BestEffort.read_opt f with | None -> false | Some conf -> conf.OpamFile.Switch_config.opam_root = Some root | exception (OpamPp.Bad_version _ as e) -> match OpamFile.Config.raw_root_version (OpamPath.config root) with | None -> raise e | Some _ -> match downgrade_2_1_switch f with | None -> raise e | Some conf -> if conf.OpamFile.Switch_config.opam_root = Some root then (OpamFile.Switch_config.write f conf; true) else false let resolve_local_switch root s = let switch_root = OpamSwitch.get_root root s in if OpamSwitch.is_external s && OpamFilename.dirname_dir switch_root = root then OpamSwitch.of_string (OpamFilename.remove_prefix_dir root switch_root) else s let get_current_switch_from_cwd root = try let open OpamStd.Option.Op in OpamFilename.find_in_parents (fun dir -> OpamSwitch.of_string (OpamFilename.Dir.to_string dir) |> local_switch_exists root) (OpamFilename.cwd ()) >>| OpamSwitch.of_dirname >>| resolve_local_switch root with OpamPp.Bad_version _ -> None (* do we want `load_defaults` to fail / run a format upgrade ? *) let load_defaults ?lock_kind root_dir = let current_switch = match E.switch () with | Some "" | None -> get_current_switch_from_cwd root_dir | _ -> (* OPAMSWITCH is set, no need to lookup *) None in match try load ?lock_kind root_dir with OpamPp.Bad_version _ -> None with | None -> update ?current_switch (); None | Some conf -> let open OpamStd.Option.Op in OpamRepositoryConfig.update ?download_tool:(OpamFile.Config.dl_tool conf >>| function | (CString c,None)::_ as t when OpamStd.String.ends_with ~suffix:"curl" c -> lazy (t, `Curl) | t -> lazy (t, `Default)) ~validation_hook:(OpamFile.Config.validation_hook conf) (); update ?current_switch:(OpamFile.Config.switch conf) ~switch_from:`Default ?jobs:(OpamFile.Config.jobs conf >>| fun s -> lazy s) ~dl_jobs:(OpamFile.Config.dl_jobs conf) (); update ?current_switch (); Some conf let get_switch_opt () = match !r.current_switch with | Some s -> Some (resolve_local_switch !r.root_dir s) | None -> None let get_switch () = match get_switch_opt () with | Some s -> s | None -> OpamConsole.error_and_exit `Configuration_error "No switch is currently set. Please use 'opam switch' to set or install \ a switch" opam-2.1.5/src/state/shellscripts/0002755000175000017500000000000014427463453016147 5ustar stephstephopam-2.1.5/src/state/shellscripts/env_hook.zsh0000644000175000017500000000032314427463453020501 0ustar stephsteph_opam_env_hook() { eval $(opam env --shell=zsh --readonly 2> /dev/null <&-); } typeset -ag precmd_functions; if [[ -z ${precmd_functions[(r)_opam_env_hook]} ]]; then precmd_functions+=_opam_env_hook; fi opam-2.1.5/src/state/shellscripts/bwrap.sh0000644000175000017500000001026414427463453017617 0ustar stephsteph#!/usr/bin/env bash set -ue if ! command -v bwrap >/dev/null; then echo "The 'bwrap' command was not found. Install 'bubblewrap' on your system, or" >&2 echo "disable sandboxing in ${OPAMROOT:-~/.opam}/config at your own risk." >&2 echo "See https://github.com/projectatomic/bubblewrap for bwrap details." >&2 echo "For 'bwrap' use in opam, see the FAQ:" >&2 echo " https://opam.ocaml.org/doc/FAQ.html#Why-does-opam-require-bwrap" >&2 exit 10 fi # --new-session requires bubblewrap 0.1.7 # --die-with-parent requires bubblewrap 0.1.8 ARGS=(--unshare-net --new-session --die-with-parent) ARGS=("${ARGS[@]}" --proc /proc --dev /dev) ARGS=("${ARGS[@]}" --setenv TMPDIR /opam-tmp --setenv TMP /opam-tmp --setenv TEMPDIR /opam-tmp --setenv TEMP /opam-tmp) ARGS=("${ARGS[@]}" --tmpfs /opam-tmp) ARGS=("${ARGS[@]}" --tmpfs /run) add_mount() { case "$1" in ro) B="--ro-bind";; rw) B="--bind";; sym) B="--symlink";; esac ARGS=("${ARGS[@]}" "$B" "$2" "$3") } add_mounts() { local flag="$1"; shift for dir in "$@"; do if [ -d "$dir" ]; then add_mount "$flag" "$dir" "$dir" fi done } # Mounts the standard system paths. Maintains symlinks, to handle cases # like `/bin` -> `usr/bin`, where `/bin/../foo` resolves to `/usr/foo`, # not `/foo`. We handle symlinks here but not in `add_mounts` because # system paths are pretty much guaranteed not to accidentally escape into # off-limits directories. add_sys_mounts() { for dir in "$@"; do if [ -L "$dir" ]; then local src=$(readlink -f "$dir") add_mount sym "$src" "$dir" else add_mounts ro "$dir" fi done } # remove some unusual paths (/nix/stored and /rw/usrlocal ) # use OPAM_USER_PATH_RO variable to add them # the OPAM_USER_PATH_RO format is the same as PATH # ie: export OPAM_USER_PATH_RO=/nix/store:/rw/usrlocal add_sys_mounts /usr /bin /lib /lib32 /lib64 /etc /opt /home /var /tmp # C compilers using `ccache` will write to a shared cache directory # that remain writeable. ccache seems widespread in some Fedora systems. add_ccache_mount() { if command -v ccache > /dev/null; then ccache_dir_regex='cache_dir = (.*)$' local IFS=$'\n' for f in $(ccache -p 2>/dev/null); do if [[ $f =~ $ccache_dir_regex ]]; then ccache_dir=${BASH_REMATCH[1]} break fi done CCACHE_DIR=${CCACHE_DIR-$HOME/.ccache} ccache_dir=${ccache_dir-$CCACHE_DIR} add_mounts rw "$ccache_dir" fi } add_dune_cache_mount() { local u_cache=${XDG_CACHE_HOME:-$HOME/.cache} local u_dune_cache=$u_cache/dune local cache=$(readlink -m "$u_cache") local dune_cache=$cache/dune local dune_cache=$(readlink -m "$u_dune_cache") mkdir -p "${dune_cache}" add_mount rw "$u_dune_cache" "$dune_cache" } # mount unusual path in ro if [ -n "${OPAM_USER_PATH_RO-}" ]; then add_mounts ro $(echo "${OPAM_USER_PATH_RO}" | sed 's|:| |g') fi # When using opam variable that must be defined at action time, add them also # at init check in OpamAuxCommands.check_and_revert_sandboxing (like # OPAM_SWITCH_PREFIX). # This case-switch should remain identical between the different sandbox implems COMMAND="$1"; shift case "$COMMAND" in build) add_mounts ro "$OPAM_SWITCH_PREFIX" add_mounts rw "$PWD" add_ccache_mount add_dune_cache_mount ;; install) add_mounts rw "$OPAM_SWITCH_PREFIX" add_mounts ro "$OPAM_SWITCH_PREFIX/.opam-switch" add_mounts rw "$PWD" ;; remove) add_mounts rw "$OPAM_SWITCH_PREFIX" add_mounts ro "$OPAM_SWITCH_PREFIX/.opam-switch" if [ "X${PWD#$OPAM_SWITCH_PREFIX/.opam-switch/}" != "X${PWD}" ]; then add_mounts rw "$PWD" fi ;; *) echo "$0: unknown command $COMMAND, must be one of 'build', 'install' or 'remove'" >&2 exit 2 esac if ! command -v "$1" >/dev/null; then echo "[ERROR] Command not found: $1" >&2 exit 10 fi # Note: we assume $1 can be trusted, see https://github.com/projectatomic/bubblewrap/issues/259 # As of now we are compatible up to 0.1.8, '--' can be added here when we require >= 0.3.0 exec bwrap "${ARGS[@]}" "$@" opam-2.1.5/src/state/shellscripts/prompt.sh0000644000175000017500000000122514427463453020022 0ustar stephsteph# This script allows you to see the active opam switch in your prompt. It # should be portable across all shells in common use. # # To enable, change your PS1 to call _opam_ps1 using command substitution. For # example, in bash: # # PS1="$(__opam_ps1 "(%s)")\u@\h:\w\$ " # __opam_ps1() { local exit=$? local printf_format='(%s)' case "$#" in 0|1) printf_format="${1:-$printf_format}" ;; *) return $exit ;; esac local switch_name="$(opam switch show --safe 2>/dev/null)" if [ -z "$switch_name" ]; then return $exit fi printf -- "$printf_format" "$switch_name" return $exit } opam-2.1.5/src/state/shellscripts/env_hook.csh0000644000175000017500000000006614427463453020456 0ustar stephstephalias precmd 'eval `opam env --shell=csh --readonly`' opam-2.1.5/src/state/shellscripts/sandbox_exec.sh0000644000175000017500000000546514427463453021155 0ustar stephsteph#!/usr/bin/env bash set -ue POL='(version 1)(allow default)(deny network*)(deny file-write*)' POL="$POL"'(allow network* (remote unix))' POL="$POL"'(allow file-write* (literal "/dev/null") (literal "/dev/dtracehelper"))' add_mounts() { if [ -d "$2" ]; then local DIR="$(cd "$2" && pwd -P)" case "$1" in ro) POL="$POL"'(deny file-write* (subpath "'"$DIR"'"))';; rw) POL="$POL"'(allow file-write* (subpath "'"$DIR"'"))';; esac fi } # Even if TMPDIR is set, some applications uses /tmp directly add_mounts rw /tmp if [ -z ${TMPDIR+x} ]; then # Others applications obtain the per-user temporary # directory differently; the latter should be made readable/writable # too and getconf seems to be a robust way to get it if [ -z /usr/bin/getconf ]; then TMPDIR=$(getconf DARWIN_USER_TEMP_DIR) add_mounts rw "$TMPDIR" export TMPDIR fi else add_mounts rw "$TMPDIR" fi # C compilers using `ccache` will write to a shared cache directory # that remain writeable. ccache seems widespread in some Fedora systems. add_ccache_mount() { if command -v ccache > /dev/null; then ccache_dir_regex='cache_dir = (.*)$' local IFS=$'\n' for f in $(ccache -p 2>/dev/null); do if [[ $f =~ $ccache_dir_regex ]]; then ccache_dir=${BASH_REMATCH[1]} break fi done CCACHE_DIR=${CCACHE_DIR-$HOME/.ccache} ccache_dir=${ccache_dir-$CCACHE_DIR} add_mounts rw "$ccache_dir" fi } add_dune_cache_mount() { local dune_cache=${XDG_CACHE_HOME:-$HOME/.cache}/dune mkdir -p "${dune_cache}" add_mounts rw "$dune_cache" } # mount unusual path in ro if [ -n "${OPAM_USER_PATH_RO-}" ]; then add_mounts ro $(echo "${OPAM_USER_PATH_RO}" | sed 's|:| |g') fi # When using opam variable that must be defined at action time, add them also # at init check in OpamAuxCommands.check_and_revert_sandboxing (like # OPAM_SWITCH_PREFIX). # This case-switch should remain identical between the different sandbox implems COMMAND="$1"; shift case "$COMMAND" in build) add_mounts ro "$OPAM_SWITCH_PREFIX" add_mounts rw "$PWD" add_ccache_mount add_dune_cache_mount ;; install) add_mounts rw "$OPAM_SWITCH_PREFIX" add_mounts ro "$OPAM_SWITCH_PREFIX/.opam-switch" add_mounts rw "$PWD" ;; remove) add_mounts rw "$OPAM_SWITCH_PREFIX" add_mounts ro "$OPAM_SWITCH_PREFIX/.opam-switch" if [ "X${PWD#$OPAM_SWITCH_PREFIX/.opam-switch/}" != "X${PWD}" ]; then add_mounts rw "$PWD" fi ;; *) echo "$0: unknown command $COMMAND, must be one of 'build', 'install' or 'remove'" >&2 exit 2 esac if ! command -v "$1" >/dev/null; then echo "[ERROR] Command not found: $1" >&2 exit 10 fi exec sandbox-exec -p "$POL" "$@" opam-2.1.5/src/state/shellscripts/env_hook.sh0000644000175000017500000000037714427463453020320 0ustar stephsteph_opam_env_hook() { local previous_exit_status=$?; eval $(opam env --shell=bash --readonly 2> /dev/null <&- ); return $previous_exit_status; }; if ! [[ "$PROMPT_COMMAND" =~ _opam_env_hook ]]; then PROMPT_COMMAND="_opam_env_hook;$PROMPT_COMMAND"; fi opam-2.1.5/src/state/shellscripts/complete.sh0000644000175000017500000001620314427463453020313 0ustar stephstephif [ -z "$BASH_VERSION" ]; then return 0; fi _opam_add() { IFS=$'\n' _opam_reply+=("$@") } _opam_add_f() { local cmd cmd=$1; shift _opam_add "$($cmd "$@" 2>/dev/null)" } _opam_flags() { opam "$@" --help=groff 2>/dev/null | \ sed -n \ -e 's%\\-\|\\N'"'45'"'%-%g' \ -e 's%, \\fB%\n\\fB%g' \ -e '/^\\fB-/p' | \ sed -e 's%^\\fB\(-[^\\]*\).*%\1%' } _opam_commands() { opam "$@" --help=groff 2>/dev/null | \ sed -n \ -e 's%\\-\|\\N'"'45'"'%-%g' \ -e '/^\.SH COMMANDS$/,/^\.SH/ s%^\\fB\([^,= ]*\)\\fR.*%\1%p' echo '--help' } _opam_vars() { opam var --safe 2>/dev/null | \ sed -n \ -e '/^PKG:/d' \ -e 's%^\([^#= ][^ ]*\).*%\1%p' } _opam_argtype() { local cmd flag cmd="$1"; shift flag="$1"; shift case "$flag" in -*) opam "$cmd" --help=groff 2>/dev/null | \ sed -n \ -e 's%\\-\|\\N'"'45'"'%-%g' \ -e 's%.*\\fB'"$flag"'\\fR[= ]\\fI\([^, ]*\)\\fR.*%\1%p' ;; esac } _opam() { local IFS cmd subcmd cur prev compgen_opt COMPREPLY=() cmd=${COMP_WORDS[1]} subcmd=${COMP_WORDS[2]} cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} compgen_opt=() _opam_reply=() if [ $COMP_CWORD -eq 1 ]; then _opam_add_f opam help topics COMPREPLY=( $(compgen -W "${_opam_reply[*]}" -- $cur) ) unset _opam_reply return 0 fi case "$(_opam_argtype $cmd $prev)" in LEVEL|JOBS|RANK) _opam_add 1 2 3 4 5 6 7 8 9;; FILE|FILENAME) compgen_opt+=(-o filenames -f);; DIR|ROOT) compgen_opt+=(-o filenames -d);; MAKE|CMD) compgen_opt+=(-c);; KIND) _opam_add http local git darcs hg;; WHEN) _opam_add always never auto;; SWITCH|SWITCHES) _opam_add_f opam switch list --safe -s;; COLUMNS|FIELDS) _opam_add name version package synopsis synopsis-or-target \ description installed-version pin source-hash \ opam-file all-installed-versions available-versions \ all-versions repository installed-files vc-ref depexts;; PACKAGE|PACKAGES|PKG|PATTERN|PATTERNS) _opam_add_f opam list --safe -A -s;; FLAG) _opam_add light-uninstall verbose plugin compiler conf;; REPOS) _opam_add_f opam repository list --safe -s -a;; SHELL) _opam_add bash sh csh zsh fish;; TAGS) ;; CRITERIA) ;; STRING) ;; URL) compgen_opt+=(-o filenames -d) _opam_add "https://" "http://" "file://" \ "git://" "git+file://" "git+ssh://" "git+https://" \ "hg+file://" "hg+ssh://" "hg+https://" \ "darcs+file://" "darcs+ssh://" "darcs+https://";; "") case "$cmd" in install|show|info|inst|ins|in|i|inf|sh) _opam_add_f opam list --safe -a -s if [ $COMP_CWORD -gt 2 ]; then _opam_add_f _opam_flags "$cmd" fi;; reinstall|remove|uninstall|reinst|remov|uninst|unins) _opam_add_f opam list --safe -i -s if [ $COMP_CWORD -gt 2 ]; then _opam_add_f _opam_flags "$cmd" fi;; upgrade|upg) _opam_add_f opam list --safe -i -s _opam_add_f _opam_flags "$cmd" ;; switch|sw) case $COMP_CWORD in 2) _opam_add_f _opam_commands "$cmd" _opam_add_f opam switch list --safe -s;; 3) case "$subcmd" in create|install) _opam_add_f opam switch list-available --safe -s -a;; set|remove|reinstall) _opam_add_f opam switch list --safe -s;; import|export) compgen_opt+=(-o filenames -f);; *) _opam_add_f _opam_flags "$cmd" esac;; *) _opam_add_f _opam_flags "$cmd" esac;; config|conf|c) case $COMP_CWORD in 2) _opam_add_f _opam_commands "$cmd";; 3) case "$subcmd" in var) _opam_add_f _opam_vars;; exec) compgen_opt+=(-c);; *) _opam_add_f _opam_flags "$cmd" esac;; *) _opam_add_f _opam_flags "$cmd" esac;; repository|remote|repos|repo) case $COMP_CWORD in 2) _opam_add_f _opam_commands "$cmd";; 3) case "$subcmd" in list) _opam_add_f _opam_flags "$cmd";; *) _opam_add_f opam repository list --safe -a -s esac;; *) _opam_add_f _opam_flags "$cmd" case "$subcmd" in set-url|add) compgen_opt+=(-o filenames -f);; set-repos) _opam_add_f opam repository list --safe -a -s;; esac;; esac;; update|upd) _opam_add_f opam repository list --safe -s _opam_add_f opam pin list --safe -s _opam_add_f _opam_flags "$cmd" ;; source|so) if [ $COMP_CWORD -eq 2 ]; then _opam_add_f opam list --safe -A -s else _opam_add_f _opam_flags "$cmd" fi;; pin) case $COMP_CWORD in 2) _opam_add_f _opam_commands "$cmd";; 3) case "$subcmd" in add) compgen_opt+=(-o filenames -d) _opam_add_f opam list --safe -A -s;; remove|edit) _opam_add_f opam pin list --safe -s;; *) _opam_add_f _opam_flags "$cmd" esac;; *) case "$subcmd" in add) compgen_opt+=(-o filenames -d);; *) _opam_add_f _opam_flags "$cmd" esac esac;; unpin) if [ $COMP_CWORD -eq 2 ]; then _opam_add_f opam pin list --safe -s else _opam_add_f _opam_flags "$cmd" fi;; var|v) if [ $COMP_CWORD -eq 2 ]; then _opam_add_f _opam_vars else _opam_add_f _opam_flags "$cmd"; fi;; exec|e) if [ $COMP_CWORD -eq 2 ]; then compgen_opt+=(-c) else _opam_add_f _opam_flags "$cmd"; fi;; lint|build) if [ $COMP_CWORD -eq 2 ]; then compgen_opt+=(-f -X '!*opam' -o plusdirs) else _opam_add_f _opam_flags "$cmd"; fi;; admin) if [ $COMP_CWORD -eq 2 ]; then _opam_add_f _opam_commands "$cmd" else _opam_add_f _opam_flags "$cmd" "$subcmd"; fi;; *) _opam_add_f _opam_commands "$cmd" _opam_add_f _opam_flags "$cmd" esac;; esac COMPREPLY=($(compgen -W "${_opam_reply[*]}" "${compgen_opt[@]}" -- "$cur")) unset _opam_reply return 0 } complete -F _opam opam opam-2.1.5/src/state/shellscripts/complete.zsh0000644000175000017500000001626314427463453020513 0ustar stephsteph#compdef opam if [ -z "$ZSH_VERSION" ]; then return 0; fi _opam_add() { IFS=$'\n' _opam_reply+=("$@") } _opam_add_f() { local cmd cmd=$1; shift _opam_add "$($cmd "$@" 2>/dev/null)" } _opam_flags() { opam "$@" --help=groff 2>/dev/null | \ sed -n \ -e 's%\\-\|\\N'"'45'"'%-%g' \ -e 's%, \\fB%\n\\fB%g' \ -e '/^\\fB-/p' | \ sed -e 's%^\\fB\(-[^\\]*\).*%\1%' } _opam_commands() { opam "$@" --help=groff 2>/dev/null | \ sed -n \ -e 's%\\-\|\\N'"'45'"'%-%g' \ -e '/^\.SH COMMANDS$/,/^\.SH/ s%^\\fB\([^,= ]*\)\\fR.*%\1%p' echo '--help' } _opam_vars() { opam var -safe 2>/dev/null | \ sed -n \ -e '/^PKG:/d' \ -e 's%^\([^#= ][^ ]*\).*%\1%p' } _opam_argtype() { local cmd flag cmd="$1"; shift flag="$1"; shift case "$flag" in -*) opam "$cmd" --help=groff 2>/dev/null | \ sed -n \ -e 's%\\-\|\\N'"'45'"'%-%g' \ -e 's%.*\\fB'"$flag"'\\fR[= ]\\fI\([^, ]*\)\\fR.*%\1%p' ;; esac } _opam() { local IFS cmd subcmd cur prev compgen_opt COMPREPLY=() cmd=${COMP_WORDS[1]} subcmd=${COMP_WORDS[2]} cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} compgen_opt=() _opam_reply=() if [ $COMP_CWORD -eq 1 ]; then _opam_add_f opam help topics COMPREPLY=( $(compgen -W "${_opam_reply[*]}" -- $cur) ) unset _opam_reply return 0 fi case "$(_opam_argtype $cmd $prev)" in LEVEL|JOBS|RANK) _opam_add 1 2 3 4 5 6 7 8 9;; FILE|FILENAME) compgen_opt+=(-o filenames -f);; DIR|ROOT) compgen_opt+=(-o filenames -d);; MAKE|CMD) compgen_opt+=(-c);; KIND) _opam_add http local git darcs hg;; WHEN) _opam_add always never auto;; SWITCH|SWITCHES) _opam_add_f opam switch list --safe -s;; COLUMNS|FIELDS) _opam_add name version package synopsis synopsis-or-target \ description installed-version pin source-hash \ opam-file all-installed-versions available-versions \ all-versions repository installed-files vc-ref depexts;; PACKAGE|PACKAGES|PKG|PATTERN|PATTERNS) _opam_add_f opam list --safe -A -s;; FLAG) _opam_add light-uninstall verbose plugin compiler conf;; REPOS) _opam_add_f opam repository list --safe -s -a;; SHELL) _opam_add bash sh csh zsh fish;; TAGS) ;; CRITERIA) ;; STRING) ;; URL) compgen_opt+=(-o filenames -d) _opam_add "https://" "http://" "file://" \ "git://" "git+file://" "git+ssh://" "git+https://" \ "hg+file://" "hg+ssh://" "hg+https://" \ "darcs+file://" "darcs+ssh://" "darcs+https://";; "") case "$cmd" in install|show|info|inst|ins|in|i|inf|sh) _opam_add_f opam list --safe -a -s if [ $COMP_CWORD -gt 2 ]; then _opam_add_f _opam_flags "$cmd" fi;; reinstall|remove|uninstall|reinst|remov|uninst|unins) _opam_add_f opam list --safe -i -s if [ $COMP_CWORD -gt 2 ]; then _opam_add_f _opam_flags "$cmd" fi;; upgrade|upg) _opam_add_f opam list --safe -i -s _opam_add_f _opam_flags "$cmd" ;; switch|sw) case $COMP_CWORD in 2) _opam_add_f _opam_commands "$cmd" _opam_add_f opam switch list --safe -s;; 3) case "$subcmd" in create|install) _opam_add_f opam switch list-available --safe -s -a;; set|remove|reinstall) _opam_add_f opam switch list --safe -s;; import|export) compgen_opt+=(-o filenames -f);; *) _opam_add_f _opam_flags "$cmd" esac;; *) _opam_add_f _opam_flags "$cmd" esac;; config|conf|c) case $COMP_CWORD in 2) _opam_add_f _opam_commands "$cmd";; 3) case "$subcmd" in var) _opam_add_f _opam_vars;; exec) compgen_opt+=(-c);; *) _opam_add_f _opam_flags "$cmd" esac;; *) _opam_add_f _opam_flags "$cmd" esac;; repository|remote|repos|repo) case $COMP_CWORD in 2) _opam_add_f _opam_commands "$cmd";; 3) case "$subcmd" in list) _opam_add_f _opam_flags "$cmd";; *) _opam_add_f opam repository list --safe -a -s esac;; *) _opam_add_f _opam_flags "$cmd" case "$subcmd" in set-url|add) compgen_opt+=(-o filenames -f);; set-repos) _opam_add_f opam repository list --safe -a -s;; esac;; esac;; update|upd) _opam_add_f opam repository list --safe -s _opam_add_f opam pin list --safe -s _opam_add_f _opam_flags "$cmd" ;; source|so) if [ $COMP_CWORD -eq 2 ]; then _opam_add_f opam list --safe -A -s else _opam_add_f _opam_flags "$cmd" fi;; pin) case $COMP_CWORD in 2) _opam_add_f _opam_commands "$cmd";; 3) case "$subcmd" in add) compgen_opt+=(-o filenames -d) _opam_add_f opam list --safe -A -s;; remove|edit) _opam_add_f opam pin list --safe -s;; *) _opam_add_f _opam_flags "$cmd" esac;; *) case "$subcmd" in add) compgen_opt+=(-o filenames -d);; *) _opam_add_f _opam_flags "$cmd" esac esac;; unpin) if [ $COMP_CWORD -eq 2 ]; then _opam_add_f opam pin list --safe -s else _opam_add_f _opam_flags "$cmd" fi;; var|v) if [ $COMP_CWORD -eq 2 ]; then _opam_add_f _opam_vars else _opam_add_f _opam_flags "$cmd"; fi;; exec|e) if [ $COMP_CWORD -eq 2 ]; then compgen_opt+=(-c) else _opam_add_f _opam_flags "$cmd"; fi;; lint|build) if [ $COMP_CWORD -eq 2 ]; then compgen_opt+=(-f -X '!*opam' -o plusdirs) else _opam_add_f _opam_flags "$cmd"; fi;; admin) if [ $COMP_CWORD -eq 2 ]; then _opam_add_f _opam_commands "$cmd" else _opam_add_f _opam_flags "$cmd" "$subcmd"; fi;; *) _opam_add_f _opam_commands "$cmd" _opam_add_f _opam_flags "$cmd" esac;; esac COMPREPLY=($(compgen -W "${_opam_reply[*]}" "${compgen_opt[@]}" -- "$cur")) unset _opam_reply return 0 } autoload bashcompinit bashcompinit complete -F _opam opam opam-2.1.5/src/state/shellscripts/env_hook.fish0000644000175000017500000000016614427463453020633 0ustar stephstephfunction __opam_env_export_eval --on-event fish_prompt; eval (opam env --shell=fish --readonly 2> /dev/null); end opam-2.1.5/src/state/opamFormatUpgrade.mli0000644000175000017500000000732614427463453017556 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** This modules handles the conversion from older repository and package versions to the current one *) open OpamTypes open OpamStateTypes (** Raised when the opam root has been updated to a newer format, and further action (opam init/update) is needed. [Upgrade_done conf reinit] specifies the new config file and a reinit function to call instead of default (see [OpamCliMain.main_catch_all]). *) exception Upgrade_done of OpamFile.Config.t * (OpamFile.Config.t -> unit) option (** The latest version of the opam root format, that normal operation of this instance of opam requires *) val latest_version: OpamVersion.t (** [as_necessary requested_lock global_lock root config] Runs the upgrade from its current format to the latest compatible version for the opam root at [root] directory. Performs an on-the-fly upgrade (loaded state, not written) if possible: no hard upgrade needed, and no write lock required ([requested_lock]). If upgrade need to be written (hard upgrade), a write lock on the global state ([global_lock]) is taken and when it's done raises [Upgrade_done updated_config]. Otherwise, it returns the upgraded or unchanged config file.*) val as_necessary: ?reinit:(OpamFile.Config.t -> unit) -> 'a lock -> OpamSystem.lock -> dirname -> OpamFile.Config.t -> OpamFile.Config.t (* Try to launch a hard upgrade from 2;1 alpha's & beta's root to 2.1~rc one. Raises [Upgrade_done] (catched by main function) if an upgrade is done, otherwise do nothing. It is intend to be called after a config file that error with [OpamPp.Bad_version] *) val hard_upgrade_from_2_1_intermediates: ?reinit:(OpamFile.Config.t -> unit) -> ?global_lock: OpamSystem.lock -> dirname -> unit (** Converts the opam file format, including rewriting availability conditions based on OCaml-related variables into dependencies. The filename is used to report errors *) val opam_file_from_1_2_to_2_0: ?filename:OpamFile.OPAM.t OpamFile.t -> OpamFile.OPAM.t -> OpamFile.OPAM.t (** Runs the opam file format from the file's format to current. Supplying [filename] enables additional notification messages *) val opam_file: ?quiet:bool -> ?filename:OpamFile.OPAM.t OpamFile.t -> OpamFile.OPAM.t -> OpamFile.OPAM.t (** Convert the comp file to an opam one, using [OpamFile.Comp.to_package] and applying filter rewriting *) val comp_file: ?package:package -> ?descr:OpamFile.Descr.t -> OpamFile.Comp.t -> OpamFile.OPAM.t (** Runs the opam file format from the file's format to current, and adds data from 'url' and 'descr' files found in the specified dir or the opam file's metadata dir, if not already present in the opam file. If [files] is [true], also adds the names and hashes of files found below 'files/'. Supplying [filename] enables additional notification messages *) val opam_file_with_aux: ?quiet:bool -> ?dir:dirname -> files:bool -> ?filename:OpamFile.OPAM.t OpamFile.t -> OpamFile.OPAM.t -> OpamFile.OPAM.t opam-2.1.5/src/state/opamGlobalState.mli0000644000175000017500000000654714427463453017223 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Loading and handling of the global state of an opam root *) open OpamTypes open OpamStateTypes (** Loads the global state (from the opam root obtained through [OpamStateConfig.(!r.root)]) *) val load: 'a lock -> 'a global_state (** Loads the global state as [load], and calls the given function while keeping it locked (as per the [lock] argument), releasing the lock afterwards *) val with_: 'a lock -> ('a global_state -> 'b) -> 'b (** The set of all installed packages, in any switch *) val all_installed: 'a global_state -> package_set val switches: 'a global_state -> switch list (** Fold over switches, using switch selections. Switch selection file [switch-state] is loaded only read-only; no further checks are done on the opam root version. *) val fold_switches: (switch -> switch_selections -> 'a -> 'a) -> 'b global_state -> 'a -> 'a (** Checks a switch for existence: either configured in the opam root, or an existing local switch with a configuration file pointing to the current root *) val switch_exists: 'a global_state -> switch -> bool (** Returns the map of installed instances of the package name towards the list of switches they are installed in *) val installed_versions: 'a global_state -> name -> switch list package_map (** Default list of repositories to get packages from, ordered by decreasing priority. This can be overridden by switch-specific selections, and does not have to include all configured repositories. *) val repos_list: 'a global_state -> repository_name list (** Releases any locks on the given global_state *) val unlock: 'a global_state -> unlocked global_state (** Releases any locks on the given global state and then ignores it. Using [drop gt] is equivalent to [ignore (unlock gt)], and safer than other uses of [ignore] where it is not enforced by the type-system that the value is unlocked before it is lost. *) val drop: 'a global_state -> unit (** Calls the provided function, ensuring a temporary write lock on the given global state *) val with_write_lock: ?dontblock:bool -> 'a global_state -> (rw global_state -> 'b * 'c global_state) -> 'b * 'a global_state (** Writes back the global configuration file ~/.opam/config *) val write: rw global_state -> unit (** Updates the configured list of switches, making sure the current switch is registered if it is set and exists, and removing any non-existing switches. Writes back to disk if possible (ie lock is available) *) val fix_switch_list: 'a global_state -> 'a global_state (** Description used for system inferred variables *) val inferred_from_system: string opam-2.1.5/src/state/opamSysInteract.mli0000644000175000017500000000305514427463453017261 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019-2020 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (* Given a list of system packages, retrieve their installation status from the system and returns a pair of [sys_package] set: * first one is available set: package that exist on the default repositories, but not installed) * second one, not found set: packages not found on the defined repositories *) val packages_status: OpamSysPkg.Set.t -> OpamSysPkg.Set.t * OpamSysPkg.Set.t (* Return the commands to run to install given system packages *) val install_packages_commands: OpamSysPkg.Set.t -> (string * string list) list (* Install given system packages, by calling local system package manager *) val install: OpamSysPkg.Set.t -> unit val update: unit -> unit (* Determine if special packages may need installing to enable other repositories. Presently used to check for epel-release on CentOS and RHEL. *) val repo_enablers : unit -> string option opam-2.1.5/src/state/opamSwitchState.mli0000644000175000017500000002634214427463453017257 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Loading and querying a switch state *) open OpamTypes open OpamStateTypes val load: 'a lock -> 'b global_state -> 'c repos_state -> switch -> 'a switch_state (** Loads the switch state and calls the given function on it, releasing the lock afterwards. The repository state is automatically loaded if not provided. The switch is selected, if not set, using [OpamStateConfig.get_switch] -- which can fail if no switch is configured. Additionally, in case of a write lock, a backup is saved and a message is printed on restoring if [f] raised an exception and there were changes. *) val with_: 'a lock -> ?rt:([< unlocked ] repos_state) -> ?switch:switch -> [< unlocked ] global_state -> ('a switch_state -> 'b) -> 'b (** Creates a virtual state with nothing installed. Availability is computed just from the global state, and [avail_default] (default [true]) controls the result when the availability can't be computed due to undefined variables. Useful for querying and simulating actions when no switch is yet configured, or querying packages directly from the repos *) val load_virtual: ?repos_list: repository_name list -> ?avail_default: bool -> 'a global_state -> 'b repos_state -> unlocked switch_state (** Load the switch's state file, without constructing the package maps: much faster than loading the full switch state *) val load_selections: ?lock_kind: 'a lock -> 'b global_state -> switch -> switch_selections (** Raw function to compute the availability of all packages, in [opams], given the switch configuration and the set of pinned packages. (The result is precomputed in global_state.available_packages once the state is loaded) *) val compute_available_packages: 'a global_state -> switch -> OpamFile.Switch_config.t -> pinned:package_set -> opams:OpamFile.OPAM.t package_map -> package_set (** Raw function to compute the conflicts for all packages, given the set of available packages and the corresponding opam files. This is useful to populate the `u_conflicts` field when building a universe manually. *) val get_conflicts_t: (package -> OpamFilter.env) -> package_set -> OpamFile.OPAM.t package_map -> formula package_map (** Infer a switch invariant from a switch state with compiler_packages and roots set, using some heuristics. Useful for migration from pre-2.1 opam *) val infer_switch_invariant: 'a switch_state -> OpamFormula.t (** Releases any locks on the given switch_state *) val unlock: 'a switch_state -> unlocked switch_state (** Releases any locks on the given switch state and then ignores it. Using [drop st] is equivalent to [ignore (unlock st)], and safer than other uses of [ignore] where it is not enforced by the type-system that the value is unlocked before it is lost. *) val drop: 'a switch_state -> unit (** Calls the provided function, ensuring a temporary write lock on the given switch state *) val with_write_lock: ?dontblock:bool -> 'a switch_state -> (rw switch_state -> 'b * rw switch_state) -> 'b * 'a switch_state (** {2 Helpers to access state data} *) (** Returns the repositories configured in the current switch or, if none, the globally set default. highest priority first. *) val repos_list: 'a switch_state -> repository_name list val selections: 'a switch_state -> switch_selections (** Return the OPAM file for the given package. @raise Not_found when appropriate *) val opam: 'a switch_state -> package -> OpamFile.OPAM.t (** Return the OPAM file, including URL and descr, for the given package, if any *) val opam_opt: 'a switch_state -> package -> OpamFile.OPAM.t option (** Return the URL field for the given package *) val url: 'a switch_state -> package -> OpamFile.URL.t option (** Returns the primary URL from the URL field of the given package *) val primary_url: 'a switch_state -> package -> url option val primary_url_with_subpath: 'a switch_state -> package -> url option (** Return the descr field for the given package (or an empty descr if none) *) val descr: 'a switch_state -> package -> OpamFile.Descr.t (** Return the descr field for the given package *) val descr_opt: 'a switch_state -> package -> OpamFile.Descr.t option (** Returns the full paths of overlay files under the files/ directory *) val files: 'a switch_state -> package -> filename list (** Return the installed package's local configuration *) val package_config: 'a switch_state -> name -> OpamFile.Dot_config.t (** Check whether a package name is installed *) val is_name_installed: 'a switch_state -> name -> bool (** Return the installed package with the right name @raise Not_found when appropriate *) val find_installed_package_by_name: 'a switch_state -> name -> package (** Return all packages satisfying one of the given atoms from a state *) val packages_of_atoms: 'a switch_state -> atom list -> package_set (** Gets the current version of package [name]: pinned version, installed version, max available version or max existing version, tried in this order. @raise Not_found only if there is no package by this name *) val get_package: 'a switch_state -> name -> package (** "dev packages" are any package with an upstream that isn't the usual HTTP, and without an archive checksum. These need to be updated from upstream independently when installed. It's generally only the case of source-pinned packages, but no rule enforces it in opam itself. *) val is_dev_package: 'a switch_state -> package -> bool (** Checks if the given package name is pinned *) val is_pinned: 'a switch_state -> name -> bool (** Checks if the given package is version-pinned, i.e. pinned without overlay metadata, and relying on the repo's data *) val is_version_pinned: 'a switch_state -> name -> bool (** The set of all "dev packages" (see [is_dev_package] for a definition) *) val dev_packages: 'a switch_state -> package_set (** Returns the local source mirror for the given package ([OpamPath.Switch.sources] or [OpamPath.Switch.pinned_package], depending on wether it's pinned). *) val source_dir: 'a switch_state -> package -> dirname (** Returns the set of active external dependencies for the package, computed from the values of the system-specific variables *) val depexts: 'a switch_state -> package -> OpamSysPkg.Set.t (** Returns required system packages of each of the given packages (elements are not added to the map if they don't have system dependencies) *) val depexts_status_of_packages: 'a switch_state -> package_set -> OpamSysPkg.status package_map (** Returns not found depexts for the package *) val depexts_unavailable: 'a switch_state -> package -> OpamSysPkg.Set.t option (** [conflicts_with st subset pkgs] returns all packages declared in conflict with at least one element of [subset] within [pkgs], through forward or backward conflict definition or common conflict-class. Packages in [subset] (all their versions) are excluded from the result. *) val conflicts_with: 'a switch_state -> package_set -> package_set -> package_set (** Put the package data in a form suitable for the solver, pre-computing some maps and sets. Packages in the [requested] set are the ones that will get affected by the global [build_test] and [build_doc] flags. [test] and [doc], if unspecified, are taken from [OpamStateConfig.r]. [reinstall] marks package not considered current in the universe, and that should therefore be reinstalled. If unspecified, it is the packages marked in [switch_state.reinstall] that are present in [requested]. *) val universe: 'a switch_state -> ?test:bool -> ?doc:bool -> ?force_dev_deps:bool -> ?reinstall:package_set -> requested:name_set -> user_action -> universe (** Dumps the current switch state in PEF format, for interaction with Dose tools *) val dump_pef_state: 'a switch_state -> out_channel -> unit (** {2 Updating} *) (** Sets the given opam file for the given package, updating the other related fields along the way *) val update_package_metadata: package -> OpamFile.OPAM.t -> 'a switch_state -> 'a switch_state (** Removes the metadata associated to the given package, also updating the packages and available sets. *) val remove_package_metadata: package -> 'a switch_state -> 'a switch_state (** Like [update_package_metadata], but also ensures the package is pinned to the given version. The version specified in the opam file, if any, takes precedence over the version of [package]. Also marks it for reinstall if changed. *) val update_pin: package -> OpamFile.OPAM.t -> 'a switch_state -> 'a switch_state (** Updates the selected repositories in the given switch (does not load the full switch state, but takes a transient write lock on the switch, so make sure not to hold other locks to avoid deadlocks). Sets the switch repositories in any case, even if unchanged from the defaults. *) val update_repositories: 'a global_state -> (repository_name list -> repository_name list) -> switch -> unit (** {2 User interaction and reporting } *) (** Returns [true] if the switch of the state is the one set in [$OPAMROOT/config], [false] otherwise. This doesn't imply that the switch is current w.r.t. either the process or the shell, for that you need to check [OpamStateConfig.(!r.switch_from)] *) val is_switch_globally_set: 'a switch_state -> bool (** Returns a message about a package or version that couldn't be found *) val not_found_message: 'a switch_state -> atom -> string val unavailable_reason_raw: 'a switch_state -> name * OpamFormula.version_formula -> [ `UnknownVersion | `UnknownPackage | `NoDefinition | `Pinned of OpamPackage.t | `Unavailable of string | `ConflictsBase | `ConflictsInvariant of string | `MissingDepexts of string list | `Default ] (** Returns a printable explanation why a package is not currently available (pinned to an incompatible version, unmet [available:] constraints...). [default] is returned if no reason why it wouldn't be available was found (empty string if unspecified). *) val unavailable_reason: 'a switch_state -> ?default:string -> name * OpamFormula.version_formula -> string (** Returns whether or not the package can be upgraded to a version tagged with avoid-version *) val can_upgrade_to_avoid_version : OpamPackage.Name.t -> 'a switch_state -> bool (** Handle a cache of the opam files of installed packages *) module Installed_cache: sig type t = OpamFile.OPAM.t OpamPackage.Map.t val save: OpamFilename.t -> t -> unit val remove: OpamFilename.t -> unit end opam-2.1.5/src/state/opamPackageVar.ml0000644000175000017500000003213514427463453016645 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamStd.Op open OpamTypes open OpamStateTypes (* Lists of defined variables, for documentation *) let global_variable_names = [ "opam-version", "The currently running opam version"; "switch", "The identifier of the current switch"; "jobs", "The number of parallel jobs set up in opam \ configuration"; "root", "The current opam root directory"; "make", "The 'make' command to use"; "exe", "Suffix needed for executable filenames (Windows)"; ] let package_variable_names = [ "name", "Name of the package"; "version", "Version of the package"; "depends", "Resolved direct dependencies of the package"; "installed", "Whether the package is installed"; "enable", "Takes the value \"enable\" or \"disable\" depending on whether \ the package is installed"; "pinned", "Whether the package is pinned"; "bin", "Binary directory for this package"; "sbin", "System binary directory for this package"; "lib", "Library directory for this package"; "man", "Man directory for this package"; "doc", "Doc directory for this package"; "share", "Share directory for this package"; "etc", "Etc directory for this package"; "build", "Directory where the package was built"; "hash", "Hash of the package archive"; "dev", "True if this is a development package"; "build-id", "A hash identifying the precise package version with all its \ dependencies"; "opamfile", "Path of the curent opam file"; ] let predefined_depends_variables = List.map OpamVariable.Full.of_string [ "build"; "post"; "with-test"; "with-doc"; "dev"; ] let resolve_global gt full_var = let module V = OpamVariable in if V.Full.(scope full_var <> Global) then None else let var = V.Full.variable full_var in match V.Full.read_from_env full_var with | Some _ as c -> c | None -> match OpamVariable.Map.find_opt var gt.global_variables with | Some (lazy (Some _ as some), _) -> some | _ -> match V.to_string var with | "opam-version" -> Some (V.string OpamVersion.(to_string current)) | "jobs" -> Some (V.int (OpamStateConfig.(Lazy.force !r.jobs))) | "root" -> Some (V.string (OpamFilename.Dir.to_string gt.root)) | "make" -> Some (V.string OpamStateConfig.(Lazy.force !r.makecmd)) | "exe" -> Some (V.string (OpamStd.Sys.executable_name "")) | "switch" -> OpamStd.Option.map (OpamSwitch.to_string @> V.string) (OpamStateConfig.get_switch_opt ()) | _ -> None (** Resolve switch-global variables only, as allowed by the 'available:' field *) let resolve_switch_raw ?package gt switch switch_config full_var = let module V = OpamVariable in let var = V.Full.variable full_var in let allowed_package_variables = match V.Full.scope full_var, package with | _, None -> None | V.Full.Package n, Some nv when n <> nv.name -> None | _, Some nv -> match V.to_string var with | "name" -> Some (S (OpamPackage.Name.to_string nv.name)) | "version" -> Some (S (OpamPackage.Version.to_string nv.version)) | _ -> None in if allowed_package_variables <> None then allowed_package_variables else if V.Full.scope full_var <> V.Full.Global then None else match V.Full.read_from_env full_var with | Some _ as c -> c | None -> try let stdpath = OpamTypesBase.std_path_of_string (V.to_string var) in let dir = OpamPath.Switch.get_stdpath gt.root switch switch_config stdpath in Some (V.string (OpamFilename.Dir.to_string dir)) with Failure _ -> match OpamFile.Switch_config.variable switch_config var with | Some _ as c -> c | None -> match resolve_global gt full_var with | Some _ as c -> c | None -> match V.to_string var with (* we keep it in case no global switch is defined *) | "switch" -> Some (V.string (OpamSwitch.to_string switch)) | _ -> None let resolve_switch ?package st full_var = resolve_switch_raw ?package st.switch_global st.switch st.switch_config full_var open OpamVariable let is_dev_package st opam = match OpamFile.OPAM.url opam with | None -> false | Some urlf -> match OpamFile.URL.(url urlf, checksum urlf) with | { OpamUrl.backend = `http; _ }, _ when not (OpamPackage.Set.mem (OpamFile.OPAM.package opam) st.pinned) -> false | _, _::_ -> false | _, [] -> true let filter_depends_formula ?(build=true) ?(post=false) ?(test=OpamStateConfig.(!r.build_test)) ?(doc=OpamStateConfig.(!r.build_doc)) ?(dev=false) ?default ~env ff = ff |> OpamFilter.partial_filter_formula (fun v -> if List.mem v predefined_depends_variables then None else env v) |> OpamFilter.filter_deps ~build ~post ~test ~doc ~dev ?default let all_depends ?build ?post ?test ?doc ?dev ?(filter_default=false) ?(depopts=true) st opam = let dev = match dev with None -> is_dev_package st opam | Some d -> d in let deps = OpamFormula.ands (OpamFile.OPAM.depends opam :: if depopts then [OpamFile.OPAM.depopts opam] else []) in filter_depends_formula ?build ?post ?test ?doc ~dev ~default:filter_default ~env:(resolve_switch ~package:(OpamFile.OPAM.package opam) st) deps let all_installed_deps st opam = let deps = OpamFormula.atoms (all_depends ~post:false st opam) in List.fold_left (fun deps (n,cstr) -> try let nv = OpamPackage.Set.find (fun nv -> nv.name = n) st.installed in let version = nv.version in match cstr with | None -> OpamPackage.Set.add nv deps | Some (op,v) when OpamFormula.eval_relop op version v -> OpamPackage.Set.add nv deps | Some _ -> deps with Not_found -> deps) OpamPackage.Set.empty deps let build_id st opam = let kind = `SHA256 in let rec aux hash_map nv opam = try hash_map, OpamPackage.Map.find nv hash_map with Not_found -> match OpamFile.OPAM.url opam with | Some urlf when OpamFile.URL.checksum urlf = [] -> (* no fixed source: build-id undefined *) raise Exit | _ -> let hash_map, deps_hashes = OpamPackage.Set.fold (fun nv (hash_map, hashes) -> let hash_map, hash = aux hash_map nv (OpamPackage.Map.find nv st.opams) in hash_map, hash::hashes) (all_installed_deps st opam) (hash_map, []) in let opam_hash = OpamHash.compute_from_string ~kind (OpamFile.OPAM.write_to_string (OpamFile.OPAM.effective_part opam)) in let hash = OpamHash.compute_from_string ~kind (OpamStd.List.concat_map " " OpamHash.contents (opam_hash :: deps_hashes)) in OpamPackage.Map.add nv hash hash_map, hash in try let _hash_map, hash = aux OpamPackage.Map.empty (OpamFile.OPAM.package opam) opam in Some (OpamHash.contents hash) with Exit -> None (* filter handling *) let resolve st ?opam:opam_arg ?(local=OpamVariable.Map.empty) v = let dirname dir = string (OpamFilename.Dir.to_string dir) in let pkgname = OpamStd.Option.map OpamFile.OPAM.name opam_arg in let read_package_var v = let get name = try let cfg = OpamPackage.Name.Map.find name st.conf_files in OpamFile.Dot_config.variable cfg (OpamVariable.Full.variable v) with Not_found -> None in match OpamVariable.Full.scope v with | OpamVariable.Full.Global -> None | OpamVariable.Full.Package n -> get n | OpamVariable.Full.Self -> OpamStd.Option.Op.(pkgname >>= get) in let get_local_var v = match OpamVariable.Full.package v with | Some _ -> None | None -> let var = OpamVariable.Full.variable v in try match OpamVariable.Map.find var local with | None -> raise Exit (* Variable explicitly undefined *) | some -> some with Not_found -> None in let get_package_var v = if OpamVariable.Full.is_global v then None else let var_str = OpamVariable.to_string (OpamVariable.Full.variable v) in let name = match OpamVariable.Full.scope v with | OpamVariable.Full.Global -> assert false | OpamVariable.Full.Package n -> n | OpamVariable.Full.Self -> match pkgname with Some n -> n | None -> raise Exit in let opam = (* ensure opam, if not None, corresponds to name *) match opam_arg with | Some o when OpamFile.OPAM.name o = name -> opam_arg | _ -> try let nv = OpamPackage.package_of_name st.installed name in Some (OpamPackage.Map.find nv st.opams) with Not_found -> None in let get_nv opam = OpamPackage.create name (OpamFile.OPAM.version opam) in let root = st.switch_global.root in match var_str, opam with | "installed", Some _ -> Some (bool (OpamPackage.has_name st.installed name)) | "installed", None -> Some (bool false) | "pinned", _ -> Some (bool (OpamPackage.has_name st.pinned name)) | "name", opam -> (* On reinstall, orphan packages are not present in the state, and we need to resolve their internal name variable *) if OpamStd.Option.map OpamFile.OPAM.name opam = Some name || OpamPackage.has_name st.packages name then Some (string (OpamPackage.Name.to_string name)) else None | _, None -> None | "bin", _ -> Some (dirname (OpamPath.Switch.bin root st.switch st.switch_config)) | "sbin", _ -> Some (dirname (OpamPath.Switch.sbin root st.switch st.switch_config)) | "lib", _ -> Some (dirname (OpamPath.Switch.lib root st.switch st.switch_config name)) | "man", _ -> Some (dirname (OpamPath.Switch.man_dir root st.switch st.switch_config)) | "doc", _ -> Some (dirname (OpamPath.Switch.doc root st.switch st.switch_config name)) | "share", _ -> Some (dirname (OpamPath.Switch.share root st.switch st.switch_config name)) | "etc", _ -> Some (dirname (OpamPath.Switch.etc root st.switch st.switch_config name)) | "build", Some opam -> Some (dirname (OpamPath.Switch.build root st.switch (get_nv opam))) | "version", Some opam -> Some (string (OpamPackage.Version.to_string (OpamFile.OPAM.version opam))) | "depends", Some opam -> let str_deps = all_installed_deps st opam |> OpamPackage.Set.elements |> OpamStd.List.concat_map " " OpamPackage.to_string in Some (string str_deps) | "hash", Some opam -> OpamStd.Option.Op.( OpamFile.OPAM.url opam >>| OpamFile.URL.checksum (* on download, the cache is populated with the first checksum found *) >>= (function [] -> None | h::_ -> Some (string (OpamHash.to_string h)))) | "dev", Some opam -> Some (bool (is_dev_package st opam)) | "build-id", Some opam -> OpamStd.Option.map string (build_id st opam) | "opamfile", Some opam -> (* Opamfile path is retrieved from overlay directory for pinned packages, or from temporary repository in /tmp *) let repos_roots reponame = match Hashtbl.find st.switch_repos.repos_tmp reponame with | lazy repo_root -> repo_root | exception Not_found -> OpamRepositoryPath.root st.switch_global.root reponame in OpamFile.OPAM.get_metadata_dir ~repos_roots opam |> OpamStd.Option.map (fun d -> OpamFilename.Op.(d//"opam") |> OpamFilename.to_string |> string ) | _, _ -> None in let make_package_local v = (* [var] within the opam file of [pkg] is tried as [pkg:var] *) match OpamVariable.Full.is_global v, pkgname with | true, Some name -> OpamVariable.Full.create name (OpamVariable.Full.variable v) | _ -> v in let skip _ = None in let v' = make_package_local v in let contents = try List.fold_left (function None -> (fun (f,v) -> f v) | r -> (fun _ -> r)) None [ get_local_var, v; Full.read_from_env, v; (if v' <> v then Full.read_from_env else skip), v'; read_package_var, v; resolve_switch st, v; (if v' <> v then read_package_var else skip), v'; get_package_var, v'; ] with Exit -> None in contents opam-2.1.5/src/state/opamSwitchState.ml0000644000175000017500000013213314427463453017102 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamStd.Op open OpamPackage.Set.Op let log fmt = OpamConsole.log "STATE" fmt let slog = OpamConsole.slog open OpamStateTypes let load_selections ?lock_kind gt switch = OpamStateConfig.Switch.safe_read_selections ?lock_kind gt switch let load_switch_config ?lock_kind gt switch = match OpamStateConfig.Switch.read_opt ?lock_kind gt switch with | Some c -> c | exception (OpamPp.Bad_version _ as e) -> OpamFormatUpgrade.hard_upgrade_from_2_1_intermediates ~global_lock:gt.global_lock gt.root; raise e | None -> (OpamConsole.error "No config file found for switch %s. Switch broken?" (OpamSwitch.to_string switch); OpamFile.Switch_config.empty) let filter_available_packages gt switch switch_config ~opams = OpamPackage.keys @@ OpamPackage.Map.filter (fun package opam -> OpamFilter.eval_to_bool ~default:false (OpamPackageVar.resolve_switch_raw ~package gt switch switch_config) (OpamFile.OPAM.available opam)) opams let compute_available_and_pinned_packages gt switch switch_config ~pinned ~opams = (* remove all versions of pinned packages, but the pinned-to version *) let pinned_names = OpamPackage.names_of_packages pinned in let (opams, pinned) = OpamPackage.Map.partition (fun nv _ -> not (OpamPackage.Name.Set.mem nv.name pinned_names) || OpamPackage.Set.mem nv pinned) opams in (filter_available_packages gt switch switch_config ~opams, pinned) let compute_available_packages gt switch switch_config ~pinned ~opams = fst @@ compute_available_and_pinned_packages gt switch switch_config ~pinned ~opams let repos_list_raw rt switch_config = let global, repos = match switch_config.OpamFile.Switch_config.repos with | None -> true, OpamGlobalState.repos_list rt.repos_global | Some repos -> false, repos in let found, notfound = List.partition (fun r -> OpamRepositoryName.Map.mem r rt.repositories) repos in List.iter (fun r -> log "Ignoring %s-selected repository %S, no configured repository by \ this name found" (if global then "globally" else "switch") (OpamRepositoryName.to_string r)) notfound; found let repos_list st = repos_list_raw st.switch_repos st.switch_config let infer_switch_invariant_raw gt switch switch_config opams packages compiler_packages installed_roots available_packages = let compiler = compiler_packages %% installed_roots in let compiler = if OpamPackage.Set.is_empty compiler then compiler_packages else compiler in let env nv v = if List.mem v OpamPackageVar.predefined_depends_variables then match OpamVariable.Full.to_string v with | "dev" | "with-test" | "with-doc" -> Some (B false) | _ -> None else OpamPackageVar.resolve_switch_raw ~package:nv gt switch switch_config v in let resolve_deps nv = let opam = OpamPackage.Map.find nv opams in OpamPackageVar.filter_depends_formula ~build:true ~post:true ~default:true ~env:(env nv) (OpamFormula.ands [ OpamFile.OPAM.depends opam; OpamFile.OPAM.depopts opam ]) |> OpamFormula.packages packages in let dmap = OpamPackage.Set.fold (fun nv dmap -> let deps = resolve_deps nv in let dmap = OpamPackage.Map.update nv ((++) deps) OpamPackage.Set.empty dmap in let dmap = OpamPackage.Set.fold (fun d dmap -> OpamPackage.Map.update d (OpamPackage.Set.add nv) OpamPackage.Set.empty dmap) deps dmap in dmap) (OpamPackage.packages_of_names available_packages @@ OpamPackage.names_of_packages @@ compiler) OpamPackage.Map.empty in let counts = OpamPackage.Set.fold (fun nv counts -> let count = try OpamPackage.Set.cardinal (OpamPackage.Map.find nv dmap) with Not_found -> 0 in (nv, count) :: counts ) compiler [] in match List.sort (fun (_, c1) (_, c2) -> compare c1 c2) counts with | (nv, _) :: _ -> let versions = OpamPackage.packages_of_name available_packages nv.name in let n = OpamPackage.Set.cardinal versions in if n <= 1 then OpamFormula.Atom (nv.name, Empty) else if nv = OpamPackage.Set.max_elt versions then OpamFormula.Atom (nv.name, Atom (`Geq, nv.version)) else OpamFormula.Atom (nv.name, Atom (`Eq, nv.version)) | [] -> OpamFormula.Empty let infer_switch_invariant st = let compiler_packages = if OpamPackage.Set.is_empty st.compiler_packages then OpamPackage.Set.filter (fun nv -> OpamFile.OPAM.has_flag Pkgflag_Compiler (OpamPackage.Map.find nv st.opams)) st.installed else st.compiler_packages in let lazy available_packages = st.available_packages in infer_switch_invariant_raw st.switch_global st.switch st.switch_config st.opams st.packages compiler_packages st.installed_roots available_packages let depexts_raw ~env nv opams = try let opam = OpamPackage.Map.find nv opams in List.fold_left (fun depexts (names, filter) -> if OpamFilter.eval_to_bool ~default:false env filter then OpamSysPkg.Set.Op.(names ++ depexts) else depexts) OpamSysPkg.Set.empty (OpamFile.OPAM.depexts opam) with Not_found -> OpamSysPkg.Set.empty module Installed_cache = OpamCached.Make(struct type t = OpamFile.OPAM.t OpamPackage.Map.t let name = "installed" end) let depexts_status_of_packages_raw ~depexts global_config switch_config packages = let open OpamSysPkg.Set.Op in let syspkg_set, syspkg_map = OpamPackage.Set.fold (fun nv (set, map) -> let s = depexts nv in s ++ set, if OpamSysPkg.Set.is_empty s then map else OpamPackage.Map.add nv s map) packages (OpamSysPkg.Set.empty, OpamPackage.Map.empty) in let chronos = OpamConsole.timer () in let bypass = OpamFile.Config.depext_bypass global_config ++ switch_config.OpamFile.Switch_config.depext_bypass in let syspkg_set = syspkg_set -- bypass in let ret = match OpamSysInteract.packages_status syspkg_set with | avail, not_found -> let avail, not_found = if OpamStateConfig.(!r.no_depexts) then (* Mark all as available. This is necessary to store the exceptions afterwards *) avail ++ not_found, OpamSysPkg.Set.empty else if OpamFile.Config.depext_cannot_install global_config then OpamSysPkg.Set.empty, avail ++ not_found else avail, not_found in OpamPackage.Map.map (fun set -> { OpamSysPkg.s_available = set %% avail; OpamSysPkg.s_not_found = set %% not_found} ) syspkg_map | exception (Failure msg) -> OpamConsole.note "%s\nYou can disable this check using 'opam \ option --global depext=false'" msg; OpamPackage.Map.empty in log "depexts loaded in %.3fs" (chronos()); ret let depexts_unavailable_raw sys_packages nv = match OpamPackage.Map.find_opt nv sys_packages with | Some { OpamSysPkg.s_not_found; _} when not (OpamSysPkg.Set.is_empty s_not_found) -> Some s_not_found | _ -> None let load lock_kind gt rt switch = let chrono = OpamConsole.timer () in log "LOAD-SWITCH-STATE %@ %a" (slog OpamSwitch.to_string) switch; if not (OpamGlobalState.switch_exists gt switch) then (log "The switch %a does not appear to be installed according to %a" (slog OpamSwitch.to_string) switch (slog @@ OpamFile.to_string @* OpamPath.config) gt.root; OpamConsole.error_and_exit (if OpamStateConfig.(!r.switch_from = `Command_line) then `Bad_arguments else `Configuration_error) "The selected switch %s is not installed.%s" (OpamSwitch.to_string switch) @@ match OpamStateConfig.(!r.switch_from) with | `Command_line -> "" | `Default -> " Please choose a different one using 'opam switch ', or use the \ '--switch ' flag." | `Env -> " Please fix the value of the OPAMSWITCH environment variable, or use \ the '--switch ' flag") else let gt = OpamGlobalState.fix_switch_list gt in let lock = OpamFilename.flock lock_kind (OpamPath.Switch.lock gt.root switch) in let switch_config = load_switch_config ~lock_kind gt switch in if OpamStateConfig.is_newer_than_self gt then log "root version (%s) is greater than running binary's (%s); \ load with best-effort (read-only)" (OpamVersion.to_string (OpamFile.Config.opam_root_version gt.config)) (OpamVersion.to_string (OpamFile.Config.root_version)); if OpamVersion.compare switch_config.opam_version OpamFile.Switch_config.oldest_compatible_format_version < 0 then OpamConsole.error_and_exit `Configuration_error "Could not load opam switch %s: it reports version %s while >= %s was \ expected" (OpamSwitch.to_string switch) (OpamVersion.to_string (switch_config.opam_version)) (OpamVersion.to_string OpamFile.Switch_config.oldest_compatible_format_version); let { sel_installed = installed; sel_roots = installed_roots; sel_pinned = pinned; sel_compiler = compiler_packages; } = load_selections ~lock_kind gt switch in let pinned, pinned_opams = OpamPackage.Set.fold (fun nv (pinned,opams) -> let overlay_dir = OpamPath.Switch.Overlay.package gt.root switch nv.name in match OpamFileTools.read_opam overlay_dir with | None -> (* No overlay => just pinned to a version *) OpamPackage.Set.add nv pinned, opams | Some o -> let version = match OpamFile.OPAM.version_opt o with | Some v when v <> nv.version -> log "warn: %s has conflicting pinning versions between \ switch-state (%s) and overlay (%s). Using %s." (OpamPackage.Name.to_string nv.name) (OpamPackage.Version.to_string nv.version) (OpamPackage.Version.to_string v) (OpamPackage.Version.to_string v); v | _ -> nv.version in let nv = OpamPackage.create nv.name version in let o = OpamFile.OPAM.with_version version o in OpamPackage.Set.add nv pinned, OpamPackage.Map.add nv o opams ) pinned (OpamPackage.Set.empty, OpamPackage.Map.empty) in let installed_opams = let cache_file = OpamPath.Switch.installed_opams_cache gt.root switch in match Installed_cache.load cache_file with | Some opams -> OpamPackage.Map.mapi (fun nv opam -> let metadata_dir = OpamPath.Switch.installed_opam gt.root switch nv |> OpamFile.filename |> OpamFilename.dirname |> OpamFilename.Dir.to_string in OpamFile.OPAM.with_metadata_dir (Some (None, metadata_dir)) opam) opams | None -> let opams = OpamPackage.Set.fold (fun nv opams -> OpamStd.Option.Op.( (OpamFile.OPAM.read_opt (OpamPath.Switch.installed_opam gt.root switch nv) >>| fun opam -> OpamPackage.Map.add nv opam opams) +! opams)) installed OpamPackage.Map.empty in Installed_cache.save cache_file opams; opams in let repos_package_index = OpamRepositoryState.build_index rt (repos_list_raw rt switch_config) in let opams = OpamPackage.Map.union (fun _ x -> x) repos_package_index pinned_opams in let available_packages = lazy (compute_available_and_pinned_packages gt switch switch_config ~pinned ~opams) in let opams = (* Keep definitions of installed packages, but lowest priority, and after computing availability *) OpamPackage.Map.union (fun _ x -> x) installed_opams opams in let packages = OpamPackage.keys opams in let installed_without_def = OpamPackage.Set.fold (fun nv nodef -> if OpamPackage.Map.mem nv installed_opams then nodef else try let o = OpamPackage.Map.find nv opams in if lock_kind = `Lock_write then (* auto-repair *) (log "Definition missing for installed package %s, \ copying from repo" (OpamPackage.to_string nv); OpamFile.OPAM.write (OpamPath.Switch.installed_opam gt.root switch nv) o); nodef with Not_found -> OpamPackage.Set.add nv nodef) installed OpamPackage.Set.empty in if not (OpamPackage.Set.is_empty installed_without_def) then OpamConsole.error "No definition found for the following installed packages: %s\n\ This switch may need to be reinstalled" (OpamPackage.Set.to_string installed_without_def); let changed = lazy ( (* Note: This doesn't detect changed _dev_ packages, since it's based on the metadata or the archive hash changing and they don't have an archive hash. Therefore, dev package update needs to add to the reinstall file *) let changed = OpamPackage.Map.merge (fun _ opam_new opam_installed -> match opam_new, opam_installed with | Some r, Some i when not (OpamFile.OPAM.effectively_equal i r) -> Some () | _ -> None) opams installed_opams |> OpamPackage.keys in log "Detected changed packages (marked for reinstall): %a" (slog OpamPackage.Set.to_string) changed; changed ) in (* Detect and initialise missing switch description *) let switch_config = if switch_config <> OpamFile.Switch_config.empty && switch_config.synopsis = "" then let synopsis = match OpamPackage.Set.elements (compiler_packages %% installed_roots) with | [] -> OpamSwitch.to_string switch | [nv] -> let open OpamStd.Option.Op in (OpamPackage.Map.find_opt nv opams >>= OpamFile.OPAM.synopsis) +! OpamPackage.to_string nv | pkgs -> OpamStd.List.concat_map " " OpamPackage.to_string pkgs in let conf = { switch_config with synopsis } in if lock_kind = `Lock_write then (* auto-repair *) OpamFile.Switch_config.write (OpamPath.Switch.switch_config gt.root switch) conf; conf else switch_config in let switch_config, switch_invariant = match switch_config.invariant with | Some invariant -> switch_config, invariant | None -> let available_packages = let lazy (available_packages, pinned) = available_packages in OpamPackage.Set.union available_packages @@ filter_available_packages gt switch switch_config ~opams:pinned in let invariant = infer_switch_invariant_raw gt switch switch_config opams packages compiler_packages installed_roots available_packages in log "Inferred invariant: from base packages %a, (roots %a) => %a" (slog OpamPackage.Set.to_string) compiler_packages (slog @@ fun () -> OpamPackage.Set.to_string (compiler_packages %% installed_roots)) () (slog OpamFileTools.dep_formula_to_string) invariant; let min_opam_version = OpamVersion.of_string "2.0" in let opam_version = if OpamVersion.compare switch_config.opam_version min_opam_version < 0 then min_opam_version else switch_config.opam_version in let switch_config = {switch_config with invariant = Some invariant; opam_version} in if lock_kind = `Lock_write then OpamFile.Switch_config.write (OpamPath.Switch.switch_config gt.root switch) switch_config; switch_config, invariant in let conf_files = let conf_files = OpamFilename.files (OpamPath.Switch.config_dir gt.root switch) in List.fold_left (fun acc f -> if OpamFilename.check_suffix f ".config" then match OpamPackage.Name.of_string OpamFilename.(Base.to_string (basename (chop_extension f))) with | name when OpamPackage.has_name installed name -> OpamPackage.Name.Map.add name (OpamFile.Dot_config.safe_read (OpamPath.Switch.config gt.root switch name)) acc | exception (Failure _) -> acc | _ -> acc else acc) OpamPackage.Name.Map.empty conf_files in let ext_files_changed = lazy ( OpamPackage.Name.Map.fold (fun name conf acc -> let nv = OpamPackage.package_of_name installed name in if List.exists (fun (file, hash) -> let exists = OpamFilename.exists file in let should_exist = let count_not_zero c = function '0' -> c | _ -> succ c in OpamStd.String.fold_left count_not_zero 0 (OpamHash.contents hash) <> 0 in let changed = exists <> should_exist || exists && not (OpamHash.check_file (OpamFilename.to_string file) hash) in if not exists && should_exist then OpamConsole.warning "System file %s, which package %s depends upon, no longer \ exists.\n\ The package will need to either be removed, or reinstalled. \ You may need to restore its system dependencies for the \ latter." (OpamFilename.to_string file) (OpamPackage.to_string nv) else if changed then OpamConsole.warning "File %s, which package %s depends upon, was changed on your \ system.\n\ The package will need to be reinstalled." (OpamFilename.to_string file) (OpamPackage.to_string nv); changed) (OpamFile.Dot_config.file_depends conf) then OpamPackage.Set.add nv acc else acc) conf_files OpamPackage.Set.empty ) in (* depext check *) let available_packages = OpamCompat.Lazy.map fst available_packages in let sys_packages = if not (OpamFile.Config.depext gt.config) || OpamStateConfig.(!r.no_depexts) then lazy OpamPackage.Map.empty else lazy ( depexts_status_of_packages_raw gt.config switch_config (Lazy.force available_packages) ~depexts:(fun package -> let env = OpamPackageVar.resolve_switch_raw ~package gt switch switch_config in depexts_raw ~env package opams) ) in let available_packages = if not (OpamFile.Config.depext gt.config) then available_packages else lazy ( let sys_packages = Lazy.force sys_packages in OpamPackage.Set.filter (fun nv -> depexts_unavailable_raw sys_packages nv = None) (Lazy.force available_packages) ) in let sys_packages_changed = lazy ( let sys_packages = OpamPackage.Map.filter (fun pkg spkg -> OpamPackage.Set.mem pkg installed && not (OpamSysPkg.Set.is_empty spkg.OpamSysPkg.s_available && OpamSysPkg.Set.is_empty spkg.OpamSysPkg.s_not_found)) (Lazy.force sys_packages) in if OpamPackage.Map.is_empty sys_packages then OpamPackage.Set.empty else let lchanged = OpamPackage.Map.keys sys_packages in let changed = OpamPackage.Set.of_list lchanged in let sgl_pkg = OpamPackage.Set.is_singleton changed in let open OpamSysPkg.Set.Op in let missing_map = OpamPackage.Map.map (fun sys -> sys.OpamSysPkg.s_available ++ sys.OpamSysPkg.s_not_found) sys_packages in let missing_set = OpamPackage.Map.fold (fun _ -> OpamSysPkg.Set.union) missing_map OpamSysPkg.Set.empty in let sgl_spkg = OpamSysPkg.Set.is_singleton missing_set in if sgl_pkg then OpamConsole.warning "Opam package %s depends on the following system package%s that can \ no longer be found: %s" (OpamPackage.to_string (OpamPackage.Set.choose_one changed)) (if sgl_spkg then "" else "s") (OpamStd.List.concat_map " " OpamSysPkg.to_string (OpamSysPkg.Set.elements missing_set)) else (OpamConsole.warning "Opam packages %s depend on the following system package%s that are \ no longer installed: %s" (OpamStd.Format.pretty_list (List.map OpamPackage.to_string lchanged)) (if sgl_spkg then "" else "s") (OpamStd.List.concat_map " " OpamSysPkg.to_string (OpamSysPkg.Set.elements missing_set)); if OpamConsole.verbose () then OpamConsole.errmsg "%s" (OpamStd.Format.itemize (fun (pkg, spkg) -> Printf.sprintf "%s: depends on %s" (OpamPackage.to_string pkg) (OpamStd.List.concat_map ", " OpamSysPkg.to_string (OpamSysPkg.Set.elements spkg))) (OpamPackage.Map.bindings missing_map))); changed ) in let reinstall = lazy ( OpamFile.PkgList.safe_read (OpamPath.Switch.reinstall gt.root switch) ++ Lazy.force changed ++ (Lazy.force ext_files_changed %% Lazy.force available_packages) ++ Lazy.force sys_packages_changed ) in let invalidated = lazy ( Lazy.force ext_files_changed ++ Lazy.force sys_packages_changed -- Lazy.force available_packages ) in let st = { switch_global = (gt :> unlocked global_state); switch_repos = (rt :> unlocked repos_state); switch_lock = lock; switch; switch_invariant; compiler_packages; switch_config; repos_package_index; installed_opams; installed; pinned; installed_roots; opams; conf_files; packages; available_packages; sys_packages; reinstall; invalidated; } in log "Switch state loaded in %.3fs" (chrono ()); st let load_virtual ?repos_list ?(avail_default=true) gt rt = let repos_list = match repos_list with | Some rl -> rl | None -> OpamGlobalState.repos_list gt in let opams = OpamRepositoryState.build_index rt repos_list in let packages = OpamPackage.keys opams in let available_packages = lazy ( OpamPackage.Map.filter (fun _ opam -> OpamFilter.eval_to_bool ~default:avail_default (OpamPackageVar.resolve_global gt) (OpamFile.OPAM.available opam)) opams |> OpamPackage.keys ) in { switch_global = (gt :> unlocked global_state); switch_repos = (rt :> unlocked repos_state); switch_lock = OpamSystem.lock_none; switch = OpamSwitch.unset; switch_invariant = OpamFormula.Empty; compiler_packages = OpamPackage.Set.empty; switch_config = { OpamFile.Switch_config.empty with OpamFile.Switch_config.repos = Some repos_list; }; installed = OpamPackage.Set.empty; installed_opams = OpamPackage.Map.empty; pinned = OpamPackage.Set.empty; installed_roots = OpamPackage.Set.empty; repos_package_index = opams; opams; conf_files = OpamPackage.Name.Map.empty; packages; sys_packages = lazy OpamPackage.Map.empty; available_packages; reinstall = lazy OpamPackage.Set.empty; invalidated = lazy (OpamPackage.Set.empty); } let selections st = { sel_installed = st.installed; sel_roots = st.installed_roots; sel_compiler = st.compiler_packages; sel_pinned = st.pinned; } let unlock st = OpamSystem.funlock st.switch_lock; (st :> unlocked switch_state) let drop st = let _ = unlock st in () let with_write_lock ?dontblock st f = if OpamStateConfig.is_newer_than_self st.switch_global then OpamConsole.error_and_exit `Locked "The opam root has been upgraded by a newer version of opam-state \ and cannot be written to"; let ret, st = OpamFilename.with_flock_upgrade `Lock_write ?dontblock st.switch_lock @@ fun _ -> f ({ st with switch_lock = st.switch_lock } : rw switch_state) (* We don't actually change the field value, but this makes restricting the phantom lock type possible*) in ret, { st with switch_lock = st.switch_lock } let opam st nv = OpamPackage.Map.find nv st.opams let opam_opt st nv = try Some (opam st nv) with Not_found -> None let descr_opt st nv = OpamStd.Option.Op.(opam_opt st nv >>= OpamFile.OPAM.descr) let descr st nv = OpamStd.Option.Op.(descr_opt st nv +! OpamFile.Descr.empty) let url st nv = OpamStd.Option.Op.(opam_opt st nv >>= OpamFile.OPAM.url) let primary_url st nv = OpamStd.Option.Op.(url st nv >>| OpamFile.URL.url) let primary_url_with_subpath st nv = match url st nv with | None -> None | Some urlf -> let url = OpamFile.URL.url urlf in match OpamFile.URL.subpath urlf with | None -> Some url | Some subpath -> Some (OpamUrl.Op.(url / subpath)) let files st nv = match opam_opt st nv with | None -> [] | Some opam -> List.map (fun (file,_base,_hash) -> file) (OpamFile.OPAM.get_extra_files ~repos_roots:(OpamRepositoryState.get_root st.switch_repos) opam) let package_config st name = OpamPackage.Name.Map.find name st.conf_files let is_name_installed st name = OpamPackage.has_name st.installed name let find_installed_package_by_name st name = OpamPackage.package_of_name st.installed name let packages_of_atoms st atoms = OpamFormula.packages_of_atoms st.packages atoms let get_package st name = try OpamPinned.package st name with Not_found -> try find_installed_package_by_name st name with Not_found -> try OpamPackage.max_version (Lazy.force st.available_packages) name with Not_found -> OpamPackage.max_version st.packages name let is_dev_package st nv = let opam_opt = if OpamPackage.Set.mem nv st.pinned then opam_opt st nv else OpamPackage.Map.find_opt nv st.repos_package_index in match opam_opt with | Some opam -> OpamPackageVar.is_dev_package st opam | None -> false let is_pinned st name = OpamPackage.has_name st.pinned name let is_version_pinned st name = match OpamPackage.package_of_name_opt st.pinned name with | None -> false | Some nv -> match opam_opt st nv with | Some opam -> OpamPackage.Map.find_opt nv st.repos_package_index = Some opam | None -> false let source_dir st nv = if OpamPackage.Set.mem nv st.pinned then OpamPath.Switch.pinned_package st.switch_global.root st.switch nv.name else OpamPath.Switch.sources st.switch_global.root st.switch nv let depexts st nv = let env v = OpamPackageVar.resolve_switch ~package:nv st v in depexts_raw ~env nv st.opams let depexts_status_of_packages st set = depexts_status_of_packages_raw st.switch_global.config st.switch_config set ~depexts:(depexts st) let depexts_unavailable st nv = depexts_unavailable_raw (Lazy.force st.sys_packages) nv let dev_packages st = OpamPackage.Set.filter (is_dev_package st) (st.installed ++ OpamPinned.packages st) let conflicts_with st subset = let forward_conflicts, conflict_classes = OpamPackage.Set.fold (fun nv (cf,cfc) -> try let opam = OpamPackage.Map.find nv st.opams in let conflicts = OpamFilter.filter_formula ~default:false (OpamPackageVar.resolve_switch ~package:nv st) (OpamFile.OPAM.conflicts opam) in OpamFormula.ors [cf; conflicts], List.fold_right OpamPackage.Name.Set.add (OpamFile.OPAM.conflict_class opam) cfc with Not_found -> cf, cfc) subset (OpamFormula.Empty, OpamPackage.Name.Set.empty) in OpamPackage.Set.filter (fun nv -> not (OpamPackage.has_name subset nv.name) && (OpamFormula.verifies forward_conflicts nv || try let opam = OpamPackage.Map.find nv st.opams in List.exists (fun cl -> OpamPackage.Name.Set.mem cl conflict_classes) (OpamFile.OPAM.conflict_class opam) || let backwards_conflicts = OpamFilter.filter_formula ~default:false (OpamPackageVar.resolve_switch ~package:nv st) (OpamFile.OPAM.conflicts opam) in OpamPackage.Set.exists (OpamFormula.verifies backwards_conflicts) subset with Not_found -> false)) let remove_conflicts st subset pkgs = pkgs -- conflicts_with st subset pkgs let get_conflicts_t env packages opams_map = let conflict_classes = OpamPackage.Map.fold (fun nv opam acc -> List.fold_left (fun acc cc -> OpamPackage.Name.Map.update cc (OpamPackage.Set.add nv) OpamPackage.Set.empty acc) acc (OpamFile.OPAM.conflict_class opam)) opams_map OpamPackage.Name.Map.empty in let conflict_class_formulas = OpamPackage.Name.Map.map (fun pkgs -> OpamPackage.to_map pkgs |> OpamPackage.Name.Map.mapi (fun name versions -> let all_versions = OpamPackage.versions_of_name packages name in if OpamPackage.Version.Set.equal versions all_versions then Empty else (* OpamFormula.simplify_version_set all_versions (*a possible optimisation?*) *) (OpamFormula.ors (List.map (fun v -> Atom (`Eq, v)) (OpamPackage.Version.Set.elements versions))))) conflict_classes in OpamPackage.Map.fold (fun nv opam acc -> let conflicts = OpamFilter.filter_formula ~default:false (env nv) (OpamFile.OPAM.conflicts opam) in let conflicts = List.fold_left (fun acc cl -> let cmap = OpamPackage.Name.Map.find cl conflict_class_formulas |> OpamPackage.Name.Map.remove nv.name in OpamPackage.Name.Map.fold (fun name vformula acc -> OpamFormula.ors [acc; Atom (name, vformula)]) cmap acc) conflicts (OpamFile.OPAM.conflict_class opam) in OpamPackage.Map.add nv conflicts acc) opams_map OpamPackage.Map.empty let get_conflicts st packages opams_map = get_conflicts_t (fun package -> OpamPackageVar.resolve_switch ~package st) packages opams_map let can_upgrade_to_avoid_version name st = OpamPackage.Set.exists (fun pkg -> OpamPackage.Name.equal (OpamPackage.name pkg) name && OpamFile.OPAM.has_flag Pkgflag_AvoidVersion (OpamPackage.Map.find pkg st.opams) ) st.installed let universe st ?(test=OpamStateConfig.(!r.build_test)) ?(doc=OpamStateConfig.(!r.build_doc)) ?(force_dev_deps=false) ?reinstall ~requested user_action = let requested_allpkgs = OpamPackage.packages_of_names st.packages requested in let env nv v = if List.mem v OpamPackageVar.predefined_depends_variables then match OpamVariable.Full.to_string v with | "dev" -> Some (B (force_dev_deps || is_dev_package st nv)) | "with-test" -> Some (B (test && OpamPackage.Set.mem nv requested_allpkgs)) | "with-doc" -> Some (B (doc && OpamPackage.Set.mem nv requested_allpkgs)) | _ -> None (* Computation delayed to the solver *) else let r = OpamPackageVar.resolve_switch ~package:nv st v in if r = None then (if OpamFormatConfig.(!r.strict) then OpamConsole.error_and_exit `File_error "undefined filter variable in dependencies of %s: %s" else log "ERR: undefined filter variable in dependencies of %s: %s") (OpamPackage.to_string nv) (OpamVariable.Full.to_string v); r in let get_deps f opams = OpamPackage.Map.mapi (fun nv opam -> OpamFilter.partial_filter_formula (env nv) (f opam) ) opams in let u_depends = let depend = let ignored = OpamStateConfig.(!r.ignore_constraints_on) in if OpamPackage.Name.Set.is_empty ignored then OpamFile.OPAM.depends else fun opam -> OpamFormula.map (fun (name, cstr as atom) -> if OpamPackage.Name.Set.mem name ignored then let cstr = OpamFormula.map (function Constraint _ -> Empty | Filter _ as f -> Atom f) cstr in Atom (name, cstr) else Atom atom) (OpamFile.OPAM.depends opam) in get_deps depend st.opams in let u_depopts = get_deps OpamFile.OPAM.depopts st.opams in let u_conflicts = get_conflicts st st.packages st.opams in let base = st.compiler_packages in let u_invariant = if OpamStateConfig.(!r.unlock_base) then OpamFormula.Empty else st.switch_invariant in let u_available = (* TODO: removing what conflicts with the base is no longer correct now that we use invariants instead. Removing what conflicts with the invariant would be much more involved, but some solvers might struggle without any cleanup at this point *) (* remove_conflicts st base *) (Lazy.force st.available_packages) in let u_reinstall = (* Ignore reinstalls outside of the dependency cone of [requested_allpkgs] *) let resolve_deps nv = OpamPackageVar.filter_depends_formula ~build:true ~post:true ~default:true ~env:(env nv) (OpamFormula.ands [ OpamPackage.Map.find nv u_depends; OpamPackage.Map.find nv u_depopts ]) |> OpamFormula.packages st.packages in let requested_deps = OpamPackage.Set.fixpoint resolve_deps requested_allpkgs in requested_deps %% Lazy.force st.reinstall ++ match reinstall with | Some set -> set | None -> OpamPackage.Set.empty in let missing_depexts = OpamPackage.Map.fold (fun nv status acc -> if OpamSysPkg.Set.is_empty status.OpamSysPkg.s_available then acc else OpamPackage.Set.add nv acc) (Lazy.force st.sys_packages) OpamPackage.Set.empty in let avoid_versions = OpamPackage.Map.fold (fun nv opam acc -> if OpamFile.OPAM.has_flag Pkgflag_AvoidVersion opam && not (can_upgrade_to_avoid_version (OpamFile.OPAM.name opam) st) then OpamPackage.Set.add nv acc else acc) st.opams OpamPackage.Set.empty in let u = { u_packages = st.packages; u_action = user_action; u_installed = st.installed; u_available; u_depends; u_depopts; u_conflicts; u_installed_roots = st.installed_roots; u_pinned = OpamPinned.packages st; u_base = base; u_invariant; u_reinstall; u_attrs = ["opam-query", requested_allpkgs; "missing-depexts", missing_depexts; "avoid-version", avoid_versions]; } in u let dump_pef_state st oc = let conflicts = get_conflicts st st.packages st.opams in let print_def nv opam = Printf.fprintf oc "package: %s\n" (OpamPackage.name_to_string nv); Printf.fprintf oc "version: %s\n" (OpamPackage.version_to_string nv); let installed = OpamPackage.Set.mem nv st.installed in (* let root = OpamPackage.Set.mem nv st.installed_roots in *) let base = OpamPackage.Set.mem nv st.compiler_packages in let pinned = OpamPackage.Set.mem nv st.pinned in let available = OpamPackage.Set.mem nv (Lazy.force st.available_packages) in let reinstall = OpamPackage.Set.mem nv (Lazy.force st.reinstall) in let dev = OpamPackageVar.is_dev_package st opam in (* current state *) Printf.fprintf oc "available: %b\n" available; if installed then output_string oc "installed: true\n"; if pinned then output_string oc "pinned: true\n"; if base then output_string oc "base: true\n"; if reinstall then output_string oc "reinstall: true\n"; (* metadata (resolved for the current switch) *) OpamStd.List.concat_map ~left:"maintainer: " ~right:"\n" ~nil:"" " , " String.escaped (OpamFile.OPAM.maintainer opam) |> output_string oc; OpamFile.OPAM.depends opam |> OpamPackageVar.filter_depends_formula ~default:false ~dev ~env:(OpamPackageVar.resolve_switch ~package:nv st) |> OpamFormula.to_cnf |> OpamStd.List.concat_map ~left:"depends: " ~right:"\n" ~nil:"" " , " (OpamStd.List.concat_map " | " OpamFormula.string_of_atom) |> output_string oc; OpamFile.OPAM.depopts opam |> OpamPackageVar.filter_depends_formula ~default:false ~dev ~env:(OpamPackageVar.resolve_switch ~package:nv st) |> OpamFormula.to_cnf |> OpamStd.List.concat_map ~left:"recommends: " ~right:"\n" ~nil:"" " , " (OpamStd.List.concat_map " | " OpamFormula.string_of_atom) |> output_string oc; OpamFormula.ors [Atom (nv.name, Empty); OpamPackage.Map.find nv conflicts] |> OpamFormula.set_to_disjunction st.packages |> OpamStd.List.concat_map ~left:"conflicts: " ~right:"\n" ~nil:"" " , " OpamFormula.string_of_atom |> output_string oc; output_string oc "\n"; in OpamPackage.Map.iter print_def st.opams (* User-directed helpers *) let is_switch_globally_set st = OpamFile.Config.switch st.switch_global.config = Some st.switch let not_found_message st (name, cstr) = match cstr with | Some (relop,v) when OpamPackage.has_name st.packages name -> Printf.sprintf "Package %s has no version %s%s." (OpamPackage.Name.to_string name) (match relop with `Eq -> "" | r -> OpamPrinter.FullPos.relop_kind r) (OpamPackage.Version.to_string v) | _ -> Printf.sprintf "No package named %s found." (OpamPackage.Name.to_string name) (* Display a meaningful error for an unavailable package *) let unavailable_reason_raw st (name, vformula) = let candidates = OpamPackage.packages_of_name st.packages name in let candidates = OpamPackage.Set.filter (fun nv -> OpamFormula.check_version_formula vformula nv.version) candidates in if OpamPackage.Set.is_empty candidates then (if OpamPackage.has_name st.packages name then `UnknownVersion else `UnknownPackage) else let nv = try OpamPinned.package st name with Not_found -> match vformula with | Atom (_, v) when OpamPackage.Set.mem (OpamPackage.create name v) candidates -> OpamPackage.create name v | _ -> OpamPackage.max_version candidates name in match opam_opt st nv with | None -> `NoDefinition | Some opam -> let avail = OpamFile.OPAM.available opam in if not (OpamPackage.Set.mem nv candidates) then `Pinned nv else if not (OpamFilter.eval_to_bool ~default:false (OpamPackageVar.resolve_switch ~package:nv st) avail) then `Unavailable (Printf.sprintf "%s'%s'" (if OpamPackage.Set.cardinal candidates = 1 then ": " else ", e.g. ") (OpamFilter.to_string avail)) else if OpamPackage.has_name (Lazy.force st.available_packages -- remove_conflicts st st.compiler_packages (Lazy.force st.available_packages)) name then `ConflictsBase else if OpamPackage.has_name st.compiler_packages name && not OpamStateConfig.(!r.unlock_base) then `ConflictsInvariant (OpamFileTools.dep_formula_to_string st.switch_invariant) else match depexts_unavailable st (OpamPackage.Set.max_elt candidates) with | Some missing -> let missing = List.rev_map OpamSysPkg.to_string (OpamSysPkg.Set.elements missing) in `MissingDepexts missing | None -> `Default (* Display a meaningful error for an unavailable package *) let unavailable_reason st ?(default="") atom = match unavailable_reason_raw st atom with | `UnknownVersion -> "no matching version" | `UnknownPackage -> "unknown package" | `NoDefinition -> "no package definition found" | `Pinned nv -> Printf.sprintf "not available because the package is pinned to version %s" (OpamPackage.version_to_string nv) | `Unavailable msg -> Printf.sprintf "unmet availability conditions%s" msg | `ConflictsBase -> "conflict with the base packages of this switch" | `ConflictsInvariant invariant -> Printf.sprintf "incompatible with the switch invariant %s (use `--update-invariant' \ to force)" (OpamConsole.colorise `bold invariant) | `MissingDepexts missing -> let msg = match missing with | [pkg] -> " '" ^ pkg ^ "'" | pkgs -> "s " ^ (OpamStd.Format.pretty_list (List.rev_map (Printf.sprintf "'%s'") pkgs)) in Printf.sprintf "depends on the unavailable system package%s. Use \ `--no-depexts' to attempt installation anyway, or it is \ possible that a depext package name in the opam file \ is incorrect." msg | `Default -> default let update_package_metadata nv opam st = { st with opams = OpamPackage.Map.add nv opam st.opams; packages = OpamPackage.Set.add nv st.packages; available_packages = lazy ( if OpamFilter.eval_to_bool ~default:false (OpamPackageVar.resolve_switch_raw ~package:nv st.switch_global st.switch st.switch_config) (OpamFile.OPAM.available opam) then OpamPackage.Set.add nv (Lazy.force st.available_packages) else OpamPackage.Set.remove nv (Lazy.force st.available_packages) ); reinstall = lazy (match OpamPackage.Map.find_opt nv st.installed_opams with | Some inst -> if OpamFile.OPAM.effectively_equal inst opam then OpamPackage.Set.remove nv (Lazy.force st.reinstall) else OpamPackage.Set.add nv (Lazy.force st.reinstall) | _ -> Lazy.force st.reinstall); } let remove_package_metadata nv st = { st with opams = OpamPackage.Map.remove nv st.opams; packages = OpamPackage.Set.remove nv st.packages; available_packages = lazy (OpamPackage.Set.remove nv (Lazy.force st.available_packages)); } let update_pin nv opam st = let version = OpamStd.Option.default nv.version (OpamFile.OPAM.version_opt opam) in let nv = OpamPackage.create nv.name version in let pinned = OpamPackage.Set.add nv (OpamPackage.filter_name_out st.pinned nv.name) in let available_packages = lazy ( OpamPackage.filter_name_out (Lazy.force st.available_packages) nv.name ) in let st = update_package_metadata nv opam { st with pinned; available_packages } in if not (OpamFile.Config.depext st.switch_global.config) || OpamSysPkg.Set.is_empty (depexts st nv) then st else let sys_packages = lazy ( OpamPackage.Map.union (fun _ n -> n) (Lazy.force st.sys_packages) (depexts_status_of_packages st (OpamPackage.Set.singleton nv)) ) in let available_packages = lazy ( OpamPackage.Set.filter (fun nv -> depexts_unavailable st nv = None) (Lazy.force st.available_packages) ) in { st with sys_packages; available_packages } let do_backup lock st = match lock with | `Lock_write -> let file = OpamPath.Switch.backup st.switch_global.root st.switch in let previous_selections = selections st in OpamFile.SwitchSelections.write file previous_selections; (function | true -> OpamFilename.remove (OpamFile.filename file) | false -> (* Reload, in order to skip the message if there were no changes *) let new_selections = load_selections ~lock_kind:lock st.switch_global st.switch in if new_selections.sel_installed = previous_selections.sel_installed then OpamFilename.remove (OpamFile.filename file) else OpamConsole.errmsg "%s" (OpamStd.Format.reformat (Printf.sprintf "\nThe former state can be restored with:\n\ \ %s switch import %S\n" Sys.executable_name (OpamFile.to_string file) ^ if OpamPackage.Set.is_empty (new_selections.sel_roots -- new_selections.sel_installed) then "" else Printf.sprintf "Or you can retry to install your package selection with:\n\ \ %s install --restore\n" Sys.executable_name))) | _ -> fun _ -> () let with_ lock ?rt ?(switch=OpamStateConfig.get_switch ()) gt f = (match rt with | Some rt -> fun f -> f (rt :> unlocked repos_state) | None -> OpamRepositoryState.with_ `Lock_none gt) @@ fun rt -> let st = load lock gt rt switch in let cleanup_backup = do_backup lock st in try let r = f st in drop st; cleanup_backup true; r with e -> OpamStd.Exn.finalise e @@ fun () -> drop st; if not OpamCoreConfig.(!r.keep_log_dir) then cleanup_backup false let update_repositories gt update_fun switch = OpamFilename.with_flock `Lock_write (OpamPath.Switch.lock gt.root switch) @@ fun _ -> let conf = load_switch_config ~lock_kind:`Lock_write gt switch in let repos = match conf.OpamFile.Switch_config.repos with | None -> OpamGlobalState.repos_list gt | Some repos -> repos in let conf = { conf with OpamFile.Switch_config.repos = Some (update_fun repos) } in OpamFile.Switch_config.write (OpamPath.Switch.switch_config gt.root switch) conf opam-2.1.5/src/state/opamSpdxList.mli0000644000175000017500000000167114427463453016565 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Implementation generated from the SPDX lists at https://spdx.org/licenses/ See the dune file for instructions. *) (** The sets only contain the short IDs of all the licenses *) val licenses: OpamStd.String.Set.t val exceptions: OpamStd.String.Set.t opam-2.1.5/src/state/opamEnv.ml0000644000175000017500000006643614427463453015404 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamParserTypes open OpamTypes open OpamStateTypes open OpamTypesBase open OpamStd.Op open OpamFilename.Op let log fmt = OpamConsole.log "ENV" fmt let slog = OpamConsole.slog (* - Environment and updates handling - *) let split_var v = OpamStd.Sys.split_path_variable ~clean:false v let join_var l = String.concat (String.make 1 OpamStd.Sys.path_sep) l (* To allow in-place updates, we store intermediate values of path-like as a pair of list [(rl1, l2)] such that the value is [List.rev_append rl1 l2] and the place where the new value should be inserted is in front of [l2] *) let unzip_to elt current = (* If [r = l @ rs] then [remove_prefix l r] is [Some rs], otherwise [None] *) let rec remove_prefix l r = match l, r with | (l::ls, r::rs) when l = r -> remove_prefix ls rs | ([], rs) -> Some rs | _ -> None in match (if elt = "" then [""] else split_var elt) with | [] -> invalid_arg "OpamEnv.unzip_to" | hd::tl -> let rec aux acc = function | [] -> None | x::r -> if (x : string) = hd then match remove_prefix tl r with | Some r -> Some (acc, r) | None -> aux (x::acc) r else aux (x::acc) r in aux [] current let rezip ?insert (l1, l2) = List.rev_append l1 (match insert with None -> l2 | Some i -> i::l2) let rezip_to_string ?insert z = join_var (rezip ?insert z) let apply_op_zip op arg (rl1,l2 as zip) = let colon_eq ?(eqcol=false) = function (* prepend a, but keep ":"s *) | [] | [""] -> [], [arg; ""] | "" :: l -> (* keep surrounding colons *) if eqcol then l@[""], [arg] else l, [""; arg] | l -> l, [arg] in match op with | Eq -> [],[arg] | PlusEq -> [], arg :: rezip zip | EqPlus -> List.rev_append l2 rl1, [arg] | EqPlusEq -> rl1, arg::l2 | ColonEq -> let l, add = colon_eq (rezip zip) in [], add @ l | EqColon -> let l, add = colon_eq ~eqcol:true (List.rev_append l2 rl1) in l, List.rev add (** Undoes previous updates done by opam, useful for not duplicating already done updates; this is obviously not perfect, as all operators are not reversible. [cur_value] is provided as a list split at path_sep. None is returned if the revert doesn't match. Otherwise, a zip (pair of lists [(preceding_elements_reverted, following_elements)]) is returned, to keep the position of the matching element and allow [=+=] to be applied later. A pair or empty lists is returned if the variable should be unset or has an unknown previous value. *) let reverse_env_update op arg cur_value = if arg = "" && op <> Eq then None else match op with | Eq -> if arg = join_var cur_value then Some ([],[]) else None | PlusEq | EqPlusEq -> unzip_to arg cur_value | EqPlus -> (match unzip_to arg (List.rev cur_value) with | None -> None | Some (rl1, l2) -> Some (List.rev l2, List.rev rl1)) | ColonEq -> (match unzip_to arg cur_value with | Some ([], [""]) -> Some ([], []) | r -> r) | EqColon -> (match unzip_to arg (List.rev cur_value) with | Some ([], [""]) -> Some ([], []) | Some (rl1, l2) -> Some (List.rev l2, List.rev rl1) | None -> None) let updates_from_previous_instance = lazy ( match OpamStd.Env.getopt "OPAM_SWITCH_PREFIX" with | None -> None | Some pfx -> let env_file = OpamPath.Switch.env_relative_to_prefix (OpamFilename.Dir.of_string pfx) in try OpamFile.Environment.read_opt env_file with e -> OpamStd.Exn.fatal e; None ) let expand (updates: env_update list) : env = (* Reverse all previous updates, in reverse order, on current environment *) let reverts = match Lazy.force updates_from_previous_instance with | None -> [] | Some updates -> List.fold_right (fun (var, op, arg, _) defs0 -> let v_opt, defs = OpamStd.List.pick_assoc var defs0 in let v = OpamStd.Option.Op.((v_opt >>| rezip >>+ fun () -> OpamStd.Env.getopt var >>| split_var) +! []) in match reverse_env_update op arg v with | Some v -> (var, v)::defs | None -> defs0) updates [] in (* And apply the new ones *) let rec apply_updates reverts acc = function | (var, op, arg, doc) :: updates -> let zip, reverts = let f, var = if Sys.win32 then String.uppercase_ascii, String.uppercase_ascii var else (fun x -> x), var in match OpamStd.List.find_opt (fun (v, _, _) -> f v = var) acc with | Some (_, z, _doc) -> z, reverts | None -> match OpamStd.List.pick_assoc var reverts with | Some z, reverts -> z, reverts | None, _ -> match OpamStd.Env.getopt var with | Some s -> ([], split_var s), reverts | None -> ([], []), reverts in let acc = if arg = "" && op <> Eq then acc else ((var, apply_op_zip op arg zip, doc) :: acc) in apply_updates reverts acc updates | [] -> List.rev @@ List.rev_append (List.rev_map (fun (var, z, doc) -> var, rezip_to_string z, doc) acc) @@ List.rev_map (fun (var, z) -> var, rezip_to_string z, Some "Reverting previous opam update") reverts in apply_updates reverts [] updates let add (env: env) (updates: env_update list) = let env = if Sys.win32 then (* * Environment variable names are case insensitive on Windows *) let updates = List.rev_map (fun (u,_,_,_) -> (String.uppercase_ascii u, "", "", None)) updates in List.filter (fun (k,_,_) -> let k = String.uppercase_ascii k in List.for_all (fun (u,_,_,_) -> u <> k) updates) env else List.filter (fun (k,_,_) -> List.for_all (fun (u,_,_,_) -> u <> k) updates) env in env @ expand updates let env_expansion ?opam st (name, op, str, cmt) = let fenv v = try OpamPackageVar.resolve st ?opam v with Not_found -> log "Undefined variable: %s" (OpamVariable.Full.to_string v); None in let s = OpamFilter.expand_string ~default:(fun _ -> "") fenv str in name, op, s, cmt let compute_updates ?(force_path=false) st = (* Todo: put these back into their packages! let perl5 = OpamPackage.Name.of_string "perl5" in let add_to_perl5lib = OpamPath.Switch.lib t.root t.switch t.switch_config perl5 in let new_perl5lib = "PERL5LIB", "+=", OpamFilename.Dir.to_string add_to_perl5lib in *) let bindir = OpamPath.Switch.bin st.switch_global.root st.switch st.switch_config in let path = "PATH", (if force_path then PlusEq else EqPlusEq), OpamFilename.Dir.to_string bindir, Some ("Binary dir for opam switch "^OpamSwitch.to_string st.switch) in let man_path = let open OpamStd.Sys in match os () with | OpenBSD | NetBSD | FreeBSD | Darwin | DragonFly -> [] (* MANPATH is a global override on those, so disabled for now *) | _ -> ["MANPATH", EqColon, OpamFilename.Dir.to_string (OpamPath.Switch.man_dir st.switch_global.root st.switch st.switch_config), Some "Current opam switch man dir"] in let switch_env = ("OPAM_SWITCH_PREFIX", Eq, OpamFilename.Dir.to_string (OpamPath.Switch.root st.switch_global.root st.switch), Some "Prefix of the current opam switch") :: List.map (env_expansion st) st.switch_config.OpamFile.Switch_config.env in let pkg_env = (* XXX: Does this need a (costly) topological sort? *) OpamPackage.Set.fold (fun nv acc -> match OpamPackage.Map.find_opt nv st.opams with | Some opam -> List.map (env_expansion ~opam st) (OpamFile.OPAM.env opam) @ acc | None -> acc) st.installed [] in switch_env @ pkg_env @ man_path @ [path] let updates_common ~set_opamroot ~set_opamswitch root switch = let root = if set_opamroot then [ "OPAMROOT", Eq, OpamFilename.Dir.to_string root, Some "Opam root in use" ] else [] in let switch = if set_opamswitch then [ "OPAMSWITCH", Eq, OpamSwitch.to_string switch, None ] else [] in root @ switch let updates ~set_opamroot ~set_opamswitch ?force_path st = updates_common ~set_opamroot ~set_opamswitch st.switch_global.root st.switch @ compute_updates ?force_path st let get_pure ?(updates=[]) () = let env = List.map (fun (v,va) -> v,va,None) (OpamStd.Env.list ()) in add env updates let get_opam ~set_opamroot ~set_opamswitch ~force_path st = add [] (updates ~set_opamroot ~set_opamswitch ~force_path st) let get_opam_raw ~set_opamroot ~set_opamswitch ?(base=[]) ~force_path root switch = let env_file = OpamPath.Switch.environment root switch in let upd = OpamFile.Environment.safe_read env_file in let upd = ("OPAM_SWITCH_PREFIX", Eq, OpamFilename.Dir.to_string (OpamPath.Switch.root root switch), Some "Prefix of the current opam switch") :: List.filter (function ("OPAM_SWITCH_PREFIX", Eq, _, _) -> false | _ -> true) upd in let upd = if force_path then List.map (function | "PATH", EqPlusEq, v, doc -> "PATH", PlusEq, v, doc | e -> e) upd else List.map (function | "PATH", PlusEq, v, doc -> "PATH", EqPlusEq, v, doc | e -> e) upd in add base (updates_common ~set_opamroot ~set_opamswitch root switch @ upd) let get_full ~set_opamroot ~set_opamswitch ~force_path ?updates:(u=[]) ?(scrub=[]) st = let env = let env = OpamStd.Env.list () in let map = if Sys.win32 then String.uppercase_ascii else (fun x -> x) in let scrub = List.rev_map map scrub |> OpamStd.String.Set.of_list in List.filter (fun (name, _) -> not (OpamStd.String.Set.mem (map name) scrub)) env in let env0 = List.map (fun (v,va) -> v,va,None) env in let updates = u @ updates ~set_opamroot ~set_opamswitch ~force_path st in add env0 updates let is_up_to_date_raw ?(skip=OpamStateConfig.(!r.no_env_notice)) updates = skip || let not_utd = List.fold_left (fun notutd (var, op, arg, _doc as upd) -> match OpamStd.Env.getopt var with | None -> upd::notutd | Some v -> if reverse_env_update op arg (split_var v) = None then upd::notutd else List.filter (fun (v, _, _, _) -> v <> var) notutd) [] updates in let r = not_utd = [] in if not r then log "Not up-to-date env variables: [%a]" (slog @@ String.concat " " @* List.map (fun (v, _, _, _) -> v)) not_utd else log "Environment is up-to-date"; r let is_up_to_date_switch root switch = let env_file = OpamPath.Switch.environment root switch in try match OpamFile.Environment.read_opt env_file with | Some upd -> is_up_to_date_raw upd | None -> true with e -> OpamStd.Exn.fatal e; true let switch_path_update ~force_path root switch = let bindir = OpamPath.Switch.bin root switch (OpamStateConfig.Switch.safe_load_t ~lock_kind:`Lock_read root switch) in [ "PATH", (if force_path then PlusEq else EqPlusEq), OpamFilename.Dir.to_string bindir, Some "Current opam switch binary dir" ] let path ~force_path root switch = let env = expand (switch_path_update ~force_path root switch) in let (_, path_value, _) = List.find (fun (v, _, _) -> v = "PATH") env in path_value let full_with_path ~force_path ?(updates=[]) root switch = let env0 = List.map (fun (v,va) -> v,va,None) (OpamStd.Env.list ()) in add env0 (switch_path_update ~force_path root switch @ updates) let is_up_to_date ?skip st = is_up_to_date_raw ?skip (updates ~set_opamroot:false ~set_opamswitch:false ~force_path:false st) (** Returns shell-appropriate statement to evaluate [cmd]. *) let shell_eval_invocation shell cmd = match shell with | SH_fish -> Printf.sprintf "eval (%s)" cmd | SH_csh -> Printf.sprintf "eval `%s`" cmd | _ -> Printf.sprintf "eval $(%s)" cmd (** Returns "opam env" invocation string together with optional root and switch overrides *) let opam_env_invocation ?root ?switch ?(set_opamswitch=false) () = let root = OpamStd.Option.map_default (Printf.sprintf " --root=%s") "" root in let switch = OpamStd.Option.map_default (Printf.sprintf " --switch=%s") "" switch in let setswitch = if set_opamswitch then " --set-switch" else "" in Printf.sprintf "opam env%s%s%s" root switch setswitch let eval_string gt ?(set_opamswitch=false) switch = let root = let opamroot_cur = OpamFilename.Dir.to_string gt.root in let opamroot_env = OpamStd.Option.Op.( OpamStateConfig.E.root () +! OpamFilename.Dir.to_string OpamStateConfig.(default.root_dir) ) in if opamroot_cur <> opamroot_env then Some opamroot_cur else None in let switch = (* Returns the switch only if it is different from the one determined by the environment *) let f sw = let sw_cur = OpamSwitch.to_string sw in let sw_env = OpamStd.Option.Op.( OpamStateConfig.E.switch () ++ (OpamStateConfig.get_current_switch_from_cwd gt.root >>| OpamSwitch.to_string) ++ (OpamFile.Config.switch gt.config >>| OpamSwitch.to_string) ) in if Some sw_cur <> sw_env then Some sw_cur else None in OpamStd.Option.replace f switch in let shell = OpamStd.Sys.guess_shell_compat () in shell_eval_invocation shell (opam_env_invocation ?root ?switch ~set_opamswitch ()) (* -- Shell and init scripts handling -- *) (** The shells for which we generate init scripts (bash and sh are the same entry) *) let shells_list = [ SH_sh; SH_zsh; SH_csh; SH_fish ] let complete_file = function | SH_sh | SH_bash -> Some "complete.sh" | SH_zsh -> Some "complete.zsh" | SH_csh | SH_fish -> None let env_hook_file = function | SH_sh | SH_bash -> Some "env_hook.sh" | SH_zsh -> Some "env_hook.zsh" | SH_csh -> Some "env_hook.csh" | SH_fish -> Some "env_hook.fish" let variables_file = function | SH_sh | SH_bash | SH_zsh -> "variables.sh" | SH_csh -> "variables.csh" | SH_fish -> "variables.fish" let init_file = function | SH_sh | SH_bash -> "init.sh" | SH_zsh -> "init.zsh" | SH_csh -> "init.csh" | SH_fish -> "init.fish" let complete_script = function | SH_sh | SH_bash -> Some OpamScript.complete | SH_zsh -> Some OpamScript.complete_zsh | SH_csh | SH_fish -> None let env_hook_script_base = function | SH_sh | SH_bash -> Some OpamScript.env_hook | SH_zsh -> Some OpamScript.env_hook_zsh | SH_csh -> Some OpamScript.env_hook_csh | SH_fish -> Some OpamScript.env_hook_fish let export_in_shell shell = let make_comment comment_opt = OpamStd.Option.to_string (Printf.sprintf "# %s\n") comment_opt in let sh (k,v,comment) = Printf.sprintf "%s%s=%s; export %s;\n" (make_comment comment) k v k in let csh (k,v,comment) = Printf.sprintf "%sif ( ! ${?%s} ) setenv %s \"\"\nsetenv %s %s\n" (make_comment comment) k k k v in let fish (k,v,comment) = (* Fish converts some colon-separated vars to arrays, which have to be treated differently. MANPATH is handled automatically, so better not to set it at all when not already defined *) let to_arr_string v = OpamStd.List.concat_map " " (fun v -> if v = Printf.sprintf "\"$%s\"" k then "$"^k (* remove quotes *) else v) (OpamStd.String.split v ':') in match k with | "PATH" -> Printf.sprintf "%sset -gx %s %s;\n" (make_comment comment) k (to_arr_string v) | "MANPATH" -> Printf.sprintf "%sif [ (count $%s) -gt 0 ]; set -gx %s %s; end;\n" (make_comment comment) k k (to_arr_string v) | _ -> (* Regular string variables *) Printf.sprintf "%sset -gx %s %s;\n" (make_comment comment) k v in match shell with | SH_zsh | SH_bash | SH_sh -> sh | SH_fish -> fish | SH_csh -> csh let env_hook_script shell = OpamStd.Option.map (fun script -> export_in_shell shell ("OPAMNOENVNOTICE", "true", None) ^ script) (env_hook_script_base shell) let source root shell f = let fname = OpamFilename.to_string (OpamPath.init root // f) in match shell with | SH_csh -> Printf.sprintf "if ( -f %s ) source %s >& /dev/null\n" fname fname | SH_fish -> Printf.sprintf "source %s > /dev/null 2> /dev/null; or true\n" fname | SH_sh | SH_bash -> Printf.sprintf "test -r %s && . %s > /dev/null 2> /dev/null || true\n" fname fname | SH_zsh -> Printf.sprintf "[[ ! -r %s ]] || source %s > /dev/null 2> /dev/null\n" fname fname let if_interactive_script shell t e = let ielse else_opt = match else_opt with | None -> "" | Some e -> Printf.sprintf "else\n %s" e in match shell with | SH_sh| SH_bash -> Printf.sprintf "if [ -t 0 ]; then\n %s%sfi\n" t @@ ielse e | SH_zsh -> Printf.sprintf "if [[ -o interactive ]]; then\n %s%sfi\n" t @@ ielse e | SH_csh -> Printf.sprintf "if ( $?prompt ) then\n %s%sendif\n" t @@ ielse e | SH_fish -> Printf.sprintf "if isatty\n %s%send\n" t @@ ielse e let init_script root shell = let interactive = List.map (source root shell) @@ OpamStd.List.filter_some [complete_file shell; env_hook_file shell] in String.concat "\n" @@ (if interactive <> [] then [if_interactive_script shell (String.concat "\n " interactive) None] else []) @ [source root shell (variables_file shell)] let string_of_update st shell updates = let fenv = OpamPackageVar.resolve st in let aux (ident, symbol, string, comment) = let string = OpamFilter.expand_string ~default:(fun _ -> "") fenv string |> OpamStd.Env.escape_single_quotes ~using_backslashes:(shell = SH_fish) in let key, value = ident, match symbol with | Eq -> Printf.sprintf "'%s'" string | PlusEq | ColonEq | EqPlusEq -> Printf.sprintf "'%s':\"$%s\"" string ident | EqColon | EqPlus -> Printf.sprintf "\"$%s\":'%s'" ident string in export_in_shell shell (key, value, comment) in OpamStd.List.concat_map "" aux updates let write_script dir (name, body) = let file = dir // name in try OpamFilename.write file body with e -> OpamStd.Exn.fatal e; OpamConsole.error "Could not write %s" (OpamFilename.to_string file) let write_init_shell_scripts root = let scripts = List.map (fun shell -> init_file shell, init_script root shell) shells_list in List.iter (write_script (OpamPath.init root)) scripts let write_static_init_scripts root ?completion ?env_hook ?(inplace=false) () = write_init_shell_scripts root; let update_scripts filef scriptf enable = let scripts = OpamStd.List.filter_map (fun shell -> match filef shell, scriptf shell with | Some f, Some s -> Some (f, s) | _ -> None) shells_list in match enable, inplace with | Some true, _ -> List.iter (write_script (OpamPath.init root)) scripts | _, true -> List.iter (fun ((f,_) as fs) -> if OpamFilename.exists (OpamPath.init root // f) then write_script (OpamPath.init root) fs) scripts | Some false, _ -> List.iter (fun (f,_) -> OpamFilename.remove (OpamPath.init root // f)) scripts | None, _ -> () in update_scripts complete_file complete_script completion; update_scripts env_hook_file env_hook_script env_hook let write_custom_init_scripts root custom = let hookdir = OpamPath.hooks_dir root in let kind = `MD5 in List.iter (fun (name, script) -> let script_file = hookdir // name in let hash = OpamHash.compute_from_string ~kind script in let hash_name = name ^ ".hash" in let hash_file = hookdir // hash_name in if not (OpamFilename.exists hash_file) || (let same_hash = OpamHash.of_string_opt (OpamFilename.read hash_file) = Some (OpamHash.compute ~kind (OpamFilename.to_string script_file)) in same_hash || not same_hash && OpamConsole.confirm ~default:false "%s contains local modification, overwrite ?" (OpamFilename.to_string script_file)) then (write_script hookdir (name, script); OpamFilename.chmod script_file 0o777; write_script hookdir (hash_name, OpamHash.to_string hash)) ) custom let write_dynamic_init_scripts st = let updates = updates ~set_opamroot:false ~set_opamswitch:false st in try if OpamStateConfig.is_newer_than_self ~lock_kind:`Lock_write st.switch_global then raise OpamSystem.Locked; OpamFilename.with_flock_upgrade `Lock_write ~dontblock:true st.switch_global.global_lock @@ fun _ -> List.iter (fun shell -> write_script (OpamPath.init st.switch_global.root) (variables_file shell, string_of_update st shell updates)) [SH_sh; SH_csh; SH_fish] with OpamSystem.Locked -> OpamConsole.warning "Global shell init scripts not installed (could not acquire lock)" let clear_dynamic_init_scripts gt = List.iter (fun shell -> OpamFilename.remove (OpamPath.init gt.root // variables_file shell)) [SH_sh; SH_csh; SH_fish] let dot_profile_needs_update root dot_profile = if not (OpamFilename.exists dot_profile) then `yes else let body = OpamFilename.read dot_profile in let pattern1 = "opam config env" in let pattern1b = "opam env" in let pattern2 = OpamFilename.to_string (OpamPath.init root // "init") in let pattern3 = OpamStd.String.remove_prefix ~prefix:(OpamFilename.Dir.to_string root) pattern2 in let uncommented_re patts = Re.(compile (seq [bol; rep (diff any (set "#:")); alt (List.map str patts)])) in if Re.execp (uncommented_re [pattern1; pattern1b; pattern2]) body then `no else if Re.execp (uncommented_re [pattern3]) body then `otherroot else `yes let update_dot_profile root dot_profile shell = let pretty_dot_profile = OpamFilename.prettify dot_profile in let bash_src () = if (shell = SH_bash || shell = SH_sh) && OpamFilename.(Base.to_string (basename dot_profile)) <> ".bashrc" then OpamConsole.note "Make sure that %s is well %s in your ~/.bashrc.\n" pretty_dot_profile (OpamConsole.colorise `underline "sourced") in match dot_profile_needs_update root dot_profile with | `no -> OpamConsole.msg " %s is already up-to-date.\n" pretty_dot_profile; bash_src() | `otherroot -> OpamConsole.msg " %s is already configured for another opam root.\n" pretty_dot_profile | `yes -> let init_file = init_file shell in let body = if OpamFilename.exists dot_profile then OpamFilename.read dot_profile else "" in OpamConsole.msg " Updating %s.\n" pretty_dot_profile; bash_src(); let body = Printf.sprintf "%s\n\n\ # opam configuration\n\ %s" (OpamStd.String.strip body) (source root shell init_file) in OpamFilename.write dot_profile body let update_user_setup root ?dot_profile shell = if dot_profile <> None then ( OpamConsole.msg "\nUser configuration:\n"; OpamStd.Option.iter (fun f -> update_dot_profile root f shell) dot_profile ) let check_and_print_env_warning st = (* if you are trying to silence this warning, set the ~no_env_notice:true flag from OpamStateConfig, which is checked by (is_up_to_date st). *) if not (is_up_to_date st) && (OpamFile.Config.switch st.switch_global.config = Some st.switch || OpamStateConfig.(!r.switch_from <> `Command_line)) then OpamConsole.formatted_msg "# Run %s to update the current shell environment\n" (OpamConsole.colorise `bold (eval_string st.switch_global (Some st.switch))) let setup root ~interactive ?dot_profile ?update_config ?env_hook ?completion ?inplace shell = let update_dot_profile = match update_config, dot_profile, interactive with | Some false, _, _ -> None | _, None, _ -> invalid_arg "OpamEnv.setup" | Some true, Some dot_profile, _ -> Some dot_profile | None, _, false -> None | None, Some dot_profile, true -> OpamConsole.header_msg "Required setup - please read"; OpamConsole.msg "\n\ \ In normal operation, opam only alters files within ~%s.opam.\n\ \n\ \ However, to best integrate with your system, some environment variables\n\ \ should be set. If you allow it to, this initialisation step will update\n\ \ your %s configuration by adding the following line to %s:\n\ \n\ \ %s\ \n\ \ Otherwise, every time you want to access your opam installation, you will\n\ \ need to run:\n\ \n\ \ %s\n\ \n\ \ You can always re-run this setup with 'opam init' later.\n\n" Filename.dir_sep (OpamConsole.colorise `bold @@ string_of_shell shell) (OpamConsole.colorise `cyan @@ OpamFilename.prettify dot_profile) (OpamConsole.colorise `bold @@ source root shell (init_file shell)) (OpamConsole.colorise `bold @@ shell_eval_invocation shell (opam_env_invocation ())); if OpamCoreConfig.answer_is_yes () then begin OpamConsole.warning "Shell not updated in non-interactive mode: use --shell-setup"; None end else match OpamConsole.read "Do you want opam to modify %s? [N/y/f]\n\ (default is 'no', use 'f' to choose a different file)" (OpamFilename.prettify dot_profile) with | Some ("y" | "Y" | "yes" | "YES" ) -> Some dot_profile | Some ("f" | "F" | "file" | "FILE") -> begin match OpamConsole.read " Enter the name of the file to update:" with | None -> OpamConsole.msg "Alright, assuming you changed your mind, not \ performing any changes.\n"; None | Some f -> Some (OpamFilename.of_string f) end | _ -> None in let env_hook = match env_hook, interactive with | Some b, _ -> Some b | None, false -> None | None, true -> (* not just interactive mode *) if update_config <> None || completion <> None then None else Some (OpamConsole.confirm ~default:false "A hook can be added to opam's init scripts to ensure that the \ shell remains in sync with the opam environment when they are \ loaded. Set that up?") in update_user_setup root ?dot_profile:update_dot_profile shell; write_static_init_scripts root ?completion ?env_hook ?inplace () let hook_env root = let hook_vnam = OpamVariable.of_string "hooks" in let hook_vval = Some (OpamVariable.dirname (OpamPath.hooks_dir root)) in OpamVariable.Map.singleton hook_vnam hook_vval opam-2.1.5/src/state/opamSysPoll.ml0000644000175000017500000001310114427463453016236 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2017-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCompat open OpamStd.Option.Op let command_output c = match List.filter (fun s -> String.trim s <> "") (OpamSystem.read_command_output c) with | [""] -> None | [s] -> Some s | _ -> None | exception (OpamSystem.Process_error _ | OpamSystem.Command_not_found _) -> None let norm s = if s = "" then None else Some (String.lowercase_ascii s) let normalise_arch raw = match String.lowercase_ascii raw with | "x86" | "i386" | "i486" | "i586" | "i686" -> "x86_32" | "x86_64" | "amd64" -> "x86_64" | "powerpc" | "ppc" | "ppcle" -> "ppc32" | "ppc64" | "ppc64le" -> "ppc64" | "aarch64_be" | "aarch64" -> "arm64" | a when a = "armv8b" || a = "armv8l" || List.exists (fun prefix -> OpamStd.String.starts_with ~prefix a) ["armv5"; "armv6"; "earmv6"; "armv7"; "earmv7"] -> "arm32" | s -> s let arch_lazy = lazy ( let raw = match Sys.os_type with | "Unix" | "Cygwin" -> OpamStd.Sys.uname "-m" | "Win32" -> if Sys.word_size = 32 && not (OpamStubs.isWoW64 ()) then Some "i686" else Some "x86_64" | _ -> None in match raw with | None | Some "" -> None | Some a -> Some (normalise_arch a) ) let arch () = Lazy.force arch_lazy let normalise_os raw = match String.lowercase_ascii raw with | "darwin" | "osx" -> "macos" | s -> s let os_lazy = lazy ( let raw = match Sys.os_type with | "Unix" -> OpamStd.Sys.uname "-s" | s -> norm s in match raw with | None | Some "" -> None | Some s -> Some (normalise_os s) ) let os () = Lazy.force os_lazy let os_release_field = let os_release_file = lazy ( List.find Sys.file_exists ["/etc/os-release"; "/usr/lib/os-release"] |> OpamProcess.read_lines |> OpamStd.List.filter_map (fun s -> try Scanf.sscanf s "%s@= %s" (fun x v -> let contents = try Scanf.sscanf v "\"%s@\"" (fun s -> s) with Scanf.Scan_failure _ | End_of_file -> v in Some (x, contents)) with Scanf.Scan_failure _ | End_of_file -> None) ) in fun f -> try Some (List.assoc f (Lazy.force os_release_file)) with Not_found -> None let is_android, android_release = let prop = lazy (command_output ["getprop"; "ro.build.version.release"]) in (fun () -> Lazy.force prop <> None), (fun () -> Lazy.force prop) let os_distribution_lazy = lazy ( match os () with | Some "macos" as macos -> if OpamSystem.resolve_command "brew" <> None then Some "homebrew" else if OpamSystem.resolve_command "port" <> None then Some "macports" else macos | Some "linux" as linux -> (if is_android () then Some "android" else os_release_field "ID" >>= norm >>+ fun () -> command_output ["lsb_release"; "-i"; "-s"] >>= norm >>+ fun () -> try List.find Sys.file_exists ["/etc/redhat-release"; "/etc/centos-release"; "/etc/gentoo-release"; "/etc/issue"] |> fun s -> Scanf.sscanf s " %s " norm with Not_found -> linux) | os -> os ) let os_distribution () = Lazy.force os_distribution_lazy let os_version_lazy = lazy ( match os () with | Some "linux" -> android_release () >>= norm >>+ fun () -> command_output ["lsb_release"; "-s"; "-r"] >>= norm >>+ fun () -> os_release_field "VERSION_ID" >>= norm | Some "macos" -> command_output ["sw_vers"; "-productVersion"] >>= norm | Some "win32" -> let (major, minor, build, _) = OpamStubs.getWindowsVersion () in OpamStd.Option.some @@ Printf.sprintf "%d.%d.%d" major minor build | Some "cygwin" -> (try command_output ["cmd"; "/C"; "ver"] >>= fun s -> Scanf.sscanf s "%_s@[ Version %s@]" norm with Scanf.Scan_failure _ | End_of_file -> None) | Some "freebsd" -> OpamStd.Sys.uname "-U" >>= norm | _ -> OpamStd.Sys.uname "-r" >>= norm ) let os_version () = Lazy.force os_version_lazy let os_family_lazy = lazy ( match os () with | Some "linux" -> (os_release_field "ID_LIKE" >>= fun s -> Scanf.sscanf s " %s" norm (* first word *)) >>+ os_distribution | Some ("freebsd" | "openbsd" | "netbsd" | "dragonfly") -> Some "bsd" | Some ("win32" | "cygwin") -> Some "windows" | _ -> os_distribution () ) let os_family () = Lazy.force os_family_lazy let variables = List.map (fun (n, v) -> OpamVariable.of_string n, lazy (Lazy.force v >>| fun v -> OpamTypes.S v)) [ "arch", arch_lazy; "os", os_lazy; "os-distribution", os_distribution_lazy; "os-version", os_version_lazy; "os-family", os_family_lazy; ] let cores_lazy = lazy (OpamSystem.cpu_count ()) let cores () = Lazy.force cores_lazy let to_string () = let open OpamStd.Option.Op in Printf.sprintf "arch=%s os=%s os-distribution=%s os-version=%s" (arch () +! "unknown") (os () +! "unknown") (os_distribution () +! "unknown") (os_version () +! "unknown") opam-2.1.5/src/state/opamSysInteract.ml0000644000175000017500000006403714427463453017117 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019-2020 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) let log fmt = OpamConsole.log "XSYS" fmt (* Run commands *) (* Always call this function to run a command, as it handles `dryrun` option *) let run_command ?vars ?(discard_err=false) ?allow_stdin ?verbose ?(dryrun=false) cmd args = let clean_output = if not discard_err then fun k -> k None else fun k -> OpamFilename.with_tmp_dir_job @@ fun dir -> let f = OpamFilename.Op.(dir // "out") in OpamFilename.touch f; k (Some (OpamFilename.to_string f)) in let verbose = OpamStd.Option.default OpamCoreConfig.(!r.verbose_level >= 3) verbose in let env = match vars with | None -> None | Some vars -> let env = OpamStd.Env.list () in let set_vars, kept_vars, env = List.fold_left (fun (n,p,e) (op, (name, content as var)) -> match OpamStd.List.assoc_opt name env, op with | Some c, `add when String.compare c content = 0 -> n, p, e | Some _, `set -> var::n, p, (List.remove_assoc name env) | Some _, _ -> n, var::p, e | None, _ -> var::n, p, e ) ([],[], env) vars in let str_var (v,c) = Printf.sprintf "%s=%s" v c in if set_vars = [] then ((if kept_vars <> [] then log "Won't override %s" (OpamStd.List.to_string str_var kept_vars)); None) else (log "Adding to env %s" (OpamStd.List.to_string str_var set_vars); Some (set_vars @ env |> List.rev_map str_var |> Array.of_list)) in let run = if dryrun then OpamProcess.Job.dry_run else OpamProcess.Job.run in let open OpamProcess.Job.Op in run @@ clean_output @@ fun stdout -> OpamSystem.make_command ?env ?stdout ?allow_stdin ~verbose cmd args @@> fun r -> let code = r.r_code in let out = r.r_stdout in OpamProcess.cleanup r; Done (code, out) let run_query_command ?vars cmd args = let vars = (`set, ("LC_ALL","C"))::OpamStd.Option.to_list vars in let code,out = run_command ~vars cmd args in if code = 0 then out else [] let run_command_exit_code ?vars ?allow_stdin ?verbose cmd args = let code,_ = run_command ?vars ?allow_stdin ?verbose ~dryrun:OpamStateConfig.(!r.dryrun) cmd args in code (* Please keep this alphabetically ordered, in the type definition, and in below pattern matching *) type families = | Alpine | Arch | Centos | Debian | Freebsd | Gentoo | Homebrew | Macports | Netbsd | Openbsd | Suse (* System status *) let family = let family = lazy ( match OpamSysPoll.os_family () with | None -> Printf.ksprintf failwith "External dependency unusable, OS family not detected." | Some family -> match family with | "alpine" -> Alpine | "amzn" | "centos" | "fedora" | "mageia" | "oraclelinux" | "ol" | "rhel" -> Centos | "archlinux" | "arch" -> Arch | "bsd" -> begin match OpamSysPoll.os_distribution () with | Some ("freebsd" | "dragonfly") -> Freebsd | Some "netbsd" -> Netbsd | Some "openbsd" -> Openbsd | _ -> Printf.ksprintf failwith "External dependency handling not supported for OS family 'bsd'." end | "debian" | "ubuntu" -> Debian | "gentoo" -> Gentoo | "homebrew" -> Homebrew | "macports" -> Macports | "suse" | "opensuse" -> Suse | family -> Printf.ksprintf failwith "External dependency handling not supported for OS family '%s'." family ) in fun () -> Lazy.force family let yum_cmd = lazy begin if OpamSystem.resolve_command "yum" <> None then "yum" else if OpamSystem.resolve_command "dnf" <> None then "dnf" else raise (OpamSystem.Command_not_found "yum or dnf") end let packages_status packages = let (+++) pkg set = OpamSysPkg.Set.add (OpamSysPkg.of_string pkg) set in (* Some package managers don't permit to request on available packages. In this case, we consider all non installed packages as [available]. *) let open OpamSysPkg.Set.Op in let compute_sets ?sys_available sys_installed = let installed = packages %% sys_installed in let available, not_found = match sys_available with | Some sys_available -> let available = (packages -- installed) %% sys_available in let not_found = packages -- installed -- available in available, not_found | None -> let available = packages -- installed in available, OpamSysPkg.Set.empty in available, not_found in let to_string_list pkgs = OpamSysPkg.(Set.fold (fun p acc -> to_string p :: acc) pkgs []) in let names_re ?str_pkgs () = let str_pkgs = OpamStd.Option.default (to_string_list packages) str_pkgs in let need_escape = Re.(compile (group (set "+."))) in Printf.sprintf "^(%s)$" (OpamStd.List.concat_map "|" (Re.replace ~all:true need_escape ~f:(fun g -> "\\"^Re.Group.get g 1)) str_pkgs) in let with_regexp_sgl re_pkg = List.fold_left (fun pkgs l -> try Re.(Group.get (exec re_pkg l) 1) +++ pkgs with Not_found -> pkgs) OpamSysPkg.Set.empty in let with_regexp_dbl ~re_installed ~re_pkg = List.fold_left (fun (inst,avail) l -> try let pkg = Re.(Group.get (exec re_pkg l) 1) in if Re.execp re_installed l then pkg +++ inst, avail else inst, pkg +++ avail with Not_found -> inst, avail) OpamSysPkg.Set.(empty, empty) in let package_set_of_pkgpath l = List.fold_left (fun set pkg -> let short_name = match String.rindex pkg '/' with | exception Not_found -> pkg | idx -> String.sub pkg idx (String.length pkg - idx) in set |> OpamSysPkg.Set.add (OpamSysPkg.of_string pkg) |> OpamSysPkg.Set.add (OpamSysPkg.of_string short_name) ) OpamSysPkg.Set.empty l in let compute_sets_with_virtual get_avail_w_virtuals get_installed = let sys_available, sys_provides = get_avail_w_virtuals () in let need_inst_check = OpamSysPkg.Map.fold (fun cp vps set -> if OpamSysPkg.Set.(is_empty (inter vps packages)) then set else OpamSysPkg.Set.add cp set) sys_provides packages in let str_need_inst_check = to_string_list need_inst_check in let sys_installed = get_installed str_need_inst_check in let sys_installed = (* Resolve installed "provides" packages; assumes provides are not recursive *) OpamSysPkg.Set.fold (fun p acc -> match OpamSysPkg.Map.find_opt p sys_provides with | None -> acc | Some ps -> OpamSysPkg.Set.union acc ps) sys_installed sys_installed in compute_sets sys_installed ~sys_available in match family () with | Alpine -> (* Output format >capnproto policy: > 0.8.0-r1: > lib/apk/db/installed > @edgecommunity https://dl-cdn.alpinelinux.org/alpine/edge/community >at policy: > 3.2.1-r1: > https://dl-cdn.alpinelinux.org/alpine/v3.13/community >vim policy: > 8.2.2320-r0: > lib/apk/db/installed > https://dl-cdn.alpinelinux.org/alpine/v3.13/main > 8.2.2852-r0: > @edge https://dl-cdn.alpinelinux.org/alpine/edge/main >hwids-udev policy: > 20201207-r0: > https://dl-cdn.alpinelinux.org/alpine/v3.13/main > @edge https://dl-cdn.alpinelinux.org/alpine/v3.13/main > https://dl-cdn.alpinelinux.org/alpine/edge/main > @edge https://dl-cdn.alpinelinux.org/alpine/edge/main *) let sys_installed, sys_available = let pkg_name = Re.(compile @@ seq [ bol; group @@ rep1 @@ alt [ alnum; punct ]; space; str "policy:"; eol ]) in let repo_name = Re.(compile @@ seq [ bol; repn space 4 (Some 4); char '@'; group @@ rep1 @@ alt [ alnum; punct ]; space ]) in let add_pkg pkg repo installed (inst,avail) = let pkg = match repo with Some r -> pkg^"@"^r | None -> pkg in if installed then pkg +++ inst, avail else inst, pkg +++ avail in to_string_list packages |> List.map (fun s -> match OpamStd.String.cut_at s '@' with | Some (pkg, _repo) -> pkg | None -> s) |> (fun l -> run_query_command "apk" ("policy"::l)) |> List.fold_left (fun (pkg, installed, instavail) l -> try (* package name *) Re.(Group.get (exec pkg_name l) 1), false, instavail with Not_found -> if l.[2] != ' ' then (* only version field is after two spaces *) pkg, false, instavail else if l = " lib/apk/db/installed" then (* from https://git.alpinelinux.org/apk-tools/tree/src/database.c#n58 *) pkg, true, instavail else (* repo (tagged and non-tagged) *) let repo = try Some Re.(Group.get (exec repo_name l) 1) with Not_found -> None in pkg, installed, add_pkg pkg repo installed instavail) ("", false, OpamSysPkg.Set.(empty, empty)) |> (fun (_,_, instavail) -> instavail) in compute_sets sys_installed ~sys_available | Arch -> let get_avail_w_virtuals () = let package_provided str = OpamSysPkg.of_string (match OpamStd.String.cut_at str '=' with | None -> str | Some (p, _vc) -> p) in (* Output format: >Repository : core >Name : python >Version : 3.9.6-1 >Description : Next generation of the python high-level scripting language >Architecture : x86_64 >URL : https://www.python.org/ >Licenses : custom >Groups : None >Provides : python3 >Depends On : bzip2 expat gdbm libffi libnsl libxcrypt openssl >Optional Deps : python-setuptools > python-pip >[...] Format partially described in https://archlinux.org/pacman/PKGBUILD.5.html *) (* Discard stderr to not have it pollute output. Plus, exit code is the number of packages not found. *) run_command ~discard_err:true "pacman" ["-Si"] |> snd |> List.fold_left (fun (avail, provides, latest) l -> match OpamStd.String.split l ' ' with | "Name"::":"::p::_ -> p +++ avail, provides, Some (OpamSysPkg.of_string p) | "Provides"::":"::"None"::[] -> avail, provides, latest | "Provides"::":"::pkgs -> let ps = OpamSysPkg.Set.of_list (List.map package_provided pkgs) in let provides = match latest with | Some p -> OpamSysPkg.Map.add p ps provides | None -> provides (* Bad pacman output ?? *) in ps ++ avail, provides, None | _ -> avail, provides, latest) (OpamSysPkg.Set.empty, OpamSysPkg.Map.empty, None) |> (fun (a,p,_) -> a,p) in let get_installed str_pkgs = (* output: >extra/cmake 3.17.1-1 [installed] > A cross-platform open-source make system >extra/cmark 0.29.0-1 > CommonMark parsing and rendering library and program in C *) let re_pkg = Re.(compile @@ seq [ bol; rep1 @@ alt [alnum; punct]; char '/'; group @@ rep1 @@ alt [alnum; punct]; space; ]) in run_query_command "pacman" ["-Qs" ; names_re ~str_pkgs ()] |> with_regexp_sgl re_pkg in compute_sets_with_virtual get_avail_w_virtuals get_installed | Centos -> (* Output format: >crypto-policies >python3-pip-wheel *) let sys_installed = run_query_command "rpm" ["-qa"; "--qf"; "%{NAME}\\n"] |> List.map OpamSysPkg.of_string |> OpamSysPkg.Set.of_list in compute_sets sys_installed | Debian -> let get_avail_w_virtuals () = let provides_sep = Re.(compile @@ str ", ") in let package_provided str = OpamSysPkg.of_string (match OpamStd.String.cut_at str ' ' with | None -> str | Some (p, _vc) -> p) in (* Output format: >Package: apt >Version: 2.1.7 >Installed-Size: 4136 >Maintainer: APT Development Team >Architecture: amd64 >Replaces: apt-transport-https (<< 1.5~alpha4~), apt-utils (<< 1.3~exp2~) >Provides: apt-transport-https (= 2.1.7) > [...] > The `Provides' field contains provided virtual package(s) by current `Package:'. * manpages.debian.org/buster/apt/apt-cache.8.en.html * www.debian.org/doc/debian-policy/ch-relationships.html#s-virtual *) run_query_command "apt-cache" ["search"; names_re (); "--names-only"; "--full"] |> List.fold_left (fun (avail, provides, latest) l -> if OpamStd.String.starts_with ~prefix:"Package: " l then let p = String.sub l 9 (String.length l - 9) in p +++ avail, provides, Some (OpamSysPkg.of_string p) else if OpamStd.String.starts_with ~prefix:"Provides: " l then let ps = List.map package_provided (Re.split ~pos:10 provides_sep l) |> OpamSysPkg.Set.of_list in avail ++ ps, (match latest with | Some p -> OpamSysPkg.Map.add p ps provides | None -> provides (* Bad apt-cache output ?? *)), None else avail, provides, latest) (OpamSysPkg.Set.empty, OpamSysPkg.Map.empty, None) |> (fun (a,p,_) -> a,p) in let get_installed str_pkgs = (* ouput: >ii uim-gtk3 1:1.8.8-6.1 amd64 Universal ... >ii uim-gtk3-immodule:amd64 1:1.8.8-6.1 amd64 Universal ... *) let re_pkg = Re.(compile @@ seq [ bol; str "ii"; rep1 @@ space; group @@ rep1 @@ diff (alt [alnum; punct]) (char ':'); (* pkg:arch convention *) ]) in (* discard stderr as just nagging *) run_command ~discard_err:true "dpkg-query" ("-l" :: str_pkgs) |> snd |> with_regexp_sgl re_pkg in compute_sets_with_virtual get_avail_w_virtuals get_installed | Freebsd -> let sys_installed = run_query_command "pkg" ["query"; "%n\n%o"] |> List.map OpamSysPkg.of_string |> OpamSysPkg.Set.of_list in compute_sets sys_installed | Gentoo -> let sys_installed = let re_pkg = Re.(compile @@ seq [ group @@ rep1 @@ alt [alnum; punct]; char '-'; rep @@ seq [rep1 digit; char '.']; rep1 digit; rep any; eol ]) in List.fold_left (fun inst dir -> List.fold_left (fun inst pkg -> let to_string d = OpamFilename.basename_dir d |> OpamFilename.Base.to_string in let pkg = Filename.concat (to_string dir) (to_string pkg) in try Re.(Group.get (exec re_pkg pkg) 1) :: inst with Not_found -> inst ) inst (OpamFilename.dirs dir)) [] (OpamFilename.dirs (OpamFilename.Dir.of_string "/var/db/pkg")) |> package_set_of_pkgpath in compute_sets sys_installed | Homebrew -> (* accept 'pkgname' and 'pkgname@version' exampe output >openssl@1.1 >bmake >koekeishiya/formulae/skhd *) let sys_installed = run_query_command "brew" ["list"; "--full-name"] |> List.fold_left (fun res s -> List.fold_left (fun res spkg -> let parse_fullname pkg = match List.rev (OpamStd.String.split pkg '/') with | [] -> [] | [pkg] -> [pkg] | simple_name::_ -> [pkg; simple_name] in match OpamStd.String.cut_at spkg '@' with | Some (n,_v) -> parse_fullname n @ parse_fullname spkg @ res | None -> parse_fullname spkg @ res) res (OpamStd.String.split s ' ')) [] |> List.map OpamSysPkg.of_string |> OpamSysPkg.Set.of_list in compute_sets sys_installed | Macports -> let variants_map, packages = OpamSysPkg.(Set.fold (fun spkg (map, set) -> match OpamStd.String.cut_at (to_string spkg) ' ' with | Some (pkg, variant) -> OpamStd.String.Map.add pkg variant map, pkg +++ set | None -> map, Set.add spkg set) packages (OpamStd.String.Map.empty, Set.empty)) in let str_pkgs = to_string_list packages in let sys_installed = (* output: > zlib @1.2.11_0 (active) > gtk3 @3.24.21_0+quartz (active) *) let re_pkg = Re.(compile @@ seq [ bol; rep space; group @@ rep1 @@ alt [alnum; punct]; rep1 space; char '@'; rep1 @@ diff any (char '+'); opt @@ group @@ rep1 @@ alt [alnum; punct]; rep1 space; str "(active)"; eol ]) in run_query_command "port" ("installed" :: str_pkgs) |> (function _::lines -> lines | _ -> []) |> List.fold_left (fun pkgs l -> try let pkg = Re.(Group.get (exec re_pkg l) 1) in (* variant handling *) match OpamStd.String.Map.find_opt pkg variants_map with | Some variant -> (try if Re.(Group.get (exec re_pkg l) 2) = variant then (pkg ^ " " ^ variant) +++ pkgs else pkgs with Not_found -> pkgs) | None -> pkg +++ pkgs with Not_found -> pkgs) OpamSysPkg.Set.empty in let sys_available = (* example output >diffutils 3.7 sysutils textproc devel GNU diff utilities >-- >No match for gcc found *) let re_pkg = Re.(compile @@ seq [ bol; group @@ rep1 @@ alt [alnum; punct]; rep1 space; rep1 @@ alt [digit; punct]; ]) in let avail = run_query_command "port" [ "search"; "--line"; "--regex"; names_re ~str_pkgs () ] |> with_regexp_sgl re_pkg in (* variants handling *) let variants = OpamStd.String.Map.filter (fun p _ -> OpamSysPkg.Set.mem (OpamSysPkg.of_string p) avail) variants_map |> OpamStd.String.Map.keys in run_query_command "port" ([ "info"; "--name"; "--variants" ] @ variants) |> List.fold_left (fun (prec, avail) l -> match prec, OpamStd.String.split l ' ' with | _, "name:"::pkg::[] -> Some pkg, avail | Some pkg, "variants:"::variants -> None, List.fold_left (fun avail v -> (pkg ^ " +" ^ (OpamStd.String.remove_suffix ~suffix:"," v)) +++ avail) avail variants | _ -> None, avail ) (None, avail) |> snd in compute_sets sys_installed ~sys_available | Netbsd -> let sys_installed = run_query_command "pkg_info" ["-Q"; "PKGPATH"; "-a"] |> package_set_of_pkgpath in compute_sets sys_installed | Openbsd -> let sys_installed = run_query_command "pkg_info" ["-mqP"] |> package_set_of_pkgpath in compute_sets sys_installed | Suse -> (* get the second column of the table: zypper --quiet se -i -t package|grep '^i '|awk -F'|' '{print $2}'|xargs echo output: >S | Name | Summary >--+-----------------------------+------------- > | go-gosqlite | Trivial SQLi >i | libqt4-sql-sqlite-32bit | Qt 4 sqlite *) let re_pkg = Re.(compile @@ seq [ bol; rep1 any; char '|'; rep1 space; group @@ rep1 @@ alt [alnum; punct]; rep1 space; char '|'; ]) in let re_installed = Re.(compile @@ seq [bol ; char 'i']) in let sys_installed, sys_available = run_query_command "zypper" ["--quiet"; "se"; "-t"; "package"] |> with_regexp_dbl ~re_installed ~re_pkg in compute_sets sys_installed ~sys_available (* Install *) let install_packages_commands_t sys_packages = let unsafe_yes = OpamCoreConfig.answer_is `unsafe_yes in let yes ?(no=[]) yes r = if unsafe_yes then yes @ r else no @ r in let packages = List.map OpamSysPkg.to_string (OpamSysPkg.Set.elements sys_packages) in match family () with | Alpine -> ["apk", "add"::yes ~no:["-i"] [] packages], None | Arch -> ["pacman", "-Su"::yes ["--noconfirm"] packages], None | Centos -> (* TODO: check if they all declare "rhel" as primary family *) (* Kate's answer: no they don't :( (e.g. Fedora, Oraclelinux define Nothing and "fedora" respectively) *) (* When opam-packages specify the epel-release package, usually it means that other dependencies require the EPEL repository to be already setup when yum-install is called. Cf. opam-depext/#70,#76. *) let epel_release = "epel-release" in let install_epel rest = if List.mem epel_release packages then [Lazy.force yum_cmd, "install"::yes ["-y"] [epel_release]] @ rest else rest in install_epel [Lazy.force yum_cmd, "install"::yes ["-y"] (OpamStd.String.Set.of_list packages |> OpamStd.String.Set.remove epel_release |> OpamStd.String.Set.elements); "rpm", "-q"::"--whatprovides"::packages], None | Debian -> ["apt-get", "install"::yes ["-qq"; "-yy"] packages], (if unsafe_yes then Some ["DEBIAN_FRONTEND", "noninteractive"] else None) | Freebsd -> ["pkg", "install"::yes ["-y"] packages], None | Gentoo -> ["emerge", yes ~no:["-a"] [] packages], None | Homebrew -> ["brew", "install"::packages], (* NOTE: Does not have any interactive mode *) Some (["HOMEBREW_NO_AUTO_UPDATE","yes"]) | Macports -> let packages = (* Separate variants from their packages *) List.map (fun p -> OpamStd.String.split p ' ') packages |> List.flatten in ["port", yes ["-N"] ("install"::packages)], None | Netbsd -> ["pkgin", yes ["-y"] ("install" :: packages)], None | Openbsd -> ["pkg_add", yes ~no:["-i"] ["-I"] packages], None | Suse -> ["zypper", yes ["--non-interactive"] ("install"::packages)], None let install_packages_commands sys_packages = fst (install_packages_commands_t sys_packages) let sudo_run_command ?vars cmd args = let cmd, args = let not_root = Unix.getuid () <> 0 in match OpamSysPoll.os (), OpamSysPoll.os_distribution () with | Some "openbsd", _ when not_root -> "doas", cmd::args | Some ("linux" | "unix" | "freebsd" | "netbsd" | "dragonfly"), _ | Some "macos", Some "macports" when not_root -> if OpamSystem.resolve_command "sudo" = None then "su", ["root"; "-c"; Printf.sprintf "%S" (String.concat " " (cmd::args))] else "sudo", cmd::args | _ -> cmd, args in match run_command_exit_code ?vars ~allow_stdin:true ~verbose:true cmd args with | 0 -> () | code -> Printf.ksprintf failwith "failed with exit code %d at command:\n %s" code (String.concat " " (cmd::args)) let install packages = if OpamSysPkg.Set.is_empty packages then log "Nothing to install" else let commands, vars = install_packages_commands_t packages in let vars = OpamStd.Option.map (List.map (fun x -> `add, x)) vars in List.iter (fun (cmd, args) -> try sudo_run_command ?vars cmd args with Failure msg -> failwith ("System package install " ^ msg)) commands let update () = let cmd = match family () with | Alpine -> Some ("apk", ["update"]) | Arch -> Some ("pacman", ["-Sy"]) | Centos -> Some (Lazy.force yum_cmd, ["makecache"]) | Debian -> Some ("apt-get", ["update"]) | Gentoo -> Some ("emerge", ["--sync"]) | Homebrew -> Some ("brew", ["update"]) | Macports -> Some ("port", ["sync"]) | Suse -> Some ("zypper", ["--non-interactive"; "refresh"]) | Freebsd | Netbsd | Openbsd -> None in match cmd with | None -> OpamConsole.warning "Unknown update command for %s, skipping system update" OpamStd.Option.Op.(OpamSysPoll.os_family () +! "unknown") | Some (cmd, args) -> try sudo_run_command cmd args with Failure msg -> failwith ("System package update " ^ msg) let repo_enablers () = if family () <> Centos then None else let (needed, _) = packages_status (OpamSysPkg.raw_set (OpamStd.String.Set.singleton "epel-release")) in if OpamSysPkg.Set.is_empty needed then None else Some "On CentOS/RHEL, many packages may assume that the Extra Packages for \ Enterprise Linux (EPEL) repository has been enabled. \ This is typically done by installing the 'epel-release' package. \ Please see https://fedoraproject.org/wiki/EPEL for more information" opam-2.1.5/src/state/opamRepositoryState.mli0000644000175000017500000001100314427463453020161 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** loading and handling of the repository state of an opam root (i.e. what is in ~/.opam/repo) *) open OpamTypes open OpamStateTypes (** Caching of repository loading (marshall of all parsed opam files) *) module Cache: sig val save: [< rw] repos_state -> unit val load: dirname -> (OpamFile.Repo.t repository_name_map * OpamFile.OPAM.t package_map repository_name_map) option val remove: unit -> unit end val load: 'a lock -> [< unlocked ] global_state -> 'a repos_state (** Loads the repository state as [load], and calls the given function while keeping it locked (as per the [lock] argument), releasing the lock afterwards *) val with_: 'a lock -> [< unlocked ] global_state -> ('a repos_state -> 'b) -> 'b (** Returns the repo of origin and metadata corresponding to a package, if found, from a sorted list of repositories (highest priority first) *) val find_package_opt: 'a repos_state -> repository_name list -> package -> (repository_name * OpamFile.OPAM.t) option (** Given the repos state, and a list of repos to use (highest priority first), build a map of all existing package definitions *) val build_index: 'a repos_state -> repository_name list -> OpamFile.OPAM.t OpamPackage.Map.t (** Finds a package repository definition from its name (assuming it's in ROOT/repos/) *) val get_repo: 'a repos_state -> repository_name -> repository val load_opams_from_dir: repository_name -> dirname -> OpamFile.OPAM.t OpamPackage.Map.t (** Load all the metadata within the local mirror of the given repository, without cache *) val load_repo: repository -> OpamFilename.Dir.t -> OpamFile.Repo.t * OpamFile.OPAM.t OpamPackage.Map.t (** Get the (lazily extracted) repository root for the given repository *) val get_root: 'a repos_state -> repository_name -> OpamFilename.Dir.t (** Same as [get_root], but with a repository rather than just a name as argument *) val get_repo_root: 'a repos_state -> repository -> OpamFilename.Dir.t (* (\** Runs the given function with access to a (possibly temporary) directory * containing the extracted structure of the given repository, and cleans it up * afterwards if temporary. The basename of the directory is guaranteed to * match the repository name (this is important for e.g. [tar]) *\) * val with_repo_root: * 'a global_state -> repository -> (OpamFilename.Dir.t -> 'b) -> 'b * * (\** As [with_repo_root], but on jobs *\) * val with_repo_root_job: * 'a global_state -> repository -> * (OpamFilename.Dir.t -> 'b OpamProcess.job) -> 'b OpamProcess.job *) (** Releases any locks on the given repos_state, and cleans the tmp extracted tree if any unless [cleanup=false] *) val unlock: ?cleanup:bool -> 'a repos_state -> unlocked repos_state (** Releases any locks on the given repos_state and then ignores it. Using [drop ?cleanup rt] is equivalent to [ignore (unlock ?cleanup rt)], and safer than other uses of [ignore] where it is not enforced by the type-system that the value is unlocked before it is lost. *) val drop: ?cleanup:bool -> 'a repos_state -> unit (** Cleanup before removing the repository from temporary table *) val remove_from_repos_tmp: 'a repos_state -> repository_name -> unit (** Clears tmp files corresponding to a repo state (uncompressed repository contents) *) val cleanup: 'a repos_state -> unit (** Calls the provided function, ensuring a temporary write lock on the given repository state*) val with_write_lock: ?dontblock:bool -> 'a repos_state -> (rw repos_state -> 'b * rw repos_state) -> 'b * 'a repos_state (** Writes the repositories config file back to disk *) val write_config: rw repos_state -> unit (** Display a warning if repository has not been updated since 3 weeks *) val check_last_update: unit -> unit opam-2.1.5/src/state/opamGlobalState.ml0000644000175000017500000001733714427463453017051 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamStd.Op open OpamFilename.Op open OpamStateTypes let log fmt = OpamConsole.log "GSTATE" fmt let slog = OpamConsole.slog let load_config lock_kind global_lock root = let config = match OpamStateConfig.load ~lock_kind root with | Some c -> c | exception (OpamPp.Bad_version _ as e) -> OpamFormatUpgrade.hard_upgrade_from_2_1_intermediates ~global_lock root; raise e | None -> if OpamFilename.exists (root // "aliases") then OpamFile.Config.(with_opam_version (OpamVersion.of_string "1.1") empty) else OpamConsole.error_and_exit `Configuration_error "%s exists, but does not appear to be a valid opam root. Please \ remove it and use `opam init', or specify a different `--root' \ argument" (OpamFilename.Dir.to_string root) in let config = OpamFormatUpgrade.as_necessary lock_kind global_lock root config in config let inferred_from_system = "Inferred from system" let load lock_kind = let root = OpamStateConfig.(!r.root_dir) in log "LOAD-GLOBAL-STATE %@ %a" (slog OpamFilename.Dir.to_string) root; (* Always take a global read lock, this is only used to prevent concurrent ~/.opam format changes *) let has_root = OpamFilename.exists_dir root in let global_lock = if has_root then OpamFilename.flock `Lock_read (OpamPath.lock root) else OpamSystem.lock_none in (* The global_state lock actually concerns the global config file only (and the consistence thereof with the repository and switch sets, and the currently installed shell init scripts) *) if not has_root then OpamConsole.error_and_exit `Configuration_error "Opam has not been initialised, please run `opam init'"; let config_lock = OpamFilename.flock lock_kind (OpamPath.config_lock root) in let config = try load_config lock_kind global_lock root with OpamFormatUpgrade.Upgrade_done _ as e -> OpamSystem.funlock config_lock; raise e in if OpamStateConfig.is_newer config && lock_kind <> `Lock_write then log "root version (%s) is greater than running binary's (%s); \ load with best-effort (read-only)" (OpamVersion.to_string (OpamFile.Config.opam_root_version config)) (OpamVersion.to_string (OpamFile.Config.root_version)); let switches = List.filter (fun sw -> not (OpamSwitch.is_external sw) || OpamFilename.exists_dir (OpamSwitch.get_root root sw)) (OpamFile.Config.installed_switches config) in let config = OpamFile.Config.with_installed_switches switches config in let global_variables = List.fold_left (fun acc (v,value) -> OpamVariable.Map.add v (lazy (Some (OpamStd.Option.default (S "unknown") (Lazy.force value))), (* Careful on changing it, it is used to determine user defined variables on `config report`. See [OpamConfigCommand.help]. *) inferred_from_system) acc) OpamVariable.Map.empty (OpamSysPoll.variables) in let global_variables = List.fold_left (fun acc (v,value,doc) -> OpamVariable.Map.add v (lazy (Some value), doc) acc) global_variables (OpamFile.Config.global_variables config) in let eval_variables = OpamFile.Config.eval_variables config in let global_variables = let env = lazy (OpamEnv.get_pure () |> OpamTypesBase.env_array) in List.fold_left (fun acc (v, cmd, doc) -> OpamVariable.Map.update v (fun previous_value -> (lazy (try let ret = OpamSystem.read_command_output ~env:(Lazy.force env) ~allow_stdin:false cmd in Some (S (OpamStd.String.strip (String.concat "\n" ret))) with e -> OpamStd.Exn.fatal e; log "Failed to evaluate global variable %a: %a" (slog OpamVariable.to_string) v (slog Printexc.to_string) e; Lazy.force (fst previous_value))), doc) (lazy None, "") acc) global_variables eval_variables in { global_lock = config_lock; root; config; global_variables; } let switches gt = OpamFile.Config.installed_switches gt.config let fold_switches f gt acc = List.fold_left (fun acc switch -> f switch (OpamStateConfig.Switch.safe_read_selections ~lock_kind:`Lock_read gt switch) acc ) acc (OpamFile.Config.installed_switches gt.config) let switch_exists gt switch = if OpamSwitch.is_external switch then OpamStateConfig.local_switch_exists gt.root switch else List.mem switch (switches gt) let all_installed gt = fold_switches (fun _ sel acc -> OpamPackage.Set.union acc sel.sel_installed) gt OpamPackage.Set.empty let installed_versions gt name = fold_switches (fun switch sel acc -> let installed = OpamPackage.packages_of_name sel.sel_installed name in try let nv = OpamPackage.Set.choose installed in try OpamPackage.Map.add nv (switch::OpamPackage.Map.find nv acc) acc with Not_found -> OpamPackage.Map.add nv [switch] acc with Not_found -> acc) gt OpamPackage.Map.empty let repos_list gt = OpamFile.Config.repositories gt.config let unlock gt = OpamSystem.funlock gt.global_lock; (gt :> unlocked global_state) let drop gt = let _ = unlock gt in () let with_write_lock ?dontblock gt f = if OpamStateConfig.is_newer_than_self gt then OpamConsole.error_and_exit `Locked "The opam root has been upgraded by a newer version of opam-state \ and cannot be written to"; let ret, gt = OpamFilename.with_flock_upgrade `Lock_write ?dontblock gt.global_lock @@ fun _ -> f ({ gt with global_lock = gt.global_lock } : rw global_state) (* We don't actually change the field value, but this makes restricting the phantom lock type possible*) in ret, { gt with global_lock = gt.global_lock } let with_ lock f = let gt = load lock in try let r = f gt in drop gt; r with e -> OpamStd.Exn.finalise e (fun () -> drop gt) let write gt = OpamFile.Config.write (OpamPath.config gt.root) gt.config let fix_switch_list gt = let known_switches0 = switches gt in let known_switches = match OpamStateConfig.get_switch_opt () with | None -> known_switches0 | Some sw -> if List.mem sw known_switches0 || not (switch_exists gt sw) then known_switches0 else sw::known_switches0 in let known_switches = List.filter (switch_exists gt) known_switches in if known_switches = known_switches0 then gt else let config = OpamFile.Config.with_installed_switches known_switches gt.config in let gt = { gt with config } in if not OpamCoreConfig.(!r.safe_mode) && OpamSystem.get_lock_flag gt.global_lock = `Lock_write then try snd @@ with_write_lock ~dontblock:true gt @@ fun gt -> write gt, gt with OpamSystem.Locked -> gt else gt opam-2.1.5/src/state/opamFileTools.mli0000644000175000017500000001200414427463453016703 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Tools for manipulating and checking package definition ("opam") files *) open OpamTypes (** Create an OPAM package template filled with common options *) val template: package -> OpamFile.OPAM.t (** Runs several sanity checks on the opam file; returns a list of warnings. [`Error] level should be considered unfit for publication, while [`Warning] are advisory but may be accepted. The int is an identifier for this specific warning/error. If [check_extra_files] is unspecified or false, warning 53 won't be checked. *) val lint: ?check_extra_files:(basename * (OpamHash.t -> bool)) list -> ?check_upstream:bool -> OpamFile.OPAM.t -> (int * [`Warning|`Error] * string) list (** Same as [lint], but operates on a file, which allows catching parse errors too. [check_extra_files] defaults to a function that will look for a [files/] directory besides [filename]. [handle_dirname] is used for warning 4, and should be set when reading packages from a repository, so that package name and version are inferred from the filename. *) val lint_file: ?check_extra_files:(basename * (OpamHash.t -> bool)) list -> ?check_upstream:bool -> ?handle_dirname:bool -> OpamFile.OPAM.t OpamFile.typed_file -> (int * [`Warning|`Error] * string) list * OpamFile.OPAM.t option (** Same as [lint_file], but taking input from a channel. [check_extra_files] defaults to a function that will look for a [files/] directory besides [filename] *) val lint_channel: ?check_extra_files:(basename * (OpamHash.t -> bool)) list -> ?check_upstream: bool -> ?handle_dirname:bool -> OpamFile.OPAM.t OpamFile.typed_file -> in_channel -> (int * [`Warning|`Error] * string) list * OpamFile.OPAM.t option (** Like [lint_file], but takes the file contents as a string. [check_extra_files] defaults to a function that will look for a [files/] directory besides [filename] *) val lint_string: ?check_extra_files:(basename * (OpamHash.t -> bool)) list -> ?check_upstream: bool -> ?handle_dirname:bool -> OpamFile.OPAM.t OpamFile.typed_file -> string -> (int * [`Warning|`Error] * string) list * OpamFile.OPAM.t option val all_lint_warnings: unit -> (int * [`Warning|`Error] * string) list (** Utility function to print validation results *) val warns_to_string: (int * [`Warning|`Error] * string) list -> string (** Utility function to construct a json of validation results. The format is as follow: { "file" : string , "result" : string (passed | error | warning), "warnings" : [ { "id" : int, "message" : string }, ... ], "errors" : [ { "id" : int, "message" : string }, ... ] } *) val warns_to_json: ?filename:string -> (int * [`Warning|`Error] * string) list -> OpamJson.t (** Read the opam metadata from a given directory (opam file, with possible overrides from url and descr files). Also includes the names and hashes of files below files/ Warning: use [read_repo_opam] instead for correctly reading files from repositories!*) val read_opam: dirname -> OpamFile.OPAM.t option (** Like [read_opam], but additionally fills in the [metadata_dir] info correctly for the given repository. *) val read_repo_opam: repo_name:repository_name -> repo_root:dirname -> dirname -> OpamFile.OPAM.t option (** Adds data from 'url' and 'descr' files found in the specified dir or the opam file's metadata dir, if not already present in the opam file. if [files_subdir_hashes] is [true], also adds the names and hashes of files found below 'files/' *) val add_aux_files: ?dir:dirname -> files_subdir_hashes:bool -> OpamFile.OPAM.t -> OpamFile.OPAM.t (** {2 Tools to manipulate the [OpamFile.OPAM.t] contents} *) val map_all_variables: (full_variable -> full_variable) -> OpamFile.OPAM.t -> OpamFile.OPAM.t val map_all_filters: (filter -> filter) -> OpamFile.OPAM.t -> OpamFile.OPAM.t (** Converts a dependency formula to the same format as used in opam package definition files. *) val dep_formula_to_string: formula -> string (** Sort opam fields: author, tags, depexts, depends, depopts, conflicts, pin_depends, extra_files, extra_sources *) val sort_opam: OpamFile.OPAM.t -> OpamFile.OPAM.t opam-2.1.5/src/state/opamFormatUpgrade.ml0000644000175000017500000014355414427463453017411 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase open OpamStd.Op open OpamFilename.Op let log fmt = OpamConsole.log "FMT_UPG" fmt let slog = OpamConsole.slog exception Upgrade_done of OpamFile.Config.t * (OpamFile.Config.t -> unit) option (* - Package and aux functions - *) let upgrade_depexts_to_2_0_beta5 filename depexts = let arch = OpamVariable.of_string "arch" in let os = OpamVariable.of_string "os" in let os_family = OpamVariable.of_string "os-family" in let distro = OpamVariable.of_string "os-distribution" in let eq var v = FOp (FIdent ([], var, None), `Eq, FString v) in (* Transform all known tags into the corresponding filters *) let rec transform_filter = let transform_tag = function | "amd64" -> eq arch "x86_64" | "x86" -> eq arch "x86_32" | "arm"|"armv7" -> eq arch "arm32" | "ppc" -> eq arch "ppc32" | "x86_64" | "ppc64" as a -> eq arch a | "osx" -> eq os "macos" | "linux" | "unix" | "xenserver" | "freebsd" | "openbsd" | "netbsd" | "dragonfly" | "win32" | "cygwin" as o -> eq os o | "nixpkgs" -> eq distro "nixos" | "arch" -> eq distro "archlinux" | "homebrew" | "macports" | "debian" | "ubuntu" | "centos" | "fedora" | "rhel" | "opensuse" | "oraclelinux" | "ol" | "mageia" | "alpine" | "archlinux" | "gentoo" | "nixos" as d -> eq distro d | "bsd" -> eq os_family "bsd" | "mswindows" -> eq os_family "windows" | "source" -> failwith "\"source\" tag" | s -> failwith ("Unknown tag "^s) in function | FAnd (f1, f2) -> FAnd (transform_filter f1, transform_filter f2) | FString s -> transform_tag s | _ -> raise Exit (* the filter is already in the new format if it contains anything else *) in OpamStd.List.filter_map (fun (names, filter) -> try Some (names, transform_filter filter) with | Exit -> Some (names, filter) | Failure m -> OpamConsole.warning "Ignored depext in %s: %s" filename m; None) depexts let v2_0 = OpamVersion.of_string "2.0" let opam_file_from_1_2_to_2_0 ?filename opam = let ocaml_pkgname = OpamPackage.Name.of_string "ocaml" in let ocaml_wrapper_pkgname = OpamPackage.Name.of_string "ocaml" in let ocaml_official_pkgname = OpamPackage.Name.of_string "ocaml-base-compiler" in let ocaml_variants_pkgname = OpamPackage.Name.of_string "ocaml-variants" in let ocaml_system_pkgname = OpamPackage.Name.of_string "ocaml-system" in let filename = match filename with | Some f -> OpamFile.to_string f | None -> match OpamFile.OPAM.metadata_dir opam with | Some (Some r, rel_d) -> Printf.sprintf "<%s>/%s/opam" (OpamRepositoryName.to_string r) rel_d | Some (None, abs_d) -> let d = OpamFilename.Dir.of_string abs_d in OpamFilename.to_string (d // "opam") | None -> "opam file" in let available = OpamFilter.distribute_negations (OpamFile.OPAM.available opam) in let sym_op = function | (`Eq | `Neq) as op -> op | `Gt -> `Lt | `Geq -> `Leq | `Lt -> `Gt | `Leq -> `Geq in let mk_constraint op v = Atom (Constraint (op, FString v)) in let get_atom ?(op=`Eq) v = if v = "system" then ocaml_system_pkgname, Empty else (if String.contains v '+' then ocaml_variants_pkgname else ocaml_official_pkgname), mk_constraint op v in let module NMap = OpamPackage.Name.Map in let pkg_deps, pkg_conflicts, available_opt = let rec aux avail = match avail with | FOp (FString _ as fs, op, (FIdent _ as fid)) -> aux (FOp (fid, sym_op op, fs)) | FOp (FIdent ([],var,None), op, FString v) -> (match OpamVariable.to_string var, op with | "ocaml-version", _ -> NMap.singleton ocaml_wrapper_pkgname (mk_constraint op v), NMap.empty, None | "compiler", `Neq -> NMap.empty, NMap.of_list [get_atom v], None | "compiler", op -> NMap.of_list [get_atom ~op v], NMap.empty, None | _ -> NMap.empty, NMap.empty, Some avail) | FIdent ([], v, None) when OpamVariable.to_string v = "preinstalled" -> NMap.singleton ocaml_system_pkgname Empty, NMap.empty, None | FNot (FIdent ([], v, None)) when OpamVariable.to_string v = "preinstalled" -> NMap.empty, NMap.singleton ocaml_system_pkgname Empty, None | FNot f -> let pkg_deps, pkg_conflicts, available_opt = aux f in pkg_conflicts, pkg_deps, OpamStd.Option.map (fun f -> FNot f) available_opt | FAnd (f1,f2) -> let deps1, cflt1, f1 = aux f1 in let deps2, cflt2, f2 = aux f2 in (NMap.union (fun d1 d2 -> OpamFormula.ands [d1; d2]) deps1 deps2, NMap.union (fun c1 c2 -> OpamFormula.ors [c1; c2]) cflt1 cflt2, match f1, f2 with | Some f1, Some f2 -> Some (FAnd (f1, f2)) | None, f | f, None -> f) | FOr (f1,f2) -> let deps1, cflt1, f1 = aux f1 in let deps2, cflt2, f2 = aux f2 in let err () = OpamConsole.error "Unconvertible 'available:' disjunction in %s" filename in (NMap.union (fun d1 d2 -> OpamFormula.ors [d1; d2]) deps1 deps2, NMap.union (fun c1 c2 -> OpamFormula.ands [c1; c2]) cflt1 cflt2, match f1, f2 with | Some f1, Some f2 -> Some (FOr (f1,f2)) | None, None -> None | None, f | f, None -> err (); f) | f -> NMap.empty, NMap.empty, Some f in aux available in let pkg_deps = if OpamVersion.compare (OpamFile.OPAM.opam_version opam) v2_0 >= 0 || NMap.mem ocaml_wrapper_pkgname pkg_deps || OpamFile.OPAM.has_flag Pkgflag_Conf opam then pkg_deps else NMap.add ocaml_wrapper_pkgname Empty pkg_deps in let available = OpamStd.Option.default (FBool true) available_opt in if List.exists (fun v -> match OpamVariable.Full.to_string v with | "ocaml-version" | "compiler" | "preinstalled" | "ocaml-native" | "ocaml-native-tools" | "ocaml-native-dynlink" -> true | _ -> false) (OpamFilter.variables available) then OpamConsole.warning "Could not translate some 'ocaml-*' variables in the 'available:' \ field of %s: %s" filename (OpamFilter.to_string available); let depends = let to_add,conj = List.fold_left (fun (to_add,conj) -> function | Atom (pkgname, cstr) as atom -> (try NMap.remove pkgname to_add, Atom (pkgname, OpamFormula.ands [cstr; NMap.find pkgname to_add]) :: conj with Not_found -> to_add, atom :: conj) | f -> to_add, f::conj) (pkg_deps, []) (OpamFormula.ands_to_list (OpamFile.OPAM.depends opam)) in let remain = List.map (fun (name, cstr) -> Atom (name, cstr)) (NMap.bindings to_add) in OpamFormula.ands (remain @ List.rev conj) in let rwr_depflags = let rwr_vars v = match OpamVariable.Full.to_string v with | "test" -> OpamVariable.Full.of_string "with-test" | "doc" -> OpamVariable.Full.of_string "with-doc" | _ -> v in OpamFormula.map (fun (name, cstr) -> let cstr = OpamFormula.map (function | Filter f -> Atom (Filter (OpamFilter.map_variables rwr_vars f)) | Constraint _ as c -> Atom c) cstr in Atom (name, cstr)) in let depends = rwr_depflags depends in let depopts = rwr_depflags (OpamFile.OPAM.depopts opam) in let conflicts = let to_add, disj = List.fold_left (fun (to_add,disj) -> function | Atom (pkgname, cstr) as atom -> (try NMap.remove pkgname to_add, Atom (pkgname, OpamFormula.ors [cstr; NMap.find pkgname to_add]) :: disj with Not_found -> to_add, atom :: disj) | f -> to_add, f::disj) (pkg_conflicts,[]) (OpamFormula.ors_to_list (OpamFile.OPAM.conflicts opam)) in let remain = List.map (fun (name, cstr) -> Atom (name, cstr)) (NMap.bindings to_add) in OpamFormula.ors (remain @ List.rev disj) in let rewrite_var v = let mkvar s = OpamVariable.Full.create ocaml_pkgname (OpamVariable.of_string s) in match OpamVariable.Full.scope v with | OpamVariable.Full.Global -> (match OpamVariable.(to_string (Full.variable v)) with | "compiler" -> mkvar "compiler" | "preinstalled" -> mkvar "preinstalled" | "ocaml-version" -> mkvar "version" | "ocaml-native" -> mkvar "native" | "ocaml-native-tools" -> mkvar "native-tools" | "ocaml-native-dynlink" -> mkvar "native-dynlink" | _ -> v) | _ -> v in let auto_add_flags opam = (* Automatically add light-uninstall for trivial commands that won't need the source *) if OpamFile.OPAM.remove opam <> [] && List.for_all (fun (cmd, _filter) -> match cmd with | [] | (CString ("ocamlfind" | "rm"), _) :: _ -> true | _ -> false) (OpamFile.OPAM.remove opam) then OpamFile.OPAM.add_flags [Pkgflag_LightUninstall] opam else opam in let filter_out_flagtags opam = OpamFile.OPAM.with_tags (List.filter (fun tag -> OpamFile.OPAM.flag_of_tag tag = None) (OpamFile.OPAM.tags opam)) opam in let build_doc, install_doc = let rec split acc = function | [] -> List.rev acc, [] | (cmd, _ as c) :: r as l -> if List.exists (function | CString s, _ -> OpamStd.String.contains ~sub:"install" s | _ -> false) cmd then List.rev acc, l else split (c::acc) r in split [] (OpamFile.OPAM.deprecated_build_doc opam) in let add_filter to_add cmdlist = List.map (fun (cmd,filter) -> cmd, match filter with | None -> Some to_add | Some f -> Some (FAnd (to_add, f))) cmdlist in let test_filter = FIdent ([], OpamVariable.of_string "with-test", None) in let doc_filter = FIdent ([], OpamVariable.of_string "with-doc", None) in let build = OpamFile.OPAM.build opam @ add_filter test_filter (OpamFile.OPAM.deprecated_build_test opam) @ add_filter doc_filter build_doc in let install = OpamFile.OPAM.install opam @ add_filter doc_filter install_doc in let dev_repo = OpamStd.Option.map (OpamUrl.parse ~handle_suffix:true @* OpamUrl.to_string) (OpamFile.OPAM.dev_repo opam) in let depexts = upgrade_depexts_to_2_0_beta5 filename (OpamFile.OPAM.depexts opam) in let rwr_os_filters = OpamSysPoll.normalise_os in let rwr_arch_filters = OpamSysPoll.normalise_arch in let rewrite_filter = OpamFilter.map_up (function | FOp (FIdent ([],vname,None) as v, op, FString value) as ft -> (match OpamVariable.to_string vname with | "os" -> FOp (v, op, FString (rwr_os_filters value)) | "arch" -> FOp (v, op, FString (rwr_arch_filters value)) | _ -> ft) | FOp (FString value, op, (FIdent ([],vname,None) as v)) as ft -> (match OpamVariable.to_string vname with | "os" -> FOp (FString (rwr_os_filters value), op, v) | "arch" -> FOp (FString (rwr_arch_filters value), op, v) | _ -> ft) | ft -> ft) in opam |> OpamFile.OPAM.with_opam_version v2_0 |> OpamFile.OPAM.with_depends depends |> OpamFile.OPAM.with_depopts depopts |> OpamFile.OPAM.with_conflicts conflicts |> OpamFile.OPAM.with_available available |> OpamFile.OPAM.with_build build |> OpamFile.OPAM.with_install install |> OpamFile.OPAM.with_dev_repo_opt dev_repo |> OpamFile.OPAM.with_deprecated_build_test [] |> OpamFile.OPAM.with_deprecated_build_doc [] |> OpamFileTools.map_all_variables rewrite_var |> OpamFileTools.map_all_filters rewrite_filter |> OpamFile.OPAM.with_depexts depexts |> auto_add_flags |> filter_out_flagtags (* - Progressive version update functions - *) let v1_1 = OpamVersion.of_string "1.1" let from_1_0_to_1_1 root _config = OpamConsole.error_and_exit `Configuration_error "You appear to have an opam setup dating back to opam 1.0, which is no \ longer supported since opam 2.0. Please remove \"%s\" and run \ `opam init`" (OpamFilename.Dir.to_string root) let v1_2 = OpamVersion.of_string "1.2" let from_1_1_to_1_2 root config = log "Upgrade pinned packages format to 1.2"; let aliases = OpamFile.Aliases.safe_read (OpamFile.make (root // "aliases")) in let remove_pinned_suffix d = let s = OpamFilename.Dir.to_string d in if Filename.check_suffix s ".pinned" then OpamFilename.move_dir ~src:d ~dst:(OpamFilename.Dir.of_string (Filename.chop_suffix s ".pinned")) in let packages = lazy ( OpamPackage.Set.of_list (OpamPackage.Map.keys (OpamFile.Package_index.safe_read (OpamFile.make (root / "repo" // "package-index")))) ) in OpamSwitch.Map.iter (fun switch _ -> let switch_root = root / OpamSwitch.to_string switch in let pinned_version name = try let f = OpamFile.make (switch_root / "overlay" / OpamPackage.Name.to_string name // "opam") in match OpamFile.OPAM.version_opt (OpamFile.OPAM.read f) with | None -> raise Not_found | Some v -> v with e -> OpamStd.Exn.fatal e; try OpamPackage.version (OpamPackage.max_version (Lazy.force packages) name) with Not_found -> OpamPackage.Version.of_string "0" in let fix_version nv = let obsolete_pinned_v = OpamPackage.Version.of_string "pinned" in if nv.version = obsolete_pinned_v then let name = nv.name in OpamPackage.create name (pinned_version name) else nv in List.iter remove_pinned_suffix (OpamFilename.dirs (switch_root / "packages.dev")); List.iter remove_pinned_suffix (OpamFilename.dirs (switch_root / "overlay")); let switch_prefix = switch_root in let installed_f = OpamFile.make OpamFilename.Op.(switch_prefix // "installed") in let installed = OpamFile.PkgList.safe_read installed_f in OpamFile.PkgList.write installed_f (OpamPackage.Set.map fix_version installed); let installed_roots_f = OpamFile.make OpamFilename.Op.(switch_prefix // "installed.roots") in let installed_roots = OpamFile.PkgList.safe_read installed_roots_f in OpamFile.PkgList.write installed_roots_f (OpamPackage.Set.map fix_version installed_roots); (* Move .config files *) List.iter (fun f -> let name = OpamFilename.Base.to_string @@ OpamFilename.basename @@ OpamFilename.chop_extension f in if name <> "global-config" then let dst = switch_root / "lib" / name // "opam.config" in OpamFilename.mkdir (OpamFilename.dirname dst); OpamFilename.move ~src:f ~dst ) (OpamFilename.files (switch_root / "config")) ) aliases; config let v1_3_dev2 = OpamVersion.of_string "1.3~dev2" let from_1_2_to_1_3_dev2 root config = log "Upgrade switch state files format to 1.3"; let aliases = OpamFile.Aliases.safe_read (OpamFile.make (root // "aliases")) in OpamSwitch.Map.iter (fun switch c -> let switch_dir = root / OpamSwitch.to_string switch in let installed_f = switch_dir // "installed" in let installed_roots_f = switch_dir // "installed.roots" in let pinned_f = switch_dir // "pinned" in let installed = OpamFile.PkgList.safe_read (OpamFile.make installed_f) in let installed_roots = OpamFile.PkgList.safe_read (OpamFile.make installed_roots_f) in let pinned = OpamFile.Pinned_legacy.safe_read (OpamFile.make pinned_f) in let pinned = OpamPackage.Name.Map.mapi (fun name pin -> let v = match pin with | OpamFile.Pinned_legacy.Version v -> v | OpamFile.Pinned_legacy.Source _ -> let overlay = OpamFile.make (switch_dir / "overlay" / OpamPackage.Name.to_string name // "opam") in let opam = OpamFile.OPAM.safe_read overlay in OpamStd.Option.default (OpamPackage.Version.of_string "0") (OpamFile.OPAM.version_opt opam) in v, pin) pinned in let sel_pinned = OpamPackage.Name.Map.fold (fun name (v,_) -> OpamPackage.Set.add (OpamPackage.create name v)) pinned OpamPackage.Set.empty in let compiler = let version = match OpamStd.String.cut_at c '+' with | Some (v,_) -> v | None -> c in let comp = OpamFile.Comp.read (OpamFile.make (root / "compilers" / version / c // (c ^".comp"))) in let atoms = OpamFormula.atoms (OpamFile.Comp.packages comp) in List.fold_left (fun acc (name,_) -> let nv = try let v, _ = OpamPackage.Name.Map.find name pinned in OpamPackage.create name v with Not_found -> try OpamPackage.max_version installed name with Not_found -> OpamPackage.create name (OpamPackage.Version.of_string "~unknown") in OpamPackage.Set.add nv acc) OpamPackage.Set.empty atoms in OpamFile.LegacyState.write (OpamFile.make (switch_dir // "state")) { sel_installed = installed; sel_roots = installed_roots; sel_pinned; sel_compiler = compiler }; OpamFilename.remove installed_f; OpamFilename.remove installed_roots_f; OpamFilename.remove pinned_f; (* Move .config files back *) OpamPackage.Set.iter (fun nv -> let name = nv.name in let src = switch_dir / "lib" / OpamPackage.Name.to_string name // "opam.config" in let dst = switch_dir / "config" // (OpamPackage.Name.to_string name ^ ".config") in if OpamFilename.exists src then OpamFilename.move ~src ~dst) installed) aliases; config let v1_3_dev5 = OpamVersion.of_string "1.3~dev5" let from_1_3_dev2_to_1_3_dev5 root conf = log "Upgrade switch state files format to 1.3 step 2"; let aliases_f = OpamFile.make (root // "aliases") in let aliases = OpamFile.Aliases.safe_read aliases_f in OpamSwitch.Map.iter (fun switch comp_name -> (* Convert state-file table format to selections file, opam syntax format *) let switch_dir = root / OpamSwitch.to_string switch in let state_f = OpamFile.make (switch_dir // "state") in let selections = OpamFile.LegacyState.safe_read state_f in let selections_f = OpamFile.make (switch_dir // "switch-state") in let comp_version = match OpamStd.String.cut_at comp_name '+' with | Some (v,_) -> v | None -> comp_name in (* Change comp file to a package *) let selections = if comp_name <> "empty" then let comp_f = OpamFile.make (root / "compilers" / comp_version / comp_name // (comp_name ^ ".comp")) in let comp = OpamFile.Comp.read comp_f in let descr_f = OpamFile.make (root / "compilers" / comp_version / comp_name // (comp_name ^ ".descr")) in let descr = OpamStd.Option.default (OpamFile.Descr.create "Switch relying on a system-wide installation of OCaml") (OpamFile.Descr.read_opt descr_f) in let comp_opam = OpamFile.Comp.to_package comp (Some descr) in let nv = OpamFile.OPAM.package comp_opam in let name = nv.name in let switch_config_f = OpamFile.make (switch_dir / "config" // "global-config.config") in let switch_config = OpamFile.Dot_config.safe_read switch_config_f in let config = if OpamFile.Comp.preinstalled comp then let config = OpamFile.Dot_config.create @@ List.map (fun (v,c) -> OpamVariable.of_string v, c) @@ [ "compiler", S comp_name; "preinstalled", B true; ] in let ocamlc = try let path = OpamStd.Env.get "PATH" |> OpamStd.Sys.split_path_variable |> List.filter (fun s -> not (OpamStd.String.starts_with ~prefix:(OpamFilename.Dir.to_string root) s)) in List.fold_left (function | None -> fun d -> let f = OpamStd.Sys.executable_name (Filename.concat d "ocamlc") in if Sys.file_exists f then Some (OpamFilename.of_string f) else None | s -> fun _ -> s) None path with Not_found -> None in match ocamlc with | Some ocamlc -> let vnum = OpamSystem.read_command_output ~verbose:false [ OpamFilename.to_string ocamlc ; "-vnum" ] in config |> OpamFile.Dot_config.with_file_depends [ocamlc, OpamHash.compute (OpamFilename.to_string ocamlc)] |> OpamFile.Dot_config.set (OpamVariable.of_string "ocaml-version") (Some (S (String.concat "" vnum))) | None -> config else let get_dir d = match OpamFile.Dot_config.variable switch_config (OpamVariable.of_string d) with | Some (S d) -> OpamFilename.Dir.of_string d | _ -> OpamPath.Switch.get_stdpath root switch OpamFile.Switch_config.empty (std_path_of_string d) in OpamFile.Dot_config.create @@ List.map (fun (v,c) -> OpamVariable.of_string v, c) @@ [ "ocaml-version", S (OpamFile.Comp.version comp); "compiler", S comp_name; "preinstalled", B false; "ocaml-native", B (OpamFilename.exists (get_dir "bin" // "ocamlopt")); "ocaml-native-tools", B (OpamFilename.exists (get_dir "bin" // "ocamlc.opt")); "ocaml-native-dynlink", B (OpamFilename.exists (get_dir "lib" / "ocaml" // "dynlink.cmxa")); "ocaml-stubsdir", S (OpamFilename.Dir.to_string (get_dir "stublibs")); ] in let config_f = OpamFile.make (switch_dir / "config" // (OpamPackage.Name.to_string name ^".config")) in OpamFile.OPAM.write (OpamFile.make (root / "packages" / OpamPackage.Name.to_string name / OpamPackage.to_string nv // "opam")) comp_opam; OpamFile.Dot_config.write config_f config; (* Also export compiler variables as globals *) OpamFile.Dot_config.write switch_config_f (OpamFile.Dot_config.with_vars (OpamFile.Dot_config.bindings switch_config @ OpamFile.Dot_config.bindings config) switch_config); { selections with sel_installed = OpamPackage.Set.add nv selections.sel_installed; sel_compiler = OpamPackage.Set.add nv selections.sel_compiler; sel_roots = OpamPackage.Set.add nv selections.sel_roots; } else selections in OpamFile.SwitchSelections.write selections_f selections; OpamFilename.remove (OpamFile.filename state_f)) aliases; let conf = OpamFile.Config.with_installed_switches (OpamSwitch.Map.keys aliases) conf in OpamFilename.remove (OpamFile.filename aliases_f); conf let v1_3_dev6 = OpamVersion.of_string "1.3~dev6" let from_1_3_dev5_to_1_3_dev6 root conf = log "Upgrade switch state files format to 1.3 step 3"; (* Move switch internals to [switch/.opam-switch] *) List.iter (fun switch -> let switch_dir = root / OpamSwitch.to_string switch in let meta_dir = switch_dir / ".opam-switch" in OpamFilename.mkdir meta_dir; List.iter (fun f -> let src = switch_dir // f in let dst = meta_dir // f in if OpamFilename.exists src then OpamFilename.move ~src ~dst) ["lock"; "switch-state"; "reinstall"; "environment"]; List.iter (fun d -> let src = switch_dir / d in let dst = meta_dir / d in if OpamFilename.exists_dir src then OpamFilename.move_dir ~src ~dst) ["backup"; "build"; "install"; "config"; "packages.dev"; "overlay"] ) (OpamFile.Config.installed_switches conf); conf let v1_3_dev7 = OpamVersion.of_string "1.3~dev7" let from_1_3_dev6_to_1_3_dev7 root conf = log "Upgrade switch state files format to 1.3 step 4"; (* Get mirrors of the metadata of all installed packages into switch_meta_dir/packages *) List.iter (fun switch -> let switch_dir = root / OpamSwitch.to_string switch in let meta_dir = switch_dir / ".opam-switch" in let installed = (OpamFile.SwitchSelections.BestEffort.safe_read (OpamFile.make (meta_dir // "switch-state"))) .sel_installed in OpamFilename.mkdir (meta_dir / "packages"); OpamPackage.Set.iter (fun nv -> let dstdir = meta_dir / "packages" / OpamPackage.to_string nv in try let srcdir = List.find (fun d -> OpamFilename.exists (d // "opam")) [ meta_dir / "overlay" / OpamPackage.Name.to_string nv.name; root / "packages" / OpamPackage.Name.to_string nv.name / OpamPackage.to_string nv; ] in match OpamFileTools.read_opam srcdir with | Some opam -> OpamFile.OPAM.write (OpamFile.make (dstdir // "opam")) opam; OpamStd.Option.iter (fun src -> OpamFilename.copy_dir ~src ~dst:(dstdir / "files")) (OpamFilename.opt_dir (srcdir / "files")) | None -> raise Not_found with Not_found -> OpamFile.OPAM.write (OpamFile.make (dstdir // "opam")) (OpamFile.OPAM.create nv) ) installed) (OpamFile.Config.installed_switches conf); OpamFilename.rmdir (root / "packages"); OpamFilename.rmdir (root / "packages.dev"); OpamFilename.rmdir (root / "state.cache"); conf let v2_0_alpha = OpamVersion.of_string "2.0~alpha" let from_1_3_dev7_to_2_0_alpha root conf = log "Upgrade switch state files format to 2.0~alpha"; (* leftovers from previous upgrades *) OpamFilename.rmdir (root / "compilers"); OpamFilename.remove (root / "repo" // "package-index"); OpamFilename.remove (root / "repo" // "compiler-index"); (* turn repo priorities into an ordered list in ~/.opam/config, repo conf files into a single file repo/repos-config *) let prio_repositories = List.map (fun name -> let conf_file = OpamFile.make (root / "repo" / OpamRepositoryName.to_string name // "config") in let module RCL = OpamFile.Repo_config_legacy in let conf = RCL.read conf_file in OpamFilename.remove (OpamFile.filename conf_file); conf.RCL.repo_priority, name, conf.RCL.repo_url) (OpamFile.Config.repositories conf) in OpamFile.Repos_config.write (OpamPath.repos_config root) (OpamRepositoryName.Map.of_list (List.map (fun (_, r, u) -> r, Some (u,None)) prio_repositories)); let prio_repositories = List.stable_sort (fun (prio1, _, _) (prio2, _, _) -> prio2 - prio1) prio_repositories in let repositories_list = List.map (fun (_, r, _) -> r) prio_repositories in OpamFile.Config.with_repositories repositories_list conf |> OpamFile.Config.with_opam_version v2_0 let v2_0_alpha2 = OpamVersion.of_string "2.0~alpha2" let from_2_0_alpha_to_2_0_alpha2 root conf = List.iter (fun switch -> let switch_dir = root / OpamSwitch.to_string switch in let meta_dir = switch_dir / ".opam-switch" in (* Cleanup exported variables from the switch config (they are now defined in wrapper package 'ocaml', and accessed as e.g. 'ocaml:native-dynlink') *) let to_remove_vars = List.map OpamVariable.of_string [ "ocaml-version"; "compiler"; "preinstalled"; "ocaml-native"; "ocaml-native-tools"; "ocaml-native-dynlink"; "ocaml-stubsdir"; ] in let remove_vars config = OpamFile.Dot_config.with_vars (List.filter (fun (var, _) -> not (List.mem var to_remove_vars)) (OpamFile.Dot_config.bindings config)) config in let switch_config_f = OpamFile.make (meta_dir / "config" // "global-config.config") in let switch_config = OpamFile.Dot_config.safe_read switch_config_f in OpamFile.Dot_config.write switch_config_f (remove_vars switch_config); (* Rename the 'ocaml' compiler packages to their proper instance (and let the wrapper 'ocaml' package be pulled from the repository later on to detect and set the 'ocaml:*' variables *) let selections_file = OpamFile.make (meta_dir // "switch-state") in let selections = OpamFile.SwitchSelections.BestEffort.safe_read selections_file in let new_compilers = OpamPackage.Set.map (fun nv -> if nv.name <> OpamPackage.Name.of_string "ocaml" then nv else let config_f nv = OpamFile.make (meta_dir / "config" // (OpamPackage.Name.to_string nv.name ^ ".config")) in let config = OpamFile.Dot_config.safe_read (config_f nv) in let ocaml_version_var = OpamVariable.of_string "ocaml-version" in let ocaml_version = match OpamFile.Dot_config.variable switch_config ocaml_version_var with | Some (S v) -> OpamPackage.Version.of_string v | _ -> match OpamFile.Dot_config.variable config ocaml_version_var with | Some (S v) -> OpamPackage.Version.of_string v | _ -> nv.version in let full_version = OpamPackage.Version.to_string nv.version in let name, version = match OpamStd.String.cut_at full_version '+' with | None when full_version = "system" -> OpamPackage.Name.of_string "ocaml-system", ocaml_version | None -> OpamPackage.Name.of_string "ocaml-base-compiler", ocaml_version | Some (_version, _variant) -> OpamPackage.Name.of_string "ocaml-variants", OpamPackage.Version.of_string full_version in let new_nv = OpamPackage.create name version in let pkgdir nv = meta_dir / "packages" / OpamPackage.to_string nv in if OpamFilename.exists_dir (pkgdir nv) then OpamFilename.move_dir ~src:(pkgdir nv) ~dst:(pkgdir new_nv); OpamStd.Option.Op.( OpamFilename.opt_file (pkgdir new_nv // "opam") >>| OpamFile.make >>= fun f -> OpamFile.OPAM.read_opt f >>| opam_file_from_1_2_to_2_0 ~filename:f >>| OpamFile.OPAM.write_with_preserved_format f ) |> ignore; if OpamFile.exists (config_f nv) then (OpamFile.Dot_config.write (config_f new_nv) (remove_vars config); OpamFilename.remove (OpamFile.filename (config_f nv))); let install_f nv = meta_dir / "install" // (OpamPackage.Name.to_string nv.name ^ ".install") in if OpamFilename.exists (install_f nv) then OpamFilename.move ~src:(install_f nv) ~dst:(install_f new_nv); let changes_f nv = meta_dir / "install" // (OpamPackage.Name.to_string nv.name ^ ".changes") in if OpamFilename.exists (changes_f nv) then OpamFilename.move ~src:(changes_f nv) ~dst:(changes_f new_nv); new_nv ) selections.sel_compiler in let selections = let open OpamPackage.Set.Op in { selections with sel_installed = selections.sel_installed -- selections.sel_compiler ++ new_compilers; sel_roots = selections.sel_roots -- selections.sel_compiler ++ new_compilers; sel_compiler = new_compilers } in OpamFile.SwitchSelections.write selections_file selections; (* Update pinned overlay opam files *) OpamPackage.Set.iter (fun nv -> let pkg_dir = meta_dir / "overlay" / OpamPackage.Name.to_string nv.name in let opamf = pkg_dir // "opam" in let opam0 = OpamFile.make opamf in OpamStd.Option.iter (fun opam -> opam_file_from_1_2_to_2_0 ~filename:opam0 opam |> OpamFile.OPAM.write_with_preserved_format opam0; OpamFilename.remove (pkg_dir // "descr"); OpamFilename.remove (pkg_dir // "url") ) (OpamFileTools.read_opam pkg_dir) ) selections.sel_pinned; ) (OpamFile.Config.installed_switches conf); OpamFile.Config.with_eval_variables [ OpamVariable.of_string "sys-ocaml-version", ["ocamlc"; "-vnum"], "OCaml version present on your system independently of opam, if any"; ] conf let v2_0_alpha3 = OpamVersion.of_string "2.0~alpha3" let from_2_0_alpha2_to_2_0_alpha3 root conf = List.iter (fun switch -> let switch_dir = root / OpamSwitch.to_string switch in let old_global_config = switch_dir / ".opam-switch" / "config" // "global-config.config" in match OpamFile.Dot_config.read_opt (OpamFile.make old_global_config) with | None -> () | Some oldconf -> let new_config_file = switch_dir / ".opam-switch" // "switch-config" in let opam_root, paths, variables = List.fold_left (fun (root, paths, variables) (var, value) -> match OpamVariable.to_string var, value with | "root", S r -> (Some (OpamFilename.Dir.of_string r), paths, variables) | stdpath, S d when (try ignore (std_path_of_string stdpath); true with Failure _ -> false) -> root, (std_path_of_string stdpath, d) :: paths, variables | _, value -> root, paths, (var, value) :: variables) (None, [], []) (OpamFile.Dot_config.bindings oldconf) in let new_config = { OpamFile.Switch_config. opam_version = OpamVersion.nopatch v2_0_alpha3; synopsis = ""; repos = None; opam_root; paths; variables; wrappers = OpamFile.Wrappers.empty; env = []; invariant = None; depext_bypass = OpamSysPkg.Set.empty; } in OpamFile.Switch_config.write (OpamFile.make new_config_file) new_config; OpamFilename.remove old_global_config ) (OpamFile.Config.installed_switches conf); conf let v2_0_beta = OpamVersion.of_string "2.0~beta" let from_2_0_alpha3_to_2_0_beta root conf = List.iter (fun switch -> let switch_meta_dir = root / OpamSwitch.to_string switch / ".opam-switch" in let packages_dev_dir = switch_meta_dir / "packages.dev" in (* old *) let sources_dir = switch_meta_dir / "sources" in (* new *) let state = OpamFile.SwitchSelections.BestEffort.safe_read (OpamFile.make (switch_meta_dir // "switch-state")) in OpamFilename.mkdir sources_dir; List.iter (fun d -> try let name = OpamPackage.Name.of_string OpamFilename.(Base.to_string (basename_dir d)) in let dst = if OpamPackage.has_name state.sel_pinned name then sources_dir / OpamPackage.Name.to_string name else let nv = OpamPackage.package_of_name state.sel_installed name in sources_dir / OpamPackage.to_string nv in (* Extract version-pinned archives to source dirs *) match OpamFilename.files d with | file::[] when OpamFilename.is_archive file -> OpamFilename.extract_in file dst; OpamFilename.remove file | _ -> () with Failure _ | Not_found -> () ) (OpamFilename.dirs packages_dev_dir); OpamFilename.rmdir packages_dev_dir; ) (OpamFile.Config.installed_switches conf); (if OpamFile.Config.default_compiler conf <> Empty then conf else OpamFile.Config.with_default_compiler (OpamFormula.ors [ OpamFormula.Atom (OpamPackage.Name.of_string "ocaml-system", OpamFormula.Atom (`Geq, OpamPackage.Version.of_string "4.02.3")); OpamFormula.Atom (OpamPackage.Name.of_string "ocaml-base-compiler", OpamFormula.Empty); ]) conf) |> OpamFile.Config.with_eval_variables ((OpamVariable.of_string "arch", ["uname"; "-m"], "Host architecture, as returned by 'uname -m'") :: OpamFile.Config.eval_variables conf) let v2_0_beta5 = OpamVersion.of_string "2.0~beta5" let from_2_0_beta_to_2_0_beta5 root conf = List.iter (fun switch -> let switch_meta_dir = root / OpamSwitch.to_string switch / ".opam-switch" in let switch_config = OpamFile.make (switch_meta_dir // "switch-config") in let module C = OpamFile.Switch_config in let config = C.BestEffort.safe_read switch_config in let rem_variables = List.map OpamVariable.of_string ["os"; "make"] in let config = { config with C.variables = List.filter (fun (var,_) -> not (List.mem var rem_variables)) config.C.variables; } in OpamFile.Switch_config.write switch_config config; let opam_files_dirs = OpamFilename.dirs (switch_meta_dir / "packages") @ OpamFilename.dirs (switch_meta_dir / "overlay") in List.iter (fun d -> let opam = OpamFile.make (d // "opam") in try OpamFile.OPAM.read opam |> fun o -> OpamFile.OPAM.with_depexts (upgrade_depexts_to_2_0_beta5 (OpamFile.to_string opam) (OpamFile.OPAM.depexts o)) o |> OpamFile.OPAM.write_with_preserved_format opam with e -> OpamStd.Exn.fatal e) opam_files_dirs ) (OpamFile.Config.installed_switches conf); let rem_eval_variables = List.map OpamVariable.of_string ["arch"] in OpamFile.Config.with_eval_variables (List.filter (fun (v,_,_) -> not (List.mem v rem_eval_variables)) (OpamFile.Config.eval_variables conf)) conf let from_2_0_beta5_to_2_0 _ conf = conf (* swiitch config with opam-version 2.1 *) let v2_1_alpha = OpamVersion.of_string "2.1~alpha" (* config with opam-version 2.1 *) let v2_1_alpha2 = OpamVersion.of_string "2.1~alpha2" (* config & sw config downgrade opam-version to 2.0 and add opam root version *) let v2_1_rc = OpamVersion.of_string "2.1~rc" let v2_1 = OpamVersion.of_string "2.1" let from_2_0_to_2_1_alpha _ conf = conf let downgrade_2_1_switches root conf = List.iter (fun switch -> let f = OpamPath.Switch.switch_config root switch in OpamStd.Option.iter (OpamFile.Switch_config.write f) (OpamStateConfig.downgrade_2_1_switch f)) (OpamFile.Config.installed_switches conf); conf let from_2_1_alpha_to_2_1_alpha2 root conf = downgrade_2_1_switches root conf let from_2_1_alpha2_to_v2_1_rc root conf = downgrade_2_1_switches root conf let from_2_1_rc_to_v2_1 _ conf = conf let from_2_0_to_v2_1 _ conf = conf let latest_version = OpamFile.Config.root_version let latest_hard_upgrade = (* to *) v2_0_beta5 (* intermediates roots that need an hard upgrade *) let intermediate_roots = [ v2_1_alpha; v2_1_alpha2; v2_1_rc ] let remove_missing_switches root conf = let exists, missing = List.partition (fun switch -> OpamFilename.exists (OpamFile.filename (OpamPath.Switch.switch_config root switch))) (OpamFile.Config.installed_switches conf) in OpamFile.Config.with_installed_switches exists conf, missing let as_necessary ?reinit requested_lock global_lock root config = let root_version = match OpamFile.Config.opam_root_version_opt config with | Some v -> v | None -> let v = OpamFile.Config.opam_version config in if OpamVersion.compare v v2_0 <> 0 then v else try List.iter (fun switch -> ignore @@ OpamFile.Switch_config.read_opt (OpamPath.Switch.switch_config root switch)) (OpamFile.Config.installed_switches config); v with Sys_error _ | OpamPp.Bad_version _ -> v2_1_alpha in let cmp = OpamVersion.(compare OpamFile.Config.root_version root_version) in if cmp <= 0 then config (* newer or same *) else let is_intermdiate_root = List.mem root_version intermediate_roots in let keep_needed_upgrades = List.filter (fun (v,_) -> OpamVersion.compare root_version v < 0) in (* to generalise *) let intermediates = let hard = [ v2_1_alpha, from_2_0_to_2_1_alpha; v2_1_alpha2, from_2_1_alpha_to_2_1_alpha2; v2_1_rc, from_2_1_alpha2_to_v2_1_rc; ] in let light = [ v2_1, from_2_1_rc_to_v2_1; ] in keep_needed_upgrades hard, light in let hard_upg, light_upg = if is_intermdiate_root then intermediates else [ v1_1, from_1_0_to_1_1; v1_2, from_1_1_to_1_2; v1_3_dev2, from_1_2_to_1_3_dev2; v1_3_dev5, from_1_3_dev2_to_1_3_dev5; v1_3_dev6, from_1_3_dev5_to_1_3_dev6; v1_3_dev7, from_1_3_dev6_to_1_3_dev7; v2_0_alpha, from_1_3_dev7_to_2_0_alpha; v2_0_alpha2, from_2_0_alpha_to_2_0_alpha2; v2_0_alpha3, from_2_0_alpha2_to_2_0_alpha3; v2_0_beta, from_2_0_alpha3_to_2_0_beta; v2_0_beta5, from_2_0_beta_to_2_0_beta5; v2_0, from_2_0_beta5_to_2_0; v2_1, from_2_0_to_v2_1; ] |> keep_needed_upgrades |> List.partition (fun (v,_) -> OpamVersion.compare v latest_hard_upgrade <= 0) in let need_hard_upg = hard_upg <> [] in let on_the_fly, global_lock_kind = if not need_hard_upg && requested_lock <> `Lock_write then true, `Lock_read else false, `Lock_write in let erase_plugin_links root = let plugins_bin = OpamPath.plugins_bin root in if OpamFilename.exists_dir plugins_bin then begin List.iter OpamFilename.remove @@ OpamFilename.files_and_links plugins_bin end in let light config = let config = List.fold_left (fun config (v, from) -> from root config |> OpamFile.Config.with_opam_root_version v) config light_upg in if not on_the_fly then begin OpamFile.Config.write (OpamPath.config root) config; erase_plugin_links root; end; config in let hard config = List.fold_left (fun config (v, from) -> let config = from root config |> OpamFile.Config.with_opam_root_version v in (* save the current version to mitigate damage is the upgrade goes wrong afterwards *) OpamFile.Config.write (OpamPath.config root) config; erase_plugin_links root; config) config hard_upg in let config = let config, missing_switches = remove_missing_switches root config in let global = List.filter (OpamSwitch.is_external @> not) missing_switches in if not on_the_fly && global <> [] then OpamConsole.warning "Removing global switch%s %s as %s" (match global with | [_] -> "" | _ -> "es") (OpamStd.Format.pretty_list (List.map (OpamSwitch.to_string @> OpamConsole.colorise `bold @> Printf.sprintf "'%s'") global)) (match global with | [_] -> "it no longer exists" | _ -> "they no longer exist"); config in if hard_upg = [] && light_upg = [] then config (* no upgrade to do *) else let is_dev = OpamVersion.is_dev_version () in log "%s config upgrade, from %s to %s" (if on_the_fly then "On-the-fly" else if need_hard_upg then "Hard" else "Light") (OpamVersion.to_string root_version) (OpamVersion.to_string latest_version); if not on_the_fly then OpamConsole.errmsg "%s\n" @@ OpamStd.Format.reformat @@ Printf.sprintf "This %sversion of opam requires an update to the layout of %s \ from version %s to version %s, which can't be reverted.\n\ You may want to back it up before going further.\n" (if is_dev then "development " else "") (OpamFilename.Dir.to_string root) (OpamVersion.to_string root_version) (OpamVersion.to_string latest_version); let dontblock = (* Deadlock until one is killed in interactive mode, but abort in batch *) if OpamStd.Sys.tty_out then None else Some true in try OpamFilename.with_flock_upgrade global_lock_kind ?dontblock global_lock @@ fun _ -> if not on_the_fly then if need_hard_upg then if is_dev && Some "yes" = OpamConsole.read "Type \"yes\" to perform the update and continue:" || not is_dev && OpamConsole.confirm "Perform the update and continue?" then let config = hard config |> light in OpamConsole.msg "Format upgrade done.\n"; (* We need to re run init in case of hard upgrade *) raise (Upgrade_done (config, reinit)) else OpamStd.Sys.exit_because `Aborted else if OpamConsole.confirm "Continue?" then (let config = light config in OpamConsole.msg "Format upgrade done.\n"; config) else OpamStd.Sys.exit_because `Aborted else (let config = light config in log "Format upgrade done"; config) with OpamSystem.Locked -> OpamConsole.error_and_exit `Locked "Could not acquire lock for performing format upgrade." let hard_upgrade_from_2_1_intermediates ?reinit ?global_lock root = let config_f = OpamPath.config root in let opam_root_version = OpamFile.Config.raw_root_version config_f in match opam_root_version with | Some v when OpamVersion.compare v v2_0 <= 0 || OpamVersion.compare v2_1 v <= 0 -> () (* do nothing, need to reraise parsing exception *) | _ -> log "Intermediate opam root detected%s, launch hard upgrade" (match opam_root_version with None -> "" | Some v -> "("^(OpamVersion.to_string v)^")"); let filename = OpamFile.filename config_f in let opamfile = OpamParser.FullPos.file (OpamFilename.to_string filename) in let opamfile' = let open OpamParserTypes.FullPos in { opamfile with file_contents = List.map (fun item -> match item.pelem with | Variable (({pelem = "opam-version"; _} as opam_v), ({pelem = String "2.1"; _} as v)) -> { item with pelem = Variable ({opam_v with pelem = "opam-version"}, {v with pelem = String "2.0"})} | _ -> item) opamfile.file_contents} in log "Downgrade config opam-version to fix up"; OpamFilename.write filename (OpamPrinter.FullPos.opamfile opamfile'); let config = OpamFile.Config.read config_f in let global_lock = match global_lock with | Some g -> g | None -> OpamFilename.flock `Lock_read (OpamPath.lock root) in (* it will trigger only hard upgrades that won't get back *) ignore @@ as_necessary `Lock_write global_lock root ?reinit (OpamFile.Config.with_opam_root_version v2_1_alpha2 config) let opam_file ?(quiet=false) ?filename opam = let v = OpamFile.OPAM.opam_version opam in if OpamVersion.compare v v2_0_alpha3 < 0 then ((match filename with | Some f when not quiet -> log "Internally converting format of %a from %a to %a" (slog OpamFile.to_string) f (slog OpamVersion.to_string) v (slog OpamVersion.to_string) latest_version | _ -> ()); opam_file_from_1_2_to_2_0 ?filename opam) else opam let opam_file_with_aux ?(quiet=false) ?dir ~files ?filename opam = let opam = OpamFileTools.add_aux_files ?dir ~files_subdir_hashes:files opam in opam_file ~quiet ?filename opam let comp_file ?package ?descr comp = OpamFile.Comp.to_package ?package comp descr |> opam_file_from_1_2_to_2_0 opam-2.1.5/src/state/opamUpdate.ml0000644000175000017500000005250514427463453016066 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamStateTypes open OpamStd.Op open OpamProcess.Job.Op open OpamFilename.Op let log fmt = OpamConsole.log "UPDATE" fmt let slog = OpamConsole.slog let eval_redirect gt repo repo_root = if repo.repo_url.OpamUrl.backend <> `http then None else let redirect = OpamRepositoryPath.repo repo_root |> OpamFile.Repo.safe_read |> OpamFile.Repo.redirect in let redirect = List.fold_left (fun acc (redirect, filter) -> if OpamFilter.opt_eval_to_bool (OpamPackageVar.resolve_global gt) filter then (redirect, filter) :: acc else acc ) [] redirect in match redirect with | [] -> None | (redirect, f) :: _ -> let redirect_url = if OpamStd.String.contains ~sub:"://" redirect then let red = OpamUrl.parse_opt ~handle_suffix:false redirect in if red = None then OpamConsole.error "Ignoring malformed redirection url %s" redirect; red else Some OpamUrl.Op.(repo.repo_url / redirect) in match redirect_url with | Some ru when ru = repo.repo_url -> None | Some ru -> Some (ru, f) | None -> None let repository rt repo = let max_loop = 10 in let gt = rt.repos_global in if repo.repo_url = OpamUrl.empty then Done (fun rt -> rt) else let repo_root = OpamRepositoryState.get_repo_root rt repo in (* Recursively traverse redirection links, but stop after 10 steps or if we cycle back to the initial repo. *) let rec job r n = if n = 0 then (OpamConsole.warning "%s: Too many redirections, stopping." (OpamRepositoryName.to_string repo.repo_name); Done r) else let text = OpamProcess.make_command_text ~color:`blue (OpamRepositoryName.to_string repo.repo_name) OpamUrl.(string_of_backend repo.repo_url.backend) in OpamProcess.Job.with_text text @@ OpamRepository.update r repo_root @@+ fun () -> if n <> max_loop && r = repo then (OpamConsole.warning "%s: Cyclic redirections, stopping." (OpamRepositoryName.to_string repo.repo_name); Done r) else match eval_redirect gt r repo_root with | None -> Done r | Some (new_url, f) -> OpamFilename.cleandir repo_root; let reason = match f with | None -> "" | Some f -> Printf.sprintf " (%s)" (OpamFilter.to_string f) in OpamConsole.note "The repository '%s' will be *%s* redirected to %s%s" (OpamRepositoryName.to_string repo.repo_name) (OpamConsole.colorise `bold "permanently") (OpamUrl.to_string new_url) reason; job { r with repo_url = new_url } (n-1) in job repo max_loop @@+ fun repo -> let repo_file_path = OpamRepositoryPath.repo repo_root in if not (OpamFile.exists repo_file_path) then OpamConsole.warning "The repository '%s' at %s doesn't have a 'repo' file, and might not be \ compatible with this version of opam." (OpamRepositoryName.to_string repo.repo_name) (OpamUrl.to_string repo.repo_url); let repo_file = OpamFile.Repo.safe_read repo_file_path in let repo_file = OpamFile.Repo.with_root_url repo.repo_url repo_file in let repo_vers = OpamStd.Option.default OpamFile.Repo.format_version @@ OpamFile.Repo.opam_version repo_file in if not OpamFormatConfig.(!r.skip_version_checks) && OpamVersion.compare repo_vers OpamVersion.current > 0 then Printf.ksprintf failwith "repository format version is %s, and this is only opam %s" (OpamVersion.to_string repo_vers) (OpamVersion.to_string OpamVersion.current); List.iter (fun (msg, filter) -> if OpamFilter.opt_eval_to_bool (OpamPackageVar.resolve_global gt) filter then OpamConsole.formatted_msg ~indent:4 "%s (at %s): %s\n" (OpamConsole.colorise' [`bold;`green] (OpamRepositoryName.to_string repo.repo_name)) (OpamConsole.colorise `bold (OpamUrl.to_string repo.repo_url)) msg) (OpamFile.Repo.announce repo_file); OpamFilename.make_tar_gz_job (OpamRepositoryPath.tar gt.root repo.repo_name) repo_root @@+ function | Some e -> OpamStd.Exn.fatal e; Printf.ksprintf failwith "Failed to regenerate local repository archive: %s" (Printexc.to_string e) | None -> let opams = OpamRepositoryState.load_opams_from_dir repo.repo_name repo_root in let local_dir = OpamRepositoryPath.root gt.root repo.repo_name in if OpamFilename.exists_dir local_dir then (* Mark the obsolete local directory for deletion once we complete: it's no longer needed once we have a tar.gz *) Hashtbl.add rt.repos_tmp repo.repo_name (lazy local_dir); Done ( (* Return an update function to make parallel execution possible *) fun rt -> { rt with repositories = OpamRepositoryName.Map.add repo.repo_name repo rt.repositories; repos_definitions = OpamRepositoryName.Map.add repo.repo_name repo_file rt.repos_definitions; repo_opams = OpamRepositoryName.Map.add repo.repo_name opams rt.repo_opams; } ) let repositories rt repos = let command repo = OpamProcess.Job.catch (fun ex -> OpamStd.Exn.fatal ex; OpamConsole.error "Could not update repository %S: %s" (OpamRepositoryName.to_string repo.repo_name) (match ex with Failure s -> s | ex -> Printexc.to_string ex); Done ([repo], fun t -> t)) @@ fun () -> repository rt repo @@| fun f -> [], f in let failed, rt_update = OpamParallel.reduce ~jobs:OpamStateConfig.(!r.dl_jobs) ~command ~merge:(fun (failed1, f1) (failed2, f2) -> failed1 @ failed2, f1 @* f2) ~nil:([], fun x -> x) ~dry_run:OpamStateConfig.(!r.dryrun) repos in let rt = rt_update rt in OpamRepositoryState.write_config rt; OpamRepositoryState.Cache.save rt; failed, rt let fetch_dev_package url srcdir ?(working_dir=false) ?subpath nv = let remote_url = OpamFile.URL.url url in let mirrors = remote_url :: OpamFile.URL.mirrors url in let checksum = OpamFile.URL.checksum url in log "updating %a%a" (slog OpamUrl.to_string) remote_url (slog (OpamStd.Option.map_default (fun s -> " ("^s^")") "")) subpath; OpamRepository.pull_tree ~cache_dir:(OpamRepositoryPath.download_cache OpamStateConfig.(!r.root_dir)) (OpamPackage.to_string nv) srcdir checksum ~working_dir ?subpath mirrors @@| OpamRepository.report_fetch_result nv let pinned_package st ?version ?(working_dir=false) name = log "update-pinned-package %s%a" (OpamPackage.Name.to_string name) (slog @@ function true -> " (working dir)" | false -> "") working_dir; let open OpamStd.Option.Op in let root = st.switch_global.root in let overlay_dir = OpamPath.Switch.Overlay.package root st.switch name in let overlay_opam = OpamFileTools.read_opam overlay_dir in match overlay_opam >>| fun opam -> opam, OpamFile.OPAM.url opam with | None | Some (_, None) -> Done ((fun st -> st), false) | Some (opam, Some urlf) -> let url = OpamFile.URL.url urlf in let subpath = OpamFile.URL.subpath urlf in let version = OpamFile.OPAM.version_opt opam ++ version +! OpamPackage.Version.of_string "dev" in let nv = OpamPackage.create name version in let srcdir = OpamPath.Switch.pinned_package root st.switch name in (* Four versions of the metadata: from the old and new versions of the package, from the current overlay, and also the original one from the repo *) let add_extra_files srcdir file opam = if OpamFilename.dirname (OpamFile.filename file) <> srcdir then OpamFileTools.add_aux_files ~files_subdir_hashes:true opam else opam in (* append subpath to source dir to retrieve opam files *) let srcdir_find = OpamStd.Option.map_default (fun x -> OpamFilename.Op.(srcdir / x)) srcdir subpath in let old_source_opam_hash, old_source_opam = match OpamPinned.find_opam_file_in_source name srcdir_find with | None -> None, None | Some f -> Some (OpamHash.compute (OpamFile.to_string f)), try Some (OpamFile.OPAM.read f |> OpamFile.OPAM.with_name name |> add_extra_files srcdir f) with e -> OpamStd.Exn.fatal e; None in let repo_opam = let packages = OpamPackage.Map.filter (fun nv _ -> nv.name = name) st.repos_package_index in (* get the latest version below v *) match OpamPackage.Map.split nv packages with | _, (Some opam), _ -> Some opam | below, None, _ when not (OpamPackage.Map.is_empty below) -> Some (snd (OpamPackage.Map.max_binding below)) | _, None, above when not (OpamPackage.Map.is_empty above) -> Some (snd (OpamPackage.Map.min_binding above)) | _ -> None in (if working_dir then Done () else (match url.OpamUrl.hash with | None -> Done true | Some h -> OpamRepository.current_branch url @@| fun branch -> branch = Some h) @@+ function false -> Done () | true -> OpamRepository.is_dirty ?subpath url @@| function false -> () | true -> OpamConsole.note "Ignoring uncommitted changes in %s%s (`--working-dir' not active)." url.OpamUrl.path (match subpath with None -> "" | Some s -> "/" ^ s)) @@+ fun () -> (* Do the update *) fetch_dev_package urlf srcdir ~working_dir ?subpath nv @@+ fun result -> let new_source_opam = OpamPinned.find_opam_file_in_source name srcdir_find >>= fun f -> let warns, opam_opt = OpamFileTools.lint_file f in let warns, opam_opt = match opam_opt with | Some opam0 -> let opam = OpamFormatUpgrade.opam_file ~quiet:true ~filename:f opam0 in if opam <> opam0 then OpamFileTools.lint opam, Some opam else warns, Some opam0 | None -> warns, opam_opt in if warns <> [] && match old_source_opam_hash with | None -> true | Some h -> not (OpamHash.check_file (OpamFile.to_string f) h) then (OpamConsole.warning "%s opam file from upstream of %s:" (if opam_opt = None then "Fatal errors, not using" else "Failed checks in") (OpamConsole.colorise `bold (OpamPackage.Name.to_string name)); OpamConsole.errmsg "%s\n" (OpamFileTools.warns_to_string warns)); opam_opt >>| OpamFile.OPAM.with_name name >>| add_extra_files srcdir f in let equal_opam a b = let cleanup_opam o = let v = (try Some ((OpamFile.OPAM.version_opt o) +! (OpamSwitchState.get_package st name |> OpamPackage.version)) with Not_found -> None) +! (OpamPackage.Version.of_string "~dev") in o |> OpamFile.OPAM.with_url_opt None |> OpamFile.OPAM.with_version v in OpamFile.OPAM.effectively_equal (cleanup_opam (OpamFormatUpgrade.opam_file a)) (cleanup_opam (OpamFormatUpgrade.opam_file b)) in let changed_opam old new_ = match old, new_ with | None, Some _ -> true | _, None -> false | Some a, Some b -> not (equal_opam a b) in let save_overlay opam = OpamFilename.mkdir overlay_dir; let opam_file = OpamPath.Switch.Overlay.opam root st.switch name in List.iter OpamFilename.remove OpamPath.Switch.Overlay.([ OpamFile.filename opam_file; OpamFile.filename (url root st.switch name); OpamFile.filename (descr root st.switch name); ]); let files_dir = OpamPath.Switch.Overlay.files root st.switch name in OpamFilename.rmdir files_dir; let opam = OpamFile.OPAM.with_url urlf @@ OpamFile.OPAM.with_name name opam in let opam = if OpamFile.OPAM.version_opt opam = None then OpamFile.OPAM.with_version version opam else opam in List.iter (fun (file, rel_file, hash) -> if OpamFilename.exists file && OpamHash.check_file (OpamFilename.to_string file) hash then OpamFilename.copy ~src:file ~dst:(OpamFilename.create files_dir rel_file) else OpamConsole.warning "Ignoring file %s with invalid hash" (OpamFilename.to_string file)) (OpamFile.OPAM.get_extra_files ~repos_roots:(OpamRepositoryState.get_root st.switch_repos) opam); OpamFile.OPAM.write opam_file (OpamFile.OPAM.with_extra_files_opt None opam); opam in match result, new_source_opam with | Result _, Some new_opam when changed_opam old_source_opam new_source_opam && changed_opam overlay_opam new_source_opam -> log "Metadata from the package source of %s changed" (OpamPackage.to_string nv); let interactive_part st = if not (changed_opam old_source_opam overlay_opam) || not (changed_opam repo_opam overlay_opam) then (* No manual changes *) (OpamConsole.formatted_msg "[%s] Installing new package description from upstream %s\n" (OpamConsole.colorise `green (OpamPackage.Name.to_string name)) (OpamUrl.to_string url); let opam = save_overlay new_opam in OpamSwitchState.update_pin nv opam st) else if OpamConsole.formatted_msg "[%s] Conflicting update of the metadata from %s." (OpamConsole.colorise `green (OpamPackage.Name.to_string name)) (OpamUrl.to_string url); OpamConsole.confirm "\nOverride files in %s (there will be a backup)?" (OpamFilename.Dir.to_string overlay_dir) then ( let bak = OpamPath.backup_dir root / (OpamPackage.Name.to_string name ^ ".bak") in OpamFilename.mkdir (OpamPath.backup_dir root); OpamFilename.rmdir bak; OpamFilename.copy_dir ~src:overlay_dir ~dst:bak; OpamConsole.formatted_msg "User metadata backed up in %s\n" (OpamFilename.Dir.to_string bak); let opam = save_overlay new_opam in OpamSwitchState.update_pin nv opam st) else st in Done (interactive_part, true) | (Up_to_date _ | Not_available _), _ -> Done ((fun st -> st), false) | Result _, Some new_opam when not (changed_opam old_source_opam overlay_opam) -> (* The new opam is not _effectively_ different from the old, so no need to confirm, but use it still (e.g. descr may have changed) *) let opam = save_overlay new_opam in Done ((fun st -> {st with opams = OpamPackage.Map.add nv opam st.opams}), true) | Result _, _ -> Done ((fun st -> st), true) let dev_package st ?working_dir nv = log "update-dev-package %a" (slog OpamPackage.to_string) nv; if OpamSwitchState.is_pinned st nv.name && not (OpamSwitchState.is_version_pinned st nv.name) then pinned_package st ~version:nv.version ?working_dir nv.name else match OpamSwitchState.url st nv with | None -> Done ((fun st -> st), false) | Some url -> if (OpamFile.URL.url url).OpamUrl.backend = `http then Done ((fun st -> st), false) else fetch_dev_package url (OpamSwitchState.source_dir st nv) ?working_dir nv @@| fun result -> (fun st -> st), match result with Result () -> true | _ -> false let dev_packages st ?(working_dir=OpamPackage.Set.empty) packages = log "update-dev-packages"; let command nv = let working_dir = OpamPackage.Set.mem nv working_dir in OpamProcess.Job.ignore_errors ~default:(false, (fun st -> st), OpamPackage.Set.empty) @@ fun () -> dev_package st ~working_dir nv @@| fun (st_update, changed) -> true, st_update, match changed with | true -> OpamPackage.Set.singleton nv | false -> OpamPackage.Set.empty in let merge (ok1, st_update1, set1) (ok2, st_update2, set2) = ok1 && ok2, (fun st -> st_update1 (st_update2 st)), OpamPackage.Set.union set1 set2 in let success, st_update, updated_set = OpamParallel.reduce ~jobs:OpamStateConfig.(!r.dl_jobs) ~command ~merge ~nil:(true, (fun st -> st), OpamPackage.Set.empty) (OpamPackage.Set.elements packages) in let selections0 = OpamSwitchState.selections st in let st = st_update st in let st = OpamSwitchAction.add_to_reinstall st ~unpinned_only:false updated_set in (* The following is needed for pinned packages that may have changed version *) let selections1 = OpamSwitchState.selections st in if selections0 <> selections1 then OpamFile.SwitchSelections.write (OpamPath.Switch.selections st.switch_global.root st.switch) selections1; success, st, updated_set let pinned_packages st ?(working_dir=OpamPackage.Name.Set.empty) names = log "update-pinned-packages"; let command name = let working_dir = OpamPackage.Name.Set.mem name working_dir in OpamProcess.Job.ignore_errors ~default:((fun st -> st), OpamPackage.Name.Set.empty) @@ fun () -> pinned_package st ~working_dir name @@| fun (st_update, changed) -> st_update, match changed with | true -> OpamPackage.Name.Set.singleton name | false -> OpamPackage.Name.Set.empty in let merge (st_update1, set1) (st_update2, set2) = (fun st -> st_update1 (st_update2 st)), OpamPackage.Name.Set.union set1 set2 in let st_update, updates = OpamParallel.reduce ~jobs:(Lazy.force OpamStateConfig.(!r.jobs)) ~command ~merge ~nil:((fun st -> st), OpamPackage.Name.Set.empty) (OpamPackage.Name.Set.elements names) in let st = st_update st in let updates = OpamPackage.Name.Set.fold (fun name acc -> OpamPackage.Set.add (OpamPinned.package st name) acc) updates OpamPackage.Set.empty in OpamSwitchAction.add_to_reinstall st ~unpinned_only:false updates, updates let active_caches st nv = let global_cache = OpamFile.Config.dl_cache st.switch_global.config in let rt = st.switch_repos in let repo_cache = match OpamRepositoryState.find_package_opt rt (OpamSwitchState.repos_list st) nv with | None -> [] | Some (repo, _) -> let repo_def = OpamRepositoryName.Map.find repo rt.repos_definitions in let root_url = match OpamFile.Repo.root_url repo_def with | None -> OpamSystem.internal_error "repo file of unknown origin" | Some u -> u in OpamStd.List.filter_map (fun rel -> if OpamStd.String.contains ~sub:"://" rel then let r = OpamUrl.parse_opt ~handle_suffix:false rel in if r = None then OpamConsole.warning "Invalid cache url %s, skipping" rel; r else Some OpamUrl.Op.(root_url / rel)) (OpamFile.Repo.dl_cache repo_def) in repo_cache @ global_cache let cleanup_source st old_opam_opt new_opam = let open OpamStd.Option.Op in let base_url urlf = let u = OpamFile.URL.url urlf in { u with OpamUrl.hash = None } in let url_remote opam = OpamFile.OPAM.url opam >>| base_url in let new_opam_o = url_remote new_opam in let old_opam_o = old_opam_opt >>= url_remote in let backend u = u.OpamUrl.backend in let clean = match new_opam_o >>| backend, old_opam_o >>| backend with | Some #OpamUrl.version_control, (Some #OpamUrl.version_control | None) -> false | _ -> new_opam_o <> old_opam_o in if clean then OpamFilename.rmdir (OpamSwitchState.source_dir st (OpamFile.OPAM.package new_opam)) let download_package_source st nv dirname = let opam = OpamSwitchState.opam st nv in let cache_dir = OpamRepositoryPath.download_cache st.switch_global.root in let cache_urls = active_caches st nv in let fetch_source_job = match OpamFile.OPAM.url opam with | None -> Done None | Some u -> (OpamRepository.pull_tree (OpamPackage.to_string nv) ~cache_dir ~cache_urls ?subpath:(OpamFile.URL.subpath u) dirname (OpamFile.URL.checksum u) (OpamFile.URL.url u :: OpamFile.URL.mirrors u)) @@| fun r -> Some r in let fetch_extra_source_job (name, u) = function | (_, Not_available _) :: _ as err -> Done err | ret -> (OpamRepository.pull_file_to_cache (OpamPackage.to_string nv ^"/"^ OpamFilename.Base.to_string name) ~cache_dir ~cache_urls (OpamFile.URL.checksum u) (OpamFile.URL.url u :: OpamFile.URL.mirrors u)) @@| fun r -> (OpamFilename.Base.to_string name, r) :: ret in fetch_source_job @@+ function | Some (Not_available _) as r -> Done (r, []) | r -> OpamProcess.Job.seq (List.map fetch_extra_source_job (OpamFile.OPAM.extra_sources opam)) [] @@| fun r1 -> r, r1 opam-2.1.5/src/state/opamUpdate.mli0000644000175000017500000001053414427463453016233 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Synchronisation and downloading of repositories and package sources *) open OpamTypes open OpamStateTypes (* (** Update the given repository from its upstream. Returns a concurrency-safe state update function *) val repository: rw repos_state -> repository -> ('a repos_state -> 'a repos_state) OpamProcess.job *) (** Update the given repositories from their upstream, and returns the updated state. This also saves the updated cached state, and the updated repository config (it may be changed by e.g. redirects). The returned list is the list of repositories for which the update failed. *) val repositories: rw repos_state -> repository list -> repository list * rw repos_state (** [update_dev_packages t] checks for upstream changes for packages first in the switch cache and then in the global cache. Return the packages whose contents have changed upstream. Packages that are members of the [working_dir] and are bound to a local directory under version control are synchronised with its working state, bypassing version control. Side-effect: update the reinstall file, adding installed changed packages to the current switch to-reinstall set. The returned boolean is true if all updates were successful. *) val dev_packages: rw switch_state -> ?working_dir:package_set -> package_set -> bool * rw switch_state * package_set (** Updates a single dev or pinned package from its upstream. If [working_dir] is set, and the package is bound to a local, version-controlled dir, use the working dir state instead of what has been committed to version control. Returns true if changed, false otherwise, and a switch_state update function, applying possible changes in packages metadata *) val dev_package: rw switch_state -> ?working_dir:bool -> package -> ((rw switch_state -> rw switch_state) * bool) OpamProcess.job (** A subset of update_dev_packages that only takes packages names and only works on pinned packages. Also updates the reinstall file of the current switch *) val pinned_packages: rw switch_state -> ?working_dir:name_set -> name_set -> rw switch_state * package_set (** Updates a dev pinned package from its upstream; returns true if changed, false otherwise, and a switch_state update function that applies possible changes in packages metadata. Updates the on-disk overlay *) val pinned_package: rw switch_state -> ?version:version -> ?working_dir:bool -> name -> ((rw switch_state -> rw switch_state) * bool) OpamProcess.job (** Download or synchronise the upstream source for the given package into the given directory. Also places all of the package extra files (that have a known hash) into the cache. For non-VC remotes, verifies the checksum if any. Stops on first error. The extra downloads list is reverted, so that the error is always first if any. Does not print the results as it used to. *) val download_package_source: 'a switch_state -> package -> dirname -> (string download option * (string * string download) list) OpamProcess.job (** [cleanup_source old_opam_option new_opam] checks if the remote URL has changed between [old_opam_option] and [new_opam], and, depending on that, cleans up the source directory of the package ([OpamPath.Switch.sources]) if needed. *) val cleanup_source: 'a switch_state -> OpamFile.OPAM.t option -> OpamFile.OPAM.t -> unit (** Low-level function to retrieve the package source into its local cache *) val fetch_dev_package: OpamFile.URL.t -> dirname -> ?working_dir:bool -> ?subpath:string -> package -> unit download OpamProcess.job opam-2.1.5/src/state/opamSpdxList.ml0000644000175000017500000001630414427463453016413 0ustar stephsteph(* THIS FILE IS GENERATED. See dune file *) open OpamCompat let licenses = OpamStd.String.Set.of_list @@ List.map String.lowercase_ascii @@ [ "0BSD"; "AAL"; "ADSL"; "AFL-1.1"; "AFL-1.2"; "AFL-2.0"; "AFL-2.1"; "AFL-3.0"; "AGPL-1.0"; "AGPL-1.0-only"; "AGPL-1.0-or-later"; "AGPL-3.0"; "AGPL-3.0-only"; "AGPL-3.0-or-later"; "AMDPLPA"; "AML"; "AMPAS"; "ANTLR-PD"; "APAFML"; "APL-1.0"; "APSL-1.0"; "APSL-1.1"; "APSL-1.2"; "APSL-2.0"; "Abstyles"; "Adobe-2006"; "Adobe-Glyph"; "Afmparse"; "Aladdin"; "Apache-1.0"; "Apache-1.1"; "Apache-2.0"; "Artistic-1.0"; "Artistic-1.0-Perl"; "Artistic-1.0-cl8"; "Artistic-2.0"; "BSD-1-Clause"; "BSD-2-Clause"; "BSD-2-Clause-FreeBSD"; "BSD-2-Clause-NetBSD"; "BSD-2-Clause-Patent"; "BSD-3-Clause"; "BSD-3-Clause-Attribution"; "BSD-3-Clause-Clear"; "BSD-3-Clause-LBNL"; "BSD-3-Clause-No-Nuclear-License"; "BSD-3-Clause-No-Nuclear-License-2014"; "BSD-3-Clause-No-Nuclear-Warranty"; "BSD-3-Clause-Open-MPI"; "BSD-4-Clause"; "BSD-4-Clause-UC"; "BSD-Protection"; "BSD-Source-Code"; "BSL-1.0"; "Bahyph"; "Barr"; "Beerware"; "BitTorrent-1.0"; "BitTorrent-1.1"; "BlueOak-1.0.0"; "Borceux"; "CATOSL-1.1"; "CC-BY-1.0"; "CC-BY-2.0"; "CC-BY-2.5"; "CC-BY-3.0"; "CC-BY-4.0"; "CC-BY-NC-1.0"; "CC-BY-NC-2.0"; "CC-BY-NC-2.5"; "CC-BY-NC-3.0"; "CC-BY-NC-4.0"; "CC-BY-NC-ND-1.0"; "CC-BY-NC-ND-2.0"; "CC-BY-NC-ND-2.5"; "CC-BY-NC-ND-3.0"; "CC-BY-NC-ND-4.0"; "CC-BY-NC-SA-1.0"; "CC-BY-NC-SA-2.0"; "CC-BY-NC-SA-2.5"; "CC-BY-NC-SA-3.0"; "CC-BY-NC-SA-4.0"; "CC-BY-ND-1.0"; "CC-BY-ND-2.0"; "CC-BY-ND-2.5"; "CC-BY-ND-3.0"; "CC-BY-ND-4.0"; "CC-BY-SA-1.0"; "CC-BY-SA-2.0"; "CC-BY-SA-2.5"; "CC-BY-SA-3.0"; "CC-BY-SA-4.0"; "CC-PDDC"; "CC0-1.0"; "CDDL-1.0"; "CDDL-1.1"; "CDLA-Permissive-1.0"; "CDLA-Sharing-1.0"; "CECILL-1.0"; "CECILL-1.1"; "CECILL-2.0"; "CECILL-2.1"; "CECILL-B"; "CECILL-C"; "CERN-OHL-1.1"; "CERN-OHL-1.2"; "CNRI-Jython"; "CNRI-Python"; "CNRI-Python-GPL-Compatible"; "CPAL-1.0"; "CPL-1.0"; "CPOL-1.02"; "CUA-OPL-1.0"; "Caldera"; "ClArtistic"; "Condor-1.1"; "Crossword"; "CrystalStacker"; "Cube"; "D-FSL-1.0"; "DOC"; "DSDP"; "Dotseqn"; "ECL-1.0"; "ECL-2.0"; "EFL-1.0"; "EFL-2.0"; "EPL-1.0"; "EPL-2.0"; "EUDatagrid"; "EUPL-1.0"; "EUPL-1.1"; "EUPL-1.2"; "Entessa"; "ErlPL-1.1"; "Eurosym"; "FSFAP"; "FSFUL"; "FSFULLR"; "FTL"; "Fair"; "Frameworx-1.0"; "FreeImage"; "GFDL-1.1"; "GFDL-1.1-only"; "GFDL-1.1-or-later"; "GFDL-1.2"; "GFDL-1.2-only"; "GFDL-1.2-or-later"; "GFDL-1.3"; "GFDL-1.3-only"; "GFDL-1.3-or-later"; "GL2PS"; "GPL-1.0"; "GPL-1.0+"; "GPL-1.0-only"; "GPL-1.0-or-later"; "GPL-2.0"; "GPL-2.0+"; "GPL-2.0-only"; "GPL-2.0-or-later"; "GPL-2.0-with-GCC-exception"; "GPL-2.0-with-autoconf-exception"; "GPL-2.0-with-bison-exception"; "GPL-2.0-with-classpath-exception"; "GPL-2.0-with-font-exception"; "GPL-3.0"; "GPL-3.0+"; "GPL-3.0-only"; "GPL-3.0-or-later"; "GPL-3.0-with-GCC-exception"; "GPL-3.0-with-autoconf-exception"; "Giftware"; "Glide"; "Glulxe"; "HPND"; "HPND-sell-variant"; "HaskellReport"; "IBM-pibs"; "ICU"; "IJG"; "IPA"; "IPL-1.0"; "ISC"; "ImageMagick"; "Imlib2"; "Info-ZIP"; "Intel"; "Intel-ACPI"; "Interbase-1.0"; "JPNIC"; "JSON"; "JasPer-2.0"; "LAL-1.2"; "LAL-1.3"; "LGPL-2.0"; "LGPL-2.0+"; "LGPL-2.0-only"; "LGPL-2.0-or-later"; "LGPL-2.1"; "LGPL-2.1+"; "LGPL-2.1-only"; "LGPL-2.1-or-later"; "LGPL-3.0"; "LGPL-3.0+"; "LGPL-3.0-only"; "LGPL-3.0-or-later"; "LGPLLR"; "LPL-1.0"; "LPL-1.02"; "LPPL-1.0"; "LPPL-1.1"; "LPPL-1.2"; "LPPL-1.3a"; "LPPL-1.3c"; "Latex2e"; "Leptonica"; "LiLiQ-P-1.1"; "LiLiQ-R-1.1"; "LiLiQ-Rplus-1.1"; "Libpng"; "Linux-OpenIB"; "MIT"; "MIT-0"; "MIT-CMU"; "MIT-advertising"; "MIT-enna"; "MIT-feh"; "MITNFA"; "MPL-1.0"; "MPL-1.1"; "MPL-2.0"; "MPL-2.0-no-copyleft-exception"; "MS-PL"; "MS-RL"; "MTLL"; "MakeIndex"; "MirOS"; "Motosoto"; "Multics"; "Mup"; "NASA-1.3"; "NBPL-1.0"; "NCSA"; "NGPL"; "NLOD-1.0"; "NLPL"; "NOSL"; "NPL-1.0"; "NPL-1.1"; "NPOSL-3.0"; "NRL"; "NTP"; "Naumen"; "Net-SNMP"; "NetCDF"; "Newsletr"; "Nokia"; "Noweb"; "Nunit"; "OCCT-PL"; "OCLC-2.0"; "ODC-By-1.0"; "ODbL-1.0"; "OFL-1.0"; "OFL-1.1"; "OGL-UK-1.0"; "OGL-UK-2.0"; "OGL-UK-3.0"; "OGTSL"; "OLDAP-1.1"; "OLDAP-1.2"; "OLDAP-1.3"; "OLDAP-1.4"; "OLDAP-2.0"; "OLDAP-2.0.1"; "OLDAP-2.1"; "OLDAP-2.2"; "OLDAP-2.2.1"; "OLDAP-2.2.2"; "OLDAP-2.3"; "OLDAP-2.4"; "OLDAP-2.5"; "OLDAP-2.6"; "OLDAP-2.7"; "OLDAP-2.8"; "OML"; "OPL-1.0"; "OSET-PL-2.1"; "OSL-1.0"; "OSL-1.1"; "OSL-2.0"; "OSL-2.1"; "OSL-3.0"; "OpenSSL"; "PDDL-1.0"; "PHP-3.0"; "PHP-3.01"; "Parity-6.0.0"; "Plexus"; "PostgreSQL"; "Python-2.0"; "QPL-1.0"; "Qhull"; "RHeCos-1.1"; "RPL-1.1"; "RPL-1.5"; "RPSL-1.0"; "RSA-MD"; "RSCPL"; "Rdisc"; "Ruby"; "SAX-PD"; "SCEA"; "SGI-B-1.0"; "SGI-B-1.1"; "SGI-B-2.0"; "SHL-0.5"; "SHL-0.51"; "SISSL"; "SISSL-1.2"; "SMLNJ"; "SMPPL"; "SNIA"; "SPL-1.0"; "SSPL-1.0"; "SWL"; "Saxpath"; "Sendmail"; "Sendmail-8.23"; "SimPL-2.0"; "Sleepycat"; "Spencer-86"; "Spencer-94"; "Spencer-99"; "StandardML-NJ"; "SugarCRM-1.1.3"; "TAPR-OHL-1.0"; "TCL"; "TCP-wrappers"; "TMate"; "TORQUE-1.1"; "TOSL"; "TU-Berlin-1.0"; "TU-Berlin-2.0"; "UPL-1.0"; "Unicode-DFS-2015"; "Unicode-DFS-2016"; "Unicode-TOU"; "Unlicense"; "VOSTROM"; "VSL-1.0"; "Vim"; "W3C"; "W3C-19980720"; "W3C-20150513"; "WTFPL"; "Watcom-1.0"; "Wsuipa"; "X11"; "XFree86-1.1"; "XSkat"; "Xerox"; "Xnet"; "YPL-1.0"; "YPL-1.1"; "ZPL-1.1"; "ZPL-2.0"; "ZPL-2.1"; "Zed"; "Zend-2.0"; "Zimbra-1.3"; "Zimbra-1.4"; "Zlib"; "blessing"; "bzip2-1.0.5"; "bzip2-1.0.6"; "copyleft-next-0.3.0"; "copyleft-next-0.3.1"; "curl"; "diffmark"; "dvipdfm"; "eCos-2.0"; "eGenix"; "gSOAP-1.3b"; "gnuplot"; "iMatix"; "libpng-2.0"; "libtiff"; "mpich2"; "psfrag"; "psutils"; "wxWindows"; "xinetd"; "xpp"; "zlib-acknowledgement"; ] let exceptions = OpamStd.String.Set.of_list @@ List.map String.lowercase_ascii @@ [ "Libtool-exception"; "Linux-syscall-note"; "Autoconf-exception-3.0"; "OCCT-exception-1.0"; "openvpn-openssl-exception"; "gnu-javamail-exception"; "OpenJDK-assembly-exception-1.0"; "Bison-exception-2.2"; "i2p-gpl-java-exception"; "Universal-FOSS-exception-1.0"; "Qt-LGPL-exception-1.1"; "389-exception"; "Classpath-exception-2.0"; "Fawkes-Runtime-exception"; "PS-or-PDF-font-exception-20170817"; "Qt-GPL-exception-1.0"; "LZMA-exception"; "freertos-exception-2.0"; "Qwt-exception-1.0"; "CLISP-exception-2.0"; "FLTK-exception"; "Bootloader-exception"; "Nokia-Qt-exception-1.1"; "LLVM-exception"; "WxWindows-exception-3.1"; "DigiRule-FOSS-exception"; "Swift-exception"; "GCC-exception-3.1"; "eCos-exception-2.0"; "Autoconf-exception-2.0"; "GPL-CC-1.0"; "Font-exception-2.0"; "u-boot-exception-2.0"; "GCC-exception-2.0"; "mif-exception"; "OCaml-LGPL-linking-exception"; ] opam-2.1.5/src/state/opamEnv.mli0000644000175000017500000001475614427463453015553 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Process environment setup and handling, shell configuration *) open OpamTypes open OpamStateTypes (** {2 Environment handling} *) (** Get the current environment with OPAM specific additions. If [force_path], the PATH is modified to ensure opam dirs are leading. [set_opamroot] and [set_opamswitch] can be additionally used to set the [OPAMROOT] and [OPAMSWITCH] variables. [scrub] is a list of environment variables to remove from the environment. *) val get_full: set_opamroot:bool -> set_opamswitch:bool -> force_path:bool -> ?updates:env_update list -> ?scrub:string list -> 'a switch_state -> env (** Get only environment modified by OPAM. If [force_path], the PATH is modified to ensure opam dirs are leading. [set_opamroot] and [set_opamswitch] can be additionally used to set the [OPAMROOT] and [OPAMSWITCH] variables. With [base], apply the modifications to the specified base environment *) val get_opam: set_opamroot:bool -> set_opamswitch:bool -> force_path:bool -> 'a switch_state -> env (** Like [get_opam], but reads the cache file from the given opam root and switch instead of computing the environment from a switch state. With [base], apply the modifications to the specified base environment *) val get_opam_raw: set_opamroot:bool -> set_opamswitch:bool -> ?base:env -> force_path:bool -> dirname -> switch -> env (** Returns the running environment, with any opam modifications cleaned out, and optionally the given updates *) val get_pure: ?updates:env_update list -> unit -> env (** Update an environment, including reverting opam changes that could have been previously applied (therefore, don't apply to an already updated env as returned by e.g. [get_full]!) *) val add: env -> env_update list -> env (** Like [get_opam] computes environment modification by OPAM , but returns these [updates] instead of the new environment. *) val updates: set_opamroot:bool -> set_opamswitch:bool -> ?force_path:bool -> 'a switch_state -> env_update list (** Check if the shell environment is in sync with the current OPAM switch, unless [skip] is true (it's default value is OPAMNOENVNOTICE *) val is_up_to_date: ?skip:bool -> 'a switch_state -> bool (** Check if the shell environment is in sync with the given opam root and switch (or if OPAMNOENVNOTICE has been set, in which case we just assume it's up to date) *) val is_up_to_date_switch: dirname -> switch -> bool (** Returns the current environment updates to configure the current switch with its set of installed packages *) val compute_updates: ?force_path:bool -> 'a switch_state -> env_update list (** Returns shell-appropriate statement to evaluate [cmd]. *) val shell_eval_invocation: OpamTypes.shell -> string -> string (** Returns "opam env" invocation string together with optional root and switch overrides *) val opam_env_invocation: ?root:string -> ?switch:string -> ?set_opamswitch:bool -> unit -> string (** The shell command to run by the user to set his OPAM environment, adapted to the current shell (as returned by [eval `opam config env`]) *) val eval_string: 'a global_state -> ?set_opamswitch:bool -> switch option -> string (** Returns the updated contents of the PATH variable for the given opam root and switch (set [force_path] to ensure the opam path is leading) *) val path: force_path:bool -> dirname -> switch -> string (** Returns the full environment with only the PATH variable updated, as per [path] *) val full_with_path: force_path:bool -> ?updates:env_update list -> dirname -> switch -> env (** Performs variable expansion on the strings in an environment update *) val env_expansion: ?opam:OpamFile.OPAM.t -> 'a switch_state -> env_update -> env_update (** {2 Shell and initialisation support} *) (** Sets the opam configuration in the user shell, after detailing the process and asking the user if either [update_config] or [shell_hook] are unset *) val setup: dirname -> interactive:bool -> ?dot_profile:filename -> ?update_config:bool -> ?env_hook:bool -> ?completion:bool -> ?inplace:bool -> shell -> unit (* (\** Display the global and user configuration for OPAM. *\) * val display_setup: dirname -> dot_profile:filename -> shell -> unit *) (** Update the user configuration in $HOME for good opam integration. *) val update_user_setup: dirname -> ?dot_profile:filename -> shell -> unit (** Write the generic scripts in ~/.opam/opam-init needed to import state for various shells. If specified, completion and env_hook files can also be written or removed (the default is to keep them as they are). If [inplace] is true, they are updated if they exist. *) val write_static_init_scripts: dirname -> ?completion:bool -> ?env_hook:bool -> ?inplace:bool -> unit -> unit (** Write into [OpamPath.hooks_dir] the given custom scripts (listed as (filename, content)), normally provided by opamrc ([OpamFile.InitConfig]) *) val write_custom_init_scripts: dirname -> (string * string) list -> unit (** Update the shell scripts containing the current switch configuration in ~/.opam/opam-init ; prints a warning and skips if a write lock on the global state can't be acquired (note: it would be better to acquire a write lock beforehand, but only when working on the switch selected in ~/.opam/config) *) val write_dynamic_init_scripts: 'a switch_state -> unit (** Removes the dynamic init scripts setting the variables for any given switch. *) val clear_dynamic_init_scripts: rw global_state -> unit (** Print a warning if the environment is not set-up properly. (General message) *) val check_and_print_env_warning: 'a switch_state -> unit (** Hook directory environment *) val hook_env: OpamPath.t -> OpamVariable.variable_contents option OpamVariable.Map.t opam-2.1.5/src/state/opamSysPoll.mli0000644000175000017500000000326414427463453016420 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2017-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** This module polls various aspects of the host, to define the [arch], [os], etc. variables *) val arch: unit -> string option val os: unit -> string option val os_distribution: unit -> string option val os_version: unit -> string option val os_family: unit -> string option val variables: (OpamVariable.t * OpamTypes.variable_contents option Lazy.t) list (** The function used internally to get our canonical names for architectures (returns its input lowercased if not a recognised arch). This is typically called on the output of [uname -m] *) val normalise_arch: string -> string (** The function used internally to get our canonical names for OSes (returns its input lowercased if not a recognised OS). This is typically called on the output of [uname -s] *) val normalise_os: string -> string (* Number of cores *) val cores: unit -> int (** Returns a string containing arch, os, os-distribution & os-version values, unknown if they are not available *) val to_string: unit -> string opam-2.1.5/src/state/opamSwitchAction.ml0000644000175000017500000002216214427463453017237 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamStateTypes open OpamPackage.Set.Op let log fmt = OpamConsole.log "SWACT" fmt let slog = OpamConsole.slog let gen_switch_config root ?(synopsis="") ?repos ?invariant _switch = let vars = List.map (fun (s,p) -> OpamVariable.of_string s, S p) [ ("user" , try (Unix.getpwuid (Unix.getuid ())).Unix.pw_name with Not_found -> "user"); ("group", try (Unix.getgrgid (Unix.getgid ())).Unix.gr_name with Not_found -> "group"); ] in { OpamFile.Switch_config. opam_version = OpamFile.Switch_config.file_format_version; synopsis; variables = vars; paths = []; opam_root = Some root; repos; wrappers = OpamFile.Wrappers.empty; env = []; invariant; depext_bypass = OpamSysPkg.Set.empty; } let install_switch_config root switch config = log "install_switch_config switch=%a" (slog OpamSwitch.to_string) switch; OpamFile.Switch_config.write (OpamPath.Switch.switch_config root switch) config let create_empty_switch gt ?synopsis ?repos ?invariant switch = log "create_empty_switch at %a" (slog OpamSwitch.to_string) switch; let root = gt.root in let switch_dir = OpamPath.Switch.root root switch in (* Do some clean-up if necessary *) if OpamFilename.exists_dir switch_dir then failwith (Printf.sprintf "Directory %s already exists" (OpamFilename.Dir.to_string switch_dir)); try (* Create base directories *) OpamFilename.mkdir switch_dir; let config = gen_switch_config root ?synopsis ?repos ?invariant switch in OpamFilename.mkdir (OpamPath.Switch.lib_dir root switch config); OpamFilename.mkdir (OpamPath.Switch.stublibs root switch config); OpamFilename.mkdir (OpamPath.Switch.toplevel root switch config); OpamFilename.mkdir (OpamPath.Switch.build_dir root switch); OpamFilename.mkdir (OpamPath.Switch.bin root switch config); OpamFilename.mkdir (OpamPath.Switch.sbin root switch config); OpamFilename.mkdir (OpamPath.Switch.doc_dir root switch config); OpamFilename.mkdir (OpamPath.Switch.man_dir root switch config); OpamFilename.mkdir (OpamPath.Switch.install_dir root switch); OpamFilename.mkdir (OpamPath.Switch.config_dir root switch); List.iter (fun num -> OpamFilename.mkdir (OpamPath.Switch.man_dir ~num root switch config) ) ["1";"1M";"2";"3";"4";"5";"6";"7";"9"]; install_switch_config root switch config; let root_config = OpamFile.Config.with_installed_switches (switch::OpamFile.Config.installed_switches gt.config) gt.config in let gt = { gt with config = root_config } in OpamGlobalState.write gt; gt with e -> if not (OpamConsole.debug ()) then OpamFilename.rmdir switch_dir; raise e let write_selections st = if not OpamStateConfig.(!r.dryrun) then let f = OpamPath.Switch.selections st.switch_global.root st.switch in let env = OpamPath.Switch.environment st.switch_global.root st.switch in OpamFile.SwitchSelections.write f (OpamSwitchState.selections st); OpamFile.Environment.write env (OpamEnv.compute_updates st) let add_to_reinstall st ~unpinned_only packages = log "add-to-reinstall unpinned_only:%b packages:%a" unpinned_only (slog OpamPackage.Set.to_string) packages; let root = st.switch_global.root in let packages = if unpinned_only then OpamPackage.Set.filter (fun nv -> not (OpamPackage.has_name st.pinned nv.name)) packages else packages in let reinstall_file = OpamPath.Switch.reinstall root st.switch in let current_reinstall = OpamFile.PkgList.safe_read reinstall_file in let add_reinst_packages = OpamPackage.packages_of_names st.installed (OpamPackage.names_of_packages packages) in let reinstall = current_reinstall ++ add_reinst_packages in if OpamPackage.Set.equal current_reinstall reinstall then () else if OpamPackage.Set.is_empty reinstall then OpamFilename.remove (OpamFile.filename reinstall_file) else OpamFile.PkgList.write reinstall_file reinstall; { st with reinstall = lazy (Lazy.force st.reinstall ++ add_reinst_packages) } let set_current_switch gt st = if OpamSwitch.is_external st.switch then OpamConsole.error_and_exit `Bad_arguments "Can not set external switch '%s' globally. To set it in the current \ shell use:\n %s" (OpamSwitch.to_string st.switch) (OpamEnv.eval_string gt ~set_opamswitch:true (Some st.switch)); let config = OpamFile.Config.with_switch st.switch gt.config in let gt = { gt with config } in OpamGlobalState.write gt; let rt = { st.switch_repos with repos_global = gt } in let st = { st with switch_global = gt; switch_repos = rt } in OpamEnv.write_dynamic_init_scripts st; st let install_metadata st nv = OpamSwitchState.Installed_cache.remove (OpamPath.Switch.installed_opams_cache st.switch_global.root st.switch); let opam = OpamSwitchState.opam st nv in OpamFile.OPAM.write (OpamPath.Switch.installed_opam st.switch_global.root st.switch nv) opam; List.iter (fun (f, rel_path, _hash) -> let dst = OpamFilename.create (OpamPath.Switch.installed_opam_files_dir st.switch_global.root st.switch nv) rel_path in OpamFilename.mkdir (OpamFilename.dirname dst); OpamFilename.copy ~src:f ~dst) (OpamFile.OPAM.get_extra_files ~repos_roots:(OpamRepositoryState.get_root st.switch_repos) opam) let remove_metadata st packages = OpamSwitchState.Installed_cache.remove (OpamPath.Switch.installed_opams_cache st.switch_global.root st.switch); OpamPackage.Set.iter (fun nv -> OpamFilename.rmdir (OpamPath.Switch.installed_package_dir st.switch_global.root st.switch nv)) packages let update_switch_state ?installed ?installed_roots ?reinstall ?pinned st = let open OpamStd.Option.Op in let open OpamPackage.Set.Op in let installed = installed +! st.installed in let reinstall0 = Lazy.force st.reinstall in let reinstall = (reinstall +! reinstall0) %% installed in let compiler_packages = OpamPackage.Set.filter (OpamFormula.verifies st.switch_invariant) installed in let old_selections = OpamSwitchState.selections st in let st = { st with installed; installed_roots = installed_roots +! st.installed_roots; reinstall = lazy reinstall; pinned = pinned +! st.pinned; compiler_packages; } in if not OpamStateConfig.(!r.dryrun) then ( if OpamSwitchState.selections st <> old_selections then write_selections st; if not (OpamPackage.Set.equal reinstall0 reinstall) then OpamFile.PkgList.write (OpamPath.Switch.reinstall st.switch_global.root st.switch) (OpamPackage.Set.filter (OpamSwitchState.is_dev_package st) reinstall) ); st let add_to_installed st ?(root=false) nv = let st = update_switch_state st ~installed:(OpamPackage.Set.add nv st.installed) ~reinstall:(OpamPackage.Set.remove nv (Lazy.force st.reinstall)) ~installed_roots: (let roots = OpamPackage.Set.filter (fun nv1 -> nv1.name <> nv.name) st.installed_roots in if root then OpamPackage.Set.add nv roots else st.installed_roots) in let opam = OpamSwitchState.opam st nv in let conf = OpamFile.Dot_config.safe_read (OpamPath.Switch.config st.switch_global.root st.switch nv.name) in let st = { st with conf_files = OpamPackage.Name.Map.add nv.name conf st.conf_files } in if not OpamStateConfig.(!r.dryrun) then ( install_metadata st nv; if OpamFile.OPAM.env opam <> [] && OpamSwitchState.is_switch_globally_set st then OpamEnv.write_dynamic_init_scripts st; ); st let remove_from_installed ?(keep_as_root=false) st nv = let rm = OpamPackage.Set.remove nv in let st = update_switch_state st ~installed:(rm st.installed) ?installed_roots:(if keep_as_root then None else Some (rm st.installed_roots)) ~reinstall:(rm (Lazy.force st.reinstall)) in let has_setenv = match OpamStd.Option.map OpamFile.OPAM.env (OpamSwitchState.opam_opt st nv) with Some (_::_) -> true | _ -> false in if not OpamStateConfig.(!r.dryrun) && has_setenv && OpamSwitchState.is_switch_globally_set st then (* note: don't remove_metadata just yet *) OpamEnv.write_dynamic_init_scripts st; { st with conf_files = OpamPackage.Name.Map.remove nv.name st.conf_files } opam-2.1.5/src/repository/0002755000175000017500000000000014427463453014527 5ustar stephstephopam-2.1.5/src/repository/opamDownload.ml0000644000175000017500000001573314427463453017514 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamProcess.Job.Op let log fmt = OpamConsole.log "CURL" fmt exception Download_fail of string option * string let fail (s,l) = raise (Download_fail (s,l)) let user_agent = CString (Printf.sprintf "opam/%s" (OpamVersion.(to_string current))) let curl_args = [ CString "--write-out", None; CString "%%{http_code}\\n", None; CString "--retry", None; CIdent "retry", None; CString "--retry-delay", None; CString "2", None; CString "--compressed", Some (FIdent (OpamFilter.ident_of_string "compress")); CString "--user-agent", None; user_agent, None; CString "-L", None; CString "-o", None; CIdent "out", None; CString "--", None; (* End list of options *) CIdent "url", None; ] let wget_args = [ CString "--content-disposition", None; CString "-t", None; CIdent "retry", None; CString "-O", None; CIdent "out", None; CString "-U", None; user_agent, None; CString "--", None; (* End list of options *) CIdent "url", None; ] let fetch_args = [ CString "-o", None; CIdent "out", None; CString "--user-agent", None; user_agent, None; CString "--", None; (* End list of options *) CIdent "url", None; ] let ftp_args = [ CString "-o", None; CIdent "out", None; CString "-U", None; user_agent, None; CString "--", None; (* End list of options *) CIdent "url", None; ] let download_args ~url ~out ~retry ?checksum ~compress () = let cmd, _ = Lazy.force OpamRepositoryConfig.(!r.download_tool) in let cmd = match cmd with | [(CIdent "wget"), _] -> cmd @ wget_args | [(CIdent "fetch"), _] -> cmd @ fetch_args | [(CIdent "ftp"), _] -> cmd @ ftp_args | [_] -> cmd @ curl_args (* Assume curl if the command is a single arg *) | _ -> cmd in OpamFilter.single_command (fun v -> if not (OpamVariable.Full.is_global v) then None else match OpamVariable.to_string (OpamVariable.Full.variable v) with | ("curl" | "wget" | "fetch" | "ftp") as dl_tool-> Some (S dl_tool) | "url" -> Some (S (OpamUrl.to_string url)) | "out" -> Some (S out) | "retry" -> Some (S (string_of_int retry)) | "compress" -> Some (B compress) | "opam-version" -> Some (S OpamVersion.(to_string current)) | "checksum" -> OpamStd.Option.map (fun c -> S OpamHash.(to_string c)) checksum | "hashalgo" -> OpamStd.Option.map (fun c -> S OpamHash.(string_of_kind (kind c))) checksum | "hashpath" -> OpamStd.Option.map (fun c -> S (String.concat Filename.dir_sep OpamHash.(to_path c))) checksum | "hashvalue" -> OpamStd.Option.map (fun c -> S OpamHash.(contents c)) checksum | _ -> None) cmd let tool_return url ret = match Lazy.force OpamRepositoryConfig.(!r.download_tool) with | _, `Default -> if OpamProcess.is_failure ret then fail (Some "Download command failed", Printf.sprintf "Download command failed: %s" (OpamProcess.result_summary ret)) else Done () | _, `Curl -> if OpamProcess.is_failure ret then fail (Some "Curl failed", Printf.sprintf "Curl failed: %s" (OpamProcess.result_summary ret)); match ret.OpamProcess.r_stdout with | [] -> fail (Some "curl empty response", Printf.sprintf "curl: empty response while downloading %s" (OpamUrl.to_string url)) | l -> let code = List.hd (List.rev l) in let num = try int_of_string code with Failure _ -> 999 in if num >= 400 then fail (Some ("curl error code " ^ code), Printf.sprintf "curl: code %s while downloading %s" code (OpamUrl.to_string url)) else Done () let download_command ~compress ?checksum ~url ~dst () = let cmd, args = match download_args ~url ~out:dst ~retry:OpamRepositoryConfig.(!r.retries) ?checksum ~compress () with | cmd::args -> cmd, args | [] -> OpamConsole.error_and_exit `Configuration_error "Empty custom download command" in OpamSystem.make_command cmd args @@> tool_return url let really_download ?(quiet=false) ~overwrite ?(compress=false) ?checksum ?(validate=true) ~url ~dst () = assert (url.OpamUrl.backend = `http); let tmp_dst = dst ^ ".part" in if Sys.file_exists tmp_dst then OpamSystem.remove tmp_dst; OpamProcess.Job.catch (function | Failure s as e -> OpamSystem.remove tmp_dst; if not quiet then OpamConsole.error "%s" s; raise e | e -> OpamSystem.remove tmp_dst; OpamStd.Exn.fatal e; log "Could not download file at %s." (OpamUrl.to_string url); raise e) @@ fun () -> download_command ~compress ?checksum ~url ~dst:tmp_dst () @@+ fun () -> if not (Sys.file_exists tmp_dst) then fail (Some "Downloaded file not found", "Download command succeeded, but resulting file not found") else if Sys.file_exists dst && not overwrite then OpamSystem.internal_error "The downloaded file will overwrite %s." dst; if validate && OpamRepositoryConfig.(!r.force_checksums <> Some false) then OpamStd.Option.iter (fun cksum -> if not (OpamHash.check_file tmp_dst cksum) then fail (Some "Bad checksum", Printf.sprintf "Bad checksum, expected %s" (OpamHash.to_string cksum))) checksum; OpamSystem.mv tmp_dst dst; Done () let download_as ?quiet ?validate ~overwrite ?compress ?checksum url dst = match OpamUrl.local_file url with | Some src -> if src = dst then Done () else (if OpamFilename.exists dst then if overwrite then OpamFilename.remove dst else OpamSystem.internal_error "The downloaded file will overwrite %s." (OpamFilename.to_string dst); OpamFilename.copy ~src ~dst; Done ()) | None -> OpamFilename.(mkdir (dirname dst)); really_download ?quiet ~overwrite ?compress ?checksum ?validate ~url ~dst:(OpamFilename.to_string dst) () let download ?quiet ?validate ~overwrite ?compress ?checksum url dstdir = let dst = OpamFilename.(create dstdir (Base.of_string (OpamUrl.basename url))) in download_as ?quiet ?validate ~overwrite ?compress ?checksum url dst @@| fun () -> dst opam-2.1.5/src/repository/opamHTTP.ml0000644000175000017500000000770014427463453016517 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamStd.Op open OpamProcess.Job.Op let log msg = OpamConsole.log "CURL" msg let slog = OpamConsole.slog let index_archive_name = "index.tar.gz" let remote_index_archive url = OpamUrl.Op.(url / index_archive_name) let sync_state name destdir url = OpamFilename.with_tmp_dir_job @@ fun dir -> let local_index_archive = OpamFilename.Op.(dir // index_archive_name) in OpamDownload.download_as ~quiet:true ~overwrite:true (remote_index_archive url) local_index_archive @@+ fun () -> List.iter OpamFilename.rmdir (OpamFilename.dirs destdir); OpamProcess.Job.with_text (Printf.sprintf "[%s: unpacking]" (OpamConsole.colorise `green (OpamRepositoryName.to_string name))) @@ OpamFilename.extract_in_job local_index_archive destdir @@+ function | None -> Done () | Some err -> raise err module B = struct let name = `http let fetch_repo_update repo_name ?cache_dir:_ repo_root url = log "pull-repo-update"; let quarantine = OpamFilename.Dir.(of_string (to_string repo_root ^ ".new")) in OpamFilename.mkdir quarantine; let finalise () = OpamFilename.rmdir quarantine in OpamProcess.Job.catch (fun e -> finalise (); Done (OpamRepositoryBackend.Update_err e)) @@ fun () -> OpamRepositoryBackend.job_text repo_name "sync" (sync_state repo_name quarantine url) @@+ fun () -> if not (OpamFilename.exists_dir repo_root) || OpamFilename.dir_is_empty repo_root then Done (OpamRepositoryBackend.Update_full quarantine) else OpamProcess.Job.finally finalise @@ fun () -> OpamRepositoryBackend.job_text repo_name "diff" (OpamRepositoryBackend.get_diff (OpamFilename.dirname_dir repo_root) (OpamFilename.basename_dir repo_root) (OpamFilename.basename_dir quarantine)) @@| function | None -> OpamRepositoryBackend.Update_empty | Some patch -> OpamRepositoryBackend.Update_patch patch let repo_update_complete _ _ = Done () let pull_url ?cache_dir:_ ?subpath:_ dirname checksum remote_url = log "pull-file into %a: %a" (slog OpamFilename.Dir.to_string) dirname (slog OpamUrl.to_string) remote_url; OpamProcess.Job.catch (fun e -> OpamStd.Exn.fatal e; let s,l = let str = Printf.sprintf "%s (%s)" (OpamUrl.to_string remote_url) in match e with | OpamDownload.Download_fail (s,l) -> s, str l | _ -> Some "Download failed", str "download failed" in Done (Not_available (s,l))) @@ fun () -> OpamDownload.download ~quiet:true ~overwrite:true ?checksum remote_url dirname @@+ fun local_file -> Done (Result (Some local_file)) let revision _ = Done None let sync_dirty ?subpath:_ dir url = pull_url dir None url (* do not propagate *) let get_remote_url ?hash:_ _ = Done None end (* Helper functions used by opam-admin *) let make_index_tar_gz repo_root = OpamFilename.in_dir repo_root (fun () -> let to_include = [ "version"; "packages"; "repo" ] in match List.filter Sys.file_exists to_include with | [] -> () | d -> OpamSystem.command ("tar" :: "czhf" :: "index.tar.gz" :: "--exclude=.git*" :: d) ) opam-2.1.5/src/repository/opamDarcs.ml0000644000175000017500000001674214427463453017002 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamFilename.Op open OpamProcess.Job.Op module VCS = struct let name = `darcs let exists repo_root = OpamFilename.exists_dir (repo_root / "_darcs") let darcs repo_root = let dir = OpamFilename.Dir.to_string repo_root in fun ?verbose ?env ?stdout args -> OpamSystem.make_command ~dir ?verbose ?env ?stdout "darcs" args let with_tag repo_url = match repo_url.OpamUrl.hash with | None -> fun cmd -> cmd | Some t -> fun cmd -> cmd @ [ "-t"; t ] let init repo_root _repo_url = OpamFilename.mkdir repo_root; darcs repo_root [ "init" ] @@> fun r -> OpamSystem.raise_on_process_error r; Done () let vc_dir repo_root = repo_root / "_darcs" (* Darcs has no branches, no proper diff, no way to reset, can't return a workdir diff including added/removed files... That makes it hard for handling as a remote, and the following is a bit convoluted. *) let opam_remote_tag = "opam-remote-tag" (* Marks the last fetched state *) let opam_reverse_commit = "opam-revert-laststate" let opam_local_tag = "opam-local-tag" (* Marks the current state, in the form of a reversing patch on top of the fetched state *) let fetch ?cache_dir:_ ?subpath:_ repo_root repo_url = (* Just do a fresh pull into a temp directory, and replace _darcs/ There is no easy way to diff or make sure darcs forgets about local patches otherwise. *) let repo_str = match OpamUrl.local_dir repo_url with | Some path -> OpamFilename.Dir.to_string path | None -> OpamUrl.base_url repo_url in OpamFilename.with_tmp_dir_job @@ fun d -> let repodir = d / "repo" in darcs repo_root (with_tag repo_url [ "get"; repo_str; "--repodir"; OpamFilename.Dir.to_string repodir; "--quiet"; "--lazy" ]) (* --no-working-dir would be fine, except it is stored in _darcs/format *) @@> fun r -> OpamSystem.raise_on_process_error r; let darcsdir = vc_dir repo_root in OpamFilename.rmdir darcsdir; OpamFilename.move_dir ~src:(vc_dir repodir) ~dst:darcsdir; (* We put the patch that reverts to the current state on top *) darcs repo_root [ "tag"; opam_remote_tag; "-A"; "opam" ] @@> fun r -> OpamSystem.raise_on_process_error r; darcs repo_root [ "record"; "-l"; "--boring"; "--all"; "-m"; opam_reverse_commit; "-A"; "opam" ] @@> fun _r -> (* May fail if patch empty, it's ok, we keep the two tags for comparison *) darcs repo_root [ "tag"; opam_local_tag; "-A"; "opam" ] @@> fun r -> OpamSystem.raise_on_process_error r; Done () let clean repo_root = darcs repo_root [ "obliterate"; "--all"; "-t"; opam_local_tag ] @@> fun r -> OpamSystem.raise_on_process_error r; Done () let reset_tree repo_root _repo_url = clean repo_root @@+ fun () -> darcs repo_root [ "obliterate"; "--all"; "-p"; opam_reverse_commit ] @@> fun r -> (* returns 0 even if patch doesn't exist *) OpamSystem.raise_on_process_error r; Done () let patch_applied _ _ = Done () let revision repo_root = (* 'Weak hash' is only supported from 2.10.3, so provide a fallback *) darcs repo_root [ "show"; "repo" ] @@> fun r -> OpamSystem.raise_on_process_error r; try OpamStd.List.find_map (fun s -> match OpamStd.String.rcut_at s ' ' with | Some (label, value) when OpamStd.String.contains ~sub:"Weak Hash" label -> Some (Done (Some value)) | _ -> None) r.OpamProcess.r_stdout with Not_found -> try OpamStd.List.find_map (fun s -> match OpamStd.String.rcut_at s ' ' with | Some (label, value) when OpamStd.String.contains ~sub:"Num Patches" label -> Some (Done (Some (Printf.sprintf "darcs-%s" value))) | _ -> None) r.OpamProcess.r_stdout with Not_found -> Done None let is_up_to_date repo_root _repo_url = darcs repo_root [ "log"; "-p"; opam_reverse_commit; "--last"; "2" ] (* last 2 since the tag counts as one *) @@> function | { OpamProcess.r_code = 0; _ } -> Done false | { OpamProcess.r_code = 1; _ } as r-> OpamProcess.cleanup ~force:true r; Done true | r -> OpamSystem.process_error r let diff repo_root repo_url = is_up_to_date repo_root repo_url @@+ function | true -> Done None | false -> let patch_file = OpamSystem.temp_file ~auto_clean: false "darcs-diff" in let finalise () = OpamSystem.remove_file patch_file in OpamProcess.Job.catch (fun e -> finalise (); raise e) @@ fun () -> darcs repo_root ~stdout:patch_file [ "diff"; "--from-tag"; opam_remote_tag; "--to-tag"; opam_local_tag; "--diff-command"; "diff -ruNa %2 %1"; "--no-pause-for-gui"; ] (* changing 'from' and 'to' doesn't work, so run a reverse diff command instead*) @@> fun r -> OpamSystem.raise_on_process_error r; if OpamSystem.file_is_empty patch_file then (finalise (); Done None) else Done (Some (OpamFilename.of_string patch_file)) let versioned_files repo_root = darcs repo_root [ "show" ; "files" ] @@> fun r -> OpamSystem.raise_on_process_error r; Done r.OpamProcess.r_stdout let current_branch _dir = Done None (* No branches in Darcs *) let is_dirty ?subpath:_ dir = darcs dir [ "whatsnew"; "--quiet"; "--summary" ] @@> fun r -> Done (OpamProcess.check_success_and_cleanup r) let modified_files repo_root = darcs repo_root [ "whatsnew"; "--summary" ] @@> fun r -> OpamSystem.raise_on_process_error r; let files = OpamStd.List.filter_map (fun line -> match OpamStd.String.split line ' ' with | ("A" | "M")::file::[] | _::"->"::file::[] -> Some file | _ -> None) r.OpamProcess.r_stdout in Done (List.sort_uniq compare files) let get_remote_url ?hash:_ repo_root = darcs repo_root [ "show"; "repo" ] @@> function | { OpamProcess.r_code = 0; _ } as r -> let res = (let valid c e = match OpamStd.String.cut_at (OpamStd.String.strip e) ':' with | Some (p,rhs) when p = c -> Some rhs | _ -> None in match OpamStd.List.filter_map (valid "Cache") r.r_stdout with | [line] -> (let repo = OpamStd.List.filter_map (valid "repo") (OpamStd.String.split line ',') in match repo with | [repo] -> Some repo | _ -> None) | _ -> None) in Done (OpamStd.Option.map (fun u -> OpamUrl.parse ~backend:`darcs u) res) | { OpamProcess.r_code = 1; _ } -> Done None | r -> OpamSystem.process_error r end module B = OpamVCS.Make(VCS) opam-2.1.5/src/repository/opamDownload.mli0000644000175000017500000000300214427463453017647 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2018 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Configuration init and handling of downloading commands *) exception Download_fail of string option * string (** downloads a file from an URL, using Curl, Wget, or a custom configured tool, to the given directory. Returns the downloaded filename. @raise Failure if the download failed or if the checksum is specified and doesn't match*) val download: ?quiet:bool -> ?validate:bool -> overwrite:bool -> ?compress:bool -> ?checksum:OpamHash.t -> OpamUrl.t -> OpamFilename.Dir.t -> OpamFilename.t OpamProcess.job (** As [download], but with a specified output filename. *) val download_as: ?quiet:bool -> ?validate:bool -> overwrite:bool -> ?compress:bool -> ?checksum:OpamHash.t -> OpamUrl.t -> OpamFilename.t -> unit OpamProcess.job opam-2.1.5/src/repository/opamRepositoryPath.ml0000644000175000017500000000431614427463453020734 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamFilename.Op let root root name = root / "repo" / OpamRepositoryName.to_string name let tar root name = root / "repo" // (OpamRepositoryName.to_string name ^ ".tar.gz") let download_cache root = root / "download-cache" let pin_cache_dir = let dir = lazy (OpamSystem.mk_temp_dir ~prefix:"opam-pin-cache" () |> OpamFilename.Dir.of_string ) in fun () -> Lazy.force dir let pin_cache u = pin_cache_dir () / String.sub (OpamHash.contents @@ OpamHash.compute_from_string ~kind:`SHA512 @@ OpamUrl.to_string u) 0 16 let repo repo_root = repo_root // "repo" |> OpamFile.make let packages_dir repo_root = repo_root / "packages" let packages repo_root prefix nv = match prefix with | None -> packages_dir repo_root / OpamPackage.to_string nv | Some p -> packages_dir repo_root / p / OpamPackage.to_string nv let opam repo_root prefix nv = packages repo_root prefix nv // "opam" |> OpamFile.make let descr repo_root prefix nv = packages repo_root prefix nv // "descr" |> OpamFile.make let url repo_root prefix nv = packages repo_root prefix nv // "url" |> OpamFile.make let files repo_root prefix nv = packages repo_root prefix nv / "files" module Remote = struct (** URL, not FS paths *) open OpamUrl.Op let repo root_url = root_url / "repo" let packages_url root_url = root_url / "packages" let archive root_url nv = root_url / "archives" / (OpamPackage.to_string nv ^ "+opam.tar.gz") end opam-2.1.5/src/repository/dune0000644000175000017500000000061014427463453015400 0ustar stephsteph(library (name opam_repository) (public_name opam-repository) (synopsis "OCaml Package Manager remote repository handling library") (libraries opam-format) (flags (:standard (:include ../ocaml-flags-standard.sexp) (:include ../ocaml-flags-configure.sexp) (:include ../ocaml-context-flags.sexp))) (wrapped false)) opam-2.1.5/src/repository/opamHTTP.mli0000644000175000017500000000162114427463453016664 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2016 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Main HTTP repository backend, based on Curl *) module B: OpamRepositoryBackend.S open OpamTypes val make_index_tar_gz: dirname -> unit opam-2.1.5/src/repository/opamRepository.ml0000644000175000017500000004524614427463453020126 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamProcess.Job.Op let log fmt = OpamConsole.log "REPOSITORY" fmt let slog = OpamConsole.slog let find_backend_by_kind = function | `http -> (module OpamHTTP.B: OpamRepositoryBackend.S) | `rsync -> (module OpamLocal.B: OpamRepositoryBackend.S) | `git -> (module OpamGit.B: OpamRepositoryBackend.S) | `hg -> (module OpamHg.B: OpamRepositoryBackend.S) | `darcs -> (module OpamDarcs.B: OpamRepositoryBackend.S) let find_vcs_backend = function | `git -> (module OpamGit.VCS: OpamVCS.VCS) | `hg -> (module OpamHg.VCS: OpamVCS.VCS) | `darcs -> (module OpamDarcs.VCS: OpamVCS.VCS) let url_backend url = find_backend_by_kind url.OpamUrl.backend let find_backend r = url_backend r.repo_url let cache_url root_cache_url checksum = List.fold_left OpamUrl.Op.(/) root_cache_url (OpamHash.to_path checksum) let cache_file cache_dir checksum = let rec aux acc = function | [f] -> OpamFilename.Op.(acc // f) | d::d1 -> aux OpamFilename.Op.(acc / d) d1 | [] -> assert false in aux cache_dir (OpamHash.to_path checksum) let fetch_from_cache = let currently_downloading = ref [] in let rec no_concurrent_dls key f x = if List.mem key !currently_downloading then Run (OpamProcess.command "sleep" ["1"], (fun _ -> no_concurrent_dls key f x)) else (currently_downloading := key :: !currently_downloading; OpamProcess.Job.finally (fun () -> currently_downloading := List.filter (fun k -> k <> key) !currently_downloading) (fun () -> f x)) in fun cache_dir cache_urls checksums -> let mismatch file = OpamConsole.error "Conflicting file hashes, or broken or compromised cache!\n%s" (OpamStd.Format.itemize (fun ck -> OpamHash.to_string ck ^ if OpamHash.check_file (OpamFilename.to_string file) ck then OpamConsole.colorise `green " (match)" else OpamConsole.colorise `red " (MISMATCH)") checksums); OpamFilename.remove file; let m = "cache CONFLICT" in Done (Not_available (Some m, m)) in let dl_from_cache_job root_cache_url checksum file = let url = cache_url root_cache_url checksum in match url.OpamUrl.backend with | `http -> OpamDownload.download_as ~quiet:true ~validate:false ~overwrite:true ~checksum url file | `rsync -> begin match OpamUrl.local_file url with | Some src -> OpamFilename.copy ~src ~dst:file; OpamProcess.Job.Op.Done () | None -> (OpamLocal.rsync_file url file @@| function | Result _ | Up_to_date _-> () | Not_available (s,l) -> raise (OpamDownload.Download_fail (s,l))) end | #OpamUrl.version_control -> failwith "Version control not allowed as cache URL" in try let hit_file = OpamStd.List.find_map (fun ck -> let f = cache_file cache_dir ck in if OpamFilename.exists f then Some f else None) checksums in if List.for_all (fun ck -> OpamHash.check_file (OpamFilename.to_string hit_file) ck) checksums then Done (Up_to_date (hit_file, OpamUrl.empty)) else mismatch hit_file with Not_found -> match checksums with | [] -> let m = "cache miss" in Done (Not_available (Some m, m)) | checksum::_ -> (* Try all cache urls in order, but only the first checksum *) let local_file = cache_file cache_dir checksum in let tmpfile = OpamFilename.add_extension local_file "tmp" in let rec try_cache_dl = function | [] -> let m = "cache miss" in Done (Not_available (Some m, m)) | root_cache_url::other_caches -> OpamProcess.Job.catch (function Failure _ | OpamDownload.Download_fail _ -> try_cache_dl other_caches | e -> raise e) @@ fun () -> dl_from_cache_job root_cache_url checksum tmpfile @@+ fun () -> if List.for_all (OpamHash.check_file (OpamFilename.to_string tmpfile)) checksums then (OpamFilename.move ~src:tmpfile ~dst:local_file; Done (Result (local_file, root_cache_url))) else mismatch tmpfile in no_concurrent_dls checksum try_cache_dl cache_urls let validate_and_add_to_cache label url cache_dir file checksums = try let mismatch, expected = OpamStd.List.find_map (fun c -> match OpamHash.mismatch (OpamFilename.to_string file) c with | Some found -> Some (found, c) | None -> None) checksums in OpamConsole.error "%s: Checksum mismatch for %s:\n\ \ expected %s\n\ \ got %s" label (OpamUrl.to_string url) (OpamHash.to_string expected) (OpamHash.to_string mismatch); OpamFilename.remove file; false with Not_found -> (match cache_dir, checksums with | Some dir, ck::_ -> OpamFilename.copy ~src:file ~dst:(cache_file dir ck) (* idea: hardlink to the other checksums? *) | _ -> ()); true (* [cache_dir] used to add to cache only *) let pull_from_upstream label ?(working_dir=false) ?subpath cache_dir destdir checksums url = let module B = (val url_backend url: OpamRepositoryBackend.S) in let cksum = match checksums with [] -> None | c::_ -> Some c in let text = OpamProcess.make_command_text label (OpamUrl.string_of_backend url.OpamUrl.backend) in OpamProcess.Job.with_text text @@ (if working_dir then B.sync_dirty ?subpath destdir url else let pin_cache_dir = OpamRepositoryPath.pin_cache url in let url, pull = if OpamUrl.(match url.backend with | #version_control -> false | _ -> true) && OpamFilename.exists_dir pin_cache_dir then (log "Pin cache existing for %s : %s\n" (OpamUrl.to_string url) @@ OpamFilename.Dir.to_string pin_cache_dir; let rsync = OpamUrl.parse ~backend:`rsync ~from_file:false @@ OpamFilename.Dir.to_string pin_cache_dir in let pull = let module BR = (val url_backend rsync: OpamRepositoryBackend.S) in BR.pull_url in rsync, pull ) else if OpamUrl.(match url.backend with | `git -> true | _ -> false) && OpamFilename.exists_dir pin_cache_dir then (log "Pin cache (git) existing for %s : %s\n" (OpamUrl.to_string url) @@ OpamFilename.Dir.to_string pin_cache_dir; let git_cached = OpamUrl.parse ~backend:`git @@ OpamFilename.Dir.to_string pin_cache_dir in let pull = let module BR = (val url_backend git_cached: OpamRepositoryBackend.S) in BR.pull_url in git_cached, pull ) else url, B.pull_url in pull ?cache_dir ?subpath destdir cksum url ) @@| function | (Result (Some file) | Up_to_date (Some file)) as ret -> if OpamRepositoryConfig.(!r.force_checksums) = Some false || validate_and_add_to_cache label url cache_dir file checksums then ret else let m = "Checksum mismatch" in Not_available (Some m, m) | (Result None | Up_to_date None) as ret -> ret | Not_available _ as na -> na let pull_from_mirrors label ?working_dir ?subpath cache_dir destdir checksums urls = let rec aux = function | [] -> invalid_arg "pull_from_mirrors: empty mirror list" | [url] -> pull_from_upstream label ?working_dir ?subpath cache_dir destdir checksums url @@| fun r -> url, r | url::mirrors -> pull_from_upstream label ?working_dir ?subpath cache_dir destdir checksums url @@+ function | Not_available (_,s) -> OpamConsole.warning "%s: download of %s failed (%s), trying mirror" label (OpamUrl.to_string url) s; aux mirrors | r -> Done (url, r) in aux urls @@| function | url, (Result None | Up_to_date None) when checksums <> [] -> OpamConsole.error "%s: file checksum specified, but a directory was \ retrieved from %s" label (OpamUrl.to_string url); OpamFilename.rmdir destdir; let m = "can't check directory checksum" in url, Not_available (Some m, m) | ret -> ret let pull_tree label ?cache_dir ?(cache_urls=[]) ?working_dir ?subpath local_dirname checksums remote_urls = let extract_archive f s = OpamFilename.cleandir local_dirname; OpamFilename.extract_job f local_dirname @@+ function | None -> Done (Up_to_date s) | Some (Failure s) -> Done (Not_available (Some s, "Could not extract archive:\n"^s)) | Some (OpamSystem.Process_error pe) -> Done (Not_available (Some (OpamProcess.result_summary pe), OpamProcess.string_of_result pe)) | Some e -> Done (Not_available (None, Printexc.to_string e)) in (match cache_dir with | Some cache_dir -> let text = OpamProcess.make_command_text label "dl" in OpamProcess.Job.with_text text @@ fetch_from_cache cache_dir cache_urls checksums | None -> assert (cache_urls = []); let m = "no cache" in Done (Not_available (Some m, m))) @@+ function | Up_to_date (archive, _) -> extract_archive archive "cached" | Result (archive, url) -> let msg = match url.OpamUrl.backend with | `rsync -> url.OpamUrl.path | _ -> OpamUrl.to_string url in extract_archive archive msg | Not_available _ -> if checksums = [] && OpamRepositoryConfig.(!r.force_checksums = Some true) then Done ( Not_available ( Some ("missing checksum"), label ^ ": Missing checksum, and `--require-checksums` was set.")) else pull_from_mirrors label ?working_dir ?subpath cache_dir local_dirname checksums remote_urls @@+ function | _, Up_to_date None -> Done (Up_to_date "no changes") | url, (Up_to_date (Some archive) | Result (Some archive)) -> OpamFilename.with_tmp_dir_job @@ fun tmpdir -> let tmp_archive = OpamFilename.(create tmpdir (basename archive)) in OpamFilename.move ~src:archive ~dst:tmp_archive; extract_archive tmp_archive (OpamUrl.to_string url) | url, Result None -> Done (Result (OpamUrl.to_string url)) | _, (Not_available _ as na) -> Done na let revision dirname url = let kind = url.OpamUrl.backend in let module B = (val find_backend_by_kind kind: OpamRepositoryBackend.S) in B.revision dirname let pull_file label ?cache_dir ?(cache_urls=[]) ?(silent_hits=false) file checksums remote_urls = (match cache_dir with | Some cache_dir -> let text = OpamProcess.make_command_text label "dl" in OpamProcess.Job.with_text text @@ fetch_from_cache cache_dir cache_urls checksums | None -> assert (cache_urls = []); let m = "no cache" in Done (Not_available (Some m, m))) @@+ function | Up_to_date (f, _) -> if not silent_hits then OpamConsole.msg "[%s] found in cache\n" (OpamConsole.colorise `green label); OpamFilename.copy ~src:f ~dst:file; Done (Result ()) | Result (f, url) -> OpamConsole.msg "[%s] downloaded from %s\n" (OpamConsole.colorise `green label) (OpamUrl.to_string url); OpamFilename.copy ~src:f ~dst:file; Done (Result ()) | Not_available _ -> if checksums = [] && OpamRepositoryConfig.(!r.force_checksums = Some true) then Done ( Not_available (Some "missing checksum", label ^ ": Missing checksum, and `--require-checksums` was set.")) else OpamFilename.with_tmp_dir_job (fun tmpdir -> pull_from_mirrors label cache_dir tmpdir checksums remote_urls @@| function | _, Up_to_date _ -> assert false | _, Result (Some f) -> OpamFilename.move ~src:f ~dst:file; Result () | _, Result None -> let m = "is a directory" in Not_available (Some m, m) | _, (Not_available _ as na) -> na) let pull_file_to_cache label ~cache_dir ?(cache_urls=[]) checksums remote_urls = let text = OpamProcess.make_command_text label "dl" in OpamProcess.Job.with_text text @@ fetch_from_cache cache_dir cache_urls checksums @@+ function | Up_to_date (_, _) -> Done (Up_to_date "cached") | Result (_, url) -> Done (Result (OpamUrl.to_string url)) | Not_available _ -> OpamFilename.with_tmp_dir_job (fun tmpdir -> pull_from_mirrors label (Some cache_dir) tmpdir checksums remote_urls @@| function | _, Up_to_date _ -> assert false | url, Result (Some _) -> Result (OpamUrl.to_string url) | _, Result None -> let m = "is a directory" in Not_available (Some m, m) | _, (Not_available _ as na) -> na) let packages repo_root = OpamPackage.list (OpamRepositoryPath.packages_dir repo_root) let packages_with_prefixes repo_root = OpamPackage.prefixes (OpamRepositoryPath.packages_dir repo_root) let validate_repo_update repo repo_root update = match repo.repo_trust, OpamRepositoryConfig.(!r.validation_hook), OpamRepositoryConfig.(!r.force_checksums) with | None, Some _, Some true -> OpamConsole.error "No trust anchors for repository %s, and security was enforced: \ not updating" (OpamRepositoryName.to_string repo.repo_name); Done false | None, _, _ | _, None, _ | _, _, Some false -> Done true | Some ta, Some hook, _ -> let cmd = let open OpamRepositoryBackend in let env v = match OpamVariable.Full.to_string v, update with | "anchors", _ -> Some (S (String.concat "," ta.fingerprints)) | "quorum", _ -> Some (S (string_of_int ta.quorum)) | "repo", _ -> Some (S (OpamFilename.Dir.to_string repo_root)) | "patch", Update_patch f -> Some (S (OpamFilename.to_string f)) | "incremental", Update_patch _ -> Some (B true) | "incremental", _ -> Some (B false) | "dir", Update_full d -> Some (S (OpamFilename.Dir.to_string d)) | _ -> None in match OpamFilter.single_command env hook with | cmd::args -> OpamSystem.make_command ~name:"validation-hook" ~verbose:OpamCoreConfig.(!r.verbose_level >= 2) cmd args | [] -> failwith "Empty validation hook" in cmd @@> fun r -> log "validation: %s" (OpamProcess.result_summary r); Done (OpamProcess.check_success_and_cleanup r) open OpamRepositoryBackend let apply_repo_update repo repo_root = function | Update_full d -> log "%a: applying update from scratch at %a" (slog OpamRepositoryName.to_string) repo.repo_name (slog OpamFilename.Dir.to_string) d; OpamFilename.rmdir repo_root; if OpamFilename.is_symlink_dir d then (OpamFilename.copy_dir ~src:d ~dst:repo_root; OpamFilename.rmdir d) else OpamFilename.move_dir ~src:d ~dst:repo_root; OpamConsole.msg "[%s] Initialised\n" (OpamConsole.colorise `green (OpamRepositoryName.to_string repo.repo_name)); Done () | Update_patch f -> OpamConsole.msg "[%s] synchronised from %s\n" (OpamConsole.colorise `green (OpamRepositoryName.to_string repo.repo_name)) (OpamUrl.to_string repo.repo_url); log "%a: applying patch update at %a" (slog OpamRepositoryName.to_string) repo.repo_name (slog OpamFilename.to_string) f; let preprocess = match repo.repo_url.OpamUrl.backend with | `http | `rsync -> false | _ -> true in (OpamFilename.patch ~preprocess f repo_root @@+ function | Some e -> if not (OpamConsole.debug ()) then OpamFilename.remove f; raise e | None -> OpamFilename.remove f; Done ()) | Update_empty -> OpamConsole.msg "[%s] no changes from %s\n" (OpamConsole.colorise `green (OpamRepositoryName.to_string repo.repo_name)) (OpamUrl.to_string repo.repo_url); log "%a: applying empty update" (slog OpamRepositoryName.to_string) repo.repo_name; Done () | Update_err _ -> assert false let cleanup_repo_update upd = if not (OpamConsole.debug ()) then match upd with | Update_full d -> OpamFilename.rmdir d | Update_patch f -> OpamFilename.remove f | _ -> () let update repo repo_root = log "update %a" (slog OpamRepositoryBackend.to_string) repo; let module B = (val find_backend repo: OpamRepositoryBackend.S) in B.fetch_repo_update repo.repo_name repo_root repo.repo_url @@+ function | Update_err e -> raise e | Update_empty -> log "update empty, no validation performed"; apply_repo_update repo repo_root Update_empty @@+ fun () -> B.repo_update_complete repo_root repo.repo_url | (Update_full _ | Update_patch _) as upd -> OpamProcess.Job.catch (fun exn -> cleanup_repo_update upd; raise exn) @@ fun () -> validate_repo_update repo repo_root upd @@+ function | false -> cleanup_repo_update upd; failwith "Invalid repository signatures, update aborted" | true -> apply_repo_update repo repo_root upd @@+ fun () -> B.repo_update_complete repo_root repo.repo_url let on_local_version_control url ~default f = match url.OpamUrl.backend with | #OpamUrl.version_control as backend -> (match OpamUrl.local_dir url with | None -> default | Some dir -> f dir (find_vcs_backend backend)) | #OpamUrl.backend -> default let current_branch url = on_local_version_control url ~default:(Done None) @@ fun dir (module VCS) -> VCS.current_branch dir let is_dirty ?subpath url = on_local_version_control url ~default:(Done false) @@ fun dir (module VCS) -> VCS.is_dirty ?subpath dir let report_fetch_result pkg = function | Result msg -> OpamConsole.msg "[%s] synchronised (%s)\n" (OpamConsole.colorise `green (OpamPackage.to_string pkg)) msg; Result () | Up_to_date msg -> OpamConsole.msg "[%s] synchronised (%s)\n" (OpamConsole.colorise `green (OpamPackage.to_string pkg)) msg; Up_to_date () | Not_available (s, l) -> let msg = match s with None -> l | Some s -> s in OpamConsole.msg "[%s] fetching sources failed: %s\n" (OpamConsole.colorise `red (OpamPackage.to_string pkg)) msg; Not_available (s, l) opam-2.1.5/src/repository/opamLocal.ml0000644000175000017500000002107214427463453016770 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase open OpamProcess.Job.Op let log fmt = OpamConsole.log "RSYNC" fmt (* Rsync args recap: - recurse into directories (r) - skip based on checksum, not mod-time & size (c) - preserve permissions (p), times (t), group (g), owner (o), device & special files (D) - transform symlink into referent file/dir (L) *) let rsync_arg = "-rLptgoDvc" (* if rsync -arv return 4 lines, this means that no files have changed *) let rsync_trim = function | [] -> [] | _ :: t -> match List.rev t with | _ :: _ :: _ :: l -> List.filter ((<>) "./") l | _ -> [] let convert_path = OpamSystem.get_cygpath_function ~command:"rsync" let call_rsync check args = OpamSystem.make_command "rsync" args @@> fun r -> match r.OpamProcess.r_code with | 0 -> Done (Some (rsync_trim r.OpamProcess.r_stdout)) | 3 | 5 | 10 | 11 | 12 -> (* protocol or file errors *) Done None | 20 -> (* signal *) raise Sys.Break | 23 | 24 -> (* partial, mostly mode, link or perm errors. But may also be a complete error so we do an additional check *) if check () then (OpamConsole.warning "Rsync partially failed:\n%s" (OpamStd.Format.itemize ~bullet:"" (fun x -> x) r.OpamProcess.r_stderr); Done (Some (rsync_trim r.OpamProcess.r_stdout))) else Done None | 30 | 35 -> (* timeouts *) Done None | _ -> OpamSystem.process_error r let rsync ?(args=[]) ?(exclude_vcdirs=true) src dst = log "rsync: src=%s dst=%s" src dst; let remote = String.contains src ':' in let overlap src dst = let norm d = Filename.concat d "" in OpamStd.String.starts_with ~prefix:(norm src) (norm dst) && not (OpamStd.String.contains ~sub:OpamSwitch.external_dirname (norm dst)) || OpamStd.String.starts_with ~prefix:(norm dst) (norm src) in (* See also [OpamVCS.sync_dirty] *) let exclude_args = (if not exclude_vcdirs then [] else [ "--exclude"; ".git"; "--exclude"; "_darcs"; "--exclude"; ".hg"; ]) @ [ "--exclude"; ".#*"; "--exclude"; OpamSwitch.external_dirname ^ "*"; "--exclude"; "_build"; ] in if not(remote || Sys.file_exists src) then Done (Not_available (None, src)) else if src = dst then Done (Up_to_date []) else if overlap src dst then (OpamConsole.error "Cannot sync %s into %s: they overlap" src dst; Done (Not_available (None, src))) else ( OpamSystem.mkdir dst; let convert_path = Lazy.force convert_path in call_rsync (fun () -> not (OpamSystem.dir_is_empty dst)) ( rsync_arg :: args @ exclude_args @ [ "--delete"; "--delete-excluded"; convert_path src; convert_path dst; ]) @@| function | None -> Not_available (None, src) | Some [] -> Up_to_date [] | Some lines -> Result lines ) let is_remote url = url.OpamUrl.transport <> "file" let rsync_dirs ?args ?exclude_vcdirs url dst = let src_s = OpamUrl.(Op.(url / "").path) in (* Ensure trailing '/' *) let dst_s = OpamFilename.Dir.to_string dst in if not (is_remote url) && not (OpamFilename.exists_dir (OpamFilename.Dir.of_string src_s)) then Done (Not_available (None, Printf.sprintf "Directory %s does not exist" src_s)) else rsync ?args ?exclude_vcdirs src_s dst_s @@| function | Not_available _ as na -> na | Result _ -> if OpamFilename.exists_dir dst then Result dst else Not_available (None, dst_s) | Up_to_date _ -> Up_to_date dst let rsync_file ?(args=[]) url dst = let src_s = url.OpamUrl.path in let dst_s = OpamFilename.to_string dst in log "rsync_file src=%s dst=%s" src_s dst_s; if not (is_remote url || OpamFilename.(exists (of_string src_s))) then Done (Not_available (None, src_s)) else if src_s = dst_s then Done (Up_to_date dst) else (OpamFilename.mkdir (OpamFilename.dirname dst); let convert_path = Lazy.force convert_path in call_rsync (fun () -> Sys.file_exists dst_s) ( rsync_arg :: args @ [ convert_path src_s; convert_path dst_s ]) @@| function | None -> Not_available (None, src_s) | Some [] -> Up_to_date dst | Some [_] -> if OpamFilename.exists dst then Result dst else Not_available (None, src_s) | Some l -> OpamSystem.internal_error "unknown rsync output: {%s}" (String.concat ", " l)) module B = struct let name = `rsync let pull_dir_quiet local_dirname url = rsync_dirs url local_dirname let fetch_repo_update repo_name ?cache_dir:_ repo_root url = log "pull-repo-update"; let quarantine = OpamFilename.Dir.(of_string (to_string repo_root ^ ".new")) in let finalise () = OpamFilename.rmdir quarantine in OpamProcess.Job.catch (fun e -> finalise (); Done (OpamRepositoryBackend.Update_err e)) @@ fun () -> OpamRepositoryBackend.job_text repo_name "sync" (match OpamUrl.local_dir url with | Some dir -> OpamFilename.copy_dir ~src:dir ~dst:quarantine; (* fixme: Would be best to symlink, but at the moment our filename api isn't able to cope properly with the symlinks afterwards OpamFilename.link_dir ~target:dir ~link:quarantine; *) Done (Result quarantine) | None -> if OpamFilename.exists_dir repo_root then OpamFilename.copy_dir ~src:repo_root ~dst:quarantine else OpamFilename.mkdir quarantine; pull_dir_quiet quarantine url) @@+ function | Not_available _ -> finalise (); Done (OpamRepositoryBackend.Update_err (Failure "rsync failed")) | Up_to_date _ -> finalise (); Done OpamRepositoryBackend.Update_empty | Result _ -> if not (OpamFilename.exists_dir repo_root) || OpamFilename.dir_is_empty repo_root then Done (OpamRepositoryBackend.Update_full quarantine) else OpamProcess.Job.finally finalise @@ fun () -> OpamRepositoryBackend.job_text repo_name "diff" @@ OpamRepositoryBackend.get_diff (OpamFilename.dirname_dir repo_root) (OpamFilename.basename_dir repo_root) (OpamFilename.basename_dir quarantine) @@| function | None -> OpamRepositoryBackend.Update_empty | Some p -> OpamRepositoryBackend.Update_patch p let repo_update_complete _ _ = Done () let pull_url ?cache_dir:_ ?subpath local_dirname _checksum remote_url = let local_dirname = OpamStd.Option.map_default (fun x -> OpamFilename.Op.(local_dirname / x)) local_dirname subpath in OpamFilename.mkdir local_dirname; let dir = OpamFilename.Dir.to_string local_dirname in let remote_url = OpamStd.Option.map_default (fun x -> OpamUrl.Op.(remote_url / x)) remote_url subpath in let remote_url = match OpamUrl.local_dir remote_url with | Some _ -> (* ensure that rsync doesn't recreate a subdir: add trailing '/' *) OpamUrl.Op.(remote_url / "") | None -> remote_url in rsync remote_url.OpamUrl.path dir @@| function | Not_available _ as na -> na | (Result _ | Up_to_date _) as r -> let res x = match r with | Result _ -> Result x | Up_to_date _ -> Up_to_date x | _ -> assert false in if OpamUrl.has_trailing_slash remote_url then res None else let filename = OpamFilename.Op.(local_dirname // OpamUrl.basename remote_url) in if OpamFilename.exists filename then res (Some filename) else Not_available (None, Printf.sprintf "Could not find target file %s after rsync with %s. \ Perhaps you meant %s/ ?" (OpamUrl.basename remote_url) (OpamUrl.to_string remote_url) (OpamUrl.to_string remote_url)) let revision _ = Done None let sync_dirty ?subpath dir url = pull_url ?subpath dir None url let get_remote_url ?hash:_ _ = Done None end opam-2.1.5/src/repository/opamDarcs.mli0000644000175000017500000000156214427463453017145 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2016 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Darcs repository backend (based on OpamVCS) *) module VCS: OpamVCS.VCS module B: OpamRepositoryBackend.S opam-2.1.5/src/repository/opamGit.mli0000644000175000017500000000156014427463453016632 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2016 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Git repository backend (based on OpamVCS) *) module VCS: OpamVCS.VCS module B: OpamRepositoryBackend.S opam-2.1.5/src/repository/opamRepositoryConfig.ml0000644000175000017500000001052714427463453021246 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2015-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes module E = struct type OpamStd.Config.E.t += | CURL of string option | FETCH of string option | NOCHECKSUMS of bool option | REQUIRECHECKSUMS of bool option | RETRIES of int option | VALIDATIONHOOK of string option open OpamStd.Config.E let curl = value (function CURL s -> s | _ -> None) let fetch = value (function FETCH s -> s | _ -> None) let nochecksums = value (function NOCHECKSUMS b -> b | _ -> None) let requirechecksums = value (function REQUIRECHECKSUMS b -> b | _ -> None) let retries = value (function RETRIES i -> i | _ -> None) let validationhook = value (function VALIDATIONHOOK s -> s | _ -> None) end type dl_tool_kind = [ `Curl | `Default ] type t = { download_tool: (arg list * dl_tool_kind) Lazy.t; validation_hook: arg list option; retries: int; force_checksums: bool option; } type 'a options_fun = ?download_tool:(OpamTypes.arg list * dl_tool_kind) Lazy.t -> ?validation_hook:arg list option -> ?retries:int -> ?force_checksums:bool option -> 'a let default = { download_tool = lazy ( let os = OpamStd.Sys.os () in try let curl = "curl", `Curl in let tools = match os with | Darwin -> ["wget", `Default; curl] | FreeBSD -> ["fetch", `Default ; curl] | OpenBSD -> ["ftp", `Default; curl] | _ -> [curl; "wget", `Default] in let cmd, kind = List.find (fun (c,_) -> OpamSystem.resolve_command c <> None) tools in [ CIdent cmd, None ], kind with Not_found -> OpamConsole.error_and_exit `Configuration_error "Could not find a suitable download command. Please make sure you \ have %s installed, or specify a custom command through variable \ OPAMFETCH." (match os with | FreeBSD -> "fetch" | OpenBSD -> "ftp" | _ -> "either \"curl\" or \"wget\"") ); validation_hook = None; retries = 3; force_checksums = None; } let setk k t ?download_tool ?validation_hook ?retries ?force_checksums = let (+) x opt = match opt with Some x -> x | None -> x in k { download_tool = t.download_tool + download_tool; validation_hook = t.validation_hook + validation_hook; retries = t.retries + retries; force_checksums = t.force_checksums + force_checksums; } let set t = setk (fun x () -> x) t let r = ref default let update ?noop:_ = setk (fun cfg () -> r := cfg) !r let initk k = let open OpamStd.Option.Op in let download_tool = E.fetch () >>= (fun s -> let args = OpamStd.String.split s ' ' in match args with | cmd::a -> let cmd, kind = if OpamStd.String.ends_with ~suffix:"curl" cmd then (CIdent "curl", None), `Curl else if cmd = "wget" then (CIdent "wget", None), `Default else (CString cmd, None), `Default in let c = cmd :: List.map (fun a -> OpamTypes.CString a, None) a in Some (lazy (c, kind)) | [] -> None ) >>+ fun () -> E.curl () >>| (fun s -> lazy ([CString s, None], `Curl)) in let validation_hook = E.validationhook () >>| fun s -> match List.map (fun s -> CString s, None) (OpamStd.String.split s ' ') with | [] -> None | l -> Some l in let force_checksums = match E.requirechecksums (), E.nochecksums () with | Some true, _ -> Some (Some true) | _, Some true -> Some (Some false) | None, None -> None | _ -> Some None in setk (setk (fun c -> r := c; k)) !r ?download_tool ?validation_hook ?retries:(E.retries ()) ?force_checksums let init ?noop:_ = initk (fun () -> ()) opam-2.1.5/src/repository/opamRepository.mli0000644000175000017500000000636414427463453020275 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Operations on repositories (update, fetch...) based on the different backends implemented in separate modules *) open OpamTypes (** Get the list of packages *) val packages: dirname -> package_set (** Get the list of packages (and their possible prefix) *) val packages_with_prefixes: dirname -> string option package_map (** {2 Repository backends} *) (** Update {i $opam/repo/$repo}. Raises [Failure] in case the update couldn't be achieved. *) val update: repository -> dirname -> unit OpamProcess.job (** Fetch an URL and put the resulting tree into the supplied directory. The URL must either point to a tree (VCS, rsync) or to a known archive type. In case of an archive, the cache is used and supplied the hashes verified, then the archive uncompressed. In case of a version-controlled URL, it's checked out, or synchronised directly if local and [working_dir] was set. *) val pull_tree: string -> ?cache_dir:dirname -> ?cache_urls:url list -> ?working_dir:bool -> ?subpath:string -> dirname -> OpamHash.t list -> url list -> string download OpamProcess.job (** Same as [pull_tree], but for fetching a single file. *) val pull_file: string -> ?cache_dir:dirname -> ?cache_urls:url list -> ?silent_hits:bool -> filename -> OpamHash.t list -> url list -> unit download OpamProcess.job (** Same as [pull_file], but without a destination file: just ensures the file is present in the cache. *) val pull_file_to_cache: string -> cache_dir:dirname -> ?cache_urls:url list -> OpamHash.t list -> url list -> string download OpamProcess.job (** The file where the file with the given hash is stored under cache at given dirname. *) val cache_file: dirname -> OpamHash.t -> filename (** Get the optional revision associated to a backend (git hash, etc.). *) val revision: dirname -> url -> version option OpamProcess.job (** Get the version-control branch for that url. Only applicable for local, version controlled URLs. Returns [None] in other cases. *) val current_branch: url -> string option OpamProcess.job (** Returns true if the url points to a local, version-controlled directory that has uncommitted changes *) val is_dirty: ?subpath:string -> url -> bool OpamProcess.job (** Find a backend *) val find_backend: repository -> (module OpamRepositoryBackend.S) val find_backend_by_kind: OpamUrl.backend -> (module OpamRepositoryBackend.S) (** Prints user messages upon the result of a download *) val report_fetch_result: package -> string download -> unit download opam-2.1.5/src/repository/opamHg.mli0000644000175000017500000000156614427463453016453 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2016 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Mercurial repository backend (based on OpamVCS) *) module VCS: OpamVCS.VCS module B: OpamRepositoryBackend.S opam-2.1.5/src/repository/opamGit.ml0000644000175000017500000003250714427463453016466 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamFilename.Op open OpamProcess.Job.Op (* let log fmt = OpamConsole.log "GIT" fmt *) module VCS : OpamVCS.VCS = struct let name = `git let exists repo_root = OpamFilename.exists_dir (repo_root / ".git") || OpamFilename.exists (repo_root // ".git") let cygpath = OpamSystem.get_cygpath_function ~command:"git" let git repo_root = let dir = OpamFilename.Dir.to_string repo_root in (* If the ?env arg is restored here, then the caching for the Cygwin-ness of git will need to change, as altering PATH could select a different Git *) fun ?verbose ?stdout args -> OpamSystem.make_command ~dir ?verbose ?stdout "git" args let init repo_root repo_url = OpamFilename.mkdir repo_root; OpamProcess.Job.of_list [ git repo_root [ "init" ]; (* Enforce this option, it can break our use of git if set *) git repo_root [ "config" ; "--local" ; "fetch.prune"; "false"]; (* We reset diff.noprefix to ensure we get a `-p1` patch and avoid . *) git repo_root [ "config" ; "--local" ; "diff.noprefix"; "false"]; (* Disable automatic line-ending conversion and switch core.eol to Unix. THIS DOES NOT MEAN ALL FILES GET LF-ONLY LINE-ENDINGS! This combination of settings means that files will be checked out exactly as they appear in the repository, so if files are checked in with CRLF line-endings (either by not having .gitattributes with core.autocrlf = false, or having an explicit eol=crlf in .gitattributes), then they will still be checked out with CRLF endings. *) git repo_root [ "config" ; "--local" ; "core.autocrlf"; "false"]; git repo_root [ "config" ; "--local" ; "core.eol"; "lf"]; (* Document the remote for user-friendliness (we don't use it) *) git repo_root [ "remote"; "add"; "origin"; OpamUrl.base_url repo_url ]; ] @@+ function | None -> Done () | Some (_,err) -> OpamSystem.process_error err let remote_ref url = match url.OpamUrl.hash with | Some h -> "refs/remotes/opam-ref-"^h | None -> "refs/remotes/opam-ref" let fetch ?cache_dir ?subpath repo_root repo_url = (match subpath with | Some sp -> git repo_root [ "config"; "--local"; "core.sparseCheckout"; "true" ] @@> fun r -> OpamSystem.raise_on_process_error r; OpamFilename.write (repo_root / ".git" / "info" // "sparse-checkout") sp; Done() | None -> Done()) @@+ fun _ -> (match cache_dir with | Some c when OpamUrl.local_dir repo_url = None -> let dir = c / "git" in if not (OpamFilename.exists_dir dir) then (OpamFilename.mkdir dir; git dir [ "init"; "--bare" ] @@> fun r -> OpamSystem.raise_on_process_error r; Done (Some dir)) else Done (Some dir) | _ -> Done None) @@+ fun global_cache -> let repo_url = OpamUrl.map_file_url (Lazy.force cygpath) repo_url in let origin = OpamUrl.base_url repo_url in let branch = OpamStd.Option.default "HEAD" repo_url.OpamUrl.hash in let opam_ref = remote_ref repo_url in let refspec = Printf.sprintf "+%s:%s" branch opam_ref in git repo_root [ "remote" ; "set-url"; "origin"; origin ] @@> fun _ -> OpamStd.Option.iter (fun cache -> let alternates = repo_root / ".git" / "objects" / "info" // "alternates" in if not (OpamFilename.exists alternates) then OpamFilename.write alternates (OpamFilename.Dir.to_string (cache / "objects"))) global_cache; git repo_root [ "fetch" ; "-q"; origin; "--update-shallow"; refspec ] @@> fun r -> if OpamProcess.check_success_and_cleanup r then let refspec = Printf.sprintf "+%s:refs/remotes/%s" opam_ref (Digest.to_hex (Digest.string (OpamUrl.to_string repo_url))) in match global_cache with | Some cache -> git repo_root [ "push" ; OpamFilename.Dir.to_string cache ; refspec ] @@> fun _ -> Done () | None -> Done () else (* fallback to fetching all first (workaround, git 2.1 fails silently on 'fetch HASH' when HASH isn't available locally already). Also, remove the [--update-shallow] option in case git is so old that it didn't exist yet, as that is not needed in the general case *) git repo_root [ "fetch" ; "-q" ] @@> fun r -> OpamSystem.raise_on_process_error r; (* retry to fetch the specific branch *) git repo_root [ "fetch" ; "-q"; origin; refspec ] @@> fun r -> if OpamProcess.check_success_and_cleanup r then Done () else if OpamStd.String.fold_left (fun acc c -> match acc, c with | true, ('0'..'9' | 'a'..'f' | 'A'..'F') -> true | _ -> false) true branch then (* the above might still fail on raw, untracked hashes: try to bind to the direct refspec, if found *) (git repo_root [ "update-ref" ; opam_ref; branch ] @@> fun r -> if OpamProcess.check_success_and_cleanup r then Done() else (* check if the commit exists *) (git repo_root [ "fetch"; "-q" ] @@> fun r -> OpamSystem.raise_on_process_error r; git repo_root [ "show"; "-s"; "--format=%H"; branch ] @@> fun r -> if OpamProcess.check_success_and_cleanup r then failwith "Commit found, but unreachable: enable uploadpack.allowReachableSHA1InWant on server" else failwith "Commit not found on repository")) else let error = r in git repo_root ["ls-files"] @@> function | { OpamProcess.r_code = 0; OpamProcess.r_stdout = []; _ } -> git repo_root ["show"] @@> fun r -> if OpamProcess.is_failure r then failwith "Git repository seems just initialized, \ try again after your first commit" else OpamSystem.process_error error | _ -> OpamSystem.process_error error let revision repo_root = git repo_root ~verbose:false [ "rev-parse"; "HEAD" ] @@> fun r -> if r.OpamProcess.r_code = 128 then (OpamProcess.cleanup ~force:true r; Done None) else (OpamSystem.raise_on_process_error r; match r.OpamProcess.r_stdout with | [] -> Done None | full::_ -> Done (Some full)) let clean repo_root = git repo_root [ "clean"; "-fdx" ] @@> fun r -> OpamSystem.raise_on_process_error r; Done () let reset_tree repo_root repo_url = let rref = remote_ref repo_url in git repo_root [ "reset" ; "--hard"; rref; "--" ] @@> fun r -> if OpamProcess.is_failure r then OpamSystem.internal_error "Git error: %s not found." rref else clean repo_root @@+ fun () -> if OpamFilename.exists (repo_root // ".gitmodules") then git repo_root [ "submodule"; "update"; "--init"; "--recursive" ] @@> fun r -> if OpamProcess.is_failure r then OpamConsole.warning "Git submodule update failed in %s" (OpamFilename.Dir.to_string repo_root); Done () else Done () let patch_applied _ _ = (* This might be a good place to do 'git reset --soft' and check for unstaged changes. See . *) Done () let diff repo_root repo_url = let rref = remote_ref repo_url in let patch_file = OpamSystem.temp_file ~auto_clean: false "git-diff" in let finalise () = OpamSystem.remove_file patch_file in OpamProcess.Job.catch (fun e -> finalise (); raise e) @@ fun () -> git repo_root [ "add"; "." ] @@> fun r -> (* Git diff is to the working dir, but doesn't work properly for unregistered directories. *) OpamSystem.raise_on_process_error r; (* We also reset diff.noprefix here to handle already existing repo. *) git repo_root ~stdout:patch_file [ "-c" ; "diff.noprefix=false" ; "diff" ; "--text" ; "--no-ext-diff" ; "-R" ; "-p" ; rref; "--" ] @@> fun r -> if not (OpamProcess.check_success_and_cleanup r) then (finalise (); OpamSystem.internal_error "Git error: %s not found." rref) else if OpamSystem.file_is_empty patch_file then (finalise (); Done None) else Done (Some (OpamFilename.of_string patch_file)) let is_up_to_date repo_root repo_url = let rref = remote_ref repo_url in git repo_root [ "diff" ; "--no-ext-diff" ; "--quiet" ; rref; "--" ] @@> function | { OpamProcess.r_code = 0; _ } -> Done true | { OpamProcess.r_code = 1; _ } as r -> OpamProcess.cleanup ~force:true r; Done false | r -> OpamSystem.process_error r let versioned_files repo_root = git repo_root ~verbose:false [ "ls-files" ] @@> fun r -> OpamSystem.raise_on_process_error r; Done r.OpamProcess.r_stdout let vc_dir repo_root = OpamFilename.Op.(repo_root / ".git") let current_branch dir = git dir [ "symbolic-ref"; "--quiet"; "--short"; "HEAD" ] @@> function | { OpamProcess.r_code = 0; OpamProcess.r_stdout = [s]; _ } -> Done (Some s) | _ -> Done (Some "HEAD") let is_dirty ?subpath dir = let subpath = match subpath with | None -> [] | Some dir -> ["--" ; dir] in git dir ([ "diff"; "--no-ext-diff"; "--quiet" ; "HEAD" ] @ subpath) @@> function | { OpamProcess.r_code = 0; _ } -> (git dir ["ls-files"; "--others"; "--exclude-standard"] @@> function | { OpamProcess.r_code = 0; OpamProcess.r_stdout = []; _ } -> Done false | { OpamProcess.r_code = 0; _ } | { OpamProcess.r_code = 1; _ } as r -> OpamProcess.cleanup ~force:true r; Done true | r -> OpamSystem.process_error r ) | { OpamProcess.r_code = 1; _ } as r -> OpamProcess.cleanup ~force:true r; Done true | r -> OpamSystem.process_error r let modified_files repo_root = git repo_root ~verbose:false [ "status" ; "--short" ] @@> fun r -> OpamSystem.raise_on_process_error r; let files = OpamStd.List.filter_map (fun line -> match OpamStd.String.split line ' ' with | ("A" | "M" | "AM")::file::[] | ("R"|"RM"|"C"|"CM")::_::"->"::file::[] -> Some file | _ -> None) r.OpamProcess.r_stdout in Done files let origin = "origin" (** check if a hash or branch is present in remote origin and returns *) let check_remote repo_root hash_or_b = let is_hex str = OpamStd.String.fold_left (fun hex ch -> hex && match ch with | '0'..'9' | 'A'..'F' | 'a'..'f' -> true | _ -> false ) true str in (* get the hash of the branch *) let hash = git repo_root ["branch"] @@> fun r -> if OpamProcess.is_success r then let is_branch = List.exists (OpamStd.String.contains ~sub:hash_or_b) r.r_stdout in if is_branch then git repo_root [ "rev-list"; hash_or_b; "-1" ] @@> fun r -> if OpamProcess.is_success r then (match List.filter is_hex r.r_stdout with | [hash] -> Done (Some hash) | _ -> Done None) else Done None else if is_hex hash_or_b then Done (Some hash_or_b) else Done None else Done None in hash @@+ function | Some hash -> (* check if hash / branch is present in remote *) (git repo_root ["branch"; "-r"; "--contains"; hash] @@> function | { OpamProcess.r_code = 0; _ } as r -> if r.r_stdout <> [] && (List.exists (OpamStd.String.contains ~sub:origin) r.r_stdout) then Done (Some hash_or_b) else Done None | { OpamProcess.r_code = 1; _ } -> Done None | r -> OpamSystem.process_error r) | None -> Done None let get_remote_url ?hash repo_root = git repo_root ["remote"; "get-url"; origin] @@> function | { OpamProcess.r_code = 0; OpamProcess.r_stdout = [url]; _ } -> (let u = OpamUrl.parse ~backend:`git url in if OpamUrl.local_dir u <> None then Done None else let hash_in_remote = match hash with | None -> (current_branch repo_root @@+ function | None | Some "HEAD" -> Done None | Some hash -> check_remote repo_root hash) | Some hash -> check_remote repo_root hash in hash_in_remote @@+ function | Some _ as hash -> Done (Some { u with OpamUrl.hash = hash }) | None -> Done (Some { u with OpamUrl.hash = None }) ) | { OpamProcess.r_code = 0; _ } | { OpamProcess.r_code = 1; _ } -> Done None | r -> OpamSystem.process_error r end module B = OpamVCS.Make(VCS) opam-2.1.5/src/repository/opamLocal.mli0000644000175000017500000000216114427463453017137 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2016 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Rsync repository backend, for local or ssh sources *) module B: OpamRepositoryBackend.S open OpamTypes val rsync_dirs: ?args:string list -> ?exclude_vcdirs:bool -> OpamUrl.t -> OpamFilename.Dir.t -> OpamFilename.Dir.t download OpamProcess.job val rsync_file: ?args:string list -> OpamUrl.t -> OpamFilename.t -> OpamFilename.t download OpamProcess.job opam-2.1.5/src/repository/opamRepositoryConfig.mli0000644000175000017500000000324314427463453021414 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2015-2016 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Configuration options for the repository lib (record, global reference, setter, initialisation) *) module E : sig type OpamStd.Config.E.t += | CURL of string option | FETCH of string option | NOCHECKSUMS of bool option | REQUIRECHECKSUMS of bool option | RETRIES of int option | VALIDATIONHOOK of string option val curl: unit -> string option val fetch: unit -> string option end (** Toggles parsing of the tool's output to detect errors (curl returns 0 on a 404) *) type dl_tool_kind = [ `Curl | `Default ] type t = { download_tool: (OpamTypes.arg list * dl_tool_kind) Lazy.t; validation_hook: OpamTypes.arg list option; retries: int; force_checksums: bool option; } type 'a options_fun = ?download_tool:(OpamTypes.arg list * dl_tool_kind) Lazy.t -> ?validation_hook:OpamTypes.arg list option -> ?retries:int -> ?force_checksums:bool option -> 'a include OpamStd.Config.Sig with type t := t and type 'a options_fun := 'a options_fun opam-2.1.5/src/repository/opamRepositoryBackend.ml0000644000175000017500000000674014427463453021372 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2015-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes let log = OpamConsole.log "REPO_BACKEND" let slog = OpamConsole.slog type update = | Update_full of dirname | Update_patch of filename | Update_empty | Update_err of exn module type S = sig val name: OpamUrl.backend val pull_url: ?cache_dir:dirname -> ?subpath:string -> dirname -> OpamHash.t option -> url -> filename option download OpamProcess.job val fetch_repo_update: repository_name -> ?cache_dir:dirname -> dirname -> url -> update OpamProcess.job val repo_update_complete: dirname -> url -> unit OpamProcess.job val revision: dirname -> version option OpamProcess.job val sync_dirty: ?subpath:string -> dirname -> url -> filename option download OpamProcess.job val get_remote_url: ?hash:string -> dirname -> url option OpamProcess.job end let compare r1 r2 = compare r1.repo_name r2.repo_name let to_string r = Printf.sprintf "%s from %s" (OpamRepositoryName.to_string r.repo_name) (OpamUrl.to_string r.repo_url) let to_json r = `O [ ("name", OpamRepositoryName.to_json r.repo_name); ("kind", `String (OpamUrl.string_of_backend r.repo_url.OpamUrl.backend)); ] let check_digest filename = function | Some expected when OpamRepositoryConfig.(!r.force_checksums) <> Some false -> (match OpamHash.mismatch (OpamFilename.to_string filename) expected with | None -> true | Some bad_hash -> OpamConsole.error "Bad checksum for %s: expected %s\n\ \ got %s\n\ Metadata might be out of date, in this case use `opam update`." (OpamFilename.to_string filename) (OpamHash.to_string expected) (OpamHash.to_string bad_hash); false) | _ -> true open OpamProcess.Job.Op let job_text name label = OpamProcess.Job.with_text (Printf.sprintf "[%s: %s]" (OpamConsole.colorise `green (OpamRepositoryName.to_string name)) label) let get_diff parent_dir dir1 dir2 = log "diff: %a/{%a,%a}" (slog OpamFilename.Dir.to_string) parent_dir (slog OpamFilename.Base.to_string) dir1 (slog OpamFilename.Base.to_string) dir2; let patch = OpamSystem.temp_file ~auto_clean: false "patch" in let patch_file = OpamFilename.of_string patch in let finalise () = OpamFilename.remove patch_file in OpamProcess.Job.catch (fun e -> finalise (); raise e) @@ fun () -> OpamSystem.make_command ~verbose:OpamCoreConfig.(!r.verbose_level >= 2) ~dir:(OpamFilename.Dir.to_string parent_dir) ~stdout:patch "diff" [ "-ruaN"; OpamFilename.Base.to_string dir1; OpamFilename.Base.to_string dir2; ] @@> function | { OpamProcess.r_code = 0; _ } -> finalise(); Done None | { OpamProcess.r_code = 1; _ } as r -> OpamProcess.cleanup ~force:true r; Done (Some patch_file) | r -> OpamSystem.process_error r opam-2.1.5/src/repository/opamHg.ml0000644000175000017500000001364614427463453016304 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamFilename.Op open OpamProcess.Job.Op module VCS = struct let name = `hg let mark_prefix = "opam-mark" let exists repo_root = OpamFilename.exists_dir (repo_root / ".hg") let hg repo_root = let dir = OpamFilename.Dir.to_string repo_root in fun ?verbose ?env ?stdout args -> OpamSystem.make_command ~dir ?verbose ?env ?stdout "hg" args let init repo_root _repo_url = OpamFilename.mkdir repo_root; hg repo_root [ "init" ] @@> fun r -> OpamSystem.raise_on_process_error r; Done () let mark_from_url url = match url.OpamUrl.hash with | None -> mark_prefix | Some fragment -> mark_prefix ^ "-" ^ fragment let fetch ?cache_dir:_ ?subpath:_ repo_root repo_url = let src = OpamUrl.base_url repo_url in let rev = OpamStd.Option.default "default" repo_url.OpamUrl.hash in let mark = mark_from_url repo_url in hg repo_root [ "pull"; "--rev"; rev; src ] @@> fun r -> OpamSystem.raise_on_process_error r; hg repo_root [ "bookmark"; "--force"; "--rev"; rev; mark ] @@> fun r -> OpamSystem.raise_on_process_error r; Done () let revision repo_root = hg repo_root [ "identify"; "--id" ] @@> fun r -> OpamSystem.raise_on_process_error r; match r.OpamProcess.r_stdout with | [] -> Done None | full::_ -> Done (Some full) let clean repo_root = hg repo_root ["revert"; "--all"; "--no-backup"] @@> fun r -> OpamSystem.raise_on_process_error r; Done () let reset_tree repo_root repo_url = let mark = mark_from_url repo_url in hg repo_root [ "update"; "--clean"; "--rev"; mark ] @@> fun r -> OpamSystem.raise_on_process_error r; Done () let patch_applied = reset_tree let diff repo_root repo_url = let patch_file = OpamSystem.temp_file ~auto_clean:false "hg-diff" in let finalise () = OpamSystem.remove_file patch_file in OpamProcess.Job.catch (fun e -> finalise (); raise e) @@ fun () -> let mark = mark_from_url repo_url in hg repo_root ~stdout:patch_file [ "diff"; "--text"; "--subrepos"; "--reverse"; "--rev"; mark ] @@> fun r -> if OpamProcess.is_failure r then (finalise (); OpamSystem.internal_error "Hg error: '%s' not found." mark) else if OpamSystem.file_is_empty patch_file then (finalise (); Done None) else Done (Some (OpamFilename.of_string patch_file)) let is_up_to_date repo_root repo_url = let mark = mark_from_url repo_url in hg repo_root [ "status"; "--subrepos"; "--rev"; mark ] @@> fun r -> OpamSystem.raise_on_process_error r; Done (r.OpamProcess.r_stdout = []) let versioned_files repo_root = hg repo_root [ "locate" ] @@> fun r -> OpamSystem.raise_on_process_error r; Done r.OpamProcess.r_stdout let vc_dir repo_root = OpamFilename.Op.(repo_root / ".hg") let current_branch repo_root = hg repo_root [ "identify"; "--bookmarks" ] @@> fun r -> OpamSystem.raise_on_process_error r; match r.OpamProcess.r_stdout with | [] -> Done None | marks::_ -> let marks = OpamStd.String.split marks ' ' in let marks = List.filter (OpamStd.String.starts_with ~prefix:mark_prefix) marks in match marks with | mark::_ -> Done (Some mark) | [] -> hg repo_root [ "identify"; "--branch" ] @@> fun r -> OpamSystem.raise_on_process_error r; match r.OpamProcess.r_stdout with | branch::_ when branch <> "default" -> Done (Some branch) | _ -> Done None let is_dirty ?subpath:_ repo_root = hg repo_root [ "status"; "--subrepos" ] @@> fun r -> OpamSystem.raise_on_process_error r; Done (r.OpamProcess.r_stdout = []) let modified_files repo_root = hg repo_root [ "status"; "--subrepos" ] @@> fun r -> OpamSystem.raise_on_process_error r; let files = OpamStd.List.filter_map (fun line -> match OpamStd.String.split line ' ' with | ("A" | "M")::file::[] -> Some file | _ -> None) r.OpamProcess.r_stdout in Done files let get_remote_url ?hash repo_root = hg repo_root [ "paths"; "default" ] @@> function | { OpamProcess.r_code = 0; _ } as r -> (match r.r_stdout with | [url] -> (let url = OpamUrl.parse ~backend:`hg url in if OpamUrl.local_dir url <> None then Done None else let check_remote hash = hg repo_root [ "id"; "-r"; hash; "default" ] @@> fun r -> if OpamProcess.is_success r then Done (Some { url with hash = Some hash }) (* default branch of hg is default *) else Done (Some { url with hash = None}) in match hash with | None -> (hg repo_root ["branch"] @@> function | { OpamProcess.r_code = 0; OpamProcess.r_stdout = [hash]; _ } -> check_remote hash | { OpamProcess.r_code = 0; _ } | { OpamProcess.r_code = 1; _ } -> Done (Some url) | r -> OpamSystem.process_error r) | Some hash -> check_remote hash) | _ -> Done None) | { OpamProcess.r_code = 1; _ } -> Done None | r -> OpamSystem.process_error r end module B = OpamVCS.Make(VCS) opam-2.1.5/src/repository/opamRepositoryPath.mli0000644000175000017500000000513414427463453021104 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Defines the file hierarchy in repositories *) open OpamTypes (** Repository local path: {i $opam/repo/} *) val root: dirname -> repository_name -> dirname val tar: dirname -> repository_name -> filename (** Prefix where to store the downloaded files cache: {i $opam/download-cache}. Warning, this is relative to the opam root, not a repository root. *) val download_cache: dirname -> dirname (** Pin global cache, located in temporary directory, cleaned at end of process *) val pin_cache_dir: unit -> dirname (** Pin cache for a given download url. *) val pin_cache: OpamUrl.t -> dirname (** Return the repo file *) val repo: dirname -> OpamFile.Repo.t OpamFile.t (** Packages folder: {i $repo/packages} *) val packages_dir: dirname -> dirname (** Package folder: {i $repo/packages/XXX/$NAME.$VERSION} *) val packages: dirname -> string option -> package -> dirname (** Return the OPAM file for a given package: {i $repo/packages/XXX/$NAME.$VERSION/opam} *) val opam: dirname -> string option -> package -> OpamFile.OPAM.t OpamFile.t (** Return the description file for a given package: {i $repo/packages/XXX/$NAME.VERSION/descr} *) val descr: dirname -> string option -> package -> OpamFile.Descr.t OpamFile.t (** urls {i $repo/package/XXX/$NAME.$VERSION/url} *) val url: dirname -> string option -> package -> OpamFile.URL.t OpamFile.t (** files {i $repo/packages/XXX/$NAME.$VERSION/files} *) val files: dirname -> string option -> package -> dirname (** Url constructor for parts of remote repositories, when applicable (http and rsync). Function take the repo's root url. *) module Remote: sig (** Remote repo file *) val repo: url -> url (** Remote package files: {i $remote/packages} *) val packages_url: url -> url (** Remote archive {i $remote/archives/$NAME.$VERSION.tar.gz} *) val archive: url -> package -> url end opam-2.1.5/src/repository/opamVCS.ml0000644000175000017500000001615314427463453016375 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamStd.Op open OpamProcess.Job.Op module type VCS = sig val name: OpamUrl.backend val exists: dirname -> bool val init: dirname -> url -> unit OpamProcess.job val fetch: ?cache_dir:dirname -> ?subpath:string -> dirname -> url -> unit OpamProcess.job val reset_tree: dirname -> url -> unit OpamProcess.job val patch_applied: dirname -> url -> unit OpamProcess.job val diff: dirname -> url -> filename option OpamProcess.job val is_up_to_date: dirname -> url -> bool OpamProcess.job val revision: dirname -> string option OpamProcess.job val versioned_files: dirname -> string list OpamProcess.job val vc_dir: dirname -> dirname val current_branch: dirname -> string option OpamProcess.job val is_dirty: ?subpath:string -> dirname -> bool OpamProcess.job val modified_files: dirname -> string list OpamProcess.job val get_remote_url: ?hash:string -> dirname -> url option OpamProcess.job val clean: dirname -> unit OpamProcess.job end let convert_path = OpamSystem.get_cygpath_function ~command:"rsync" module Make (VCS: VCS) = struct let name = VCS.name let fetch_repo_update repo_name ?cache_dir repo_root repo_url = if VCS.exists repo_root then OpamProcess.Job.catch (fun e -> Done (OpamRepositoryBackend.Update_err e)) @@ fun () -> OpamRepositoryBackend.job_text repo_name "sync" (VCS.fetch ?cache_dir repo_root repo_url) @@+ fun () -> OpamRepositoryBackend.job_text repo_name "diff" (VCS.diff repo_root repo_url) @@| function | None -> OpamRepositoryBackend.Update_empty | Some patch -> OpamRepositoryBackend.Update_patch patch else OpamProcess.Job.catch (fun e -> OpamFilename.rmdir repo_root; Done (OpamRepositoryBackend.Update_err e)) @@ fun () -> OpamRepositoryBackend.job_text repo_name "init" (VCS.init repo_root repo_url) @@+ fun () -> OpamRepositoryBackend.job_text repo_name "sync" (VCS.fetch ?cache_dir repo_root repo_url) @@+ fun () -> let tmpdir = OpamFilename.Dir.(of_string (to_string repo_root ^".new")) in OpamFilename.copy_dir ~src:repo_root ~dst:tmpdir; OpamProcess.Job.catch (fun e -> OpamFilename.rmdir tmpdir; raise e) @@ fun () -> VCS.reset_tree tmpdir repo_url @@| fun () -> OpamRepositoryBackend.Update_full tmpdir let repo_update_complete dirname url = VCS.patch_applied dirname url @@+ fun () -> Done () let pull_url ?cache_dir ?subpath dirname checksum url = if checksum <> None then invalid_arg "VC pull_url doesn't allow checksums"; OpamProcess.Job.catch (fun e -> OpamConsole.error "Could not synchronize %s from %S:\n%s" (OpamFilename.Dir.to_string dirname) (OpamUrl.to_string url) (match e with Failure fw -> fw | _ -> Printexc.to_string e); Done (Not_available (None, OpamUrl.to_string url))) @@ fun () -> if VCS.exists dirname then VCS.clean dirname @@+ fun () -> VCS.fetch ?cache_dir ?subpath dirname url @@+ fun () -> VCS.is_up_to_date dirname url @@+ function | true -> Done (Up_to_date None) | false -> VCS.reset_tree dirname url @@+ fun () -> Done (Result None) else (OpamFilename.mkdir dirname; VCS.init dirname url @@+ fun () -> VCS.fetch ?cache_dir ?subpath dirname url @@+ fun () -> VCS.reset_tree dirname url @@+ fun () -> Done (Result None)) let revision repo_root = VCS.revision repo_root @@+ fun r -> Done (OpamStd.Option.map OpamPackage.Version.of_string r) let sync_dirty ?subpath repo_root repo_url = let filter_subpath files = match subpath with | None -> files | Some sp -> OpamStd.List.filter_map (fun f -> if OpamStd.String.remove_prefix ~prefix:(sp ^ Filename.dir_sep) f <> f then Some f else None) files in pull_url ?subpath repo_root None repo_url @@+ fun result -> match OpamUrl.local_dir repo_url with | None -> Done (result) | Some dir -> VCS.versioned_files dir @@+ fun vc_files -> VCS.modified_files dir @@+ fun vc_dirty_files -> let files = filter_subpath (List.map OpamFilename.(remove_prefix dir) (OpamFilename.rec_files dir)) in (* Remove non-listed files from destination *) (* fixme: doesn't clean directories *) let fset = OpamStd.String.Set.of_list files in let rm_list = List.filter (fun f -> let basename = OpamFilename.remove_prefix repo_root f in not (OpamFilename.(starts_with (VCS.vc_dir repo_root) f) || OpamStd.String.Set.mem basename fset)) (OpamFilename.rec_files repo_root) in List.iter OpamFilename.remove rm_list; (* We do the list cleaning here because of rsync options: with `--files-from`, `--exclude` need to be explicitly given directory descendants, e.g `--exclude _build/**` *) let excluded = (* from [OpamLocal.rsync] exclude list *) let exc = [ OpamSwitch.external_dirname; "_build"; ".git"; "_darcs"; ".hg" ] in OpamStd.String.Set.filter (fun f -> List.exists (fun prefix -> OpamStd.String.starts_with ~prefix f) exc) fset in let vcset = OpamStd.String.Set.of_list (filter_subpath vc_files) in let vc_dirty_set = OpamStd.String.Set.of_list (filter_subpath vc_dirty_files) in let final_set = OpamStd.String.Set.Op.(fset -- vcset ++ vc_dirty_set -- excluded) in let stdout_file = let f = OpamSystem.temp_file "rsync-files" in let fd = open_out f in (* Using the set here to keep the list file sorted, it helps rsync *) OpamStd.String.Set.iter (fun s -> output_string fd s; output_char fd '\n') final_set; close_out fd; f in let args = [ "--files-from"; (Lazy.force convert_path) stdout_file; ] in OpamLocal.rsync_dirs ~args repo_url repo_root @@+ fun result -> OpamSystem.remove stdout_file; Done (match result with | Up_to_date _ when rm_list = [] -> Up_to_date None | Up_to_date _ | Result _ -> Result None | Not_available _ as na -> na) let get_remote_url = VCS.get_remote_url end opam-2.1.5/src/repository/opamVCS.mli0000644000175000017500000000717114427463453016546 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Layer for handling version control sources through a functor *) open OpamTypes (** Each backend should implement this signature. *) module type VCS = sig val name: OpamUrl.backend (** Test whether the given repository is correctly initialized. *) val exists: dirname -> bool (** Init a repository. *) val init: dirname -> url -> unit OpamProcess.job (** Fetch changes from upstream. This is supposed to put the changes in a staging area. Be aware that the remote URL might have been changed, so make sure to update accordingly. *) val fetch: ?cache_dir:dirname -> ?subpath:string -> dirname -> url -> unit OpamProcess.job (** Reset the master branch of the repository to match the remote repository state. This might still fetch more data (git submodules...), so is unsuitable for running after validation. *) val reset_tree: dirname -> url -> unit OpamProcess.job (** Confirm that applying the patch results in a clean synchronization of the working tree with its repository state. *) val patch_applied: dirname -> url -> unit OpamProcess.job (** Returns the pending modifications in the form of a patch file, or None if [dirname] is up to date with what was last fetched. *) val diff: dirname -> url -> filename option OpamProcess.job (** Returns true if the last fetched state is equal to the current, on-disk state *) val is_up_to_date: dirname -> url -> bool OpamProcess.job (** Returns an backend-specific identifier for the current revision. *) val revision: dirname -> string option OpamProcess.job (** Returns the list of files under version control *) val versioned_files: dirname -> string list OpamProcess.job (** Returns the absolute directory name for vc data (e.g. [.../project/.git]) *) val vc_dir: dirname -> dirname (** Returns the currently selected branch handle. It should be valid as the [hash] field of [OpamUrl.t]. *) val current_branch: dirname -> string option OpamProcess.job (** Returns true if the working tree state is different from the state recorded in the VCS as current. This differs from [is_up_to_date], which compares specifically to the last fetched state. This should always be [false] after [reset] has been called. *) val is_dirty: ?subpath:string -> dirname -> bool OpamProcess.job (** Returns the list of files under version control, modified in the working tree but not committed *) val modified_files: dirname -> string list OpamProcess.job (* Returns associated remote url, if found *) val get_remote_url: ?hash:string -> dirname -> url option OpamProcess.job (* Remove uncommitted changes *) val clean: dirname -> unit OpamProcess.job end (** Create a backend from a [VCS] implementation. *) module Make(VCS : VCS) : OpamRepositoryBackend.S [@@ocaml.warning "-67"] (* TODO: Remove this once we get past OCaml 4.02 *) opam-2.1.5/src/repository/opamRepositoryBackend.mli0000644000175000017500000001141214427463453021533 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2015-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Signature for repository handlers and some helpers for the repository type *) open OpamTypes (** Type returned by repository updates. *) type update = | Update_full of dirname (** No previous known state, the full contents have been put in the given temporary directory *) | Update_patch of filename (** The given patch file corresponds to the update, i.e. applying it to the local repository with 'patch -p1' would get it to the upstream state *) | Update_empty (** The repository is already up to date *) | Update_err of exn (** Failed to obtain the update *) (** Backend signature *) module type S = sig val name: OpamUrl.backend (** [pull_url local_dir checksum remote_url] pulls the contents of [remote_url] into [local_dir]. Two kinds of results are allowed: - a single file was downloaded, in this case it is placed within [local_dir] and returned as [Some filename] - a directory was retrieved, in this case the contents of [local_dir] have been synchronised with its own, and [None] is returned [checksum] can be used for retrieval but is NOT checked by this function. *) val pull_url: ?cache_dir:dirname -> ?subpath:string -> dirname -> OpamHash.t option -> url -> filename option download OpamProcess.job (** [pull_repo_update] fetches the remote update from [url] to the local repository at [dirname], but does not apply it, allowing for further verifications. The file or directory returned is always temporary and should be cleaned up by the caller. *) val fetch_repo_update: repository_name -> ?cache_dir:dirname -> dirname -> url -> update OpamProcess.job (** [repo_update_complete dirname url] finalizes the update of the repository after verification of the patch returned from [pull_repo_update] with [Update_patch file] is applied. Version control systems, e.g. Mercurial, that track the state of the working directory automatically use this to update internal caches. *) val repo_update_complete: dirname -> url -> unit OpamProcess.job (** Return the (optional) revision of a given repository. Only useful for VCS backends. Is not expected to work with [pull_repo_update], which doesn't update the VCS commit information. *) val revision: dirname -> version option OpamProcess.job (** Like [pull_url], except for locally-bound version control backends, where it should get the latest, uncommitted source. First, it performs a [pull_url], then remove deleted files, and finally copy via rsync unversioned & modified-uncommitted files. *) val sync_dirty: ?subpath:string -> dirname -> url -> filename option download OpamProcess.job (** [get_remote_url ?hash dirname] return the distant url of repo [dirname], \ if found. When [hash] is specified, it checks that this hash (branch or \ commit) is present in the distant repository and returns the url with \ this hash. If the hash is absent it returns the remote url with no hash. *) val get_remote_url: ?hash:string -> dirname -> url option OpamProcess.job end (** Pretty-print *) val to_string: repository -> string val to_json: repository -> json (** Compare repositories *) val compare: repository -> repository -> int (** [check_digest file expected] check that the [file] digest is the one [expected]. *) val check_digest: filename -> OpamHash.t option -> bool (** Adds a label to the given job, for the corresponding repository name and action *) val job_text: repository_name -> string -> 'a OpamProcess.job -> 'a OpamProcess.job (** [get_diff parent_dir subdir1 subdir2] computes the diff between the two subdirs of [parent_dir], returns None if they are equal, and the corresponding patch otherwise. Note: this relies on the [diff -ruN] command, a built-in diff may be more portable -- in particular, [-u], [-N] are not POSIX, and recursive diffs might not be completely reliable. It also assumes text files only, and fails otherwise. *) val get_diff: dirname -> basename -> basename -> filename option OpamProcess.job opam-2.1.5/src/manifest/0002755000175000017500000000000014427463453014116 5ustar stephstephopam-2.1.5/src/manifest/Opam.Runtime.amd64.manifest0000644000175000017500000000054514427463453021100 0ustar stephsteph opam-2.1.5/src/manifest/opam-mingw64.xmlf0000644000175000017500000000054014427463453017230 0ustar stephsteph OCaml Package Manager opam-2.1.5/src/manifest/Opam.Runtime.x86.manifest0000644000175000017500000000054214427463453020607 0ustar stephsteph opam-2.1.5/src/manifest/install.i3860000644000175000017500000000077314427463453016204 0ustar stephsteph(rule (targets libstdc++-6.dll libwinpthread-1.dll libgcc_s_sjlj-1.dll) (deps (:link ../../shell/link_runtime.ml)) (action (run ocaml %{link} %{targets}))) (install (section bin) (files (Opam.Runtime.x86.manifest as Opam.Runtime.x86\Opam.Runtime.x86.manifest) (libstdc++-6.dll as Opam.Runtime.x86\libstdc++-6.dll) (libwinpthread-1.dll as Opam.Runtime.x86\libwinpthread-1.dll) (libgcc_s_sjlj-1.dll as Opam.Runtime.x86\libgcc_s_sjlj-1.dll)) (package opam)) opam-2.1.5/src/manifest/opam-mingw.xmlf0000644000175000017500000000053214427463453017057 0ustar stephsteph OCaml Package Manager opam-2.1.5/src/manifest/install.amd640000644000175000017500000000100414427463453016412 0ustar stephsteph(rule (targets libstdc++-6.dll libwinpthread-1.dll libgcc_s_seh-1.dll) (deps (:link ../../shell/link_runtime.ml)) (action (run ocaml %{link} %{targets}))) (install (section bin) (files (Opam.Runtime.amd64.manifest as Opam.Runtime.amd64\Opam.Runtime.amd64.manifest) (libstdc++-6.dll as Opam.Runtime.amd64\libstdc++-6.dll) (libwinpthread-1.dll as Opam.Runtime.amd64\libwinpthread-1.dll) (libgcc_s_seh-1.dll as Opam.Runtime.amd64\libgcc_s_seh-1.dll)) (package opam)) opam-2.1.5/src/manifest/dune-manifest0000644000175000017500000000245514427463453016604 0ustar stephsteph(library (name opam_manifest) (public_name opam-client.manifest) (c_names dummy) (c_library_flags ("src/manifest/opam-manifest.o")) (synopsis "mingw-w64 runtime manifest")) (rule (targets dummy.c) (deps opam-manifest.o) (action (with-stdout-to %{targets} (echo "")))) (rule (targets opam-manifest.o) (deps (:rcfile opam.rc)) (action (system "%{read-lines:tool-arch}-w64-mingw32-windres %{rcfile} %{targets}"))) (rule (with-stdout-to tool-arch (run ocaml %{dep:../../shell/context_flags.ml} mingw-arch))) (rule (targets opam.exe.manifest) (deps opam-mingw.xmlf opam-mingw64.xmlf) (action (with-stdout-to %{targets} (progn (echo "\n") (echo "\n") (system "cat opam-%{ocaml-config:system}.xmlf 2> %{null} || type opam-%{ocaml-config:system}.xmlf") (cat default-manifest.xmlf) (echo ""))))) (rule (targets opam.rc) (deps (:manifest opam.exe.manifest)) (action (with-stdout-to opam.rc (echo "#include \nCREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST %{manifest}")))) (include install.inc) opam-2.1.5/src/manifest/default-manifest.xmlf0000644000175000017500000000221014427463453020227 0ustar stephsteph opam-2.1.5/src/crowbar/0002755000175000017500000000000014427463453013747 5ustar stephstephopam-2.1.5/src/crowbar/opamVariable_crowbar.ml0000644000175000017500000000212314427463453020416 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamVariable open! Crowbar open OpamCrowbar let variable = map [nice_string] @@ of_string let full = choose [ map [variable] @@ Full.global; map [variable] @@ Full.self; map [OpamPackage_crowbar.name; variable] @@ Full.create; ] let check () = let equal v1 v2 = Full.to_string v1 = Full.to_string v2 in check_json_roundtrip ~name:"OpamVariable.t" full equal Full.to_json Full.of_json; opam-2.1.5/src/crowbar/opamHash_crowbar.ml0000644000175000017500000000200614427463453017554 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamHash open! Crowbar open OpamCrowbar let kind : kind gen = choose [ const `MD5; const `SHA256; const `SHA512; ] let hash = map [kind; bytes] @@ fun kind string -> OpamHash.compute_from_string ~kind string let check () = check_json_roundtrip ~name:"OpamHash.t" hash (=) OpamHash.to_json OpamHash.of_json; opam-2.1.5/src/crowbar/dune0000644000175000017500000000114214427463453014621 0ustar stephsteph(executable (name test) (modules opamCrowbar opamFilename_crowbar opamHash_crowbar opamUrl_crowbar opamVersion_crowbar opamCudf_crowbar opamPackage_crowbar opamVariable_crowbar opamActionGraph_crowbar test) (libraries crowbar opam-core opam-format opam-solver) (flags (:standard (:include ../ocaml-flags-standard.sexp) (:include ../ocaml-flags-configure.sexp) (:include ../ocaml-context-flags.sexp))) ) opam-2.1.5/src/crowbar/opamFilename_crowbar.ml0000644000175000017500000000262614427463453020421 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamFilename open! Crowbar open OpamCrowbar let base : Base.t gen = let dirname = map [nice_string] @@ Base.of_string in choose [ dirname; map [dirname; nice_string] Base.add_extension; ] let dir : Dir.t gen = let dir_s = choose [ nice_string; (map [nice_string] @@ fun s -> "~" ^ Filename.dir_sep ^ s); const "~"; ] in map [dir_s] @@ OpamFilename.Dir.of_string let filename : t gen = map [dir; base] @@ create let check () = check_json_roundtrip ~name:"OpamFilename.Base.t" base (=) Base.to_json Base.of_json; check_json_roundtrip ~name:"OpamFilename.Dir.t" dir (=) Dir.to_json Dir.of_json; check_json_roundtrip ~name:"OpamFilename.t" filename (=) to_json of_json; opam-2.1.5/src/crowbar/opamPackage_crowbar.ml0000644000175000017500000000315314427463453020230 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamPackage open! Crowbar open OpamCrowbar let version = let main_part = map [list1 nice_uint] @@ fun ns -> List.map string_of_int ns |> String.concat "." in let weird_stuff = choose [ map [nice_uint] (fun n -> "~" ^ string_of_int n); map [nice_uint] (fun n -> "+" ^ string_of_int n); map [nice_string] (fun s -> "+" ^ s); ] in let version_string = choose [ main_part; map [main_part; weird_stuff] @@ (^); map [main_part; weird_stuff; weird_stuff; weird_stuff] @@ Printf.sprintf "%s%s%s%s" ] in map [version_string] Version.of_string let name = let name_string = choose [ nice_string; map [nice_string; nice_uint] (Printf.sprintf "%s%d"); ] in map [name_string] Name.of_string let package = map [name; version] create let check () = check_json_roundtrip ~name:"OpamPackage.t" package (eq_of_comp OpamPackage.compare) to_json of_json; opam-2.1.5/src/crowbar/opamCrowbar.ml0000644000175000017500000000312114427463453016550 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open! Crowbar (* this 'pair' combinator exists in crowbar master but not 0.1 *) let pair gena genb = map [gena; genb] (fun a b -> (a,b)) let nice_int = int8 let nice_uint = uint8 let nice_string = let letter = map [range 25] (fun n -> char_of_int (int_of_char 'a' + n)) in with_printer Format.pp_print_string @@ map [letter; letter; letter; letter; letter] @@ fun a b c d e -> String.of_seq (List.to_seq [a;b;c;d;e]) let eq_of_comp comp v1 v2 = (comp v1 v2 = 0) let check_json_roundtrip ~name gen equal to_json of_json = let pp ppf = function | None -> assert false | Some x -> Format.fprintf ppf "%s\n%!" (OpamJson.to_string (to_json x)) in let equal x y = match x, y with | None, None -> true | Some _, None | None, Some _ -> false | Some x, Some y -> equal x y in Crowbar.add_test ~name [gen] @@ (fun x -> Crowbar.check_eq ~pp ~eq:equal (Some x) (of_json (to_json x)) ) opam-2.1.5/src/crowbar/opamUrl_crowbar.ml0000644000175000017500000000271314427463453017440 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamUrl open! Crowbar open OpamCrowbar let version_control = choose [ const `git; const `darcs; const `hg; ] let backend = let print ppf b = Format.pp_print_string ppf (string_of_backend b) in with_printer print @@ choose [ const `http; const `rsync; version_control; ] let transport = choose [ const "http"; const "ssh"; const "file"; const "git"; const "hg"; const "darcs"; ] let url : OpamUrl.t gen = map [ transport; nice_string; option nice_string; ] @@ fun transport path hash -> String.concat "" [transport; "://"; path; (match hash with None -> "" | Some h -> h)] |> OpamUrl.parse let check () = check_json_roundtrip ~name:"OpamUrl.t" url (=) OpamUrl.to_json OpamUrl.of_json; opam-2.1.5/src/crowbar/dune-project0000644000175000017500000000004414427463453016265 0ustar stephsteph(lang dune 1.2) (name opam-crowbar) opam-2.1.5/src/crowbar/test.ml0000644000175000017500000000167314427463453015265 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) let () = OpamCudf_crowbar.check (); OpamFilename_crowbar.check (); OpamHash_crowbar.check (); OpamUrl_crowbar.check (); OpamVersion_crowbar.check (); OpamPackage_crowbar.check (); OpamVariable_crowbar.check (); OpamActionGraph_crowbar.check (); opam-2.1.5/src/crowbar/opamActionGraph_crowbar.ml0000644000175000017500000000425314427463453021076 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open! Crowbar open OpamCrowbar let atomic_action gen = choose [ (map [gen] @@ fun v -> `Remove v); (map [gen] @@ fun v -> `Install v); ] let highlevel_action gen = choose [ atomic_action gen; (map [choose [const `Up; const `Down]; gen; gen] @@ fun dir a b -> `Change (dir, a, b)); (map [gen] @@ fun v -> `Reinstall v); ] let concrete_action gen = choose [ atomic_action gen; (map [gen] @@ fun v -> `Build v); ] let action gen = choose [ atomic_action gen; highlevel_action gen; concrete_action gen; ] module Action = OpamCudf.Action let cudf_action = action OpamCudf_crowbar.package module ActionGraph = OpamCudf.ActionGraph let cudf_graph = map [list cudf_action; list (pair int int)] @@ fun vertices edge_codes -> if vertices = [] then ActionGraph.build [] [] else begin let get_vertex = let array = Array.of_list vertices in fun i -> array.((abs i) mod Array.length array) in let get_edge (i, j) = let src = get_vertex i in let dst = get_vertex j in ActionGraph.E.create src () dst in let edges = List.map get_edge edge_codes in ActionGraph.build vertices edges end let check () = check_json_roundtrip ~name:"OpamActionGraph.Make(OpamCudf).t" cudf_action (eq_of_comp Action.compare) Action.to_json Action.of_json; check_json_roundtrip ~name:"OpamActionGraph.Make(OpamCudf).g" cudf_graph (eq_of_comp ActionGraph.compare) ActionGraph.to_json ActionGraph.of_json; opam-2.1.5/src/crowbar/opam-crowbar.opam0000644000175000017500000000103714427463453017215 0ustar stephstephopam-version: "2.0" version: "2.0.0" maintainer: "opam-devel@lists.ocaml.org" authors: [ "Gabriel Scherer " ] homepage: "https://opam.ocaml.org" bug-reports: "https://github.com/ocaml/opam/issues" dev-repo: "git+https://github.com/ocaml/opam.git" depends: [ "ocaml" {>= "4.02.3"} "crowbar" "afl" ] messages: """ This file is for easy use of (opam install --deps-only), use the Makefile targets 'crowbar' and 'crowbar-afl' at the root for actual usage. (crowbar-afl requires being in a +afl switch. """ opam-2.1.5/src/crowbar/opamCrowbar.mli0000644000175000017500000000204414427463453016724 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) val nice_int : int Crowbar.gen val nice_uint : int Crowbar.gen val nice_string : string Crowbar.gen val eq_of_comp : ('a -> 'a -> int) -> ('a -> 'a -> bool) val pair : 'a Crowbar.gen -> 'b Crowbar.gen -> ('a * 'b) Crowbar.gen val check_json_roundtrip : name:string -> 'a Crowbar.gen -> ('a -> 'a -> bool) -> 'a OpamJson.encoder -> 'a OpamJson.decoder -> unit opam-2.1.5/src/crowbar/opamCudf_crowbar.ml0000644000175000017500000001077514427463453017566 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open Cudf_types open Cudf open! Crowbar open OpamCrowbar let version = nice_int let relop : relop gen = choose [ const `Eq; const `Neq; const `Geq; const `Gt; const `Leq; const `Lt; ] let constr = option (pair relop version) let pkgname = nice_string let vpkg = pair pkgname constr let vpkglist = list vpkg let enum_keep : enum_keep gen = choose [ const `Keep_version; const `Keep_package; const `Keep_feature; const `Keep_none; ] let vpkgformula = list (list vpkg) let veqpkg = pair pkgname (option (pair (const `Eq) version)) let veqpkglist = list veqpkg let rec typedecl1 : typedecl1 gen Lazy.t = lazy (choose [ (map [option nice_int] @@ fun v -> `Int v); (map [option nice_uint] @@ fun v -> `Posint v); (map [option nice_uint] @@ fun v -> `Nat v); (map [option bool] @@ fun v -> `Bool v); (map [option nice_string] @@ fun v -> `String v); (map [option nice_string] @@ fun v -> `Pkgname v); (map [option nice_string] @@ fun v -> `Ident v); (map [list nice_string; option nice_string; list nice_string] @@ fun left s right -> `Enum (left @ (match s with None -> [] | Some s -> [s]) @ right, s)); (map [option vpkg] @@ fun v -> `Vpkg v); (map [option vpkgformula] @@ fun v -> `Vpkgformula v); (map [option vpkglist] @@ fun v -> `Vpkglist v); (map [option veqpkg] @@ fun v -> `Veqpkg v); (map [option veqpkglist] @@ fun v -> `Veqpkglist v); (map [option (Crowbar.unlazy typedecl)] @@ fun v -> `Typedecl v); ]) and typedecl = lazy (list (pair nice_string (unlazy typedecl1))) let (lazy typedecl1) = typedecl1 and (lazy typedecl) = typedecl let typed_value : typed_value gen = choose [ (map [nice_int] @@ fun v -> `Int v); (map [nice_uint] @@ fun v -> `Posint v); (map [nice_uint] @@ fun v -> `Nat v); (map [bool] @@ fun v -> `Bool v); (map [nice_string] @@ fun v -> `String v); (map [nice_string] @@ fun v -> `Pkgname v); (map [nice_string] @@ fun v -> `Ident v); (map [nice_string] @@ fun v -> `Pkgname v); (map [list nice_string; nice_string; list nice_string] @@ fun left s right -> `Enum (left @ [s] @ right, s)); (map [vpkg] @@ fun v -> `Vpkg v); (map [vpkgformula] @@ fun v -> `Vpkgformula v); (map [vpkglist] @@ fun v -> `Vpkglist v); (map [veqpkg] @@ fun v -> `Veqpkg v); (map [veqpkglist] @@ fun v -> `Veqpkglist v); (map [typedecl] @@ fun v -> `Typedecl v); ] let stanza gen = list (pair nice_string gen) let package : package gen = map [ pkgname; version; vpkgformula; vpkglist; veqpkglist; bool; bool; enum_keep; stanza typed_value; ] (fun package version depends conflicts provides installed was_installed keep pkg_extra -> { package; version; depends; conflicts; provides; installed; was_installed; keep; pkg_extra; }) let check () = let open OpamCudf.Json in check_json_roundtrip ~name:"Cudf_types.relop" relop (=) relop_to_json relop_of_json; check_json_roundtrip ~name:"Cudf_types.constr" constr (=) constr_to_json constr_of_json; check_json_roundtrip ~name:"Cudf_types.vpkg" vpkg (=) vpkg_to_json vpkg_of_json; check_json_roundtrip ~name:"Cudf_types.enum_keep" enum_keep (=) enum_keep_to_json enum_keep_of_json; check_json_roundtrip ~name:"Cudf_types.veqpkg" veqpkg (=) veqpkg_to_json veqpkg_of_json; check_json_roundtrip ~name:"Cudf_types.typedecl1" typedecl1 (=) typedecl1_to_json typedecl1_of_json; check_json_roundtrip ~name:"Cudf_types.typed_value" typed_value (=) typed_value_to_json typed_value_of_json; check_json_roundtrip ~name:"Cudf.package" package OpamCudf.Package.equal package_to_json package_of_json; opam-2.1.5/src/crowbar/opamVersion_crowbar.ml0000644000175000017500000000173114427463453020322 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamVersion open! Crowbar open OpamCrowbar let version = choose [ const current; const (major current); const current_nopatch; const (full ()); ] let check () = check_json_roundtrip ~name:"OpamVersion.t" version (eq_of_comp OpamVersion.compare) to_json of_json; opam-2.1.5/src/ocaml-flags-configure.sexp.in0000644000175000017500000000002414427463453017754 0ustar stephsteph(@CONF_OCAMLFLAGS@) opam-2.1.5/src/format/0002755000175000017500000000000014427463453013600 5ustar stephstephopam-2.1.5/src/format/opamSysPkg.mli0000644000175000017500000000206014427463453016374 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** System package *) type t include OpamStd.ABSTRACT with type t := t val raw_set: OpamStd.String.Set.t -> Set.t (** System packages status *) type status = { s_available : Set.t; (** Package available but not installed *) s_not_found : Set.t; (** Package unavailable on this system *) } val status_empty: status val string_of_status: status -> string opam-2.1.5/src/format/opamFile.ml0000644000175000017500000040115414427463453015671 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** This module contains the handlers for reading and writing all of OPAM files, and defines their internal types (records for most of them). We handle three types of files: - raw text files, without lexing - "table" files, i.e. lexing is just cutting into lines and words, returning a string list list. These are mostly used internally - files using the "opam syntax" and lexer, parsed using OpamFormat.Pp.V *) open OpamParserTypes.FullPos open OpamTypes open OpamTypesBase open OpamStd.Op module OpamParser = OpamParser.FullPos module OpamPrinter = OpamPrinter.FullPos module Pp = struct include OpamPp module V = OpamFormat.V module I = OpamFormat.I let warn ?pos ?(strict=OpamFormatConfig.(!r.strict)) ?exn fmt = if strict then match exn with | Some e -> raise e | None -> bad_format ?pos fmt else Printf.ksprintf (fun s -> if OpamConsole.verbose () then match exn with | None -> OpamConsole.warning "%s" (OpamPp.string_of_bad_format (Bad_format (pos, s))) | Some e -> OpamConsole.warning "%s" (OpamPp.string_of_bad_format e)) fmt end open Pp.Op type 'a t = filename type 'a typed_file = 'a t let make f = (f: 'a t) let filename f = (f: 'a t :> filename) let to_string f = OpamFilename.to_string (filename f) let exists f = OpamFilename.exists (filename f) module type IO_FILE = sig type t val format_version: OpamVersion.t val empty: t val write: 'a typed_file -> t -> unit val read : 'a typed_file -> t val read_opt: 'a typed_file -> t option val safe_read: 'a typed_file -> t val read_from_channel: ?filename:'a typed_file -> in_channel -> t val read_from_string: ?filename:'a typed_file -> string -> t val write_to_channel: ?filename:'a typed_file -> out_channel -> t -> unit val write_to_string: ?filename:'a typed_file -> t -> string end module type IO_Arg = sig val internal : string type t val empty : t val of_channel : 'a typed_file -> in_channel -> t val to_channel : 'a typed_file -> out_channel -> t -> unit val of_string : 'a typed_file -> string -> t val to_string : 'a typed_file -> t -> string end module Stats = struct let read_files = ref [] let write_files = ref [] let print () = let aux kind = function | [] -> () | l -> OpamConsole.msg "%d files %s:\n %s\n" (List.length !read_files) kind (String.concat "\n " l) in aux "read" !read_files; aux "write" !write_files end let dummy_file = OpamFilename.raw "" module MakeIO (F : IO_Arg) = struct let log ?level fmt = OpamConsole.log (Printf.sprintf "FILE(%s)" F.internal) ?level fmt let slog = OpamConsole.slog let write f v = let filename = OpamFilename.to_string f in let chrono = OpamConsole.timer () in let oc = OpamFilename.(mkdir (dirname f)); try open_out_bin filename with Sys_error _ -> raise (OpamSystem.File_not_found filename) in try Unix.lockf (Unix.descr_of_out_channel oc) Unix.F_LOCK 0; F.to_channel f oc v; close_out oc; Stats.write_files := filename :: !Stats.write_files; log "Wrote %s in %.3fs" filename (chrono ()) with e -> OpamStd.Exn.finalise e @@ fun () -> close_out oc; OpamFilename.remove f let read_opt f = let filename = OpamFilename.prettify f in let chrono = OpamConsole.timer () in try let ic = OpamFilename.open_in f in try Unix.lockf (Unix.descr_of_in_channel ic) Unix.F_RLOCK 0; Stats.read_files := filename :: !Stats.read_files; let r = F.of_channel f ic in close_in ic; log ~level:3 "Read %s in %.3fs" filename (chrono ()); Some r with e -> OpamStd.Exn.finalise e (fun () -> close_in ic) with | OpamSystem.File_not_found _ -> None | e -> OpamStd.Exn.fatal e; if OpamFormatConfig.(!r.strict) then (OpamConsole.error "%s" (Pp.string_of_bad_format ~file:(OpamFilename.to_string f) e); OpamConsole.error_and_exit `File_error "Strict mode: aborting") else raise e let read f = match read_opt f with | Some f -> f | None -> OpamSystem.internal_error "File %s does not exist or can't be read" (OpamFilename.to_string f) let safe_read f = try match read_opt f with | Some f -> f | None -> log ~level:2 "Cannot find %a" (slog OpamFilename.to_string) f; F.empty with | (Pp.Bad_version _ | Pp.Bad_format _) as e-> OpamConsole.error "%s [skipped]\n" (Pp.string_of_bad_format ~file:(OpamFilename.to_string f) e); F.empty let read_from_f f input = try f input with | (Pp.Bad_version _ | Pp.Bad_format _) as e-> if OpamFormatConfig.(!r.strict) then (OpamConsole.error "%s" (Pp.string_of_bad_format e); OpamConsole.error_and_exit `File_error "Strict mode: aborting") else raise e let read_from_channel ?(filename=dummy_file) ic = read_from_f (F.of_channel filename) ic let read_from_string ?(filename=dummy_file) str = read_from_f (F.of_string filename) str let write_to_channel ?(filename=dummy_file) oc t = F.to_channel filename oc t let write_to_string ?(filename=dummy_file) t = F.to_string filename t end (** I - Raw text files (no parsing) *) (** Compiler and package description opam file fields: one-line title and content. Formerly, (/packages/.../descr, /compilers/.../.descr) *) module DescrIO = struct let internal = "descr" let format_version = OpamVersion.of_string "0" type t = string * string let empty = "", "" let synopsis = fst let body = snd let full (x,y) = match y with | "" -> x ^ "\n" | y -> String.concat "" [x; "\n\n"; y; "\n"] let of_channel _ ic = let x = try OpamStd.String.strip (input_line ic) with End_of_file | Sys_error _ -> "" in let y = try OpamStd.String.strip (OpamSystem.string_of_channel ic) with End_of_file | Sys_error _ -> "" in x, y let to_channel _ oc (x,y) = output_string oc x; output_char oc '\n'; if y <> "" then (output_char oc '\n'; output_string oc y; output_char oc '\n') let create str = let head, tail = match OpamStd.String.cut_at str '\n' with | None -> str, "" | Some (h,t) -> h, t in OpamStd.String.strip head, OpamStd.String.strip tail let of_string _ = create let to_string _ = full end module Descr = struct include DescrIO include MakeIO(DescrIO) end (* module Comp_descr = Descr *) (** Raw file interface used for variable expansions ( *.in ) *) (* module SubstIO = struct let internal = "subst" type t = string let empty = "" let of_channel _ ic = OpamSystem.string_of_channel ic let to_channel _ oc t = output_string oc t let of_string _ str = str let to_string _ t = t end module Subst = struct include SubstIO include MakeIO(SubstIO) end *) (** II - Base word list list parser and associated file types *) module LinesBase = struct (* Lines of space separated words *) type t = string list list let format_version = OpamVersion.of_string "0" let empty = [] let internal = "lines" let find_escapes s len = let rec aux acc i = if i < 0 then acc else let acc = match s.[i] with | '\\' | ' ' | '\t' | '\n' -> let esc,count = acc in i::esc, count + 1 | _ -> acc in aux acc (i-1) in aux ([],0) (len - 1) let escape_spaces = function | "" -> "@" | "@" -> "\\@" | str -> let len = String.length str in match find_escapes str len with | [], _ -> str | escapes, n -> let buf = Bytes.create (len + n) in let rec aux i = function | ofs1::(ofs2::_ as r) -> Bytes.blit_string str ofs1 buf (ofs1+i) (ofs2-ofs1); Bytes.set buf (ofs2+i) '\\'; aux (i+1) r | [ofs] -> Bytes.blit_string str ofs buf (ofs+i) (len-ofs); buf | [] -> assert false in Bytes.to_string (aux 0 (0::escapes)) let of_channel (_:filename) ic = OpamLineLexer.main (Lexing.from_channel ic) let to_channel (_:filename) oc t = List.iter (function | [] -> () | w::r -> output_string oc (escape_spaces w); List.iter (fun w -> output_char oc '\t'; output_string oc (escape_spaces w)) r; output_char oc '\n') t let of_string (_:filename) str = OpamLineLexer.main (Lexing.from_string str) let to_string (_:filename) (lines: t) = let buf = Buffer.create 1024 in List.iter (fun l -> (match l with | [] -> () | w::r -> Buffer.add_string buf (escape_spaces w); List.iter (fun w -> Buffer.add_char buf '\t'; Buffer.add_string buf (escape_spaces w)) r); Buffer.add_string buf "\n" ) lines; Buffer.contents buf let file_none = OpamFilename.of_string "" let pp_string = Pp.pp (fun ~pos:_ s -> OpamLineLexer.main (Lexing.from_string s)) (fun lines -> to_string file_none lines) let pp_channel ic oc = Pp.pp (fun ~pos:_ () -> of_channel file_none ic) (to_channel file_none oc) end module Lines = struct include LinesBase include MakeIO(LinesBase) end module type LineFileArg = sig val internal: string type t val empty: t val pp: (string list list, t) Pp.t end module LineFile (X: LineFileArg) = struct module IO = struct include X let format_version = OpamVersion.of_string "0" let to_channel _ oc t = Pp.print (Lines.pp_channel stdin oc -| pp) t let to_string _ t = Pp.print (Lines.pp_string -| pp) t let of_channel filename ic = Pp.parse (Lines.pp_channel ic stdout -| pp) ~pos:(pos_file filename) () let of_string filename str = Pp.parse (Lines.pp_string -| pp) ~pos:{ pos_null with filename = OpamFilename.to_string filename } str end include IO include MakeIO(IO) end (** (1) Internal usage only *) (** Compiler aliases definitions (aliases): table *) module Aliases = LineFile(struct let internal = "aliases" type t = string switch_map let empty = OpamSwitch.Map.empty let pp = OpamSwitch.Map.(OpamFormat.lines_map ~empty ~add ~fold) @@ Pp.of_module "switch-name" (module OpamSwitch) ^+ Pp.last end) (** Indices of items and their associated source repository: table *) module Repo_index (A : OpamStd.ABSTRACT) = LineFile(struct let internal = "repo-index" type t = (repository_name * string option) A.Map.t let empty = A.Map.empty let pp = OpamFormat.lines_map ~empty ~add:A.Map.safe_add ~fold:A.Map.fold @@ Pp.of_module "name" (module A) ^+ Pp.of_module "repository" (module OpamRepositoryName) ^+ Pp.opt Pp.last end) module Package_index = Repo_index(OpamPackage) (** List of packages (/installed, /installed-roots, /reinstall): table *) module PkgList = LineFile (struct let internal = "package-version-list" type t = package_set let empty = OpamPackage.Set.empty let pp = OpamPackage.Set.(OpamFormat.lines_set ~empty ~add ~fold) @@ (Pp.of_module "pkg-name" (module OpamPackage.Name) ^+ Pp.last -| Pp.of_module "pkg-version" (module OpamPackage.Version)) -| Pp.pp (fun ~pos:_ (n,v) -> OpamPackage.create n v) (fun nv -> nv.name, nv.version) end) (** Lists of pinned packages (/pinned): table Backwards-compatibility code, do not use *) module Pinned_legacy = struct type pin_option = | Version of version | Source of url let pp_pin = let looks_like_version_re = Re.(compile @@ seq [bos; digit; rep @@ diff any (set "/\\"); eos]) in let pin_option_of_string ?kind s = match kind with | Some `version -> Version (OpamPackage.Version.of_string s) | None when Re.execp looks_like_version_re s -> Version (OpamPackage.Version.of_string s) | Some (#OpamUrl.backend as backend) -> Source (OpamUrl.parse ~backend s) | None -> Source (OpamUrl.parse ~handle_suffix:false s) in let string_of_pin_kind = function | `version -> "version" | `rsync -> "path" | #OpamUrl.backend as ub -> OpamUrl.string_of_backend ub in let pin_kind_of_string = function | "version" -> `version | "path" -> `rsync | s -> OpamUrl.backend_of_string s in let string_of_pin_option = function | Version v -> OpamPackage.Version.to_string v | Source url -> OpamUrl.to_string url in let kind_of_pin_option = function | Version _ -> `version | Source url -> (url.OpamUrl.backend :> pin_kind) in Pp.pp ~name:"?pin-kind pin-target" (fun ~pos -> function | [x] -> pin_option_of_string x | [k;x] -> pin_option_of_string ~kind:(pin_kind_of_string k) x | _ -> Pp.bad_format ~pos "Invalid number of fields") (fun x -> [string_of_pin_kind (kind_of_pin_option x); string_of_pin_option x]) include LineFile(struct let internal = "pinned" type t = pin_option OpamPackage.Name.Map.t let empty = OpamPackage.Name.Map.empty let pp = OpamPackage.Name.Map.(OpamFormat.lines_map ~empty ~add:safe_add ~fold) @@ Pp.of_module "pkg-name" (module OpamPackage.Name) ^+ pp_pin end) end (** Cached environment updates (/.opam-switch/environment) *) module Environment = LineFile(struct let internal = "environment" type t = env_update list let empty = [] let pp = (OpamFormat.lines_set ~empty:[] ~add:OpamStd.List.cons ~fold:List.fold_right @@ Pp.identity ^+ Pp.of_pair "env_update_op" (OpamLexer.FullPos.env_update_op, OpamPrinter.env_update_op_kind) ^+ Pp.identity ^+ Pp.opt Pp.singleton) -| Pp.pp (fun ~pos:_ -> List.rev) List.rev let pp = pp -| Pp.map_list (Pp.pp (fun ~pos:_ (a, (b, (c, d))) -> (a, b, c, d)) (fun (a, b, c, d) -> (a, (b, (c, d))))) end) (** (2) Part of the public repository format *) (** repository index files ("urls.txt"): table *) module File_attributes = LineFile(struct let internal = "file_attributes" type t = file_attribute_set let empty = OpamFilename.Attribute.Set.empty let pp = OpamFilename.Attribute.Set.(OpamFormat.lines_set ~empty ~add ~fold) @@ (Pp.of_module "file" (module OpamFilename.Base) ^+ Pp.of_pair "checksum" OpamHash.(of_string, contents) ^+ Pp.opt (Pp.last -| Pp.of_pair "perm" (int_of_string, string_of_int)) ) -| Pp.pp (fun ~pos:_ (base,(hash,perm)) -> OpamFilename.Attribute.create base hash perm) (fun att -> OpamFilename.Attribute.(base att, (md5 att, perm att))) end) (** (3) Available in interface *) (** Old Switch export/import format: table [pinning-kind] [pinning-url] *) module StateTable = struct let internal = "export" module M = OpamPackage.Name.Map type t = switch_selections let empty = { sel_installed = OpamPackage.Set.empty; sel_roots = OpamPackage.Set.empty; sel_compiler = OpamPackage.Set.empty; sel_pinned = OpamPackage.Set.empty; } let pp_state = Pp.pp ~name:"pkg-state" (fun ~pos:_ -> function | "compiler" -> `Compiler | "root" -> `Root | "noroot" | "installed" -> `Installed | "uninstalled" -> `Uninstalled | "uninstalled-compiler" -> `Uninstalled_compiler | _ -> Pp.unexpected ()) (function | `Compiler -> "compiler" | `Root -> "root" | `Installed -> "installed" | `Uninstalled -> "uninstalled" | `Uninstalled_compiler -> "uninstalled-compiler") let pp_lines = M.(OpamFormat.lines_map ~empty ~add:safe_add ~fold) @@ Pp.of_module "pkg-name" (module OpamPackage.Name) ^+ Pp.of_module "pkg-version" (module OpamPackage.Version) ^+ (Pp.opt (pp_state ^+ Pp.opt Pinned_legacy.pp_pin) -| Pp.default (`Root, None)) (* Convert from one name-map to type t *) let pp = pp_lines -| Pp.pp (fun ~pos:_ map -> M.fold (fun name (version,(state,pin)) t -> let nv = OpamPackage.create name version in { sel_installed = (match state with | `Installed | `Root | `Compiler -> OpamPackage.Set.add nv t.sel_installed | `Uninstalled | `Uninstalled_compiler -> t.sel_installed); sel_roots = (match state with | `Root | `Compiler -> OpamPackage.Set.add nv t.sel_roots | `Installed | `Uninstalled | `Uninstalled_compiler -> t.sel_roots); sel_compiler = (match state with | `Compiler | `Uninstalled_compiler -> OpamPackage.Set.add nv t.sel_compiler | `Root | `Installed | `Uninstalled -> t.sel_compiler); sel_pinned = (match pin with | Some (Pinned_legacy.Version v) -> OpamPackage.Set.add (OpamPackage.create name v) t.sel_pinned | Some _ -> OpamPackage.Set.add (OpamPackage.create name version) t.sel_pinned | None -> t.sel_pinned); }) map empty) (fun t -> M.empty |> OpamPackage.Set.fold (fun nv -> M.add nv.name (nv.version, (`Installed, None))) t.sel_installed |> OpamPackage.Set.fold (fun nv -> M.add nv.name (nv.version, (`Root, None))) t.sel_roots |> OpamPackage.Set.fold (fun nv acc -> let name = nv.name in try let (v, _) = M.find name acc in M.add name (v, (`Compiler, None)) acc with Not_found -> M.add name (nv.version, (`Uninstalled_compiler, None)) acc) t.sel_compiler |> OpamPackage.Set.fold (fun nv map -> let state = try let _, (state, _) = M.find nv.name map in state with Not_found -> `Uninstalled in (* Incorrect: marks all pins as version. But this is deprecated. *) M.add nv.name (nv.version, (state, Some (Pinned_legacy.Version nv.version))) map) t.sel_pinned) end module LegacyState = struct type t = switch_selections include (LineFile (StateTable) : IO_FILE with type t := t) end (** III - Opam Syntax parser and associated file types *) module Syntax = struct (* Idea: have a [(ic, oc_with_lock * t) pp] that can be used to reading and re-writing files with a guarantee that it hasn't been rewritten in the meantime *) let parser_main lexbuf filename = let error msg = let curr = lexbuf.Lexing.lex_curr_p in let start = lexbuf.Lexing.lex_start_p in let pos = { filename = curr.Lexing.pos_fname; start = start.Lexing.pos_lnum, start.Lexing.pos_cnum - start.Lexing.pos_bol; stop = (* XXX here we take current position, where error occurs as end position *) curr.Lexing.pos_lnum, curr.Lexing.pos_cnum - curr.Lexing.pos_bol; } in raise (OpamPp.Bad_format (Some pos, msg)) in let filename = OpamFilename.to_string filename in lexbuf.Lexing.lex_curr_p <- { lexbuf.Lexing.lex_curr_p with Lexing.pos_fname = filename }; try OpamParser.main OpamLexer.token lexbuf filename with | OpamLexer.Error msg -> error msg | Parsing.Parse_error -> error "Parse error" let pp_channel filename ic oc = Pp.pp (fun ~pos:_ () -> let lexbuf = Lexing.from_channel ic in parser_main lexbuf filename) (fun file -> let fmt = Format.formatter_of_out_channel oc in OpamPrinter.format_opamfile fmt file) let of_channel (filename:filename) (ic:in_channel) = Pp.parse ~pos:(pos_file filename) (pp_channel filename ic stdout) () let to_channel filename oc t = Pp.print (pp_channel filename stdin oc) t let of_string (filename:filename) str = let lexbuf = Lexing.from_string str in parser_main lexbuf filename let to_string _file_name t = OpamPrinter.opamfile t let to_string_with_preserved_format filename ?(format_from=filename) ?format_from_string ~empty ?(sections=[]) ~fields pp t = let current_str_opt = match format_from_string with | Some s -> Some s | None -> try Some (OpamFilename.read format_from) with OpamSystem.File_not_found _ -> None in match current_str_opt with | None -> to_string filename (Pp.print pp (filename, t)) | Some str -> let syn_file = of_string filename str in let syn_t = Pp.print pp (filename, t) in let it_ident it = match it.pelem with | Variable (f, _) -> `Var f.pelem | Section ({section_kind = k; section_name = n; _}) -> `Sec (k.pelem, OpamStd.Option.map (fun x -> x.pelem) n) in let lines_index = let rec aux acc s = let until = try Some (String.index_from s (List.hd acc) '\n') with Not_found -> None in match until with | Some until -> aux (until+1 :: acc) s | None -> Array.of_list (List.rev acc) in aux [0] str in let pos_index (li,col) = lines_index.(li - 1) + col in let extract start stop = String.sub str start (stop - start) in let value_list_str lastpos vlst vlst_raw = let extract_pos start stop = extract (pos_index start) (pos_index stop) in let def_blank blank = OpamStd.Option.default "\n " blank in let find_split f = let rec aux p = function | x::r when f x -> Some (p, x, r) | p::r -> aux (Some p) r | [] -> None in aux None in let full_vlst_raw = vlst_raw in let rec aux lastpos blank acc vlst vlst_raw = match vlst, vlst_raw with | v::r, vraw :: rraw when OpamPrinter.value_equals v vraw -> let blank = extract lastpos (pos_index vraw.pos.start) in let str = extract_pos vraw.pos.start vraw.pos.stop in let new_v = blank ^ str in let blank = Some blank in let lastpos = pos_index vraw.pos.stop in aux lastpos blank (new_v :: acc) r rraw | v::r , _ -> (match find_split (OpamPrinter.value_equals v) full_vlst_raw with | Some (pvraw, vraw, rraw) -> let str = extract_pos vraw.pos.start vraw.pos.stop in let blank, lastpos = if pos_index vraw.pos.start - lastpos <= 0 then def_blank blank, lastpos else (let start = match pvraw with | Some pvraw -> pos_index pvraw.pos.stop | None -> lastpos in let stop = pos_index vraw.pos.start in extract start stop), pos_index vraw.pos.stop in let new_v = blank ^ str in let blank = Some blank in aux lastpos blank (new_v :: acc) r rraw | None -> let blank, rraw, lastpos = match vlst_raw with | vraw :: rraw -> let blank = extract lastpos (pos_index vraw.pos.start) in let rraw, lastpos = if OpamStd.List.find_opt (OpamPrinter.value_equals vraw) vlst <> None then vlst_raw, lastpos else rraw, pos_index vraw.pos.stop in blank, rraw, lastpos | [] -> def_blank blank, vlst_raw, lastpos in let new_v = blank ^ (OpamPrinter.value v) in let blank = Some blank in aux lastpos blank (new_v :: acc) r rraw) | [], _ -> acc in aux lastpos None [] vlst vlst_raw in let item_var_str name field = let field_raw = List.find (fun i -> it_ident i = `Var name) syn_file.file_contents in match field.pelem with | Variable (n, { pelem = List { pelem = full_vlst;_}; _}) when n.pelem = name -> let full_vlst_raw, full_vlst_raw_pos = match field_raw.pelem with | Variable (_, {pelem = List vlst_raw; pos}) -> vlst_raw.pelem, pos | _ -> raise Not_found in (* if empty, rewrite full field *) if full_vlst_raw = [] then OpamPrinter.items [field] else (* aux *) let item_var_str = let lastpos = pos_index full_vlst_raw_pos.start +1 in let final_list = value_list_str lastpos full_vlst full_vlst_raw in String.concat "" (List.rev final_list) in let beginning = let start = pos_index field_raw.pos.start in let stop = pos_index full_vlst_raw_pos.start +1 in extract start stop in let ending = let start = pos_index (List.hd (List.rev full_vlst_raw)).pos.stop in let stop = pos_index full_vlst_raw_pos.stop in extract start stop in beginning ^ item_var_str ^ ending | _ -> OpamPrinter.items [field] in (* Fields *) let get_padding item lastpos = let start = pos_index item.pos.start in let stop = pos_index item.pos.stop in let padding = extract lastpos start in padding, stop in let field_str item lastpos strs = let start = pos_index item.pos.start in let padding, stop = get_padding item lastpos in let field = extract start stop in field :: padding :: strs, stop in let rem, (strs, lastpos) = List.fold_left (fun (rem, (strs, lastpos)) item -> List.filter (fun i -> it_ident i <> it_ident item) rem, let pos = item.pos in match item.pelem with | Variable (name, v) -> let name = name.pelem in (try let ppa = List.assoc name fields in match snd (Pp.print ppa t) with | None | Some { pelem = List { pelem = []; _}; _} | Some { pelem = List { pelem = [ { pelem = List { pelem = []; _}; _}]; _}; _} -> strs, pos_index item.pos.stop | field_syn_t when field_syn_t = snd (Pp.print ppa (Pp.parse ppa ~pos (empty, Some v))) -> (* unchanged *) field_str item lastpos strs | _ -> try let field = List.find (fun i -> it_ident i = `Var name) syn_t.file_contents in let f = item_var_str name field in let padding, stop = get_padding item lastpos in f :: padding :: strs, stop with Not_found -> strs, pos_index item.pos.stop with Not_found | OpamPp.Bad_format _ -> if OpamStd.String.starts_with ~prefix:"x-" name && OpamStd.List.find_opt (fun i -> it_ident i = `Var name) syn_t.file_contents <> None then field_str item lastpos strs else strs, pos_index item.pos.stop) | Section {section_kind; section_name; section_items} -> let section_kind = section_kind.pelem in let section_items = section_items.pelem in let section_name = OpamStd.Option.map (fun x -> x.pelem) section_name in (try let ppa = List.assoc section_kind sections in let print_sec ppa t = match snd (Pp.print ppa t) with | None -> None | Some v -> try Some (List.assoc section_name v) with Not_found -> None in let sec_field_t = print_sec ppa t in if sec_field_t <> None && sec_field_t = print_sec ppa (Pp.parse ppa ~pos (empty, Some [section_name, section_items])) then (* unchanged *) field_str item lastpos strs else let f = List.filter (fun i -> it_ident i = `Sec (section_kind, section_name)) syn_t.file_contents in let padding, stop = get_padding item lastpos in (OpamPrinter.items f :: padding :: strs), stop with Not_found | OpamPp.Bad_format _ -> strs, pos_index item.pos.stop)) (syn_t.file_contents, ([], 0)) syn_file.file_contents in let str = String.concat "" (List.rev strs) in let str = if rem = [] then str else str ^ "\n" ^ (OpamPrinter.items rem) in let str = let last = lines_index.(Array.length lines_index -1) in if last <= lastpos then str else str ^ extract lastpos last in str let contents pp ?(filename=dummy_file) t = Pp.print pp (filename, t) let to_list pp ?(filename=dummy_file) t = let rec aux acc pfx = function | {pelem=Section ({section_kind; section_name=None; section_items});_} :: r -> aux (aux acc (section_kind.pelem :: pfx) section_items.pelem) pfx r | {pelem=Section ({section_kind; section_name=Some n; section_items});_} :: r -> aux (aux acc (Printf.sprintf "%s(%s)" section_kind.pelem n.pelem :: pfx) section_items.pelem) pfx r | {pelem=Variable (name, value);_} :: r -> aux (((name.pelem :: pfx), value) :: acc) pfx r | [] -> acc in List.rev_map (fun (pfx, value) -> String.concat "." (List.rev pfx), value) (aux [] [] (contents pp ~filename t).file_contents) end module type SyntaxFileArg = sig val internal: string val format_version: OpamVersion.t type t val empty: t val pp: (opamfile, filename * t) Pp.t end module SyntaxFile(X: SyntaxFileArg) : IO_FILE with type t := X.t = struct module IO = struct let to_opamfile filename t = Pp.print X.pp (filename, t) let catch_future_syntax_error = function | {file_contents = [{pelem = Variable({pelem = "opam-version"; _}, {pelem = String ver; _}); _ }; {pelem = Section {section_kind = {pelem = "#"; _}; _}; pos}]; _} when OpamVersion.(compare (nopatch (of_string ver)) (nopatch X.format_version)) <= 0 -> raise (OpamPp.Bad_version (Some pos, "Parse error")) | opamfile -> opamfile let of_channel filename (ic:in_channel) = let opamfile = Syntax.of_channel filename ic |> catch_future_syntax_error in Pp.parse X.pp ~pos:(pos_file filename) opamfile |> snd let to_channel filename oc t = Syntax.to_channel filename oc (to_opamfile filename t) let of_string (filename:filename) str = let opamfile = Syntax.of_string filename str |> catch_future_syntax_error in Pp.parse X.pp ~pos:(pos_file filename) opamfile |> snd let to_string filename t = Syntax.to_string filename (to_opamfile filename t) end include IO include X include MakeIO(struct include X include IO end) end (* Error less reading for forward compatibility of opam roots *) module type BestEffortArg = sig include SyntaxFileArg (* Version of file format, as understood by [opam-file-format] *) (* This attribute can be deleted when 4.02 is ditched *) [@@@ocaml.warning "-32"] val file_format_version: OpamVersion.t [@@ocaml.warning "-32"] (* Construct the syntax pp, under some conditions. If [condition] is given, it is passed to [OpamFormat.show_erros] call, for error display conditions, default is to display it as a warning. If [f] is given, it is passed to [OpamFormat.check_opam_version] call, it is the check function, default is to check regarding [file_format_version]. *) val pp_cond: ?f:(OpamVersion.t -> bool) -> ?condition:(t -> bool) -> unit -> (opamfile, filename * t) Pp.t end module type BestEffortRead = sig type t val read: t typed_file -> t val read_opt: t typed_file -> t option val safe_read: t typed_file -> t val read_from_channel: ?filename:t typed_file -> in_channel -> t val read_from_string: ?filename:t typed_file -> string -> t end module MakeBestEffort (S: BestEffortArg) : BestEffortRead with type t := S.t = struct module ES = struct include S let pp = pp_cond (* to read newer oapm root with newer `opam-version` field, we need to be less strict on the check_opam_version ~f:(fun _ -> true) *) ~condition:(fun _ -> false) () end include ES include SyntaxFile(ES) end (** (1) Internal files *) (** Structure shared by a few file formats *) module Wrappers = struct type t = { pre_build : command list; wrap_build : command list; post_build : command list; pre_install : command list; wrap_install : command list; post_install : command list; pre_remove : command list; wrap_remove : command list; post_remove : command list; pre_session : command list; post_session : command list; } let empty = { pre_build = []; wrap_build = []; post_build = []; pre_install = []; wrap_install = []; post_install = []; pre_remove = []; wrap_remove = []; post_remove = []; pre_session = []; post_session = [] } let pre_build t = t.pre_build let wrap_build t = t.wrap_build let post_build t = t.post_build let pre_install t = t.pre_install let wrap_install t = t.wrap_install let post_install t = t.post_install let pre_remove t = t.pre_remove let wrap_remove t = t.wrap_remove let post_remove t = t.post_remove let pre_session t = t.pre_session let post_session t = t.post_session let with_pre_build pre_build t = { t with pre_build } let with_wrap_build wrap_build t = { t with wrap_build } let with_post_build post_build t = { t with post_build } let with_pre_install pre_install t = { t with pre_install } let with_wrap_install wrap_install t = { t with wrap_install } let with_post_install post_install t = { t with post_install } let with_pre_remove pre_remove t = { t with pre_remove } let with_wrap_remove wrap_remove t = { t with wrap_remove } let with_post_remove post_remove t = { t with post_remove } let with_pre_session pre_session t = { t with pre_session } let with_post_session post_session t = { t with post_session } let fields = [ "pre-build-commands", Pp.ppacc with_pre_build pre_build (Pp.V.map_list ~depth:2 Pp.V.command); "pre-install-commands", Pp.ppacc with_pre_install pre_install (Pp.V.map_list ~depth:2 Pp.V.command); "pre-remove-commands", Pp.ppacc with_pre_remove pre_remove (Pp.V.map_list ~depth:2 Pp.V.command); "pre-session-commands", Pp.ppacc with_pre_session pre_session (Pp.V.map_list ~depth:2 Pp.V.command); "wrap-build-commands", Pp.ppacc with_wrap_build wrap_build (Pp.V.map_list ~depth:2 Pp.V.command); "wrap-install-commands", Pp.ppacc with_wrap_install wrap_install (Pp.V.map_list ~depth:2 Pp.V.command); "wrap-remove-commands", Pp.ppacc with_wrap_remove wrap_remove (Pp.V.map_list ~depth:2 Pp.V.command); "post-build-commands", Pp.ppacc with_post_build post_build (Pp.V.map_list ~depth:2 Pp.V.command); "post-install-commands", Pp.ppacc with_post_install post_install (Pp.V.map_list ~depth:2 Pp.V.command); "post-remove-commands", Pp.ppacc with_post_remove post_remove (Pp.V.map_list ~depth:2 Pp.V.command); "post-session-commands", Pp.ppacc with_post_session post_session (Pp.V.map_list ~depth:2 Pp.V.command); ] let with_default ~default t = let f = function [] -> fun l -> l | l -> fun _ -> l in { pre_build = f t.pre_build default.pre_build; wrap_build = f t.wrap_build default.wrap_build; post_build = f t.post_build default.post_build; pre_install = f t.pre_install default.pre_install; wrap_install = f t.wrap_install default.wrap_install; post_install = f t.post_install default.post_install; pre_remove = f t.pre_remove default.pre_remove; wrap_remove = f t.wrap_remove default.wrap_remove; post_remove = f t.post_remove default.post_remove; pre_session = f t.pre_session default.pre_session; post_session = f t.post_session default.post_session; } let add ~outer ~inner = { pre_build = outer.pre_build @ inner.pre_build; wrap_build = outer.wrap_build @ inner.wrap_build; post_build = inner.post_build @ outer.post_build; pre_install = outer.pre_install @ inner.pre_install; wrap_install = outer.wrap_install @ inner.wrap_install; post_install = inner.post_install @ outer.post_install; pre_remove = outer.pre_remove @ inner.pre_remove; wrap_remove = outer.wrap_remove @ inner.wrap_remove; post_remove = inner.post_remove @ outer.post_remove; pre_session = outer.pre_session @ inner.pre_session; post_session = inner.post_session @ outer.post_session; } end (** General opam configuration (config) *) module ConfigSyntax = struct let internal = "config" let format_version = OpamVersion.of_string "2.1" let file_format_version = OpamVersion.of_string "2.0" let root_version = OpamVersion.of_string "2.1" let default_old_root_version = OpamVersion.of_string "2.1~~previous" type t = { opam_version : opam_version; opam_root_version: opam_version; repositories : repository_name list; installed_switches : switch list; switch : switch option; jobs : int option; dl_tool : arg list option; dl_jobs : int; dl_cache : url list option; wrappers : Wrappers.t; solver_criteria : (solver_criteria * string) list; best_effort_prefix : string option; solver : arg list option; global_variables : (variable * variable_contents * string) list; eval_variables : (variable * string list * string) list; validation_hook : arg list option; default_compiler : formula; default_invariant : formula; depext: bool; depext_run_installs : bool; depext_cannot_install : bool; depext_bypass: OpamSysPkg.Set.t; } let opam_version t = t.opam_version let opam_root_version t = t.opam_root_version let opam_root_version_opt t = if OpamVersion.compare t.opam_root_version default_old_root_version = 0 then None else Some t.opam_root_version let repositories t = t.repositories let installed_switches t = t.installed_switches let switch t = t.switch let jobs t = t.jobs let dl_tool t = t.dl_tool let dl_jobs t = t.dl_jobs let dl_cache t = OpamStd.Option.default [] t.dl_cache let criteria t = t.solver_criteria let best_effort_prefix t = t.best_effort_prefix let criterion kind t = try Some (List.assoc kind t.solver_criteria) with Not_found -> None let solver t = t.solver let wrappers t = t.wrappers let global_variables t = t.global_variables let eval_variables t = t.eval_variables let validation_hook t = t.validation_hook let default_compiler t = t.default_compiler let default_invariant t = t.default_invariant let depext t = t.depext let depext_run_installs t = t.depext_run_installs let depext_cannot_install t = t.depext_cannot_install let depext_bypass t = t.depext_bypass let with_opam_version opam_version t = { t with opam_version } let with_opam_root_version opam_root_version t = { t with opam_root_version } let with_repositories repositories t = { t with repositories } let with_installed_switches installed_switches t = { t with installed_switches } let with_switch_opt switch t = { t with switch } let with_switch switch t = { t with switch = Some switch } let with_jobs jobs t = { t with jobs = Some jobs} let with_jobs_opt jobs t = { t with jobs } let with_dl_tool dl_tool t = { t with dl_tool = Some dl_tool } let with_dl_tool_opt dl_tool t = { t with dl_tool } let with_dl_jobs dl_jobs t = { t with dl_jobs } let with_dl_cache dl_cache t = { t with dl_cache = Some dl_cache } let with_criteria solver_criteria t = { t with solver_criteria } let with_criterion kind criterion t = { t with solver_criteria = (kind,criterion)::List.remove_assoc kind t.solver_criteria } let with_best_effort_prefix s t = { t with best_effort_prefix = Some s } let with_best_effort_prefix_opt s t = { t with best_effort_prefix = s } let with_solver solver t = { t with solver = Some solver } let with_solver_opt solver t = { t with solver } let with_wrappers wrappers t = { t with wrappers } let with_global_variables global_variables t = { t with global_variables } let with_eval_variables eval_variables t = { t with eval_variables } let with_validation_hook validation_hook t = { t with validation_hook = Some validation_hook} let with_validation_hook_opt validation_hook t = { t with validation_hook } let with_default_compiler default_compiler t = { t with default_compiler } let with_default_invariant default_invariant t = { t with default_invariant } let with_depext depext t = { t with depext } let with_depext_run_installs depext_run_installs t = { t with depext_run_installs } let with_depext_cannot_install depext_cannot_install t = { t with depext_cannot_install } let with_depext_bypass depext_bypass t = { t with depext_bypass } let empty = { opam_version = file_format_version; opam_root_version = default_old_root_version; repositories = []; installed_switches = []; switch = None; jobs = None; dl_tool = None; dl_jobs = 1; dl_cache = None; solver_criteria = []; best_effort_prefix = None; solver = None; wrappers = Wrappers.empty; global_variables = []; eval_variables = []; validation_hook = None; default_compiler = OpamFormula.Empty; default_invariant = OpamFormula.Empty; depext = true; depext_run_installs = true; depext_cannot_install = false; depext_bypass = OpamSysPkg.Set.empty; } (* When adding a field, make sure to add it in [OpamConfigCommand.global_allowed_fields] if it is a user modifiable field. When creating sections, make sure to update [OpamConfigCommand.global_allowed_sections] and [OpamConfigCommand.get_scope]. *) let fields = let with_switch sw t = if t.switch = None then with_switch sw t else Pp.bad_format "Multiple switch specifications" in [ "opam-version", Pp.ppacc with_opam_version opam_version (Pp.V.string -| Pp.of_module "opam-version" (module OpamVersion)); "opam-root-version", Pp.ppacc with_opam_root_version opam_root_version (Pp.V.string -| Pp.of_module "opam-version" (module OpamVersion)); "repositories", Pp.ppacc with_repositories repositories (Pp.V.map_list ~depth:1 (Pp.V.string -| Pp.of_module "repository" (module OpamRepositoryName))); "installed-switches", Pp.ppacc with_installed_switches installed_switches (Pp.V.map_list ~depth:1 (Pp.V.string -| Pp.of_module "switch" (module OpamSwitch))); "switch", Pp.ppacc_opt with_switch switch (Pp.V.string -| Pp.of_module "switch" (module OpamSwitch)); "jobs", Pp.ppacc_opt with_jobs jobs Pp.V.pos_int; "download-command", Pp.ppacc_opt with_dl_tool dl_tool (Pp.V.map_list ~depth:1 Pp.V.arg); "download-jobs", Pp.ppacc with_dl_jobs dl_jobs Pp.V.pos_int; "archive-mirrors", Pp.ppacc_opt with_dl_cache (fun t -> t.dl_cache) (Pp.V.map_list ~depth:1 Pp.V.url); "solver-criteria", Pp.ppacc_opt (with_criterion `Default) (criterion `Default) Pp.V.string; "solver-upgrade-criteria", Pp.ppacc_opt (with_criterion `Upgrade) (criterion `Upgrade) Pp.V.string; "solver-fixup-criteria", Pp.ppacc_opt (with_criterion `Fixup) (criterion `Fixup) Pp.V.string; "best-effort-prefix-criteria", Pp.ppacc_opt with_best_effort_prefix best_effort_prefix Pp.V.string; "solver", Pp.ppacc_opt with_solver solver (Pp.V.map_list ~depth:1 Pp.V.arg); "global-variables", Pp.ppacc with_global_variables global_variables (Pp.V.map_list ~depth:2 (Pp.V.map_triple (Pp.V.ident -| Pp.of_module "variable" (module OpamVariable)) Pp.V.variable_contents Pp.V.string)); "eval-variables", Pp.ppacc with_eval_variables eval_variables (Pp.V.map_list ~depth:2 (Pp.V.map_triple (Pp.V.ident -| Pp.of_module "variable" (module OpamVariable)) (Pp.V.map_list Pp.V.string) Pp.V.string)); "repository-validation-command", Pp.ppacc_opt with_validation_hook validation_hook (Pp.V.map_list ~depth:1 Pp.V.arg); "default-compiler", Pp.ppacc with_default_compiler default_compiler (Pp.V.package_formula `Disj Pp.V.(constraints Pp.V.version)); "default-invariant", Pp.ppacc with_default_invariant default_invariant (Pp.V.package_formula `Conj Pp.V.(constraints Pp.V.version)); "depext", Pp.ppacc with_depext depext Pp.V.bool; "depext-run-installs", Pp.ppacc with_depext_run_installs depext_run_installs Pp.V.bool; "depext-cannot-install", Pp.ppacc with_depext_cannot_install depext_cannot_install Pp.V.bool; "depext-bypass", Pp.ppacc with_depext_bypass depext_bypass (Pp.V.map_list (Pp.V.string -| Pp.of_module "sys-package" (module OpamSysPkg)) -| Pp.of_pair "System package set" OpamSysPkg.Set.(of_list, elements)); (* deprecated fields *) "alias", Pp.ppacc_opt with_switch OpamStd.Option.none (Pp.V.string -| Pp.of_module "switch-name" (module OpamSwitch)); "ocaml-version", Pp.ppacc_opt with_switch OpamStd.Option.none (Pp.V.string -| Pp.of_module "switch-name" (module OpamSwitch)); "cores", Pp.ppacc_opt with_jobs OpamStd.Option.none Pp.V.pos_int; "system-ocaml-version", Pp.ppacc_ignore; ] @ List.map (fun (fld, ppacc) -> fld, Pp.embed with_wrappers wrappers ppacc) Wrappers.fields let pp_cond ?f ?condition () = let name = internal in let format_version = file_format_version in Pp.I.map_file @@ Pp.I.check_opam_version ?f ~format_version () -| Pp.I.opam_version ~format_version () -| Pp.I.fields ~name ~empty fields -| Pp.I.show_errors ~name ?condition () let pp = pp_cond () let to_list = Syntax.to_list pp end module Config = struct include ConfigSyntax include SyntaxFile(ConfigSyntax) module BestEffort = MakeBestEffort(ConfigSyntax) let raw_root_version f = try let opamfile = OpamParser.file (OpamFilename.to_string (filename f)) in Some (OpamStd.List.find_map (function | { pelem = Variable ({ pelem = "opam-root-version"; _}, {pelem = String version; _}); _} -> Some (OpamVersion.of_string version) | _ -> None) opamfile.file_contents) with | Sys_error _ | Not_found -> None end module InitConfigSyntax = struct let internal = "init-config" let format_version = OpamVersion.of_string "2.0" type t = { opam_version : opam_version; repositories : (repository_name * (url * trust_anchors option)) list; default_compiler : formula; default_invariant : formula; jobs : int option; dl_tool : arg list option; dl_jobs : int option; dl_cache : url list option; solver_criteria : (solver_criteria * string) list; solver : arg list option; wrappers : Wrappers.t; global_variables : (variable * variable_contents * string) list; eval_variables : (variable * string list * string) list; recommended_tools : (string list * string option * filter option) list; required_tools : (string list * string option * filter option) list; init_scripts : ((string * string) * filter option) list; } let opam_version t = t.opam_version let repositories t = t.repositories let default_compiler t = t.default_compiler let default_invariant t = t.default_invariant let jobs t = t.jobs let dl_tool t = t.dl_tool let dl_jobs t = t.dl_jobs let dl_cache t = OpamStd.Option.default [] t.dl_cache let solver_criteria t = t.solver_criteria let solver t = t.solver let wrappers t = t.wrappers let global_variables t = t.global_variables let eval_variables t = t.eval_variables let recommended_tools t = t.recommended_tools let required_tools t = t.required_tools let init_scripts t = t.init_scripts let with_opam_version opam_version t = {t with opam_version} let with_repositories repositories t = {t with repositories} let with_default_compiler default_compiler t = {t with default_compiler} let with_default_invariant default_invariant t = {t with default_invariant} let with_jobs jobs t = {t with jobs} let with_dl_tool dl_tool t = {t with dl_tool} let with_dl_jobs dl_jobs t = {t with dl_jobs} let with_dl_cache dl_cache t = {t with dl_cache = Some dl_cache} let with_solver_criteria solver_criteria t = {t with solver_criteria} let with_solver solver t = {t with solver} let with_wrappers wrappers t = {t with wrappers} let with_global_variables global_variables t = {t with global_variables} let with_eval_variables eval_variables t = {t with eval_variables} let with_recommended_tools recommended_tools t = {t with recommended_tools} let with_required_tools required_tools t = {t with required_tools} let with_init_scripts init_scripts t = {t with init_scripts} let criterion kind t = try Some (List.assoc kind t.solver_criteria) with Not_found -> None let with_criterion kind criterion t = { t with solver_criteria = (kind,criterion)::List.remove_assoc kind t.solver_criteria } let empty = { opam_version = format_version; repositories = []; default_compiler = OpamFormula.Empty; default_invariant = OpamFormula.Empty; jobs = None; dl_tool = None; dl_jobs = None; dl_cache = None; solver_criteria = []; solver = None; wrappers = Wrappers.empty; global_variables = []; eval_variables = []; recommended_tools = []; required_tools = []; init_scripts = []; } let pp_repository_def = Pp.V.map_options_3 (Pp.V.string -| Pp.of_module "repository" (module OpamRepositoryName)) (Pp.opt @@ Pp.singleton -| Pp.V.url) (Pp.map_list Pp.V.string) (Pp.opt @@ Pp.singleton -| Pp.V.int -| OpamPp.check ~name:"quorum" ~errmsg:"quorum must be >= 0" ((<=) 0)) -| Pp.pp (fun ~pos:_ (name, url, fingerprints, quorum) -> name, url, match fingerprints with [] -> None | fingerprints -> Some {fingerprints; quorum = OpamStd.Option.default 1 quorum}) (fun (name, url, ta) -> match ta with | Some ta -> name, url, ta.fingerprints, Some ta.quorum | None -> name, url, [], None) let fields = [ "opam-version", Pp.ppacc with_opam_version opam_version (Pp.V.string -| Pp.of_module "opam-version" (module OpamVersion)); "repositories", Pp.ppacc with_repositories repositories (Pp.V.map_list ~depth:1 @@ pp_repository_def -| Pp.pp (fun ~pos -> function | (name, Some url, ta) -> (name, (url, ta)) | (_, None, _) -> Pp.bad_format ~pos "Missing repository URL") (fun (name, (url, ta)) -> (name, Some url, ta))); "default-compiler", Pp.ppacc with_default_compiler default_compiler (Pp.V.package_formula `Disj Pp.V.(constraints Pp.V.version)); "default-invariant", Pp.ppacc with_default_invariant default_invariant (Pp.V.package_formula `Disj Pp.V.(constraints Pp.V.version)); "jobs", Pp.ppacc_opt (with_jobs @* OpamStd.Option.some) jobs Pp.V.pos_int; "download-command", Pp.ppacc_opt (with_dl_tool @* OpamStd.Option.some) dl_tool (Pp.V.map_list ~depth:1 Pp.V.arg); "download-jobs", Pp.ppacc_opt (with_dl_jobs @* OpamStd.Option.some) dl_jobs Pp.V.pos_int; "archive-mirrors", Pp.ppacc with_dl_cache dl_cache (Pp.V.map_list ~depth:1 Pp.V.url); "solver-criteria", Pp.ppacc_opt (with_criterion `Default) (criterion `Default) Pp.V.string; "solver-upgrade-criteria", Pp.ppacc_opt (with_criterion `Upgrade) (criterion `Upgrade) Pp.V.string; "solver-fixup-criteria", Pp.ppacc_opt (with_criterion `Fixup) (criterion `Fixup) Pp.V.string; "solver", Pp.ppacc_opt (with_solver @* OpamStd.Option.some) solver (Pp.V.map_list ~depth:1 Pp.V.arg); "global-variables", Pp.ppacc with_global_variables global_variables (Pp.V.map_list ~depth:2 (Pp.V.map_triple (Pp.V.ident -| Pp.of_module "variable" (module OpamVariable)) Pp.V.variable_contents Pp.V.string)); "eval-variables", Pp.ppacc with_eval_variables eval_variables (Pp.V.map_list ~depth:2 (Pp.V.map_triple (Pp.V.ident -| Pp.of_module "variable" (module OpamVariable)) (Pp.V.map_list Pp.V.string) Pp.V.string)); "recommended-tools", Pp.ppacc with_recommended_tools recommended_tools (Pp.V.map_list (Pp.V.map_options_2 (Pp.V.map_list ~depth:1 Pp.V.string) (Pp.opt @@ Pp.singleton -| Pp.V.string) (Pp.opt Pp.V.filter))); "required-tools", Pp.ppacc with_required_tools required_tools (Pp.V.map_list (Pp.V.map_options_2 (Pp.V.map_list ~depth:1 Pp.V.string) (Pp.opt @@ Pp.singleton -| Pp.V.string) (Pp.opt Pp.V.filter))); "init-scripts", Pp.ppacc with_init_scripts init_scripts (Pp.V.map_list ~depth:2 (Pp.V.map_option (Pp.V.map_pair (Pp.V.string) (Pp.V.string_tr)) (Pp.opt Pp.V.filter))); ] @ List.map (fun (fld, ppacc) -> fld, Pp.embed with_wrappers wrappers ppacc) Wrappers.fields let pp = let name = internal in Pp.I.map_file @@ Pp.I.check_opam_version ~optional:true ~format_version () -| Pp.I.fields ~name ~empty fields -| Pp.I.show_errors ~name ~strict:true () let add t1 t2 = let opt = function None -> fun o -> o | some -> fun _ -> some in let list = function [] -> fun l -> l | l -> fun _ -> l in { opam_version = t2.opam_version; repositories = list t2.repositories t1.repositories; default_compiler = if t2.default_compiler <> Empty then t2.default_compiler else t1.default_compiler; default_invariant = if t2.default_invariant <> Empty then t2.default_invariant else t1.default_invariant; jobs = opt t2.jobs t1.jobs; dl_tool = opt t2.dl_tool t1.dl_tool; dl_jobs = opt t2.dl_jobs t1.dl_jobs; dl_cache = opt t2.dl_cache t1.dl_cache; solver_criteria = List.fold_left (fun acc c -> try (c, List.assoc c t2.solver_criteria) :: acc with Not_found -> try (c, List.assoc c t1.solver_criteria) :: acc with Not_found -> acc) [] [`Fixup; `Upgrade; `Default]; solver = opt t2.solver t1.solver; wrappers = Wrappers.with_default ~default:t1.wrappers t2.wrappers; global_variables = list t2.global_variables t1.global_variables; eval_variables = list t2.eval_variables t1.eval_variables; recommended_tools = list t2.recommended_tools t1.recommended_tools; required_tools = list t2.required_tools t1.required_tools; init_scripts = list t2.init_scripts t1.init_scripts; } end module InitConfig = struct include InitConfigSyntax include SyntaxFile(InitConfigSyntax) end module Repos_configSyntax = struct let internal = "repos-config" let format_version = OpamVersion.of_string "2.0" let file_format_version = OpamVersion.of_string "2.0" type t = ((url * trust_anchors option) option) OpamRepositoryName.Map.t let empty = OpamRepositoryName.Map.empty let fields = [ "repositories", Pp.ppacc (fun x _ -> x) (fun x -> x) ((Pp.V.map_list ~depth:1 @@ InitConfigSyntax.pp_repository_def -| Pp.pp (fun ~pos:_ -> function | (name, Some url, ta) -> name, Some (url, ta) | (name, None, _) -> name, None) (fun (name, def) -> match def with | Some (url, ta) -> name, Some url, ta | None -> name, None, None)) -| Pp.of_pair "repository-url-list" OpamRepositoryName.Map.(of_list, bindings)); ] let pp_cond ?f ?condition () = let name = internal in let format_version = file_format_version in Pp.I.map_file @@ Pp.I.check_opam_version ~optional:true ?f ~format_version () -| Pp.I.opam_version ~format_version ~undefined:true () -| Pp.I.fields ~name ~empty fields -| Pp.I.show_errors ~name ?condition () let pp = pp_cond () end module Repos_config = struct include Repos_configSyntax include SyntaxFile(Repos_configSyntax) module BestEffort = MakeBestEffort(Repos_configSyntax) end module Switch_configSyntax = struct let internal = "switch-config" let format_version = OpamVersion.of_string "2.1" let file_format_version = OpamVersion.of_string "2.0" let oldest_compatible_format_version = OpamVersion.of_string "2.0" type t = { opam_version: OpamVersion.t; synopsis: string; repos: repository_name list option; paths: (std_path * string) list; variables: (variable * variable_contents) list; opam_root: dirname option; wrappers: Wrappers.t; env: env_update list; invariant: OpamFormula.t option; depext_bypass: OpamSysPkg.Set.t; } let empty = { opam_version = file_format_version; synopsis = ""; repos = None; paths = []; variables = []; opam_root = None; wrappers = Wrappers.empty; env = []; invariant = None; depext_bypass = OpamSysPkg.Set.empty; } (* When adding a field or section, make sure to add it in [OpamConfigCommand.switch_allowed_fields] and [OpamConfigCommand.switch_allowed_sections] if it is a user modifiable field *) let sections = [ "paths", Pp.ppacc (fun paths t -> {t with paths}) (fun t -> t.paths) (Pp.I.anonymous_section Pp.I.items -| Pp.map_list (Pp.map_pair (Pp.of_pair "std-path" (std_path_of_string, string_of_std_path)) Pp.V.string)); "variables", Pp.ppacc (fun variables t -> {t with variables}) (fun t -> t.variables) (Pp.I.anonymous_section Pp.I.items -| Pp.map_list (Pp.map_pair (Pp.of_module "variable" (module OpamVariable)) Pp.V.variable_contents)); ] let fields = [ "opam-version", Pp.ppacc (fun opam_version t -> {t with opam_version}) (fun t -> t.opam_version) (Pp.V.string -| Pp.of_module "opam-version" (module OpamVersion)); "synopsis", Pp.ppacc (fun synopsis t -> {t with synopsis}) (fun t -> t.synopsis) Pp.V.string; "repositories", Pp.ppacc_opt (fun r t -> {t with repos = Some r}) (fun t -> t.repos) (Pp.V.map_list ~depth:1 @@ Pp.V.string -| Pp.of_module "repo" (module OpamRepositoryName)); "opam-root", Pp.ppacc_opt (fun r t -> {t with opam_root = Some r}) (fun t -> t.opam_root) (Pp.V.string -| Pp.of_module "dirname" (module OpamFilename.Dir)); "setenv", Pp.ppacc (fun env t -> {t with env}) (fun t -> t.env) (Pp.V.map_list ~depth:2 Pp.V.env_binding); "invariant", Pp.ppacc_opt (fun inv t -> {t with invariant = Some inv }) (fun t -> t.invariant) (Pp.V.package_formula `Conj Pp.V.(constraints version)); "depext-bypass", Pp.ppacc (fun depext_bypass t -> { t with depext_bypass}) (fun t -> t.depext_bypass) (Pp.V.map_list (Pp.V.string -| Pp.of_module "sys-package" (module OpamSysPkg)) -| Pp.of_pair "System package set" OpamSysPkg.Set.(of_list, elements)); ] @ List.map (fun (fld, ppacc) -> fld, Pp.embed (fun wrappers t -> {t with wrappers}) (fun t -> t.wrappers) ppacc) Wrappers.fields let pp_cond ?f ?condition () = let name = internal in let format_version = file_format_version in Pp.I.map_file @@ Pp.I.check_opam_version ?f ~format_version () -| Pp.I.opam_version ~format_version () -| Pp.I.fields ~name ~empty ~sections fields -| Pp.I.show_errors ~name ?condition () let pp = pp_cond () let variable t s = try Some (List.assoc s t.variables) with Not_found -> None let path t p = try Some (List.assoc p t.paths) with Not_found -> None let wrappers t = t.wrappers let to_list = Syntax.to_list pp end module Switch_config = struct include Switch_configSyntax include SyntaxFile(Switch_configSyntax) module BestEffort = MakeBestEffort(Switch_configSyntax) end module SwitchSelectionsSyntax = struct let internal = "switch-state" let format_version = OpamVersion.of_string "2.0" let file_format_version = OpamVersion.of_string "2.0" type t = switch_selections let empty = { sel_installed = OpamPackage.Set.empty; sel_roots = OpamPackage.Set.empty; sel_compiler = OpamPackage.Set.empty; sel_pinned = OpamPackage.Set.empty; } let pp_package = Pp.of_module "package" (module OpamPackage) let pp_pkglist = Pp.V.map_list (Pp.V.string -| pp_package) -| Pp.pp (fun ~pos:_ -> OpamPackage.Set.of_list) OpamPackage.Set.elements let fields = [ "opam-version", Pp.ppacc (fun _ t -> t) (fun _ -> file_format_version) (Pp.V.string -| Pp.of_module "opam-version" (module OpamVersion)); "compiler", Pp.ppacc (fun sel_compiler t -> {t with sel_compiler}) (fun t -> t.sel_compiler) pp_pkglist; "roots", Pp.ppacc (fun sel_roots t -> {t with sel_roots}) (fun t -> t.sel_roots) pp_pkglist; "installed", Pp.ppacc (fun installed t -> {t with sel_installed = installed}) (fun t -> t.sel_installed) pp_pkglist; "pinned", Pp.ppacc (fun sel_pinned t -> {t with sel_pinned}) (fun t -> t.sel_pinned) (Pp.V.map_list ~depth:1 (Pp.V.option -| (* The contents of the option is obsolete, the information is now contained in the overlay only *) Pp.pp (fun ~pos:_ (nv,_) -> nv) (fun nv -> nv, []) -| Pp.V.string -| pp_package) -| Pp.of_pair "Package set" OpamPackage.Set.(of_list, elements)) ] let pp_cond ?f ?condition () = let name = "switch-state" in let format_version = file_format_version in Pp.I.map_file @@ Pp.I.check_opam_version ~optional:true ?f ~format_version () -| Pp.I.opam_version ~format_version () -| Pp.I.fields ~name ~empty fields -| Pp.I.show_errors ~name ?condition () let pp = pp_cond () end module SwitchSelections = struct type t = switch_selections include SyntaxFile(SwitchSelectionsSyntax) module BestEffort = MakeBestEffort(SwitchSelectionsSyntax) end (** Local repository config file (repo//config) *) module Repo_config_legacySyntax = struct let internal = "repo-file" let format_version = OpamVersion.of_string "1.2" type t = { repo_name : repository_name; repo_root : dirname; repo_url : url; repo_priority : int; } let empty = { repo_name = OpamRepositoryName.of_string ""; repo_url = OpamUrl.empty; repo_root = OpamFilename.raw_dir ""; repo_priority = 0; } let fields = [ "name", Pp.ppacc (fun repo_name (r:t) -> {r with repo_name}) (fun r -> r.repo_name) (Pp.V.string -| Pp.of_module "repository-name" (module OpamRepositoryName)); "address", Pp.ppacc (fun repo_url (r:t) -> {r with repo_url}) (fun r -> r.repo_url) Pp.V.url; "kind", Pp.ppacc_opt (* deprecated *) (fun backend (r:t) -> {r with repo_url = {r.repo_url with OpamUrl.backend}}) OpamStd.Option.none (Pp.V.string -| Pp.of_pair "repository-kind" OpamUrl.(backend_of_string, string_of_backend)); "priority", Pp.ppacc (fun repo_priority (r:t) -> {r with repo_priority}) (fun r -> r.repo_priority) Pp.V.int; "root", Pp.ppacc (fun repo_root (r:t) -> {r with repo_root}) (fun r -> r.repo_root) (Pp.V.string -| Pp.of_module "directory" (module OpamFilename.Dir)); ] let pp = let name = internal in Pp.I.map_file @@ Pp.I.fields ~name ~empty ~mandatory_fields:["root";"address";"name"] fields -| Pp.I.show_errors ~name ~strict:true () end module Repo_config_legacy = struct include Repo_config_legacySyntax include SyntaxFile(Repo_config_legacySyntax) end (** Global or package switch-local configuration variables. (/config/global-config.config, /lib//opam.config) *) module Dot_configSyntax = struct let internal = ".config" let format_version = OpamVersion.of_string "2.0" type t = { vars: (variable * variable_contents) list; file_depends: (filename * OpamHash.t) list; } let empty = { vars = []; file_depends = []; } let create vars = { empty with vars } let vars t = t.vars let with_vars vars t = { t with vars } let file_depends t = t.file_depends let with_file_depends file_depends t = { t with file_depends } let pp_variables = Pp.I.items -| Pp.map_list (Pp.map_pair (Pp.of_module "variable" (module OpamVariable)) Pp.V.variable_contents) let pp_contents = Pp.I.fields ~name:"config-file" ~empty ~sections:[ "variables", Pp.ppacc with_vars vars (Pp.I.anonymous_section pp_variables) ] [ "opam-version", Pp.ppacc (fun _ t -> t) (fun _ -> format_version) (Pp.V.string -| Pp.of_module "opam-version" (module OpamVersion)); "file-depends", Pp.ppacc with_file_depends file_depends (Pp.V.map_list ~depth:2 @@ Pp.V.map_pair (Pp.V.string -| Pp.of_module "path" (module OpamFilename)) (Pp.V.string -| Pp.of_module "checksum" (module OpamHash))) ] -| Pp.I.show_errors ~name:internal () (* Files with the variables at toplevel and no other fields are allowed for backwards-compat, when opam-version is unset or too old *) let pp = Pp.I.map_file @@ Pp.I.check_opam_version ~format_version ~optional:true () -| Pp.I.opam_version ~format_version () -| Pp.I.field "opam-version" (Pp.parse (Pp.V.string -| Pp.of_module "opam-version" (module OpamVersion))) -| Pp.pp (fun ~pos (opam_version_opt, s) -> match opam_version_opt with | Some v when OpamVersion.compare v (OpamVersion.of_string "1.3~dev3") > 0 -> Pp.parse ~pos pp_contents s | _ -> {empty with vars = Pp.parse ~pos pp_variables s}) (fun t -> None, Pp.print pp_contents t) let variables t = List.rev_map fst t.vars let bindings t = t.vars let variable t s = try Some (List.assoc s t.vars) with Not_found -> None let set k v t = let vars = List.remove_assoc k t.vars in let vars = match v with | Some v -> (k,v) :: vars | None -> vars in { t with vars } end module Dot_config = struct include Dot_configSyntax include SyntaxFile(Dot_configSyntax) end (** (2) General, public repository format *) (** Public repository definition file (/repo) *) module RepoSyntax = struct let internal = "repo" let format_version = OpamVersion.of_string "2.0" type t = { opam_version : OpamVersion.t option; browse : string option; upstream : string option; redirect : (string * filter option) list; root_url : url option; dl_cache : string list option; announce : (string * filter option) list; stamp : string option; } let create ?browse ?upstream ?opam_version ?(redirect=[]) ?root_url ?dl_cache ?(announce=[]) ?stamp () = { opam_version; browse; upstream; redirect; root_url; dl_cache; announce; stamp; } let empty = create () let opam_version t = t.opam_version let browse t = t.browse let upstream t = t.upstream let redirect t = t.redirect let root_url t = t.root_url let dl_cache t = OpamStd.Option.default [] t.dl_cache let announce t = t.announce let stamp t = t.stamp let with_opam_version opam_version t = { t with opam_version = Some opam_version } let with_browse browse t = { t with browse = Some browse } let with_upstream upstream t = { t with upstream = Some upstream } let with_redirect redirect t = { t with redirect } let with_root_url root_url t = { t with root_url = Some root_url } let with_dl_cache dl_cache t = { t with dl_cache = Some dl_cache } let with_announce announce t = { t with announce } let with_stamp id t = { t with stamp = Some id } let with_stamp_opt stamp t = { t with stamp } let fields = [ "opam-version", Pp.ppacc_opt with_opam_version opam_version (Pp.V.string -| Pp.of_module "opam-version" (module OpamVersion)); "browse", Pp.ppacc_opt with_browse browse Pp.V.string; "upstream", Pp.ppacc_opt with_upstream upstream Pp.V.string; "redirect", Pp.ppacc with_redirect redirect (Pp.V.map_list ~depth:1 (Pp.V.map_option Pp.V.string (Pp.opt Pp.V.filter))); "archive-mirrors", Pp.ppacc with_dl_cache dl_cache (Pp.V.map_list ~depth:1 Pp.V.string); "announce", Pp.ppacc with_announce announce (Pp.V.map_list ~depth:1 (Pp.V.map_option Pp.V.string (Pp.opt Pp.V.filter))); "stamp", Pp.ppacc_opt with_stamp stamp Pp.V.string ] let pp = let name = internal in Pp.I.map_file @@ Pp.I.check_opam_version ~format_version ~optional:true () -| Pp.I.opam_version ~format_version () -| Pp.I.fields ~name ~empty fields -| Pp.I.show_errors ~name ~condition:(function | {opam_version = Some v; _} -> OpamVersion.(compare format_version v) >= 0 | _ -> true) () end module Repo = struct include RepoSyntax include SyntaxFile(RepoSyntax) end (** Package url field in opam file. Formerly, file (/packages/.../url) *) module URLSyntax = struct let internal = "url-file" let format_version = OpamVersion.of_string "1.2" type t = { url : url; mirrors : url list; checksum: OpamHash.t list; errors : (string * Pp.bad_format) list; subpath : string option; } let create ?(mirrors=[]) ?(checksum=[]) ?subpath url = { url; mirrors; checksum; errors = []; subpath; } let empty = { url = OpamUrl.empty; mirrors = []; checksum= []; errors = []; subpath = None; } let url t = t.url let mirrors t = t.mirrors let checksum t = t.checksum let subpath t = t.subpath let with_url url t = { t with url } let with_mirrors mirrors t = { t with mirrors } let with_checksum checksum t = { t with checksum = checksum } let with_subpath subpath t = { t with subpath = Some subpath } let with_subpath_opt subpath t = { t with subpath = subpath } let fields = let with_url url t = if t.url <> OpamUrl.empty then Pp.bad_format "Too many URLS" else with_url url t in [ "src", Pp.ppacc with_url url Pp.V.url; "archive", Pp.ppacc_opt with_url OpamStd.Option.none (Pp.V.url_with_backend `http); "http", Pp.ppacc_opt with_url OpamStd.Option.none (Pp.V.url_with_backend `http); "git", Pp.ppacc_opt with_url OpamStd.Option.none (Pp.V.url_with_backend `git); "darcs", Pp.ppacc_opt with_url OpamStd.Option.none (Pp.V.url_with_backend `darcs); "hg", Pp.ppacc_opt with_url OpamStd.Option.none (Pp.V.url_with_backend `hg); "local", Pp.ppacc_opt with_url OpamStd.Option.none (Pp.V.url_with_backend `rsync); "checksum", Pp.ppacc with_checksum checksum (Pp.V.map_list ~depth:1 (Pp.V.string -| Pp.of_module "checksum" (module OpamHash))); "mirrors", Pp.ppacc with_mirrors mirrors (Pp.V.map_list ~depth:1 Pp.V.url); "subpath", Pp.ppacc_opt with_subpath subpath Pp.V.string; ] let pp_contents = let name = internal in Pp.I.fields ~name ~empty fields -| Pp.I.on_errors ~name (fun t e -> {t with errors = e::t.errors}) -| Pp.pp ~name (fun ~pos t -> if t.url = OpamUrl.empty then OpamPp.bad_format ~pos "missing URL" else t) (fun x -> x) let pp = Pp.I.map_file pp_contents end module URL = struct include URLSyntax include SyntaxFile(URLSyntax) end (** (3) Opam package format *) module OPAMSyntax = struct let internal = "opam" let format_version = OpamVersion.of_string "2.0" type t = { opam_version: opam_version; (* Package ident *) name : OpamPackage.Name.t option; version : OpamPackage.Version.t option; (* Relationships; solver and availability info *) depends : filtered_formula; depopts : filtered_formula; conflicts : filtered_formula; conflict_class : name list; available : filter; flags : package_flag list; env : env_update list; (* Build instructions *) build : command list; run_test : command list; install : command list; remove : command list; (* Auxiliary data affecting the build *) substs : basename list; patches : (basename * filter option) list; build_env : env_update list; features : (OpamVariable.t * filtered_formula * string) list; extra_sources: (basename * URL.t) list; (* User-facing data used by opam *) messages : (string * filter option) list; post_messages: (string * filter option) list; depexts : (OpamSysPkg.Set.t * filter) list; libraries : (string * filter option) list; syntax : (string * filter option) list; dev_repo : url option; pin_depends: (package * url) list; (* Package database details *) maintainer : string list; author : string list; license : string list; tags : string list; homepage : string list; doc : string list; bug_reports: string list; (* Extension fields (x-foo: "bar") *) extensions : value OpamStd.String.Map.t; (* Extra sections *) url : URL.t option; descr : Descr.t option; (* Extra data, not actually file fields *) (* Related metadata directory (not an actual field of the file) This can be used to locate e.g. the files/ overlays *) metadata_dir: (repository_name option * string) option; (* Names and hashes of the files below files/ *) extra_files: (OpamFilename.Base.t * OpamHash.t) list option; (* Stores any file errors for printing them later *) format_errors: (string * Pp.bad_format) list; (* Deprecated, for compat and proper linting *) ocaml_version: (OpamFormula.relop * string) OpamFormula.formula option; os : (bool * string) generic_formula; deprecated_build_test : command list; deprecated_build_doc : command list; } let empty = { opam_version = format_version; name = None; version = None; depends = OpamFormula.Empty; depopts = OpamFormula.Empty; conflicts = OpamFormula.Empty; available = FBool true; flags = []; conflict_class = []; env = []; build = []; run_test = []; install = []; remove = []; substs = []; patches = []; build_env = []; features = []; extra_sources = []; messages = []; post_messages = []; depexts = []; libraries = []; syntax = []; dev_repo = None; pin_depends= []; maintainer = []; author = []; license = []; tags = []; homepage = []; doc = []; bug_reports = []; extensions = OpamStd.String.Map.empty; url = None; descr = None; metadata_dir = None; extra_files = None; format_errors = []; ocaml_version = None; os = Empty; deprecated_build_test = []; deprecated_build_doc = []; } let create nv = let name = Some (nv.OpamPackage.name) in let version = Some (nv.OpamPackage.version) in { empty with name; version } let check t name = function | None -> let pos = OpamStd.Option.Op.(>>|) t.metadata_dir @@ function | Some r, rel -> { pos_null with filename = Printf.sprintf "<%s>/%s/opam" (OpamRepositoryName.to_string r) rel } | None, d -> pos_file OpamFilename.Op.(OpamFilename.Dir.of_string d // "opam") in Pp.bad_format ?pos "Field '%s:' is required" name | Some n -> n let ext_field_prefix = "x-" let is_ext_field = OpamStd.String.starts_with ~prefix:ext_field_prefix (* Getters *) let opam_version t = t.opam_version let name (t:t) = check t "name" t.name let name_opt (t:t) = t.name let version (t:t) = check t "version" t.version let version_opt (t:t) = t.version let package t = OpamPackage.create (name t) (version t) let depends t = t.depends let depopts t = t.depopts let conflicts t = t.conflicts let conflict_class t = t.conflict_class let available t = t.available let flags t = t.flags let has_flag f t = List.mem f t.flags let env (t:t) = List.map (fun env -> match t.name, env with | Some name, (var,op,value,None) -> var, op, value, Some ("Updated by package " ^ OpamPackage.Name.to_string name) | _, b -> b) t.env let build t = t.build let run_test t = t.deprecated_build_test @ t.run_test let deprecated_build_test t = t.deprecated_build_test let deprecated_build_doc t = t.deprecated_build_doc let install t = t.install let remove t = t.remove let substs t = t.substs let patches t = t.patches let build_env t = t.build_env let features t = t.features let extra_sources t = t.extra_sources let messages t = t.messages let post_messages t = t.post_messages let depexts t = t.depexts let libraries t = t.libraries let syntax t = t.syntax let dev_repo t = t.dev_repo let pin_depends t = t.pin_depends let maintainer t = t.maintainer let author t = t.author let license t = t.license let tags t = t.tags let homepage t = t.homepage let doc t = t.doc let bug_reports t = t.bug_reports let extensions t = t.extensions let extended t fld parse = if not (is_ext_field fld) then invalid_arg "OpamFile.OPAM.extended"; try let s = OpamStd.String.Map.find fld t.extensions in (try Some (parse s) with | Pp.Bad_format _ as e -> raise (Pp.add_pos s.pos e)) with Not_found -> None let url t = t.url let descr t = t.descr let synopsis t = OpamStd.Option.map Descr.synopsis t.descr let descr_body t = match t.descr with | None | Some (_, "") -> None | Some (_, text) -> Some text let get_url t = match url t with Some u -> Some (URL.url u) | None -> None let format_errors t = t.format_errors let metadata_dir t = t.metadata_dir let extra_files t = t.extra_files (* Setters *) let with_opam_version opam_version t = { t with opam_version } let with_name name (t:t) = { t with name = Some name } let with_name_opt name (t:t) = { t with name } let with_version version (t:t) = { t with version = Some version } let with_version_opt version (t:t) = { t with version } let with_nv nv (t:t) = { t with name = Some (nv.OpamPackage.name); version = Some (nv.OpamPackage.version) } let with_depends depends t = { t with depends } let with_depopts depopts t = { t with depopts } let with_conflicts conflicts t = {t with conflicts } let with_conflict_class conflict_class t = { t with conflict_class } let with_available available t = { t with available } let with_flags flags t = { t with flags } let add_flags flags t = { t with flags = OpamStd.List.sort_nodup compare (flags @ t.flags) } let with_env env t = { t with env } let with_build build t = { t with build } let with_run_test run_test t = { t with run_test } let with_deprecated_build_test deprecated_build_test t = { t with deprecated_build_test } let with_deprecated_build_doc deprecated_build_doc t = { t with deprecated_build_doc } let with_install install t = { t with install } let with_remove remove t = { t with remove } let with_substs substs t = { t with substs } let with_patches patches t = { t with patches } let with_build_env build_env t = { t with build_env } let with_features features t = {t with features } let with_extra_sources extra_sources t = { t with extra_sources } let with_messages messages t = { t with messages } let with_post_messages post_messages t = { t with post_messages } let with_depexts depexts t = { t with depexts = depexts } let with_libraries libraries t = { t with libraries } let with_syntax syntax t = { t with syntax } let with_dev_repo dev_repo t = { t with dev_repo = Some dev_repo } let with_dev_repo_opt dev_repo t = { t with dev_repo } let with_pin_depends pin_depends t = { t with pin_depends } let with_maintainer maintainer t = { t with maintainer } let with_author author t = { t with author } let with_license license t = { t with license } let with_tags tags t = { t with tags } let with_homepage homepage t = { t with homepage } let with_doc doc t = { t with doc } let with_bug_reports bug_reports t = { t with bug_reports } let with_extensions extensions t = if not (OpamStd.String.Map.for_all (fun k _ -> is_ext_field k) extensions) then invalid_arg "OpamFile.OPAM.with_extensions"; {t with extensions = extensions } let add_extension t fld syn = if not (is_ext_field fld) then invalid_arg "OpamFile.OPAM.add_extension"; {t with extensions = OpamStd.String.Map.add fld syn t.extensions } let remove_extension t fld = if not (is_ext_field fld) then invalid_arg "OpamFile.OPAM.remove_extension"; {t with extensions = OpamStd.String.Map.remove fld t.extensions } let with_url url t = let format_errors = List.map (fun (name,bf) -> "url."^name, bf) url.URL.errors in { t with url = Some url; format_errors = format_errors @ t.format_errors } let with_url_opt url t = let format_errors = match url with | None -> [] | Some u -> List.map (fun (name,bf) -> "url."^name, bf) u.URL.errors in { t with url; format_errors = format_errors @ t.format_errors } let with_descr descr t = { t with descr = Some descr } let with_descr_opt descr t = { t with descr } let with_synopsis synopsis t = { t with descr = Some (synopsis, OpamStd.Option.default "" (descr_body t)) } let with_descr_body text t = { t with descr = Some (OpamStd.Option.default "" (synopsis t), text) } let with_metadata_dir metadata_dir t = { t with metadata_dir } let with_extra_files extra_files t = { t with extra_files = Some extra_files } let with_extra_files_opt extra_files t = { t with extra_files } let with_format_errors format_errors t = { t with format_errors } let with_ocaml_version ocaml_version t = { t with ocaml_version = Some ocaml_version } let with_os os t = { t with os } (* Adds an opam constraint as an 'available' constraint, without restricting the file format compatibility *) let pp_minimal_opam_version min_version = let opam_version_var = OpamVariable.of_string "opam-version" in let add_avail_constr t = if OpamVersion.compare t.opam_version min_version >= 0 then t else let available = let opam_restricted = OpamFilter.fold_down_left (fun acc filter -> acc || match filter with | FOp (FIdent ([], var, None), (`Eq|`Geq), FString version) | FOp (FString version, (`Eq|`Leq), FIdent ([], var, None)) -> var = opam_version_var && OpamVersion.(compare (of_string version) min_version) >= 0 | _ -> false) false t.available in if opam_restricted then t.available else let opam_restriction = FOp (FIdent ([], opam_version_var, None), `Geq, FString (OpamVersion.to_string min_version)) in match t.available with | FBool true -> opam_restriction | available -> FAnd (available, opam_restriction) in { t with available } in let parse ~pos:_ t = add_avail_constr t (* This is not strictly needed since we know the constraint will be verified for the running opam version, but avoids a discrepency if re-parsing a printed file. *) in let print t = (* remove constraints that are already implied by the file format version *) let available = OpamFilter.map_up (function | FOp (FIdent ([], var, None), (`Eq|`Geq), FString version) | FOp (FString version, (`Eq|`Leq), FIdent ([], var, None)) when var = opam_version_var && OpamVersion.compare (OpamVersion.of_string version) t.opam_version <= 0 -> FBool true | FAnd (FBool true, f) | FAnd (f, FBool true) -> f | FOr (FBool true, _) | FOr (_, FBool true) -> FBool true | f -> f ) t.available in add_avail_constr { t with available } (* The constraint needs to be added here as well, in case the file was just generated and has a subpath without the constraint already *) in Pp.pp parse print (* Post-processing functions used for some fields (optional, because we don't want them when linting). It's better to do them in the same pass as parsing, because it allows one to get file positions, which we lose afterwards *) (* Allow 'flag:xxx' tags as flags, for compat *) let flag_of_tag tag = let prefix = "flags:" in if OpamStd.String.starts_with ~prefix tag then Some (pkg_flag_of_string (OpamStd.String.remove_prefix ~prefix tag)) else None let cleanup_depopts opam_version ~pos depopts = if OpamFormatConfig.(!r.skip_version_checks) || OpamVersion.compare opam_version (OpamVersion.of_string "1.2") < 0 then depopts else (* Make sure depopts are a pure disjunction *) let rec aux acc disjunction = List.fold_left (fun acc -> function | OpamFormula.Atom _ as atom -> atom :: acc | f -> Pp.warn ~pos "Optional dependencies must be a disjunction. \ Treated as such."; aux acc (OpamFormula.fold_left (fun acc a -> OpamFormula.Atom a::acc) [] f) ) acc disjunction in OpamFormula.ors_to_list depopts |> aux [] |> List.rev |> OpamFormula.ors let cleanup_conflicts opam_version ~pos conflicts = (* Conflicts were encoded as a conjunction before 1.3, which didn't match the semantics. The rewrite is done for all versions, but on 1.3+ it should be an error. *) let is_disjunction f = List.for_all (function Atom _ -> true | _ -> false) OpamFormula.(ors_to_list f) in if is_disjunction conflicts then conflicts else let force_disjunction f = OpamFormula.map_formula (function | And (a, b) -> Or (a, b) | f -> f) f in if OpamVersion.(compare opam_version (of_string "1.3") >= 0) then Pp.warn ~pos "Conflicts must be a disjunction, '&' is not \ supported (treated as '|')."; force_disjunction conflicts let cleanup_flags _opam_version ~pos flags = let known_flags = List.filter (function Pkgflag_Unknown _ -> false | _ -> true) flags in if known_flags <> flags then Pp.warn ~pos "Unknown package flags %s ignored" (OpamStd.Format.pretty_list (OpamStd.List.filter_map (function | Pkgflag_Unknown s -> Some s | _ -> None) flags)); known_flags let cleanup_tags opam_version ~pos tags = let flags = OpamStd.List.filter_map flag_of_tag tags in ignore (cleanup_flags opam_version ~pos flags); tags let cleanup_dev_repo opam_version ~pos:_ dev_repo = if OpamVersion.(compare opam_version (of_string "1.3") >= 0) then dev_repo else OpamUrl.parse ~handle_suffix:true (OpamUrl.to_string dev_repo) let pp_basename = Pp.V.string -| Pp.of_module "file" (module OpamFilename.Base) (* Field parser-printers *) (* [field name, (pure pp, pp including cleanup/check function)] *) let fields_gen = let no_cleanup (ppacc: ?cleanup:(pos:_ -> _) -> _) set get pp = let p = ppacc set get pp in p, p in let with_cleanup cleanup (ppacc: ?cleanup:(pos:_ -> _) -> _) set get pp = let cleanup ~pos acc x = cleanup acc.opam_version ~pos x in ppacc set get pp, ppacc set get ~cleanup pp in [ "opam-version", no_cleanup Pp.ppacc with_opam_version opam_version (Pp.V.string -| Pp.of_module "opam-version" (module OpamVersion)); "name", no_cleanup Pp.ppacc_opt with_name name_opt Pp.V.pkgname; "version", no_cleanup Pp.ppacc_opt with_version version_opt (Pp.V.string_tr -| Pp.of_module "version" (module OpamPackage.Version)); "synopsis", no_cleanup Pp.ppacc_opt with_synopsis synopsis Pp.V.string_tr; "description", no_cleanup Pp.ppacc_opt with_descr_body descr_body Pp.V.string_tr; "maintainer", no_cleanup Pp.ppacc with_maintainer maintainer (Pp.V.map_list ~depth:1 Pp.V.string); "authors", no_cleanup Pp.ppacc with_author author (Pp.V.map_list ~depth:1 Pp.V.string); "author", no_cleanup Pp.ppacc (fun a t -> if t.author = [] then with_author a t else Pp.bad_format "multiple \"authors:\" fields" author) (fun _ -> []) (Pp.V.map_list ~depth:1 Pp.V.string); "license", no_cleanup Pp.ppacc with_license license (Pp.V.map_list ~depth:1 Pp.V.string); "tags", with_cleanup cleanup_tags Pp.ppacc with_tags tags (Pp.V.map_list ~depth:1 Pp.V.string); "homepage", no_cleanup Pp.ppacc with_homepage homepage (Pp.V.map_list ~depth:1 Pp.V.string); "doc", no_cleanup Pp.ppacc with_doc doc (Pp.V.map_list ~depth:1 Pp.V.string); "bug-reports", no_cleanup Pp.ppacc with_bug_reports bug_reports (Pp.V.map_list ~depth:1 Pp.V.string); "depends", no_cleanup Pp.ppacc with_depends depends (Pp.V.package_formula `Conj Pp.V.(filtered_constraints ext_version)); "depopts", with_cleanup cleanup_depopts Pp.ppacc with_depopts depopts (Pp.V.package_formula `Disj Pp.V.(filtered_constraints ext_version)); "conflicts", with_cleanup cleanup_conflicts Pp.ppacc with_conflicts conflicts (Pp.V.package_formula `Disj Pp.V.(filtered_constraints ext_version)); "conflict-class", no_cleanup Pp.ppacc with_conflict_class conflict_class (Pp.V.map_list ~depth:1 Pp.V.pkgname); "available", no_cleanup Pp.ppacc with_available available (Pp.V.list_depth 1 -| Pp.V.list -| Pp.V.filter); "flags", with_cleanup cleanup_flags Pp.ppacc add_flags flags (Pp.V.map_list ~depth:1 @@ Pp.V.ident -| Pp.of_pair "package-flag" (pkg_flag_of_string, string_of_pkg_flag)); "setenv", no_cleanup Pp.ppacc with_env env (Pp.V.map_list ~depth:2 Pp.V.env_binding); "build", no_cleanup Pp.ppacc with_build build (Pp.V.map_list ~depth:2 Pp.V.command); "run-test", no_cleanup Pp.ppacc with_run_test run_test (Pp.V.map_list ~depth:2 Pp.V.command); "install", no_cleanup Pp.ppacc with_install install (Pp.V.map_list ~depth:2 Pp.V.command); "remove", no_cleanup Pp.ppacc with_remove remove (Pp.V.map_list ~depth:2 Pp.V.command); "substs", no_cleanup Pp.ppacc with_substs substs (Pp.V.map_list ~depth:1 pp_basename); "patches", no_cleanup Pp.ppacc with_patches patches (Pp.V.map_list ~depth:1 @@ Pp.V.map_option pp_basename (Pp.opt Pp.V.filter)); "build-env", no_cleanup Pp.ppacc with_build_env build_env (Pp.V.map_list ~depth:2 Pp.V.env_binding); "features", no_cleanup Pp.ppacc with_features features (Pp.V.map_list ~depth:1 @@ Pp.V.map_options_2 (Pp.V.ident -| Pp.of_module "variable" (module OpamVariable)) (Pp.V.package_formula_items `Conj Pp.V.(filtered_constraints ext_version)) (Pp.singleton -| Pp.V.string)); "messages", no_cleanup Pp.ppacc with_messages messages (Pp.V.map_list ~depth:1 @@ Pp.V.map_option Pp.V.string_tr (Pp.opt Pp.V.filter)); "post-messages", no_cleanup Pp.ppacc with_post_messages post_messages (Pp.V.map_list ~depth:1 @@ Pp.V.map_option Pp.V.string_tr (Pp.opt Pp.V.filter)); "depexts", no_cleanup Pp.ppacc with_depexts depexts (let map_syspkg = (Pp.V.map_list (Pp.V.string -| Pp.of_module "sys-package" (module OpamSysPkg)) -| Pp.pp (fun ~pos:_ -> OpamSysPkg.Set.of_list) OpamSysPkg.Set.elements) in Pp.fallback (Pp.V.map_list ~depth:2 @@ Pp.V.map_option map_syspkg (Pp.V.filter)) (Pp.V.map_list ~depth:3 (let rec filter_of_taglist = function | [] -> FBool true | [v] -> FString v | v :: r -> FAnd (FString v, filter_of_taglist r) in Pp.V.map_pair (Pp.V.map_list Pp.V.string -| Pp.of_pair "tag-list" (filter_of_taglist, fun _ -> assert false)) map_syspkg -| Pp.pp (fun ~pos:_ (a,b) -> b,a) (fun (b,a) -> a,b)))); "libraries", no_cleanup Pp.ppacc with_libraries libraries (Pp.V.map_list ~depth:1 @@ Pp.V.map_option Pp.V.string (Pp.opt Pp.V.filter)); "syntax", no_cleanup Pp.ppacc with_syntax syntax (Pp.V.map_list ~depth:1 @@ Pp.V.map_option Pp.V.string (Pp.opt Pp.V.filter)); "dev-repo", with_cleanup cleanup_dev_repo Pp.ppacc_opt with_dev_repo dev_repo (Pp.V.string -| Pp.of_pair "vc-url" OpamUrl.(parse ?backend:None ~handle_suffix:false ~from_file:true, to_string)); "pin-depends", no_cleanup Pp.ppacc with_pin_depends pin_depends (OpamFormat.V.map_list ~depth:2 (OpamFormat.V.map_pair (OpamFormat.V.string -| OpamPp.of_module "versioned package" (module OpamPackage)) (OpamFormat.V.string -| OpamPp.of_module "URL" (module OpamUrl)))); "extra-files", no_cleanup Pp.ppacc_opt with_extra_files extra_files (Pp.V.map_list ~depth:2 @@ Pp.V.map_pair pp_basename (Pp.V.string -| Pp.of_module "checksum" (module OpamHash))); (* deprecated fields, here for compat *) "configure-style", (Pp.ppacc_ignore, Pp.ppacc_ignore); "ocaml-version", no_cleanup Pp.ppacc_opt with_ocaml_version OpamStd.Option.none (Pp.V.list_depth 1 -| Pp.V.list -| Pp.V.constraints Pp.V.compiler_version); "os", no_cleanup Pp.ppacc_opt with_os OpamStd.Option.none Pp.V.os_constraint; "descr", no_cleanup Pp.ppacc_opt with_descr OpamStd.Option.none (Pp.V.string_tr -| Pp.of_pair "descr" Descr.(of_string (), to_string ())); "extra-sources", no_cleanup Pp.ppacc_opt with_extra_sources OpamStd.Option.none (Pp.V.map_list ~depth:2 @@ Pp.V.map_pair (Pp.V.map_option Pp.V.url (Pp.opt @@ Pp.singleton -| pp_basename)) (Pp.V.string -| Pp.of_module "checksum" (module OpamHash)) -| Pp.pp (fun ~pos:_ ((u,b),md5) -> OpamStd.Option.default (OpamFilename.Base.of_string (OpamUrl.basename u)) b, URL.create ~checksum:[md5] u) (fun (f, urlf) -> URL.((url urlf, Some f), List.hd (checksum urlf)))); "build-test", no_cleanup Pp.ppacc_opt with_deprecated_build_test OpamStd.Option.none (Pp.V.map_list ~depth:2 Pp.V.command); "build-doc", no_cleanup Pp.ppacc_opt with_deprecated_build_doc (fun x -> Some (deprecated_build_doc x)) (Pp.V.map_list ~depth:2 Pp.V.command); ] (* These don't have a printer and their info is stored in new fields *) let alias_fields = [ "author", "authors"; "descr", "description"; ] (* These don't have a printer and their info can't be retrieved in the same format anymore *) let deprecated_fields = [ "ocaml-version"; "os"; "configure-style"; "extra-sources"; "build-test"; "build-doc"; ] let fields = List.map (fun (name, (_, cleaned_up_pp)) -> name, cleaned_up_pp) fields_gen let sections = [ "url", Pp.ppacc_opt with_url url (Pp.I.anonymous_section URL.pp_contents); "extra-source", Pp.ppacc with_extra_sources extra_sources (Pp.map_list (Pp.map_pair (Pp.pp (fun ~pos -> function | Some o -> OpamFilename.Base.of_string o | None -> Pp.bad_format ~pos "missing extra-source name") (fun b -> Some (OpamFilename.Base.to_string b))) URL.pp_contents)) ] let raw_fields = List.map (fun (name, (raw_pp, _)) -> name, raw_pp) fields_gen let handle_flags_in_tags = let parse ~pos:_ t = let flags = List.fold_left (fun flags tag -> match flag_of_tag tag with | Some flag -> flag :: flags | None -> flags) t.flags t.tags in {t with flags} in let print t = let flags, tags = List.fold_left (fun (flags, tags) tag -> match flag_of_tag tag with | Some flag -> if List.mem flag flags then List.filter ((<>) flag) flags, tag::tags else flags, tags | None -> flags, tag::tags) (t.flags,[]) (List.rev t.tags) in {t with flags; tags} in Pp.pp parse print let handle_deprecated_available = let add_available available filter = match available with | FBool true -> filter | f -> FAnd (filter, f) in let parse ~pos:_ t = let available = t.available in let available = match t.ocaml_version with | None -> available | Some ocaml_version -> let var = OpamVariable.of_string "ocaml-version" in let mk_atom (op,v) = FOp (FIdent ([], var, None), op, FString v) in let filter = OpamFilter.of_formula mk_atom ocaml_version in add_available available filter in let available = match t.os with | Empty -> available | os -> let var = OpamVariable.of_string "os" in let mk_atom (eq,name) = FOp (FIdent ([], var, None), (if eq then `Eq else `Neq), FString name) in let filter = OpamFilter.of_formula mk_atom os in add_available available filter in { t with available } in Pp.pp parse (fun x -> x) let handle_subpath_2_0 = let subpath_xfield = "x-subpath" in let pp_constraint = pp_minimal_opam_version (OpamVersion.of_string "2.1") in let parse ~pos t = if OpamVersion.(compare t.opam_version (of_string "2.0") > 0) then t else match OpamStd.String.Map.find_opt subpath_xfield t.extensions with | Some {pelem = String subpath;_} -> let url = match t.url with | Some u -> Some (URL.with_subpath subpath u) | None -> None in { t with url } |> Pp.parse ~pos pp_constraint | Some {pos;_} -> Pp.bad_format ~pos "Field %s must be a string" (OpamConsole.colorise `underline subpath_xfield) | None -> t in let print t = match t.url with | Some ({ URL.subpath = Some sb ; _ } as url) -> if OpamVersion.(compare t.opam_version (of_string "2.0") > 0) then t else add_extension t subpath_xfield (nullify_pos @@ String sb) |> with_url (URL.with_subpath_opt None url) |> Pp.print pp_constraint | _ -> t in Pp.pp parse print (* Doesn't handle package name encoded in directory name *) let pp_raw_fields = Pp.I.check_opam_version ~format_version () -| Pp.I.opam_version ~format_version () -| Pp.I.partition_fields ~section:true (is_ext_field @> not) -| Pp.map_pair (Pp.I.fields ~name:"opam-file" ~empty ~sections fields -| Pp.I.on_errors (fun t e -> {t with format_errors=e::t.format_errors}) -| handle_flags_in_tags -| handle_deprecated_available) (Pp.I.items -| OpamStd.String.Map.(Pp.pp (fun ~pos:_ -> of_list) bindings)) -| Pp.pp (fun ~pos:_ (t, extensions) -> with_extensions extensions t) (fun t -> t, extensions t) -| Pp.check (fun t -> OpamVersion.(compare t.opam_version (of_string "2.0") > 0) || OpamStd.Option.Op.(t.url >>= URL.subpath) = None) ~errmsg:"The url.subpath field is not allowed in files with \ `opam-version` <= 2.0" -| handle_subpath_2_0 let pp_raw = Pp.I.map_file @@ pp_raw_fields let pp = pp_raw -| Pp.pp (fun ~pos:_ (filename, t) -> filename, let metadata_dir = if filename <> dummy_file then Some (None, OpamFilename.(Dir.to_string (dirname filename))) else None in let t = { t with metadata_dir } in match OpamPackage.of_filename filename with | Some nv -> if t.name <> None && t.name <> Some nv.name || t.version <> None && t.version <> Some nv.version then Pp.warn "This file is for package '%s' but has mismatching fields%s%s." (OpamPackage.to_string nv) (OpamStd.Option.to_string (fun n -> " 'name:"^OpamPackage.Name.to_string n) t.name) (OpamStd.Option.to_string (fun v -> " 'version:"^OpamPackage.Version.to_string v) t.version); with_nv nv t | None -> t) (fun (filename, t) -> filename, match OpamPackage.of_filename filename, t.name, t.version with | Some _, None, None -> t | None, Some _, Some _ -> t | None, _, _ -> OpamConsole.log "FILE(opam)" "Outputting opam file %s with unspecified name or version" (OpamFilename.to_string filename); t | Some nv, _, _ -> if t.name <> None && t.name <> Some (nv.OpamPackage.name) || t.version <> None && t.version <> Some (nv.OpamPackage.version) then OpamConsole.warning "Skipping inconsistent 'name:' or 'version:' fields (%s) \ while saving %s" (OpamPackage.to_string @@ OpamPackage.create (OpamStd.Option.default (nv.OpamPackage.name) t.name) (OpamStd.Option.default (nv.OpamPackage.version) t.version)) (OpamFilename.prettify filename); {t with name = None; version = None} ) let to_string_with_preserved_format ?format_from ?format_from_string filename t = Syntax.to_string_with_preserved_format ?format_from ?format_from_string filename ~empty ~sections ~fields:raw_fields pp t let write_with_preserved_format ?format_from ?format_from_string filename t = let s = to_string_with_preserved_format ?format_from ?format_from_string filename t in OpamFilename.write filename s let contents = Syntax.contents pp let to_list = Syntax.to_list pp let print_field_as_syntax field t = let field = try List.assoc field alias_fields with Not_found -> field in if List.mem field deprecated_fields then raise Not_found; match OpamStd.String.cut_at field '.' with | None -> if is_ext_field field then OpamStd.String.Map.find_opt field t.extensions else snd (Pp.print (List.assoc field fields) t) | Some (sec, field) -> match snd (Pp.print (List.assoc sec sections) t) with | None -> None | Some items -> (* /!\ returns only the first result for multiple named sections *) Some (OpamStd.List.find_map (fun i -> match i.pelem with | Variable (f, contents) when f.pelem = field -> Some contents | _ -> None) (List.flatten (List.map snd items))) end module OPAM = struct include OPAMSyntax include SyntaxFile(OPAMSyntax) (** Extra stuff for opam files *) let effective_part (t:t) = { opam_version = empty.opam_version; name = t.name; version = t.version; depends = t.depends; depopts = t.depopts; conflicts = t.conflicts; conflict_class = t.conflict_class; available = t.available; flags = (List.filter (function | Pkgflag_LightUninstall | Pkgflag_Verbose | Pkgflag_Plugin | Pkgflag_Compiler | Pkgflag_Conf | Pkgflag_AvoidVersion | Pkgflag_Unknown _ -> false) t.flags); env = t.env; build = t.build; run_test = t.deprecated_build_test @ t.run_test; install = t.install; remove = t.remove; substs = t.substs; patches = t.patches; build_env = t.build_env; features = t.features; extra_sources = t.extra_sources; messages = empty.messages; post_messages = empty.post_messages; depexts = empty.depexts; libraries = empty.libraries; syntax = empty.syntax; dev_repo = empty.dev_repo; pin_depends = empty.pin_depends; maintainer = empty.maintainer; author = empty.author; license = empty.license; tags = empty.tags; homepage = empty.homepage; doc = empty.doc; bug_reports = empty.bug_reports; extensions = empty.extensions; url = (match t.url with | None -> None | Some u -> match URL.checksum u with | [] -> Some (URL.create (URL.url u)) (* ignore mirrors *) | cksum::_ -> Some (URL.with_checksum [cksum] URL.empty)); (* ignore actual url and extra checksums *) descr = empty.descr; metadata_dir = empty.metadata_dir; extra_files = OpamStd.Option.Op.(t.extra_files ++ Some []); format_errors = empty.format_errors; ocaml_version = empty.ocaml_version; os = empty.os; deprecated_build_test = []; (* merged into run_test *) deprecated_build_doc = t.deprecated_build_doc; } let effectively_equal o1 o2 = effective_part o1 = effective_part o2 let equal o1 o2 = with_metadata_dir None o1 = with_metadata_dir None o2 let get_metadata_dir ~repos_roots o = match metadata_dir o with | None -> None | Some (None, abs) -> Some (OpamFilename.Dir.of_string abs) | Some (Some r, rel) -> Some OpamFilename.Op.(repos_roots r / rel) let get_extra_files ~repos_roots o = OpamStd.Option.Op.( (get_metadata_dir ~repos_roots o >>= fun mdir -> let files_dir = OpamFilename.Op.(mdir / "files") in extra_files o >>| List.map @@ fun (basename, hash) -> OpamFilename.create files_dir basename, basename, hash) +! [] ) let print_errors ?file o = if o.format_errors <> [] then OpamConsole.error "In the opam file%s:\n%s\ %s %s been %s." (match o.name, o.version, file, o.metadata_dir with | Some n, Some v, _, _ -> Printf.sprintf " for %s" (OpamPackage.to_string (OpamPackage.create n v)) | _, _, Some f, _ -> Printf.sprintf " at %s" (to_string f) | _, _, _, Some (None, dir) -> Printf.sprintf " in %s" dir | _, _, _, Some (Some repo, dir) -> Printf.sprintf " %s from repository %s" (Filename.concat dir "opam") (OpamRepositoryName.to_string repo) | _ -> "") (OpamStd.Format.itemize (fun (_, bf) -> Pp.string_of_bad_format (OpamPp.Bad_format bf)) o.format_errors) (OpamStd.List.concat_map ", " (fun (f,_) -> Printf.sprintf "'%s'" f) o.format_errors) (match o.format_errors with [_] -> "has" | _ -> "have") (OpamConsole.colorise `bold "ignored") end (** Optional package.install files (/.install, /packages/.../files/.install) *) module Dot_installSyntax = struct let internal = ".install" let format_version = OpamVersion.of_string "2.0" type t = { bin : (basename optional * basename option) list; sbin : (basename optional * basename option) list; lib : (basename optional * basename option) list; toplevel: (basename optional * basename option) list; stublibs: (basename optional * basename option) list; share : (basename optional * basename option) list; share_root: (basename optional * basename option) list; etc : (basename optional * basename option) list; doc : (basename optional * basename option) list; man : (basename optional * basename option) list; libexec : (basename optional * basename option) list; lib_root: (basename optional * basename option) list; libexec_root: (basename optional * basename option) list; misc : (basename optional * filename) list; } let empty = { lib = []; bin = []; sbin = []; toplevel = []; stublibs = []; misc = []; share = []; share_root = []; etc = []; man = []; libexec = []; lib_root = []; libexec_root = []; doc = []; } let bin t = t.bin let sbin t = t.sbin let lib t = t.lib let toplevel t = t.toplevel let stublibs t = t.stublibs let misc t = t.misc let share t = t.share let share_root t = t.share_root let etc t = t.etc let raw_man t = t.man let doc t = t.doc let libexec t = t.libexec let lib_root t = t.lib_root let libexec_root t = t.libexec_root let with_bin bin t = { t with bin } let with_sbin sbin t = { t with sbin } let with_lib lib t = { t with lib } let with_toplevel toplevel t = { t with toplevel } let with_stublibs stublibs t = { t with stublibs } let with_misc misc t = { t with misc } let with_share share t = { t with share } let with_share_root share_root t = { t with share_root } let with_etc etc t = { t with etc } let with_man man t = { t with man } let with_doc doc t = { t with doc } let with_libexec libexec t = { t with libexec } let with_lib_root lib_root t = { t with lib_root } let with_libexec_root libexec_root t = { t with libexec_root } let add_man_section_dir src = let file = Filename.basename (OpamFilename.Base.to_string src.c) in let section = let base = if Filename.check_suffix file ".gz" then Filename.chop_suffix file ".gz" else file in let dot = String.rindex base '.' in if dot < String.length base - 1 then match base.[dot+1] with | '1'..'8' as c -> Some (Printf.sprintf "man%c" c) | _ -> None else None in OpamStd.Option.Op.( section >>| (fun s -> Filename.concat s file) >>| OpamFilename.Base.of_string ) let man t = List.map (fun (src, dst) -> src, match dst with | Some _ -> dst | None -> add_man_section_dir src ) t.man (* Filenames starting by ? are not always present. *) let pp_optional = Pp.pp ~name:"file-name" (fun ~pos:_ str -> let mk = OpamFilename.Base.of_string in if String.length str > 0 && str.[0] = '?' then { optional = true; c = mk (String.sub str 1 (String.length str - 1)) } else { optional = false; c = mk str }) (fun op -> if op.optional then "?" ^ OpamFilename.Base.to_string op.c else OpamFilename.Base.to_string op.c) let fields = let pp_field = Pp.V.map_list ~depth:1 @@ Pp.V.map_option (Pp.V.string -| pp_optional) (Pp.opt @@ Pp.singleton -| Pp.V.string -| Pp.of_module "rel-filename" (module OpamFilename.Base)) in let pp_misc = Pp.V.map_list ~depth:1 @@ Pp.V.map_option (Pp.V.string -| pp_optional) (Pp.singleton -| Pp.V.string -| Pp.pp ~name:"abs-filename" (fun ~pos s -> if not (Filename.is_relative s) then OpamFilename.of_string s else Pp.bad_format ~pos "%s is not an absolute filename." s) OpamFilename.to_string) in [ "lib", Pp.ppacc with_lib lib pp_field; "bin", Pp.ppacc with_bin bin pp_field; "sbin", Pp.ppacc with_sbin sbin pp_field; "misc", Pp.ppacc with_misc misc pp_misc; "toplevel", Pp.ppacc with_toplevel toplevel pp_field; "stublibs", Pp.ppacc with_stublibs stublibs pp_field; "share", Pp.ppacc with_share share pp_field; "share_root", Pp.ppacc with_share_root share_root pp_field; "etc", Pp.ppacc with_etc etc pp_field; "doc", Pp.ppacc with_doc doc pp_field; "man", Pp.ppacc with_man raw_man pp_field; "libexec", Pp.ppacc with_libexec libexec pp_field; "lib_root", Pp.ppacc with_lib_root lib_root pp_field; "libexec_root", Pp.ppacc with_libexec_root libexec_root pp_field; ] let pp = let name = internal in Pp.I.map_file @@ Pp.I.check_opam_version ~optional:true ~format_version () -| Pp.I.opam_version ~format_version ~undefined:true () -| Pp.I.fields ~name ~empty fields -| Pp.I.show_errors ~name () -| Pp.check ~errmsg:"man file without destination or recognised suffix" (fun t -> List.for_all (function | m, None -> add_man_section_dir m <> None | _, Some _ -> true) t.man) end module Dot_install = struct include Dot_installSyntax include SyntaxFile(Dot_installSyntax) end module ChangesSyntax = struct let internal = "changes" let format_version = OpamVersion.of_string "2.0" open OpamDirTrack type t = OpamDirTrack.t module SM = OpamStd.String.Map let empty = SM.empty let field kind get_kind = Pp.ppacc (fun files t -> List.fold_left (fun t (f,digest) -> SM.add f (kind digest) t) t files) (fun t -> SM.fold (fun f op acc -> match get_kind op with Some dg -> (f, dg) :: acc | None -> acc) t [] |> List.rev) (Pp.V.map_list ~depth:1 @@ Pp.V.map_option Pp.V.string (Pp.opt (Pp.singleton -| Pp.V.string -| Pp.of_pair "digest" (digest_of_string, string_of_digest)))) let fields = [ "added", field (function Some dg -> Added dg | None -> Pp.bad_format "Missing digest") (function Added dg -> Some (Some dg) | _ -> None); "removed", field (function Some _ -> Pp.bad_format "Extra digest" | None -> Removed) (function Removed -> Some None | _ -> None); "contents-changed", field (function Some dg -> Contents_changed dg | None -> Pp.bad_format "Missing digest") (function Contents_changed dg -> Some (Some dg) | _ -> None); "perm-changed", field (function Some dg -> Perm_changed dg | None -> Pp.bad_format "Missing digest") (function Perm_changed dg -> Some (Some dg) | _ -> None); "kind-changed", field (function Some dg -> Kind_changed dg | None -> Pp.bad_format "Missing digest") (function Kind_changed dg -> Some (Some dg) | _ -> None); ] let pp_contents = Pp.I.check_opam_version ~format_version ~optional:true () -| Pp.I.opam_version ~format_version ~undefined:true () -| Pp.I.fields ~name:internal ~empty fields -| Pp.I.show_errors ~name:internal () let pp = Pp.I.map_file pp_contents end module Changes = struct type t = OpamDirTrack.t include SyntaxFile(ChangesSyntax) end module SwitchExportSyntax = struct let internal = "switch-export" let format_version = OpamVersion.of_string "2.1" type t = { selections: switch_selections; extra_files: string OpamHash.Map.t; overlays: OPAM.t OpamPackage.Name.Map.t; } let empty = { selections = SwitchSelectionsSyntax.empty; extra_files = OpamHash.Map.empty; overlays = OpamPackage.Name.Map.empty; } let fields = [ "extra-files", Pp.ppacc (fun extra_files t -> { t with extra_files }) (fun t -> t.extra_files) ((Pp.V.map_list ~depth:2 @@ (Pp.V.map_pair (Pp.V.string -| Pp.of_module "checksum" (module OpamHash)) Pp.V.string)) -| Pp.of_pair "HashMap" OpamHash.Map.(of_list, bindings)) ] @ List.map (fun (fld, ppacc) -> fld, Pp.embed (fun selections t -> { t with selections }) (fun t -> t.selections) ppacc) SwitchSelectionsSyntax.fields let pp = let name = "export-file" in Pp.I.map_file @@ Pp.I.check_opam_version ~format_version () -| Pp.I.opam_version ~format_version ~undefined:true () -| Pp.I.partition (fun i -> match i.pelem with | Section ({ section_kind={pelem="package";_}; section_name=Some _; _ }) -> false | _ -> true) -| Pp.map_pair (Pp.I.fields ~name ~empty fields -| Pp.I.show_errors ~name ()) (Pp.map_list (Pp.I.section "package" -| Pp.map_pair (Pp.map_option (Pp.of_module "package-name" (module OpamPackage.Name))) OPAMSyntax.pp_raw_fields -| Pp.pp (fun ~pos:_ (name, opam) -> match name with | Some name -> name, OPAM.with_name name opam | None -> OPAM.name opam, opam) (fun (name, opam) -> Some name, OPAM.with_name_opt None opam)) -| Pp.of_pair "package-metadata-map" OpamPackage.Name.Map.(of_list,bindings)) -| Pp.pp (fun ~pos:_ (t, overlays) -> {t with overlays}) (fun t -> t, t.overlays) end module SwitchExport = struct type t = SwitchExportSyntax.t = { selections: switch_selections; extra_files: string OpamHash.Map.t; overlays: OPAM.t OpamPackage.Name.Map.t; } include SyntaxFile(SwitchExportSyntax) end module CompSyntax = struct let internal = "comp" let format_version = OpamVersion.of_string "1.2" type compiler = string type compiler_version = string type t = { opam_version : opam_version ; name : compiler ; version : compiler_version ; preinstalled : bool; src : url option ; patches : url list ; configure : string list ; make : string list ; build : command list ; packages : formula ; env : env_update list; tags : string list; } let empty = { opam_version = format_version; name = ""; version = ""; src = None; preinstalled = false; patches = []; configure = []; make = []; build = []; packages = OpamFormula.Empty; env = []; tags = []; } let create_preinstalled name version packages env = let mk n = Atom (n, Empty) in let packages = OpamFormula.ands (List.map mk packages) in { empty with name; version; preinstalled = true; packages; env } let name (t:t) = t.name let version (t:t) = t.version let patches t = t.patches let configure t = t.configure let make t = t.make let build t = t.build let src t = t.src let opam_version t = t.opam_version let packages t = t.packages let preinstalled t = t.preinstalled let env (t:t) = List.map (function | var,op,value,None -> var, op, value, Some ("Updated by compiler " ^ t.name) | b -> b) t.env let tags t = t.tags let with_opam_version opam_version t = {t with opam_version} let with_name name (t:t) = {t with name} let with_version version (t:t) = {t with version} let with_src src t = { t with src } let with_patches patches t = {t with patches} let with_configure configure t = {t with configure} let with_make make t = {t with make} let with_build build t = {t with build} let with_packages packages t = {t with packages} let with_preinstalled preinstalled t = {t with preinstalled} let with_env env t = {t with env} let with_tags tags t = {t with tags} let fields = let with_src url t = if t.src <> None then Pp.bad_format "Too many URLS" else with_src (Some url) t in [ "opam-version", Pp.ppacc with_opam_version opam_version (Pp.V.string -| Pp.of_module "opam-version" (module OpamVersion)); "name", Pp.ppacc_opt with_name (fun t -> if t.name = empty.name then None else Some t.name) Pp.V.string; "version", Pp.ppacc_opt with_version (fun t -> if t.version = empty.version then None else Some t.version) Pp.V.string; "src", Pp.ppacc_opt with_src src Pp.V.url; "http", Pp.ppacc_opt with_src OpamStd.Option.none (Pp.V.url_with_backend `http); "archive", Pp.ppacc_opt with_src OpamStd.Option.none (Pp.V.url_with_backend `http); "git", Pp.ppacc_opt with_src OpamStd.Option.none (Pp.V.url_with_backend `git); "darcs", Pp.ppacc_opt with_src OpamStd.Option.none (Pp.V.url_with_backend `darcs); "hg", Pp.ppacc_opt with_src OpamStd.Option.none (Pp.V.url_with_backend `hg); "local", Pp.ppacc_opt with_src OpamStd.Option.none (Pp.V.url_with_backend `rsync); "patches", Pp.ppacc with_patches patches (Pp.V.map_list ~depth:1 @@ Pp.V.url); "configure", Pp.ppacc with_configure configure (Pp.V.map_list ~depth:1 Pp.V.string); "make", Pp.ppacc with_make make (Pp.V.map_list ~depth:1 Pp.V.string); "build", Pp.ppacc with_build build (Pp.V.map_list ~depth:1 Pp.V.command); "packages", Pp.ppacc with_packages packages (Pp.V.package_formula `Conj (Pp.V.constraints Pp.V.version)); "env", Pp.ppacc with_env env (Pp.V.map_list ~depth:2 Pp.V.env_binding); "preinstalled", Pp.ppacc_opt with_preinstalled (fun t -> if t.preinstalled then Some true else None) Pp.V.bool; "tags", Pp.ppacc with_tags tags (Pp.V.map_list ~depth:1 Pp.V.string); ] let system_compiler = "system" let version_of_name name = match OpamStd.String.cut_at name '+' with | Some (v,_) -> v | None -> name let pp_raw = let name = internal in Pp.I.map_file @@ Pp.I.check_opam_version ~format_version () -| Pp.I.opam_version ~format_version () -| Pp.I.fields ~name ~empty fields -| Pp.I.show_errors ~name () -| Pp.check ~errmsg:"fields 'build:' and 'configure:'+'make:' are mutually \ exclusive " (fun t -> t.build = [] || t.configure = [] && t.make = []) let of_filename f = if OpamFilename.check_suffix f ".comp" then f |> OpamFilename.chop_extension |> OpamFilename.basename |> OpamFilename.Base.to_string |> fun x -> Some x else None let pp = pp_raw -| Pp.pp (fun ~pos (filename, (t:t)) -> filename, match of_filename filename with | None -> if t.name = empty.name || t.name <> "system" && t.version = empty.version then Pp.bad_format ~pos "File name not in the form ., and missing 'name:' \ or 'version:' fields" else Pp.warn ~pos ".comp file name not in the form ."; t | Some name -> let version = if name = "system" then t.version else version_of_name name in if t.name <> empty.name && t.name <> name then Pp.warn ~pos "Mismatching file name and 'name:' field"; if name <> system_compiler && t.version <> empty.version && t.version <> version then Pp.warn ~pos "Mismatching file name and 'version:' field"; {t with name; version}) (fun (filename, t) -> filename, match of_filename filename with | None -> if t.name = empty.name || t.name <> system_compiler && t.version = empty.version then OpamConsole.warning "Outputting .comp file %s with unspecified name or version" (OpamFilename.to_string filename); t | Some name -> let version = if name = system_compiler then t.version else version_of_name name in if t.name <> empty.name && t.name <> name || name <> system_compiler && t.version <> empty.version && t.version <> version then OpamConsole.warning "Skipping inconsistent 'name:' or 'version:' fields (%s.%s) \ while saving %s" t.name version (OpamFilename.to_string filename); { t with name = empty.name }) let to_package ?package comp descr_opt = let package = match package with | Some p -> p | None -> OpamPackage.create (OpamPackage.Name.of_string "ocaml") (OpamPackage.Version.of_string (name comp)) in let nofilter x = x, (None: filter option) in let depends = OpamFormula.map (fun (n, formula) -> let cstr (op, v) = OpamFormula.ands [ Atom (Constraint (op, FString (OpamPackage.Version.to_string v))); ] in let post_flag = Filter (FIdent ([], OpamVariable.of_string "post", None)) in Atom (n, OpamFormula.ands [OpamFormula.map cstr formula; Atom post_flag])) (OpamFormula.ands [ Atom (OpamPackage.Name.of_string "ocaml", Atom (`Eq, OpamPackage.Version.of_string comp.version)); comp.packages ]) in let url = OpamStd.Option.map (fun url -> URL.with_url url URL.empty) comp.src in let build, install = match comp.build with | [] -> List.map (fun l -> nofilter (List.map nofilter l)) [ (List.map (fun s -> CString s) ("./configure" :: configure comp )) @ [ CString "-prefix"; CIdent "prefix" ]; CIdent "make" :: List.map (fun s -> CString s) (make comp); ], List.map (fun l -> nofilter (List.map nofilter l)) [ [ CIdent "make"; CString "install" ]; ] | cl -> match List.rev cl with | install::cl -> List.rev cl, [install] | [] -> assert false in let extra_sources = List.map (fun url -> OpamFilename.Base.of_string (OpamUrl.basename url), URL.create url) comp.patches in let patches = List.map (fun u -> nofilter (OpamFilename.Base.of_string (OpamUrl.basename u))) comp.patches in let pkg = OPAM.create package in { pkg with OPAM. depends; build; install; maintainer = [ "platform@lists.ocaml.org" ]; extra_sources; patches; env = comp.env; flags = [Pkgflag_Compiler]; url; descr = descr_opt; } end module Comp = struct include CompSyntax include SyntaxFile(CompSyntax) end opam-2.1.5/src/format/opamVariable.ml0000644000175000017500000000636314427463453016542 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) include OpamStd.AbstractString type variable = t type variable_contents = | B of bool | S of string | L of string list let string_of_variable_contents = function | B b -> string_of_bool b | S s -> s | L l -> String.concat " " l let string str = S str let bool b = B b let int i = string (string_of_int i) let dirname dir = string (OpamFilename.Dir.to_string dir) module Full = struct type scope = | Global | Self | Package of OpamPackage.Name.t type t = { scope: scope; variable: variable; } let variable t = t.variable let scope t = t.scope let package ?self t = match t.scope with | Package p -> Some p | Self -> self | Global -> None let create package variable = let scope = if OpamPackage.Name.to_string package = "_" then Self else Package package in { scope; variable } (* Read the variables overridden through the environment *) let read_from_env v = let var_str = to_string (variable v) in let undash = OpamStd.String.map (function '-' -> '_' | c -> c) in let var_hook = match package v with | Some n -> Printf.sprintf "%s_%s" (undash (OpamPackage.Name.to_string n)) (undash var_str) | None -> undash var_str in try match OpamStd.Env.get ("OPAMVAR_" ^ var_hook) with | "true" | "1" -> Some (bool true) | "false" | "0" -> Some (bool false) | s -> Some (string s) with Not_found -> None let global variable = { scope = Global; variable } let self variable = { scope = Self; variable } let is_global variable = match variable.scope with | Global -> true | Self | Package _ -> false let of_string s = match OpamStd.String.rcut_at s ':' with | None -> global (of_string s) | Some ("_",v) -> { scope = Self; variable = of_string v } | Some (p,v) -> create (OpamPackage.Name.of_string p) (of_string v) let to_string t = let prefix = match t.scope with | Global -> "" | Self -> "_:" | Package p -> OpamPackage.Name.to_string p ^ ":" in prefix ^ to_string t.variable let to_json x = `String (to_string x) let of_json = function | `String s -> (try Some (of_string s) with _ -> None) | _ -> None module O = struct type tmp = t type t = tmp let compare = compare let to_string = to_string let to_json = to_json let of_json = of_json end module Set = OpamStd.Set.Make(O) module Map = OpamStd.Map.Make(O) end opam-2.1.5/src/format/opamPp.mli0000644000175000017500000001452314427463453015542 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2018 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Generic bidirectional transformation toolbox for parsing/printing *) open OpamParserTypes.FullPos (** {2 Parsing positions and error reporting helpers} *) (** Format error reporting: position and message *) type bad_format = pos option * string (** All the following parsing function raise [Bad_format] in case the input does not have the right format. *) exception Bad_format of bad_format exception Bad_format_list of bad_format list exception Bad_version of bad_format (** Raise [Bad_format]. *) val bad_format: ?pos:pos -> ('a, unit, string, 'b) format4 -> 'a (** Raise [Bad_version]. *) val bad_version: ?pos:pos -> ('a, unit, string, 'b) format4 -> 'a val string_of_bad_format: ?file:string -> exn -> string (** Adds a position to a Bad_format exception if it doesn't have one yet *) val add_pos: pos -> exn -> exn (** {2 Parser/printers} *) (** The type of bidirectional parsers from ['a] to ['b]. We abuse the terms and describe going from ['a] to ['b] as "parsing", and going from ['b] to ['a] as "printing". Parsing is generally error-prone, while printing is not expected to fail, so the handling isn't really symmetrical. [parse (print x)] should always be the identity, while no guarantee is given regarding [print (parse x)] *) type ('a, 'b) t = private { parse: pos:pos -> 'a -> 'b; print: 'b -> 'a; ppname: string; name_constr: string -> string; } (** Base constructor for Pp.t, from a parser function and a printer function. [name_constr] is used to construct the resulting name when on the left of a pipe. Names are for tracing errors. *) val pp : ?name:string -> ?name_constr:(string -> string) -> (pos:pos -> 'a -> 'b) -> ('b -> 'a) -> ('a, 'b) t (** Constructor of Pp.t from a name and a pair *) val of_pair : string -> ('a -> 'b) * ('b -> 'a) -> ('a, 'b) t (** Base call for parsing with a pp *) val parse : ('a, 'b) t -> pos:pos -> 'a -> 'b (** Base call for printing with a pp *) val print : ('a, 'b) t -> 'b -> 'a (** Error handling *) (** Raises an exception handled by parser calls *) val unexpected : ?pos:pos -> unit -> 'a (** {3 Various pp constructors} *) module Op : sig (** Piping pps together: the left-hand pp is called first when parsing, last when printing *) val ( -| ) : ('a, 'b) t -> ('b, 'c) t -> ('a, 'c) t (** Combinator to parse lists to different types using nested pairs *) val ( ^+ ) : ('a, 'b) t -> ('a list, 'c) t -> ('a list, 'b * 'c) t end val identity : ('a, 'a) t (** Always parses to [None] *) val ignore : ('a, 'b option) t (** Identity pp, unless the check fails. The check is turned into an assertion when printing. If no [errmsg] is given, raises [Unexpected], otherwise call [raise] with the given [errmsg]. By default [raise] raises [Bad_format]. *) val check : ?name:string -> ?raise:(?pos:pos -> (string -> 'a, unit, string, 'a) format4 -> string -> 'a) -> ?errmsg:string -> ('a -> bool) -> ('a, 'a) t val map_pair : ?name:string -> ?posf1:('a -> pos) -> ?posf2:('b -> pos) -> ('a, 'c) t -> ('b, 'd) t -> ('a * 'b, 'c * 'd) t (** Builds a pp of pairs by passing the second term along *) val map_fst : ('a, 'b) t -> ('a * 'c, 'b * 'c) t (** Builds a pp of pairs by passing the first term along *) val map_snd : ('a, 'b) t -> ('c * 'a, 'c * 'b) t val map_list : ?name:string -> ?posf:('a -> pos) -> ('a, 'b) t -> ('a list, 'b list) t val map_option : ?name:string -> ('a, 'b) t -> ('a option, 'b option) t (** Parsing fails on non-singleton lists *) val singleton : ('a list, 'a) t (** Use for the rightmost element to close a [^+] sequence, e.g. [pp1 ^+ pp2 ^+ last -| pp3] *) val last : ('a list, 'a) t module type STR = sig type t val of_string : string -> t val to_string : t -> string end (** Generates a string pp from a module with of/to string functions *) val of_module : string -> (module STR with type t = 'a) -> (string, 'a) t (** Parses to None on the empty list. Often combined with singleton ([opt (singleton _)]) *) val opt : ('a list, 'b) t -> ('a list, 'b option) t val default : 'a -> ('a option, 'a) t (** [fallback p1 p2] is [p1], except that parsing is allowed to fail and will in that case try to parse through [p2]. Can be useful for backwards compatibility, but use with care *) val fallback : ('a, 'b) t -> ('a, 'b) t -> ('a, 'b) t (** {3 Combinators to parse to a record from a list of (field name, field setter, field getter)} *) (** Used to parse a single field of a record: ['a] on the left is the accumulator, or value of the record parsed so far. (in lens terms, [get] would be the print operation that extracts the field for the record, while [set] would be the parse operation that takes the input and record, and updates a given field in the record) *) type ('a, 'value) field_parser = ('a * 'value option, 'a) t (** Make a field parser from setter, getter and base pp. [cleanup] is an optional sanitisation function that is called on parsed elements before calling the setter. *) val ppacc : ?cleanup:(pos:pos -> 'acc -> 'a -> 'a) -> ('a -> 'acc -> 'acc) -> ('acc -> 'a) -> ('value, 'a) t -> ('acc, 'value) field_parser (** Same as [ppacc], but when the field may be unset in the record, i.e. the getter returns an option *) val ppacc_opt : ?cleanup:(pos:pos -> 'acc -> 'a -> 'a) -> ('a -> 'acc -> 'acc) -> ('acc -> 'a option) -> ('value, 'a) t -> ('acc, 'value) field_parser (** A field parser that ignores its argument *) val ppacc_ignore : ('a, value) field_parser val embed : ('a -> 'acc -> 'acc) -> ('acc -> 'a) -> ('a, 'value) field_parser -> ('acc, 'value) field_parser opam-2.1.5/src/format/opamTypes.mli0000644000175000017500000002605214427463453016267 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Definitions of many types used throughout *) (** {2 Error and continuation handling} *) type 'a success = [ `Successful of 'a ] type 'a error = [ | `Error of 'a | `Exception of exn ] type ('a,'b) status = [ 'a success | 'b error ] type ('a, 'b) either = ('a, 'b) OpamCompat.Either.t = | Left of 'a | Right of 'b (** {2 Filenames} *) (** Basenames *) type basename = OpamFilename.Base.t (** Directory names (translated to absolute) *) type dirname = OpamFilename.Dir.t (** Filenames *) type filename = OpamFilename.t (** Set of files *) type filename_set = OpamFilename.Set.t (** Map of files *) type 'a filename_map = 'a OpamFilename.Map.t (** Predefined installation directories within a switch *) type std_path = | Prefix | Lib | Bin | Sbin | Share | Doc | Etc | Man | Toplevel | Stublibs (** Download result *) type 'a download = | Up_to_date of 'a | Not_available of string option * string (** Arguments are respectively the short and long version of an error message. The usage is: the first argument is displayed on normal mode (nothing if [None]), and the second one on verbose mode. *) | Result of 'a (** {2 Packages} *) (** Packages are ([name] * [version]) tuple *) type package = OpamPackage.t = private { name: OpamPackage.Name.t; version: OpamPackage.Version.t; } (** Set of packages *) type package_set = OpamPackage.Set.t (** Map of packages *) type 'a package_map = 'a OpamPackage.Map.t (** Package names *) type name = OpamPackage.Name.t (** Set of package names *) type name_set = OpamPackage.Name.Set.t (** Map of package names *) type 'a name_map = 'a OpamPackage.Name.Map.t (** Package versions *) type version = OpamPackage.Version.t (** Set of package versions *) type version_set = OpamPackage.Version.Set.t (** OPAM versions *) type opam_version = OpamVersion.t (** {2 Variables} *) (** Variables *) type variable = OpamVariable.t (** Fully qualified variables (ie. with the name of sections/sub-sections they appear in) *) type full_variable = OpamVariable.Full.t (** Content of user-defined variables *) type variable_contents = OpamVariable.variable_contents = | B of bool | S of string | L of string list (** A map from variables to their contents (i.e an environment) *) type variable_map = OpamVariable.variable_contents OpamVariable.Map.t (** Opam package flags *) type package_flag = | Pkgflag_LightUninstall (** The package doesn't require downloading to uninstall *) | Pkgflag_Verbose (** The package's scripts output is to be displayed to the user *) | Pkgflag_Plugin (** The package is an opam plugin that will install a [opam-] exec, and may be auto-installed when doing [opam ] *) | Pkgflag_Compiler (** Package may be used for 'opam switch' *) | Pkgflag_Conf (** Virtual package: no source, no install or remove instructions, .install, but likely has depexts *) | Pkgflag_AvoidVersion (** This version of the package will only be installed if strictly required *) | Pkgflag_Unknown of string (** Used for error reporting, otherwise ignored *) (** At some point we want to abstract so that the same functions can be used over CUDF and OPAM packages *) module type GenericPackage = sig include OpamParallel.VERTEX val name_to_string: t -> string val version_to_string: t -> string end (** {2 Formulas} *) (** A generic formula *) type 'a generic_formula = 'a OpamFormula.formula = | Empty | Atom of 'a | Block of 'a generic_formula | And of 'a generic_formula * 'a generic_formula | Or of 'a generic_formula * 'a generic_formula (** Formula atoms *) type atom = OpamFormula.atom (** Formula over versionned packages *) type formula = OpamFormula.t (** AND formulat *) type 'a conjunction = 'a OpamFormula.conjunction (** OR formulat *) type 'a disjunction = 'a OpamFormula.disjunction (** {2 Repositories} *) (** Repository names *) type repository_name = OpamRepositoryName.t (** Maps of repository names *) type 'a repository_name_map = 'a OpamRepositoryName.Map.t type url = OpamUrl.t (*= { transport: string; path: string; hash: string option; backend: OpamUrl.backend; } *) type trust_anchors = { quorum: int; fingerprints: string list; } (** Repositories *) type repository = { repo_name : repository_name; repo_url : url; repo_trust : trust_anchors option; } (** {2 Variable-based filters} *) type relop = OpamParserTypes.FullPos.relop_kind type filter = | FBool of bool | FString of string | FIdent of (name option list * variable * (string * string) option) (** packages (or None for self-ref through "_"), variable name, string converter (val_if_true, val_if_false_or_undef) *) | FOp of filter * relop * filter | FAnd of filter * filter | FOr of filter * filter | FNot of filter | FDefined of filter | FUndef of filter (** Returned by reduce functions when the filter could not be resolved to an atom (due to undefined variables or string expansions). The argument contains the partially reduced filter, where strings may still contain expansions (and are otherwise escaped). Used both for partial evaluation, and error messaging. Not allowed as an argument to other filters *) (** {2 Filtered formulas (to express conditional dependencies)} These are first reduced to only the dependency-flag variables build, doc, dev, test defined in [Opam formulas] *) type 'a filter_or_constraint = | Filter of filter | Constraint of (relop * 'a) type filtered_formula = (name * filter filter_or_constraint OpamFormula.formula) OpamFormula.formula (** {2 Solver} *) (** Used internally when computing sequences of actions *) type 'a atomic_action = [ | `Remove of 'a | `Install of 'a ] (** Used to compact the atomic actions and display to the user in a more meaningful way *) type 'a highlevel_action = [ | 'a atomic_action | `Change of [ `Up | `Down ] * 'a * 'a | `Reinstall of 'a ] (** Sub-type of [highlevel_action] corresponding to an installed package that changed state or version *) type 'a inst_action = [ | `Install of 'a | `Change of [ `Up | `Down ] * 'a * 'a ] (** Used when applying solutions, separates build from install *) type 'a concrete_action = [ | 'a atomic_action | `Build of 'a | `Fetch of 'a ] type 'a action = [ | 'a atomic_action | 'a highlevel_action | 'a concrete_action ] (** The possible causes of an action. *) type 'a cause = | Use of 'a list | Required_by of 'a list | Conflicts_with of 'a list | Upstream_changes | Requested | Unknown (** Solver result *) type actions_result = { actions_successes : package action list; actions_errors : (package action * exn) list; actions_aborted : package action list; } type solution_result = | Nothing_to_do | OK of package action list (** List of successful actions *) | Aborted | Partial_error of actions_result (** Solver result *) type ('a, 'b) result = | Success of 'a | Conflicts of 'b type solver_criteria = [ `Default | `Upgrade | `Fixup ] (** Solver request *) type 'a request = { criteria: solver_criteria; wish_install: 'a conjunction; wish_remove : 'a conjunction; wish_upgrade: 'a conjunction; extra_attributes: string list; } (** user request action *) type user_action = Query | Install | Upgrade | Reinstall | Remove | Switch | Import (** Solver universe *) type universe = { u_packages : package_set; u_installed: package_set; u_available: package_set; u_depends : filtered_formula package_map; u_depopts : filtered_formula package_map; u_conflicts: formula package_map; u_action : user_action; u_installed_roots: package_set; u_pinned : package_set; u_base : package_set; u_invariant: formula; u_reinstall: package_set; u_attrs : (string * package_set) list; } (** {2 Command line arguments} *) (** Pin kind *) type pin_kind = [ `version | OpamUrl.backend ] (** Shell compatibility modes *) type shell = OpamStd.Sys.shell = SH_sh | SH_bash | SH_zsh | SH_csh | SH_fish (** {2 Generic command-line definitions with filters} *) (** A command argument *) type simple_arg = | CString of string | CIdent of string (** Command argument *) type arg = simple_arg * filter option (** Command *) type command = arg list * filter option (** {2 Switches} *) (** Compiler switches *) type switch = OpamSwitch.t (** Set of compiler switches *) type switch_set = OpamSwitch.Set.t (** Map of compile switches *) type 'a switch_map = 'a OpamSwitch.Map.t type switch_selections = { sel_installed: package_set; sel_roots: package_set; sel_compiler: package_set; sel_pinned: package_set; } (** {2 Misc} *) (** The different kinds of locks *) type lock = | Read_lock of (unit -> unit) (** The function does not modify anything, but it needs the state not to change while it is running. *) | Global_lock of (unit -> unit) (** Take the global lock, all subsequent calls to OPAM are blocked. *) | Switch_lock of (unit -> switch) * (unit -> unit) (** Take a global read lock and a switch lock. The first function is called with the read lock, then the second function is called with the returned switch write-locked. *) | Global_with_switch_cont_lock of (unit -> switch * (unit -> unit)) (** Call the function in a global lock, then relax to a switch lock and call the function it returned *) (** A line in {i urls.tx} *) type file_attribute = OpamFilename.Attribute.t (** All the lines in {i urls.txt} *) type file_attribute_set = OpamFilename.Attribute.Set.t (** Optional contents *) type 'a optional = { c : 'a; (** Contents *) optional: bool; (** Is the contents optional *) } (** Upgrade statistics *) type stats = { s_install : int; s_reinstall: int; s_upgrade : int; s_downgrade: int; s_remove : int; } (** Environement variables: var name, value, optional comment *) type env = (string * string * string option) list (** Environment updates *) type env_update = string * OpamParserTypes.FullPos.env_update_op_kind * string * string option (** var, update_op, value, comment *) (** Tags *) type tags = OpamStd.String.Set.t OpamStd.String.SetMap.t (** {2 Repository and global states} *) (** Checksums *) type checksums = string list (** {2 JSON} *) type json = OpamJson.t type sys_package = OpamSysPkg.t type sys_pkg_status = OpamSysPkg.status opam-2.1.5/src/format/dune0000644000175000017500000000074314427463453014460 0ustar stephsteph(library (name opam_format) (public_name opam-format) (synopsis "OCaml Package Manager file format handling library") (libraries opam-core opam-file-format re) (modules_without_implementation OpamTypes) (flags (:standard (:include ../ocaml-flags-standard.sexp) (:include ../ocaml-flags-configure.sexp) (:include ../ocaml-context-flags.sexp))) (wrapped false)) (ocamllex opamLineLexer opamInterpLexer) opam-2.1.5/src/format/opamLineLexer.mli0000644000175000017500000000156114427463453017050 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2016 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** A simple lexer to list of lines, which are lists of words *) val main: Lexing.lexbuf -> string list list opam-2.1.5/src/format/opamVariable.mli0000644000175000017500000000476514427463453016717 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2017 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** OPAM variables with scope (global or module), used in "opam" package definition files in "filters" *) (** {2 Variable names} *) include OpamStd.ABSTRACT (** Shortcut to variables *) type variable = t (** Variable contents *) type variable_contents = | B of bool | S of string | L of string list (** Pretty print of variable contents *) val string_of_variable_contents: variable_contents -> string (** Variable contents constructors *) val string: string -> variable_contents val int: int -> variable_contents val bool: bool -> variable_contents val dirname: OpamFilename.Dir.t -> variable_contents module Full: sig (** Fully qualified variable. *) include OpamStd.ABSTRACT type scope = | Global (** Note: this is attributed to unqualified variables, and may also design self-referring ones *) | Self (** Variable in a package-specific file referring to that package [_:varname] *) | Package of OpamPackage.Name.t (** [pkgname:varname] *) (** Returns the scope of the variable *) val scope: t -> scope (** Returns the unqualified variable name *) val variable: t -> variable val is_global: t -> bool (** Return the package corresponding to the scope of the variable *) val package: ?self:OpamPackage.Name.t -> t -> OpamPackage.Name.t option (** Create a variable local for a given library/syntax extension *) val create: OpamPackage.Name.t -> variable -> t (** Create a global variable *) val global: variable -> t (** Create a variable in the [Self] scope *) val self: variable -> t (** Looks up for an environment override through the environment, by means of [OPAMVAR_glovar] or [OPAMVAR_pkg_pkgvar] *) val read_from_env: t -> variable_contents option end opam-2.1.5/src/format/opamLineLexer.mll0000644000175000017500000000362514427463453017056 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2016 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) { type token = | WORD of string | NEWLINE | EOF let word = Buffer.create 57 } let normalchar = [^' ' '\t' '\r' '\n' '\\'] rule main = parse | '\n' | "\r\n" { Lexing.new_line lexbuf; NEWLINE } | [' ' '\t']+ { main lexbuf } | ('@' normalchar*) as w '\\' { Buffer.reset word ; Buffer.add_string word w; escaped lexbuf } | ('@' normalchar*) as w { if w = "@" then WORD "" else WORD w } | (normalchar* as w) '\\' { Buffer.reset word ; Buffer.add_string word w; escaped lexbuf } | (normalchar+ as w) { WORD w } | eof { EOF } and escaped = parse | (_ normalchar*) as w '\\' { Buffer.add_string word w; escaped lexbuf } | (_ normalchar*) as w { Buffer.add_string word w; WORD (Buffer.contents word) } { let main lexbuf = let rec aux lines words = match main lexbuf with | WORD s -> aux lines (s::words) | NEWLINE -> let lines = if words = [] then lines else List.rev words::lines in aux lines [] | EOF -> let lines = if words = [] then lines else List.rev words::lines in List.rev lines in aux [] [] } opam-2.1.5/src/format/opamFormula.mli0000644000175000017500000002114414427463453016565 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Formulas on packages, opt. with sub-formulas on versions, and conversion functions *) (** binary operations (compatible with the Dose type for Cudf operators!) *) type relop = OpamParserTypes.FullPos.relop_kind (* = [ `Eq | `Neq | `Geq | `Gt | `Leq | `Lt ] *) (** Version constraints for OPAM *) type version_constraint = relop * OpamPackage.Version.t (** Formula atoms for OPAM *) type atom = OpamPackage.Name.t * version_constraint option (** Pretty-printing of atoms *) val string_of_atom: atom -> string (** The compact atom format used in requests, "pkgOPvers", with '.' allowed instead of '=' *) val short_string_of_atom: atom -> string (** Parses a package or atom, in a format similar to [short_string_of_atom]. @raise [Failure] if the format is incorrect *) val atom_of_string: string -> atom (** Prints atoms as a conjunction ("&") using the short format *) val string_of_atoms: atom list -> string (** Checks if a package verifies an atom *) val check: atom -> OpamPackage.t -> bool (** Return all packages satisfying the given atoms from a set (i.e. name matching at least one of the atoms, version matching all atoms with the appropriate name). If [disj] is true, returns packages that satisfy at least one of the constraint of a given name, otherwise that satisfy all constraints. *) val packages_of_atoms: ?disj:bool -> OpamPackage.Set.t -> atom list -> OpamPackage.Set.t (** AND formulas *) type 'a conjunction = 'a list (** Pretty print AND formulas *) val string_of_conjunction: ('a -> string) -> 'a conjunction -> string (** OR formulas *) type 'a disjunction = 'a list (** Pretty print OR formulas *) val string_of_disjunction: ('a -> string) -> 'a disjunction -> string (** CNF formulas (Conjunctive Normal Form) *) type 'a cnf = 'a disjunction conjunction (** DNF formulas (Disjunctive Normal Form) *) type 'a dnf = 'a conjunction disjunction (** Pretty print CNF formulas *) val string_of_cnf: ('a -> string) -> 'a cnf -> string (** Pretty print DNF formulas *) val string_of_dnf: ('a -> string) -> 'a dnf -> string (** General formulas *) type 'a formula = | Empty | Atom of 'a | Block of 'a formula | And of 'a formula * 'a formula | Or of 'a formula * 'a formula val compare_formula: ('a -> 'a -> int) -> 'a formula -> 'a formula -> int (** Eval a formula *) val eval: ('a -> bool) -> 'a formula -> bool val partial_eval: ('a -> [ `Formula of 'b formula | `True | `False ]) -> 'a formula -> [ `Formula of 'b formula | `True | `False ] (** Check a relational operator against an integer from compare *) val check_relop: relop -> int -> bool (** Evaluate a relational operator between versions *) val eval_relop: relop -> OpamPackage.Version.t -> OpamPackage.Version.t -> bool val neg_relop: relop -> relop (** Pretty print a formula *) val string_of_formula: ('a -> string) -> 'a formula -> string (** Convert a list of formulas to an AND-formula ([Empty] formulas are ignored) *) val ands: 'a formula list -> 'a formula (** Converts back an AND-formula to a list (flattens top-level ands) *) val ands_to_list: 'a formula -> 'a formula list (** Convert a list of formulas to an OR-formula ([Empty] formulas are ignored) *) val ors: 'a formula list -> 'a formula (** Converts back an OR-formula to a list (flattens top-level ors) *) val ors_to_list: 'a formula -> 'a formula list (** Map on atoms. Atoms for which the given function returns Empty will be simply removed *) val map: ('a -> 'b formula) -> 'a formula -> 'b formula (** Maps top-down on a formula *) val map_formula: ('a formula -> 'a formula) -> 'a formula -> 'a formula (** Maps bottom-up on a formula (atoms first) *) val map_up_formula: ('a formula -> 'a formula) -> 'a formula -> 'a formula (** Negates a formula (given the function to negate atoms) *) val neg: ('a -> 'a) -> 'a formula -> 'a formula (** Iter function *) val iter: ('a -> unit) -> 'a formula -> unit (** Fold function (bottom-up, left-to-right) *) val fold_left: ('a -> 'b -> 'a) -> 'a -> 'b formula -> 'a (** Fold function (bottom-up, right-to-left) *) val fold_right: ('a -> 'b -> 'a) -> 'a -> 'b formula -> 'a (** Sort formula, using [compare] function. `Block` around `Or` and `And` \ are removed. *) val sort: ('a -> 'a -> int) -> 'a formula -> 'a formula (** Expressions composed entirely of version constraints *) type version_formula = version_constraint formula (** Checks if a given version satisfies a formula *) val check_version_formula: version_formula -> OpamPackage.Version.t -> bool (** An atom is: [name] * ([relop] * [version]) formula. Examples of valid formulae: - "foo" \{> "1" & (<"3" | ="5")\} - "foo" \{= "1" | > "4"\} | ("bar" "bouh") *) type t = (OpamPackage.Name.t * version_formula) formula val compare: t -> t -> int (** Returns [true] if [package] verifies [formula] (i.e. it is within at least one package set that is a solution of the formula, and is named in the formula) *) val verifies: t -> OpamPackage.t -> bool (** Checks if a given set of (installed) packages satisfies a formula *) val satisfies_depends: OpamPackage.Set.t -> t -> bool (** Returns the subset of packages possibly matching the formula (i.e. including all disjunction cases) *) val packages: OpamPackage.Set.t -> t -> OpamPackage.Set.t val compare_nc: (OpamPackage.Name.t * version_formula) -> (OpamPackage.Name.t * version_formula) -> int (** Convert a formula to CNF *) val cnf_of_formula: 'a formula -> 'a formula (** Convert a formula to DNF *) val dnf_of_formula: 'a formula -> 'a formula (** Transform a formula where versions can be expressed using formulas to a flat atom formula *) val to_atom_formula: t -> atom formula (** Convert an atom-formula to a t-formula *) val of_atom_formula: atom formula -> t (** [simplify_ineq_formula comp f] returns a canonical version of inequality formula [f], based on comparison function [comp], where each version appears at most once, and in increasing order. Returns [Some Empty] if the formula is always [true], [None] if it is always false *) val simplify_ineq_formula: ('a -> 'a -> int) -> (relop * 'a) formula -> (relop * 'a) formula option (** Like [simplify_ineq_formula], but specialised on version formulas *) val simplify_version_formula: version_formula -> version_formula option (** A more aggressive version of [simplify_version_formula] that attempts to find a shorter formula describing the same subset of versions within a given set. The empty formula is returned for an empty set, and the original formula is otherwise returned as is if no versions match. *) val simplify_version_set: OpamPackage.Version.Set.t -> version_formula -> version_formula (** [formula_of_version_set set subset] generates a formula that is enough to describe all packages of [subset] and exclude packages otherwise in [set] *) val formula_of_version_set: OpamPackage.Version.Set.t -> OpamPackage.Version.Set.t -> version_formula (** {2 Atoms} *) (** Return all the atoms *) val atoms: t -> atom list (** Pretty print the formula *) val to_string: t -> string (** Return a conjunction. If the initial formula is not a conjunction, then fail. *) val to_conjunction: t -> atom conjunction (** Return a formula from a conjunction of atoms *) val of_conjunction: atom conjunction -> t (** Return a disjunction of atoms from a package formula. It the initial formula is not a disjunction, then fail. *) val to_disjunction: t -> atom disjunction (** Like [to_disjunction], but accepts conjunctions within constraint formulas, resolving them using the provided package set. Conjunctions between packages still raise [Failure]. *) val set_to_disjunction: OpamPackage.Set.t -> t -> atom disjunction (** Return a formula from a disjunction of atoms *) val of_disjunction: atom disjunction -> t (** Return an equivalent CNF formula *) val to_cnf: t -> atom cnf (** Return an equivalent DNF formula *) val to_dnf: t -> atom dnf opam-2.1.5/src/format/opamPackage.mli0000644000175000017500000001057114427463453016515 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** The package type, and package name type (name+version, values often called "nv" in the code) *) (** {2 Package name and versions} *) (** Versions *) module Version: sig include OpamStd.ABSTRACT (** Compare two versions using the Debian version scheme *) val compare: t -> t -> int (** Are two package versions equal? *) val equal: t -> t -> bool end (** Names *) module Name: sig include OpamStd.ABSTRACT (** Compare two package names *) val compare: t -> t -> int (** Are two package names equal? *) val equal: t -> t -> bool end type t = private { name: Name.t; version: Version.t; } (** Package (name x version) pairs *) include OpamStd.ABSTRACT with type t := t (** Return the package name *) val name: t -> Name.t (** Return None if [nv] is not a valid package name *) val of_string_opt: string -> t option (** Return the version name *) val version: t -> Version.t (** Create a new pair (name x version) *) val create: Name.t -> Version.t -> t (** To fit in the GenericPackage type, for generic display functions *) val name_to_string: t -> string val version_to_string: t -> string (** Guess the package name from a filename. This function extracts [name] and [version] from {i /path/to/$name.$version/opam}, or {i /path/to/$name.$version.opam} *) val of_filename: OpamFilename.t -> t option (** Guess the package name from a directory name. This function extracts {i $name} and {i $version} from {i /path/to/$name.$version/} *) val of_dirname: OpamFilename.Dir.t -> t option (** Guess the package name from an archive file. This function extract {i $name} and {i $version} from {i /path/to/$name.$version+opam.tar.gz} *) val of_archive: OpamFilename.t -> t option (** Convert a set of pairs to a map [name -> versions] *) val to_map: Set.t -> Version.Set.t Name.Map.t (** The converse of [to_map] *) val of_map: Version.Set.t Name.Map.t -> Set.t (** Returns the keys in a package map as a package set *) val keys: 'a Map.t -> Set.t (** Extract the versions from a collection of packages *) val versions_of_packages: Set.t -> Version.Set.t (** Return the list of versions for a given package *) val versions_of_name: Set.t -> Name.t -> Version.Set.t (** Extract the naes from a collection of packages *) val names_of_packages: Set.t -> Name.Set.t (** Returns true if the set contains a package with the given name *) val has_name: Set.t -> Name.t -> bool (** Return all the packages with the given name *) val packages_of_name: Set.t -> Name.t -> Set.t val packages_of_name_map: 'a Map.t -> Name.t -> 'a Map.t (** Return a package with the given name *) val package_of_name: Set.t -> Name.t -> t (** Return a package with the given name, if any *) val package_of_name_opt: Set.t -> Name.t -> t option (** Return all the packages with one of the given names *) val packages_of_names: Set.t -> Name.Set.t -> Set.t (** Removes all packages with the given name from a set of packages *) val filter_name_out: Set.t -> Name.t -> Set.t (** Return the maximal available version of a package name from a set. Raises [Not_found] if no such package available. *) val max_version: Set.t -> Name.t -> t (** Compare two packages *) val compare: t -> t -> int (** Are two packages equal? *) val equal: t -> t -> bool (** Hash a package *) val hash: t -> int (** Return all the package descriptions in a given directory *) val list: OpamFilename.Dir.t -> Set.t (** Return all the package descriptions in the current directory (and their eventual prefixes). *) val prefixes: OpamFilename.Dir.t -> string option Map.t (** {2 Errors} *) (** Parallel executions. *) module Graph: OpamParallel.GRAPH with type V.t = t opam-2.1.5/src/format/opamTypesBase.mli0000644000175000017500000000607414427463453017064 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2018 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Helper functions on the base types (from [OpamTypes]) *) (** This module contains basic utility functions and stringifiers for the basic OPAM types present in OpamTypes.ml *) open OpamParserTypes.FullPos open OpamTypes include module type of struct include OpamCompat end val string_of_std_path: std_path -> string val std_path_of_string: string -> std_path val all_std_paths: std_path list (** Extract a package from a package action. *) val action_contents: [< 'a action ] -> 'a val map_atomic_action: ('a -> 'b) -> 'a atomic_action -> 'b atomic_action val map_highlevel_action: ('a -> 'b) -> 'a highlevel_action -> 'b highlevel_action val map_concrete_action: ('a -> 'b) -> 'a concrete_action -> 'b concrete_action val map_action: ('a -> 'b) -> 'a action -> 'b action (** Extract a packages from a package action. This returns all concerned packages, including the old version for an up/down-grade. *) val full_action_contents: 'a action -> 'a list (** Pretty-prints the cause of an action *) val string_of_cause: ('pkg -> string) -> 'pkg cause -> string (** Pretty-print *) val string_of_shell: shell -> string (** The empty file position *) val pos_null: pos val nullify_pos : 'a -> 'a with_pos (** [pos_best pos1 pos2] returns the most detailed position between [pos1] and [pos2] (defaulting to [pos1]) *) val pos_best: pos -> pos -> pos (** Position in the given file, with unspecified line and column *) val pos_file: filename -> pos (** Prints a file position *) val string_of_pos: pos -> string val string_of_user_action: user_action -> string (** Makes sure to keep only the last binding for a given variable; doesn't preserve order *) val env_array: env -> string array (** Parses the data suitable for a filter.FIdent from a string. May raise [Failure msg] on bad package names. A self-reference [_] parses to [None] *) val filter_ident_of_string: string -> name option list * variable * (string * string) option val string_of_filter_ident: name option list * variable * (string * string) option -> string val pkg_flag_of_string: string -> package_flag val string_of_pkg_flag: package_flag -> string val all_package_flags: package_flag list (** Map on a solver result *) val map_success: ('a -> 'b) -> ('a,'fail) result -> ('b,'fail) result val iter_success: ('a -> unit) -> ('a, 'b) result -> unit opam-2.1.5/src/format/opamFormatConfig.ml0000644000175000017500000000367514427463453017376 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2015-2016 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) module E = struct type OpamStd.Config.E.t += | ALLPARENS of bool option | SKIPVERSIONCHECKS of bool option | STRICT of bool option open OpamStd.Config.E let allparens = value (function ALLPARENS b -> b | _ -> None) let skipversionchecks = value (function SKIPVERSIONCHECKS b -> b | _ -> None) let strict = value (function STRICT b -> b | _ -> None) end type t = { strict: bool; skip_version_checks: bool; all_parens: bool; } type 'a options_fun = ?strict:bool -> ?skip_version_checks:bool -> ?all_parens:bool -> 'a let default = { strict = false; skip_version_checks = false; all_parens = false; } let setk k t ?strict ?skip_version_checks ?all_parens = let (+) x opt = match opt with Some x -> x | None -> x in k { strict = t.strict + strict; skip_version_checks = t.skip_version_checks + skip_version_checks; all_parens = t.all_parens + all_parens; } let set t = setk (fun x () -> x) t (* Global configuration reference *) let r = ref default let update ?noop:_ = setk (fun cfg () -> r := cfg) !r let initk k = setk (setk (fun c -> r := c; k)) !r ?strict:(E.strict ()) ?skip_version_checks:(E.skipversionchecks ()) ?all_parens:(E.allparens ()) let init ?noop:_ = initk (fun () -> ()) opam-2.1.5/src/format/opamSwitch.mli0000644000175000017500000000311414427463453016416 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2017 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** The type for switch names *) include OpamStd.ABSTRACT (** System switch name *) val unset: t (** Determines wether this switch is internal (bound to a prefix within the opam root) or living somewhere else, in which case its prefix dir is inferred from its name using [get_root] *) val is_external: t -> bool (** Returns the root directory of the switch with the given name, assuming the given opam root *) val get_root: OpamFilename.Dir.t -> t -> OpamFilename.Dir.t (** The relative dirname in which the opam switch prefix sits for external switches ("_opam") *) val external_dirname: string (** Returns an external switch handle from a directory name. Resolves to the destination if [external_dirname] at the given dir is a symlink to another [external_dirname]. *) val of_dirname: OpamFilename.Dir.t -> t opam-2.1.5/src/format/opamFile.mli0000644000175000017500000010152214427463453016036 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Handles all OPAM file formats as record types and submodules, conversion to and from syntax *) open OpamParserTypes.FullPos open OpamTypes (** Functions to read and write OPAM configuration files in a typed way *) (** Associate a type to a filename through a phantom type *) type 'a t = private filename type 'a typed_file = 'a t val make: filename -> 'a t val filename: 'a t -> filename val to_string: 'a t -> string val exists: 'a t -> bool (** All Configuration files satisfy this signature *) module type IO_FILE = sig (** File contents *) type t val format_version: OpamVersion.t (** Empty file *) val empty: t (** Write some contents to a file *) val write: t typed_file -> t -> unit (** Read file contents. Raise an error if the file does not exist. *) val read: t typed_file -> t (** Returns [None] on non-existing file *) val read_opt: t typed_file -> t option (** Read file contents. Return [empty] if the file does not exist. *) val safe_read: t typed_file -> t val read_from_channel: ?filename:t typed_file -> in_channel -> t val read_from_string: ?filename:t typed_file -> string -> t val write_to_channel: ?filename:t typed_file -> out_channel -> t -> unit val write_to_string: ?filename:t typed_file -> t -> string end (* Error less [IO_FILE] read functions. *) module type BestEffortRead = sig type t val read: t typed_file -> t val read_opt: t typed_file -> t option val safe_read: t typed_file -> t val read_from_channel: ?filename:t typed_file -> in_channel -> t val read_from_string: ?filename:t typed_file -> string -> t end (** Lines of space-separated words. *) module Lines: IO_FILE with type t = string list list (** Command wrappers for package scripts *) module Wrappers: sig type t = { pre_build : command list; wrap_build : command list; post_build : command list; pre_install : command list; wrap_install : command list; post_install : command list; pre_remove : command list; wrap_remove : command list; post_remove : command list; pre_session : command list; post_session : command list; } val pre_build: t -> command list val wrap_build: t -> command list val post_build: t -> command list val pre_install: t -> command list val wrap_install: t -> command list val post_install: t -> command list val pre_remove: t -> command list val wrap_remove: t -> command list val post_remove: t -> command list val pre_session: t -> command list val post_session: t -> command list val with_pre_build: command list -> t -> t val with_wrap_build: command list -> t -> t val with_post_build: command list -> t -> t val with_pre_install: command list -> t -> t val with_wrap_install: command list -> t -> t val with_post_install: command list -> t -> t val with_pre_remove: command list -> t -> t val with_wrap_remove: command list -> t -> t val with_post_remove: command list -> t -> t val with_pre_session: command list -> t -> t val with_post_session: command list -> t -> t val empty : t val add: outer:t -> inner:t -> t end (** Configuration file: [$opam/config] *) module Config: sig include IO_FILE (** Current root version *) val root_version: opam_version (** OCaml switch updates *) val with_switch: switch -> t -> t val with_switch_opt: switch option -> t -> t val with_installed_switches: switch list -> t -> t (** Repository updates *) val with_repositories: repository_name list -> t -> t (** Update opam-version *) val with_opam_version: OpamVersion.t -> t -> t val with_opam_root_version: OpamVersion.t -> t -> t val with_criteria: (solver_criteria * string) list -> t -> t val with_best_effort_prefix: string -> t -> t val with_best_effort_prefix_opt: string option-> t -> t val with_solver: arg list -> t -> t val with_solver_opt: arg list option -> t -> t val with_jobs: int -> t -> t val with_jobs_opt: int option -> t -> t val with_dl_tool: arg list -> t -> t val with_dl_tool_opt: arg list option -> t -> t val with_dl_jobs: int -> t -> t val with_dl_cache: url list -> t -> t val with_wrappers: Wrappers.t -> t -> t val with_global_variables: (variable * variable_contents * string) list -> t -> t val with_eval_variables: (variable * string list * string) list -> t -> t val with_validation_hook_opt: arg list option -> t -> t val with_default_compiler: formula -> t -> t val with_default_invariant: formula -> t -> t val with_depext: bool -> t -> t val with_depext_run_installs: bool -> t -> t val with_depext_cannot_install: bool -> t -> t val with_depext_bypass: OpamSysPkg.Set.t -> t -> t (** Return the opam version *) val opam_version: t -> opam_version (** Return the opam root version, if not defined returns the default version value [2.1~~previous] *) val opam_root_version: t -> opam_version (** Return the opam root version if defined *) val opam_root_version_opt: t -> opam_version option (** Return the list of repository *) val repositories: t -> repository_name list (** Return the OCaml switch *) val switch: t -> switch option val installed_switches: t -> switch list (** Return the number of jobs defined *) val jobs: t -> int option val dl_tool: t -> arg list option (** Return the number of download jobs *) val dl_jobs: t -> int val dl_cache: t -> url list val criteria: t -> (solver_criteria * string) list val best_effort_prefix: t -> string option val solver: t -> arg list option val wrappers: t -> Wrappers.t (** variable, value, docstring *) val global_variables: t -> (variable * variable_contents * string) list (** variable, command, docstring *) val eval_variables: t -> (variable * string list * string) list val validation_hook: t -> arg list option val default_compiler: t -> formula val default_invariant: t -> formula val depext: t -> bool val depext_run_installs: t -> bool val depext_cannot_install: t -> bool val depext_bypass: t -> OpamSysPkg.Set.t val fields: (string * (t, value) OpamPp.field_parser) list (** All file fields as print-AST, Fields within sections are accessed through dot-separated paths *) val to_list: ?filename:'a typed_file -> t -> (string * value) list module BestEffort: BestEffortRead with type t := t (** Raw read the config file to extract [opam-root-version] field value. *) val raw_root_version: 'a typed_file -> OpamVersion.t option end (** Init config file [/etc/opamrc] *) module InitConfig: sig include IO_FILE val opam_version: t -> opam_version val repositories: t -> (repository_name * (url * trust_anchors option)) list val default_compiler: t -> formula val default_invariant: t -> formula val jobs: t -> int option val dl_tool: t -> arg list option val dl_jobs: t -> int option val dl_cache: t -> url list val solver_criteria: t -> (solver_criteria * string) list val solver: t -> arg list option val wrappers: t -> Wrappers.t val global_variables: t -> (variable * variable_contents * string) list val eval_variables: t -> (variable * string list * string) list val recommended_tools: t -> (string list * string option * filter option) list val required_tools: t -> (string list * string option * filter option) list val init_scripts: t -> ((string * string) * filter option) list val with_opam_version: opam_version -> t -> t val with_repositories: (repository_name * (url * trust_anchors option)) list -> t -> t val with_default_compiler: formula -> t -> t val with_default_invariant: formula -> t -> t val with_jobs: int option -> t -> t val with_dl_tool: arg list option -> t -> t val with_dl_jobs: int option -> t -> t val with_dl_cache: url list -> t -> t val with_solver_criteria: (solver_criteria * string) list -> t -> t val with_solver: arg list option -> t -> t val with_wrappers: Wrappers.t -> t -> t val with_global_variables: (variable * variable_contents * string) list -> t -> t val with_eval_variables: (variable * string list * string) list -> t -> t val with_recommended_tools: (string list * string option * filter option) list -> t -> t val with_required_tools: (string list * string option * filter option) list -> t -> t val with_init_scripts: ((string * string) * filter option) list -> t -> t (** [add t1 t2] is [t2], with the field values falling back to those of [t1] when not set in [t2] *) val add: t -> t -> t end (** Package descriptions: [$opam/descr/] *) module Descr: sig include IO_FILE val create: string -> t (** Create an abstract description file from a string *) val of_string: t typed_file -> string -> t (** Return the first line *) val synopsis: t -> string (** Return the body *) val body: t -> string (** Return the full description *) val full: t -> string end (** {2 Urls for OPAM repositories} *) module URL: sig include IO_FILE val create: ?mirrors:url list -> ?checksum:OpamHash.t list -> ?subpath:string -> url -> t (** URL address *) val url: t -> url val mirrors: t -> url list (** Archive checksum *) val checksum: t -> OpamHash.t list (** Constructor *) val with_url: url -> t -> t val with_checksum: OpamHash.t list -> t -> t val with_subpath: string -> t -> t val with_subpath_opt: string option -> t -> t val subpath: t -> string option end (** OPAM files *) module OPAM: sig type t = private { opam_version: opam_version; (* Package ident *) name : name option; version : version option; (* Relationships; solver and availability info *) depends : filtered_formula; depopts : filtered_formula; conflicts : filtered_formula; conflict_class : name list; available : filter; flags : package_flag list; env : env_update list; (* Build instructions *) build : command list; run_test : command list; install : command list; remove : command list; (* Auxiliary data affecting the build *) substs : basename list; patches : (basename * filter option) list; build_env : env_update list; features : (OpamVariable.t * filtered_formula * string) list; extra_sources: (basename * URL.t) list; (* User-facing data used by opam *) messages : (string * filter option) list; post_messages: (string * filter option) list; depexts : (OpamSysPkg.Set.t * filter) list; libraries : (string * filter option) list; syntax : (string * filter option) list; dev_repo : url option; pin_depends: (package * url) list; (* Package database details *) maintainer : string list; author : string list; license : string list; tags : string list; homepage : string list; doc : string list; bug_reports: string list; (* Extension fields (x-foo: "bar") *) extensions : value OpamStd.String.Map.t; (* Extra sections *) url : URL.t option; descr : Descr.t option; (* Related metadata directory (not an actual field of the file) This can be used to locate e.g. the files/ overlays. If the repository is specified, the string is a relative path from its root. It should otherwise be an absolute path. *) metadata_dir: (repository_name option * string) option; (* Names and hashes of the files below files/ *) extra_files: (OpamFilename.Base.t * OpamHash.t) list option; format_errors: (string * OpamPp.bad_format) list; (* Deprecated, for compat and proper linting *) ocaml_version: (OpamFormula.relop * string) OpamFormula.formula option; os : (bool * string) generic_formula; deprecated_build_test : command list; deprecated_build_doc : command list; } include IO_FILE with type t := t val empty: t (** Create an opam file *) val create: package -> t (** Returns the opam value (including url, descr) with all non-effective (i.e. user-directed information that doesn't change opam's view on the package) fields set to their empty values. Useful for comparisons. *) val effective_part: t -> t (** Returns true if the effective parts of the two package definitions are equal *) val effectively_equal: t -> t -> bool (** Compares two package definitions, ignoring the virtual fields bound to file location ([metadata_dir]...) *) val equal: t -> t -> bool (** Prints the format errors that were found when the file was read *) val print_errors: ?file:t typed_file -> t -> unit (** Get OPAM version. *) val opam_version: t -> opam_version (** Package name *) val name: t -> name val name_opt: t -> name option (** Package version *) val version: t -> version val version_opt: t -> version option (** The informations in both the name and version fields, as a package *) val package: t -> package (** Availability formula (OS + compiler constraints) *) val available: t -> filter (** Package maintainer(s) *) val maintainer: t -> string list (** File substitutions *) val substs: t -> basename list (** List of environment variables to set-up for the build *) val build_env: t -> env_update list (** List of command to run for building the package *) val build: t -> command list (** List of command to run for installing the package *) val install: t -> command list (** List of command to run for removing the package *) val remove: t -> command list (** Package dependencies *) val depends: t -> filtered_formula (** Optional dependencies *) val depopts: t -> filtered_formula (** External dependencies *) val depexts: t -> (OpamSysPkg.Set.t * filter) list val extra_sources: t -> (basename * URL.t) list (** All extended "x-" fields as a map *) val extensions: t -> value OpamStd.String.Map.t (** Parse a single extended field (reports proper file position) *) val extended: t -> string -> (value -> 'a) -> 'a option val with_messages: (string * filter option) list -> t -> t val with_post_messages: (string * filter option) list -> t -> t (** Package conflicts *) val conflicts: t -> filtered_formula val conflict_class: t -> name list (** Contents of the 'features' field *) val features: t -> (OpamVariable.t * filtered_formula * string) list (** List of exported libraries *) val libraries: t -> (string * filter option) list (** List of exported syntax extensions *) val syntax: t -> (string * filter option) list (** Patches *) val patches: t -> (basename * filter option) list (** Homepage(s) *) val homepage: t -> string list (** Author(s) *) val author: t -> string list (** License(s) *) val license: t -> string list (** API documentation *) val doc: t -> string list (** Classification tags *) val tags: t -> string list (** Commands to build and run the tests *) val run_test: t -> command list (** Commands to build the documentation *) val deprecated_build_doc: t -> command list (** Commands to build the tests *) val deprecated_build_test: t -> command list (** Messages to display before taking action *) val messages: t -> (string * filter option) list (** Messages to display at end of install *) val post_messages: t -> (string * filter option) list (** Where to post bug reports. *) val bug_reports: t -> string list (** The package flags that are present for this package. *) val flags: t -> package_flag list (** Check the package for the given flag. Allows flags specified through tags for compatibility *) val has_flag: package_flag -> t -> bool (** The environment variables that this package exports *) val env: t -> env_update list val descr: t -> Descr.t option val synopsis: t -> string option val descr_body: t -> string option val url: t -> URL.t option val get_url: t -> url option (** Related metadata directory (either repository name + relative path, or absolute path; not an actual field of the file, linked to the file location). This can be used to locate e.g. the files/ overlays *) val metadata_dir: t -> (repository_name option * string) option (** Gets the resolved metadata dir, given a mapping of repository names to their roots *) val get_metadata_dir: repos_roots:(repository_name -> dirname) -> t -> dirname option (** Names and hashes of the files below files/ *) val extra_files: t -> (OpamFilename.Base.t * OpamHash.t) list option (** Looks up the extra files, and returns their full paths, relative path to the package source, and hash. Doesn't check the hashes. *) val get_extra_files: repos_roots:(repository_name -> dirname) -> t -> (filename * basename * OpamHash.t) list (** Returns the errors that were found when parsing the file, associated to their fields (that were consequently ignored) *) val format_errors: t -> (string * OpamPp.bad_format) list (** Sets the opam version *) val with_opam_version: opam_version -> t -> t (** The package source repository address *) val dev_repo: t -> url option val pin_depends: t -> (package * url) list (** construct as [name] *) val with_name: name -> t -> t val with_name_opt: name option -> t -> t (** construct as [version] *) val with_version: version -> t -> t val with_version_opt: version option -> t -> t (** Construct as [depends] *) val with_depends: filtered_formula -> t -> t (** Construct as [depopts] *) val with_depopts: filtered_formula -> t -> t val with_conflicts: filtered_formula -> t -> t val with_conflict_class: name list -> t -> t val with_features: (OpamVariable.t * filtered_formula * string) list -> t -> t (** Construct as [build] *) val with_build: command list -> t -> t val with_run_test: command list -> t -> t val with_install: command list -> t -> t (** Construct as [remove] *) val with_remove: command list -> t -> t (** Construct as [libraries] *) val with_libraries: (string * filter option) list -> t -> t (** Replace the [syntax] field of the given OPAM file. *) val with_syntax: (string * filter option) list -> t -> t (** Construct as [substs] *) val with_substs: basename list -> t -> t val with_build_env: env_update list -> t -> t val with_available: filter -> t -> t (** Construct as [maintainer] *) val with_maintainer: string list -> t -> t val with_author: string list -> t -> t val with_homepage: string list -> t -> t val with_license: string list -> t -> t (** Construct as [patches] *) val with_patches: (basename * filter option) list -> t -> t (** Construct using [bug_reports] *) val with_bug_reports: string list -> t -> t (** Construct using [depexts] *) val with_depexts: (OpamSysPkg.Set.t * filter) list -> t -> t val with_flags: package_flag list -> t -> t val add_flags: package_flag list -> t -> t val with_tags: string list -> t -> t val with_env: env_update list -> t -> t val with_dev_repo: url -> t -> t val with_dev_repo_opt: url option -> t -> t val with_pin_depends: (package * url) list -> t -> t val with_extra_sources: (basename * URL.t) list -> t -> t val with_extensions: value OpamStd.String.Map.t -> t -> t val add_extension: t -> string -> value -> t val remove_extension: t -> string -> t val with_deprecated_build_doc: command list -> t -> t val with_deprecated_build_test: command list -> t -> t val with_descr: Descr.t -> t -> t val with_descr_opt: Descr.t option -> t -> t val with_synopsis: string -> t -> t (** If [synopsis] is not already set, split the string and use the first line as synopsis. *) val with_descr_body: string -> t -> t val with_url: URL.t -> t -> t val with_url_opt: URL.t option -> t -> t val with_metadata_dir: (repository_name option * string) option -> t -> t val with_extra_files: (OpamFilename.Base.t * OpamHash.t) list -> t -> t val with_extra_files_opt: (OpamFilename.Base.t * OpamHash.t) list option -> t -> t val with_format_errors: (string * OpamPp.bad_format) list -> t -> t (** Prints to a string, while keeping the format of the original file as much as possible. The original format is read from the given [format_from_string], the file [format_from], or the output file if it exists *) val to_string_with_preserved_format: ?format_from:(t typed_file) -> ?format_from_string:string -> t typed_file -> t -> string (** Writes an opam file, but preserving the existing formatting as much as possible. The original format is read from the given [format_from_string], the file [format_from], or the output file if it exists *) val write_with_preserved_format: ?format_from:(t typed_file) -> ?format_from_string:string -> t typed_file -> t -> unit (** Low-level values used for linting and similar processing *) (** Allow 'flag:xxx' tags as flags, for compat *) val flag_of_tag: string -> package_flag option val fields: (t, value) OpamFormat.I.fields_def val sections: (t, (string option * opamfile_item list) list) OpamFormat.I.fields_def (** Doesn't handle package name encoded in directory name *) val pp_raw_fields: (opamfile_item list, t) OpamPp.t (** Returns the raw print-AST contents of the file *) val contents: ?filename:'a typed_file -> t -> opamfile (** Returns all fields of the file as print-AST. Fields within sections are accessed through dot-separated paths (e.g. [url.checksum]) *) val to_list: ?filename:'a typed_file -> t -> (string * value) list (** Gets the print-AST for a single field in the file structure. Fields within sections can be accessed through [section.field]. *) val print_field_as_syntax: string -> t -> value option end (** Compiler aliases: [$opam/aliases]. Deprecated, used only for migration *) module Aliases: IO_FILE with type t = string switch_map (** Switch state file as table, also used for import/export. This includes compiler and root packages information, as well as pinned packages and their target (but not their local metadata). *) module LegacyState: sig type t = switch_selections include IO_FILE with type t := t end (** A newer format for switch state, using the opam file syntax rather than a table. This is more readable and extensible. *) module SwitchSelections: sig type t = switch_selections include IO_FILE with type t := t module BestEffort: BestEffortRead with type t := t end (** An extended version of SwitchSelections that can include full opam files as [package "name" {}] sections, for storing overlays *) module SwitchExport: sig type t = { selections: switch_selections; extra_files: string OpamHash.Map.t; overlays: OPAM.t OpamPackage.Name.Map.t; } include IO_FILE with type t := t end (** A simple list of packages and versions: (used for the older [$opam/$switch/{installed,installed_roots}], still needed to migrate from 1.2 repository, and for reinstall) *) module PkgList: IO_FILE with type t = package_set (** Cached environment updates (/environment) *) module Environment: IO_FILE with type t = env_update list (** Compiler version [$opam/compilers/]. Deprecated, only used to upgrade old data *) module Comp: sig include IO_FILE type compiler = string type compiler_version = string (** Create a pre-installed compiler description file *) val create_preinstalled: compiler -> compiler_version -> name list -> env_update list -> t (** Is it a pre-installed compiler description file *) val preinstalled: t -> bool (** Get OPAM version *) val opam_version: t -> opam_version (** Return the compiler name *) val name: t -> compiler (** Return the compiler version *) val version: t -> compiler_version (** Return the url of the compiler *) val src: t -> url option (** Return the list of patches to apply *) val patches: t -> url list (** Options to give to the "./configure" command *) val configure: t -> string list (** Options to give to the "make" command *) val make: t -> string list (** Options to give to build the package. If this one is provided, nothing should be specified for [configure] and [make]. *) val build: t -> command list (** Packages to install immediately after the creation of OCaml *) val packages: t -> formula (** Environment variable to set-up before running commands in the subtree *) val env: t -> env_update list val tags: t -> string list val with_src: url option -> t -> t val with_patches: url list -> t -> t val with_configure: string list -> t -> t val with_make: string list -> t -> t val with_build: command list -> t -> t val with_packages: formula -> t -> t (** Converts a compiler definition to package metadata. For compat. If [package] is unspecified, a package named "ocaml" is created for "standard" compilers (when the compiler name doesn't contain a "+" and is equal to the compiler version); otherwise, a package "ocaml-VARIANT" is created with "VARIANT" the part of the compiler name on the right of the "+". In both case, the version corresponds to the OCaml version and is [version comp]. *) val to_package: ?package:package -> t -> Descr.t option -> OPAM.t end (** {2 Configuration files} *) (** .install files *) module Dot_install: sig include IO_FILE (** List of files to install in $bin/ *) val bin: t -> (basename optional * basename option) list (** List of files to install in $sbin/ *) val sbin: t -> (basename optional * basename option) list (** List of files to install in $lib/ *) val lib: t -> (basename optional * basename option) list (** List of toplevel files *) val toplevel: t -> (basename optional * basename option) list (** C bindings *) val stublibs: t -> (basename optional * basename option) list (** List of architecture-independent files *) val share: t -> (basename optional * basename option) list (** List of files under the more general share prefix *) val share_root: t -> (basename optional * basename option) list (** List of etc files *) val etc: t -> (basename optional * basename option) list (** List of doc files *) val doc: t -> (basename optional * basename option) list (** Man pages *) val man: t -> (basename optional * basename option) list (** Executable files under lib/ *) val libexec: t -> (basename optional * basename option) list (** Not relative to the package's lib dir *) val lib_root: t -> (basename optional * basename option) list (** Not relative to the package's lib dir, and with +x set *) val libexec_root: t -> (basename optional * basename option) list (** List of other files to install *) val misc: t -> (basename optional * filename) list end (** .changes files, bound to the OpamDirTrack module *) module Changes: sig type t = OpamDirTrack.t include IO_FILE with type t := t end (** .config files *) module Dot_config: sig include IO_FILE (** Create a new .config file (containing only variables) *) val create: (variable * variable_contents) list -> t (** Dependency towards file-system paths and their hashes *) val file_depends: t -> (filename * OpamHash.t) list val with_file_depends: (filename * OpamHash.t) list -> t -> t (** Sets all bindings in the file *) val with_vars: (variable * variable_contents) list -> t -> t (** Top-level variables *) val variable: t -> variable -> variable_contents option (** The list of top-level variables *) val variables: t -> variable list (** Lists all the variable bindings in the file *) val bindings: t -> (variable * variable_contents) list (** Sets the given variable, overriding any previous definition. With [None], unsets the variable*) val set: variable -> variable_contents option -> t -> t end (** {2 Repository files} *) (** Association between package names and repositories *) module Package_index: IO_FILE with type t = (repository_name * string option) package_map (** Repository config: [$opam/repo/$repo/config]. Deprecated, for migration only *) module Repo_config_legacy : sig type t = { repo_name : repository_name; repo_root : dirname; repo_url : url; repo_priority : int; } include IO_FILE with type t := t end module Repos_config: sig type t = (url * trust_anchors option) option OpamRepositoryName.Map.t include IO_FILE with type t := t module BestEffort: BestEffortRead with type t := t end module Switch_config: sig type t = { opam_version: OpamVersion.t; synopsis: string; repos: repository_name list option; paths: (std_path * string) list; variables: (variable * variable_contents) list; opam_root: dirname option; wrappers: Wrappers.t; env: env_update list; invariant: OpamFormula.t option; depext_bypass: OpamSysPkg.Set.t; } val file_format_version: OpamVersion.t val variable: t -> variable -> variable_contents option val path: t -> std_path -> string option val wrappers: t -> Wrappers.t val sections: (string * (t, (string option * opamfile_item list) list) OpamPp.field_parser) list val fields: (string * (t, value) OpamPp.field_parser) list val to_list: ?filename:'a typed_file -> t -> (string * value) list include IO_FILE with type t := t val oldest_compatible_format_version: OpamVersion.t module BestEffort: BestEffortRead with type t := t end (** Pinned package files (only used for migration from 1.2, the inclusive State module is now used instead) *) module Pinned_legacy: sig type pin_option = | Version of version | Source of url include IO_FILE with type t = pin_option name_map end (** Repository metadata *) module Repo: sig include IO_FILE val create: ?browse:string -> ?upstream:string -> ?opam_version:OpamVersion.t -> ?redirect:(string * filter option) list -> ?root_url:url -> ?dl_cache:string list -> ?announce:(string * filter option) list -> ?stamp:string -> unit -> t (** The minimum OPAM version required for this repository, if defined *) val opam_version : t -> OpamVersion.t option (** Base URL for browsing packages on the WWW *) val browse: t -> string option (** Base URL for browsing OPAM repository source on the WWW *) val upstream: t -> string option (** The root URL of the repository (not an actual file field, determined at runtime by opam) *) val root_url: t -> url option (** Redirections. *) val redirect: t -> (string * filter option) list (** Cache URLs, either full or relative to the repo root *) val dl_cache: t -> string list val announce: t -> (string * filter option) list val stamp: t -> string option val with_opam_version : OpamVersion.t -> t -> t val with_browse: string -> t -> t val with_upstream: string -> t -> t val with_redirect: (string * filter option) list -> t -> t val with_root_url: url -> t -> t val with_dl_cache: string list -> t -> t val with_announce: (string * filter option) list -> t -> t val with_stamp: string -> t -> t val with_stamp_opt: string option -> t -> t end (** {2 urls.txt file *} *) module File_attributes: IO_FILE with type t = file_attribute_set module Stats: sig (** Display statistics about file access. *) val print: unit -> unit end (** Helper module for manipulation of the raw syntax ([opamfile]) format. (the specific file handling modules are derived from this one) *) module Syntax : sig val pp_channel: 'a typed_file -> in_channel -> out_channel -> (unit, opamfile) OpamPp.t val of_channel: 'a typed_file -> in_channel -> opamfile val to_channel: 'a typed_file -> out_channel -> opamfile -> unit val of_string: 'a typed_file -> string -> opamfile val to_string: 'a typed_file -> opamfile -> string val to_string_with_preserved_format: 'a typed_file -> ?format_from:'a typed_file -> ?format_from_string:string -> empty:'a -> ?sections:('a, (string option * opamfile_item list) list) OpamFormat.I.fields_def -> fields:('a, value) OpamFormat.I.fields_def -> (opamfile, filename * 'a) OpamPp.t -> 'a -> string end (**/**) module type SyntaxFileArg = sig val internal: string val format_version: OpamVersion.t type t val empty: t val pp: (opamfile, filename * t) OpamPp.t end module SyntaxFile(X: SyntaxFileArg) : IO_FILE with type t := X.t module type LineFileArg = sig val internal: string type t val empty: t val pp: (string list list, t) OpamPp.t end module LineFile (X: LineFileArg) : IO_FILE with type t := X.t opam-2.1.5/src/format/opamSysPkg.ml0000644000175000017500000000337014427463453016230 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (* basic ops *) type t = string let of_string s = s let to_string s = s let compare = OpamStd.String.compare_case let to_json s = `O [ ("sys_package", `String s) ] let of_json = function | `O dict -> (match List.assoc "sys_package" dict with | `String s -> Some (of_string s) | _ -> None | exception Not_found -> None) | _ -> None module O = struct type tmp = t type t = tmp let compare = compare let to_string = to_string let to_json = to_json let of_json = of_json end module Set = OpamStd.Set.Make(O) module Map = OpamStd.Map.Make(O) let raw_set set = OpamStd.String.Set.fold (fun spkg set-> Set.add (of_string spkg) set) set Set.empty type status = { s_available : Set.t; (** Package available but not installed *) s_not_found : Set.t; (** Package unavailable on this system *) } let status_empty = { s_available = Set.empty; s_not_found = Set.empty; } let string_of_status sp = Printf.sprintf "available: %s; not_found: %s" (Set.to_string sp.s_available) (Set.to_string sp.s_not_found) opam-2.1.5/src/format/opamPath.ml0000644000175000017500000001700514427463453015704 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamFilename.Op type t = dirname (* Returns a generic file, coerced by the .mli *) let ( /- ) dir f = OpamFile.make (dir // f) let config t = t /- "config" let init_config_files () = List.map OpamFile.make [ OpamFilename.Dir.of_string (OpamStd.Sys.etc ()) // "opamrc"; OpamFilename.Dir.of_string (OpamStd.Sys.home ()) // ".opamrc"; ] let state_cache_dir t = t / "repo" let state_cache t = state_cache_dir t // Printf.sprintf "state-%s.cache" (OpamVersion.magic ()) let lock t = t // "lock" let config_lock t = t // "config.lock" (* let archives_dir t = t / "archives" let archive t nv = archives_dir t // (OpamPackage.to_string nv ^ "+opam.tar.gz") *) let repos_lock t = t / "repo" // "lock" let repos_config t = t / "repo" /- "repos-config" let init t = t / "opam-init" let hooks_dir t = init t / "hooks" let log t = t / "log" let backup_file = let file = lazy Unix.( let tm = gmtime (Unix.gettimeofday ()) in Printf.sprintf "state-%04d%02d%02d%02d%02d%02d.export" (tm.tm_year+1900) (tm.tm_mon+1) tm.tm_mday tm.tm_hour tm.tm_min tm.tm_sec ) in fun () -> Lazy.force file let backup_dir t = t / "backup" let backup t = backup_dir t /- backup_file () let plugin_prefix = "opam-" let plugins t = t / "plugins" let plugins_bin t = plugins t / "bin" let plugin_bin t name = let sname = OpamPackage.Name.to_string name ^ OpamStd.Sys.executable_name "" in let basename = if OpamStd.String.starts_with ~prefix:plugin_prefix sname then sname else plugin_prefix ^ sname in plugins_bin t // basename let plugin t name = let sname = OpamPackage.Name.to_string name in assert (sname <> "bin"); plugins t / sname module type LAYOUT = sig type ctx val root : dirname -> ctx -> dirname val lib_dir : dirname -> ctx -> dirname end module Switch = struct let root t a = OpamSwitch.get_root t a (** Internal files and dirs with static location *) let meta_dirname = ".opam-switch" let meta t a = root t a / meta_dirname let lock t a = meta t a // "lock" let backup_dir t a = meta t a / "backup" let backup t a = backup_dir t a /- backup_file () let selections t a = meta t a /- "switch-state" let build_dir t a = meta t a / "build" let build t a nv = build_dir t a / OpamPackage.to_string nv let remove_dir t a = meta t a / "remove" let remove t a nv = remove_dir t a / OpamPackage.to_string nv let install_dir t a = meta t a / "install" let install t a n = install_dir t a /- (OpamPackage.Name.to_string n ^ ".install") let changes t a n = install_dir t a /- (OpamPackage.Name.to_string n ^ ".changes") let reinstall t a = meta t a /- "reinstall" let switch_config t a = meta t a /- "switch-config" let config_dir t a = meta t a / "config" let config t a n = config_dir t a /- (OpamPackage.Name.to_string n ^ ".config") let sources_dir t a = meta t a / "sources" let extra_files_dir t a = meta t a / "extra-files-cache" let extra_file t a h = extra_files_dir t a // OpamHash.contents h let sources t a nv = sources_dir t a / OpamPackage.to_string nv let pinned_package t a name = sources_dir t a / OpamPackage.Name.to_string name let env_filename = "environment" let environment t a = meta t a /- env_filename let env_relative_to_prefix pfx = pfx / meta_dirname /- env_filename let installed_opams t a = meta t a / "packages" let installed_opams_cache t a = meta t a / "packages" // "cache" let installed_package_dir t a nv = installed_opams t a / OpamPackage.to_string nv let installed_opam t a nv = installed_package_dir t a nv /- "opam" let installed_opam_files_dir t a nv = installed_package_dir t a nv / "files" module DefaultF(L:LAYOUT) = struct let lib_dir = L.lib_dir let lib t a n = L.lib_dir t a / OpamPackage.Name.to_string n let stublibs t a = L.lib_dir t a / "stublibs" let toplevel t a = L.lib_dir t a / "toplevel" let doc_dir t a = L.root t a / "doc" let man_dir ?num t a = match num with | None -> L.root t a / "man" | Some n -> L.root t a / "man" / ("man" ^ n) let share_dir t a = L.root t a / "share" let share t a n = share_dir t a / OpamPackage.Name.to_string n let etc_dir t a = L.root t a / "etc" let etc t a n = etc_dir t a / OpamPackage.Name.to_string n let doc t a n = doc_dir t a / OpamPackage.Name.to_string n let bin t a = L.root t a / "bin" let sbin t a = L.root t a / "sbin" end (** Visible files that can be redirected using [config/global-config.config] *) module Default = struct include DefaultF(struct type ctx = switch let root = root let lib_dir t a = root t a / "lib" end) end let lookup stdpath relative_to default config = let dir = OpamStd.Option.default default (OpamFile.Switch_config.path config stdpath) in if Filename.is_relative dir then if dir = "" then relative_to else relative_to / dir else OpamFilename.Dir.of_string dir let prefix t a c = lookup Prefix (root t a) "" c let lib_dir t a c = lookup Lib (prefix t a c) "lib" c let lib t a c n = lib_dir t a c / OpamPackage.Name.to_string n let stublibs t a c = lookup Stublibs (lib_dir t a c) "stublibs" c let toplevel t a c = lookup Toplevel (lib_dir t a c) "toplevel" c let doc_dir t a c = lookup Doc (prefix t a c) "doc" c let doc t a c n = doc_dir t a c / OpamPackage.Name.to_string n let man_dir ?num t a c = let base = lookup Man (prefix t a c) "man" c in match num with | None -> base | Some n -> base / ("man" ^ n) let share_dir t a c = lookup Share (prefix t a c) "share" c let share t a c n = share_dir t a c / OpamPackage.Name.to_string n let etc_dir t a c = lookup Etc (prefix t a c) "etc" c let etc t a c n = etc_dir t a c / OpamPackage.Name.to_string n let bin t a c = lookup Bin (prefix t a c) "bin" c let sbin t a c = lookup Sbin (prefix t a c) "sbin" c let get_stdpath t a c = function | Prefix -> prefix t a c | Lib -> lib_dir t a c | Bin -> bin t a c | Sbin -> sbin t a c | Share -> share_dir t a c | Doc -> doc_dir t a c | Etc -> etc_dir t a c | Man -> man_dir t a c | Toplevel -> toplevel t a c | Stublibs -> stublibs t a c module Overlay = struct let dir t a = meta t a / "overlay" let package t a n = dir t a / OpamPackage.Name.to_string n let opam t a n = package t a n /- "opam" let tmp_opam t a n = package t a n /- "opam_" let url t a n = package t a n /- "url" let descr t a n = package t a n /- "descr" let files t a n = package t a n / "files" end end module Builddir = struct let install builddir nv = builddir /- (OpamPackage.Name.to_string nv.name ^ ".install") let config builddir nv = builddir /- (OpamPackage.Name.to_string nv.name ^ ".config") end opam-2.1.5/src/format/opamInterpLexer.mli0000644000175000017500000000225214427463453017420 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2016 MetaStack Solutions Ltd. *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** OPAM format variable interpolation processor *) val main: (string -> unit) -> (string -> unit) -> Lexing.lexbuf -> unit (** [main unquoted quoted lexbuf] fully processes the given lexbuf. Strings are applied to [unquoted] until a ["] or ["""] sequence is encountered when the content within the single or triple-quoted string is applied to [quoted] (note that the quote marks themselves are passed to [unquoted]). Within either string type, backslash is the escape character. *) opam-2.1.5/src/format/opamPackage.ml0000644000175000017500000002106614427463453016345 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCompat open OpamStd.Op let log fmt = OpamConsole.log "PACKAGE" fmt let slog = OpamConsole.slog module Version = struct type version = string type t = version let to_string x = x let of_string x = if String.length x = 0 then failwith "Package version can't be empty"; String.iter (function | 'a'..'z' | 'A'..'Z' | '0'..'9' | '-' | '_' | '+' | '.' | '~' -> () | c -> failwith (Printf.sprintf "Invalid character '%c' in package version %S" c x)) x; x let compare = OpamVersionCompare.compare let equal v1 v2 = compare v1 v2 = 0 let to_json x = `String (to_string x) let of_json = function | `String x -> (try Some (of_string x) with _ -> None) | _ -> None module O = struct type t = version let to_string = to_string let compare = compare let to_json = to_json let of_json = of_json end module Set = OpamStd.Set.Make(O) module Map = OpamStd.Map.Make(O) end module Name = struct type t = string let to_string x = x let of_string x = match OpamStd.String.fold_left (fun acc c -> if acc = Some false then acc else match c with | 'a'..'z' | 'A'..'Z' -> Some true | '0'..'9' | '-' | '_' | '+' -> acc | _ -> Some false) None x with | Some false -> failwith (Printf.sprintf "Invalid character in package name %S" x) | None -> failwith (Printf.sprintf "Package name %S should contain at least one letter" x) | Some true -> x let compare = OpamStd.String.compare_case let equal n1 n2 = compare n1 n2 = 0 let to_json x = `String x let of_json = function | `String s -> (try Some (of_string s) with _ -> None) | _ -> None module O = struct type t = string let to_string = to_string let compare = compare let to_json = to_json let of_json = of_json end module Set = OpamStd.Set.Make(O) module Map = OpamStd.Map.Make(O) end type t = { name : Name.t; version: Version.t; } let create name version = { name; version } let name_to_string t = Name.to_string t.name let version_to_string t = Version.to_string t.version let name t = t.name let version t = t.version let sep = '.' let of_string_opt s = if OpamStd.String.contains_char s ' ' || OpamStd.String.contains_char s '\n' then None else match OpamStd.String.cut_at s sep with | None -> None | Some (n, v) -> try Some { name = Name.of_string n; version = Version.of_string v } with Failure _ -> None let of_string s = match of_string_opt s with | Some x -> x | None -> failwith "OpamPackage.of_string" let to_string t = match Version.to_string t.version with | "" -> Name.to_string t.name | _ -> Printf.sprintf "%s%c%s" (Name.to_string t.name) sep (Version.to_string t.version) let compare nv1 nv2 = match Name.compare nv1.name nv2.name with | 0 -> Version.compare nv1.version nv2.version | i -> i let hash nv = Hashtbl.hash nv let equal nv1 nv2 = compare nv1 nv2 = 0 let to_json nv = `O [ ("name", Name.to_json (name nv)); ("version", Version.to_json (version nv)); ] let of_json = function | `O dict -> begin try let open OpamStd.Option.Op in Name.of_json (List.assoc "name" dict) >>= fun name -> Version.of_json (List.assoc "version" dict) >>= fun version -> Some {name; version} with Not_found -> None end | _ -> None module O = struct type tmp = t type t = tmp let compare p1 p2 = let r = Name.compare p1.name p2.name in if r = 0 then Version.compare p1.version p2.version else r let hash = hash let equal = equal let to_string = to_string let to_json = to_json let of_json = of_json end module Set = OpamStd.Set.Make (O) module Map = OpamStd.Map.Make (O) let to_map nv = Set.fold (fun nv map -> let name = name nv in let version = version nv in try Name.Map.add name (Version.Set.add version (Name.Map.find name map)) map with Not_found -> Name.Map.add name (Version.Set.singleton version) map ) nv Name.Map.empty let of_map nvm = Name.Map.fold (fun n -> Version.Set.fold (fun v -> Set.add (create n v))) nvm Set.empty let keys map = Map.fold (fun nv _ set -> Set.add nv set) map Set.empty (* $DIR/$NAME.$VERSION/ *) let of_dirname f = f |> OpamFilename.basename_dir |> OpamFilename.Base.to_string |> of_string_opt (* $DIR/$NAME.$VERSION/opam *) let of_filename f = if OpamFilename.basename f = OpamFilename.Base.of_string "opam" then of_dirname (OpamFilename.dirname f) else if OpamFilename.check_suffix f ".opam" then of_string_opt OpamFilename.(Base.to_string (basename (chop_extension f))) else None (* $NAME.$VERSION+opam.tar.gz *) let of_archive f = let base = OpamFilename.basename f in match OpamStd.String.cut_at (OpamFilename.Base.to_string base) '+' with | None -> None | Some (s,_) -> of_string_opt s let list dir = log "list %a" (slog OpamFilename.Dir.to_string) dir; if OpamFilename.exists_dir dir then ( let files = OpamFilename.rec_files dir in List.fold_left (fun set f -> match of_filename f with | None -> set | Some p -> if not (Set.mem p set) then Set.add p set else let suffix = Filename.concat (to_string p) "opam" in let files = List.filter (OpamFilename.ends_with suffix) files in OpamConsole.error_and_exit `File_error "Multiple definition of package %s in %s:\n%s" (to_string p) (OpamFilename.Dir.to_string dir) (OpamStd.Format.itemize ~bullet:"" OpamFilename.to_string files); ) Set.empty files ) else Set.empty let prefixes repodir = log "prefixes %a" (slog OpamFilename.Dir.to_string) repodir; if OpamFilename.exists_dir repodir then ( let files = OpamFilename.rec_files repodir in List.fold_left (fun map f -> match of_filename f with | None -> map | Some p -> let pkgdir = OpamFilename.dirname_dir (OpamFilename.dirname f) in let prefix = match OpamFilename.remove_prefix_dir repodir pkgdir with | "" -> None | p -> Some p in Map.add p prefix map ) Map.empty files ) else Map.empty let versions_of_packages nvset = Set.fold (fun nv vset -> Version.Set.add (version nv) vset) nvset Version.Set.empty let has_name nvset n = Set.exists (fun nv -> name nv = n) nvset let names_of_packages nvset = Set.fold (fun nv vset -> Name.Set.add (name nv) vset) nvset Name.Set.empty let package_of_name_aux empty split filter nv n = if n = "" then empty else let inf = {name = String.sub n 0 (String.length n - 1); version= ""} in let sup = {name = n^"\000"; version = ""} in let _, _, nv = split inf nv in let nv, _, _ = split sup nv in filter nv let packages_of_name nv n = package_of_name_aux Set.empty Set.split (Set.filter (fun nv -> nv.name = n)) nv n let packages_of_name_map nv n = package_of_name_aux Map.empty Map.split (Map.filter (fun nv _ -> nv.name = n)) nv n let package_of_name nvset n = Set.choose (packages_of_name nvset n) let package_of_name_opt nvset n = try Some (package_of_name nvset n) with Not_found -> None let packages_of_names nvset nameset = Name.Set.fold (fun name acc -> Set.union acc (packages_of_name nvset name)) nameset Set.empty let versions_of_name packages n = versions_of_packages (packages_of_name packages n) let filter_name_out packages name = Set.diff packages (packages_of_name packages name) let max_version set name = let versions = versions_of_name set name in let version = Version.Set.max_elt versions in create name version module Graph = (OpamParallel.MakeGraph (O) : OpamParallel.GRAPH with type V.t = t) opam-2.1.5/src/format/opamFilter.mli0000644000175000017500000002143314427463453016406 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Formulas on variables, as used in opam files build scripts Filters are a small language of formulas over strings and booleans used for conditions and text replacements. It has relational operators over strings (using version-number comparison), And, Or and Not boolean operations, dynamic casting (using strings "true" and "false"), and string interpolation. Variables are resolved using a user function returning an option, undefined values are propagated. String interpolation uses the syntax [%{identifier}%] Identifiers have the form {v [package:]var[?str_if_true:str_if_false_or_undef] v} The last optional part specifies a conversion from boolean to static strings. The syntax [pkg1+pkg2+pkgn:var] is allowed as a shortcut to [pkg1:var & pkg2:var & pkgn:var]. The special variable [pkg:enable] is allowed as a shortcut for [pkg:installed?enable:disable] *) open OpamTypes (** Pretty-print *) val to_string: filter -> string (** Folds on the tree of a filter *) val fold_down_left: ('a -> filter -> 'a) -> 'a -> filter -> 'a (** Maps on all nodes of a filter, bottom-up *) val map_up: (filter -> filter) -> filter -> filter (** Returns all the variables appearing in a filter (including the ones within string interpolations *) val variables: filter -> full_variable list (** Type of filter environment. *) type env = full_variable -> variable_contents option (** The type of filter idents with (optionally multiple) qualifying package names and optional string converter. Package name [None] encodes the self-reference [_] *) type fident = name option list * variable * (string * string) option (** Maps on all variables appearing in a filter. The case where package variables are renamed differently and appear in a filter ident of the form [%{pkg1+pkg2:var}%] is not supported and raises [Invalid_argument]. *) val map_variables: (full_variable -> full_variable) -> filter -> filter (** Same limitation as [map_variables] *) val map_variables_in_string: (full_variable -> full_variable) -> string -> string (** Does not handle rewriting the variables to different names (which can't be expressed with a [fident] anymore), and raises [Invalid_argument] *) val map_variables_in_fident: (full_variable -> full_variable) -> fident -> fident (** Distributes the negations to apply only to atoms *) val distribute_negations: ?neg:bool -> filter -> filter (** Rewrites string interpolations within a string. [default] is applied to the fident string (e.g. what's between [%{] and [}%]) when the expansion is undefined. If unspecified, this raises [Failure]. With [partial], [default] defaults to the identity, and is otherwise expected to return a fident. In this case, the returned string is supposed to be expanded again (expansion results are escaped, escapes are otherwise kept). This makes the function idempotent *) val expand_string: ?partial:bool -> ?default:(string -> string) -> env -> string -> string (** Returns the (beginning, end) offsets and substrings of any unclosed [%{] expansions *) val unclosed_expansions: string -> ((int * int) * string) list (** Computes the value of a filter. May raise [Failure] if [default] isn't provided *) val eval: ?default:variable_contents -> env -> filter -> variable_contents (** Like [eval] but casts the result to a bool. Raises [Invalid_argument] if not a valid bool and no default supplied. *) val eval_to_bool: ?default:bool -> env -> filter -> bool (** Same as [eval_to_bool], but takes an option as filter and returns always [true] on [None], [false] when the filter is [Undefined]. This is the most common behaviour for using "filters" for filtering *) val opt_eval_to_bool: env -> filter option -> bool (** Like [eval] but casts the result to a string *) val eval_to_string: ?default:string -> env -> filter -> string (** Reduces what can be, keeps the rest unchanged *) val partial_eval: env -> filter -> filter (** Wraps a full_variable into a fident accessor *) val ident_of_var: full_variable -> fident (** A fident accessor directly referring a variable with the given name *) val ident_of_string: string -> fident (** Resolves a filter ident. Like [eval], may raise Failure if no default is provided *) val ident_value: ?default:variable_contents -> env -> fident -> variable_contents (** Like [ident_value], but casts the result to a string *) val ident_string: ?default:string -> env -> fident -> string (** Like [ident_value], but casts the result to a bool *) val ident_bool: ?default:bool -> env -> fident -> bool (** Rewrites [basename].in to [basename], expanding interpolations. If the first line begins ["opam-version:"], assumes that expansion of variables within strings should be properly escaped. In particular, this means that Windows paths should expand correctly when generating .config files. *) val expand_interpolations_in_file: env -> basename -> unit (** Processes filters evaluation in a command list: parameter expansion and conditional filtering *) val commands: env -> command list -> string list list (** Process a simpler command, without filters *) val single_command: env -> arg list -> string list (** Extracts variables appearing in a list of commands *) val commands_variables: command list -> full_variable list (** Converts a generic formula to a filter, given a converter for atoms *) val of_formula: ('a -> filter) -> 'a generic_formula -> filter (** Resolves the filter in a filtered formula, reducing to a pure formula. [default] is the assumed result for undefined filters. If a version filter doesn't resolve to a valid version, the constraint is dropped unless [default_version] is specified. May raise, as other filter functions, if [default] is not provided and filters don't resolve. *) val filter_formula: ?default_version:version -> ?default:bool -> env -> filtered_formula -> formula (** Reduces according to what is defined in [env], and returns the simplified formula *) val partial_filter_formula: env -> filtered_formula -> filtered_formula (** A more generic formula reduction function, that takes a "partial resolver" as argument *) val gen_filter_formula: ('a -> [< `True | `False | `Formula of 'b OpamTypes.generic_formula ]) -> ('c * 'a) OpamFormula.formula -> ('c * 'b OpamTypes.generic_formula) OpamFormula.formula val string_of_filtered_formula: filtered_formula -> string val variables_of_filtered_formula: filtered_formula -> full_variable list (** Resolves the build, post, test, doc, dev flags in a filtered formula (which is supposed to have been pre-processed to remove switch and global variables). [default] determines the behaviour on undefined filters, and the function may raise if it is undefined. If a constraint resolves to an invalid version, it is dropped, or replaced with [default_version] if specified. If test, doc or dev are unspecified, they are assumed to be filtered out already and encountering them will raise an assert. *) val filter_deps: build:bool -> post:bool -> ?test:bool -> ?doc:bool -> ?dev:bool -> ?default_version:version -> ?default:bool -> filtered_formula -> formula (** The environment used in resolving the dependency filters, as per [filter_deps]. *) val deps_var_env: build:bool -> post:bool -> ?test:bool -> ?doc:bool -> ?dev:bool -> env (** Like [OpamFormula.simplify_version_formula], but on filtered formulas (filters are kept unchanged, but put in front) *) val simplify_extended_version_formula: filter filter_or_constraint OpamFormula.formula -> filter filter_or_constraint OpamFormula.formula option val atomise_extended: filtered_formula -> (OpamPackage.Name.t * (filter * (relop * filter) option)) OpamFormula.formula (* Uses [OpamFormula.sort] to sort on names, and sort version formulas with [simplify_extended_version_formula]. *) val sort_filtered_formula: ((name * filter filter_or_constraint OpamFormula.formula) -> (name * filter filter_or_constraint OpamFormula.formula) -> int) -> filtered_formula -> filtered_formula opam-2.1.5/src/format/opamFormatConfig.mli0000644000175000017500000000254314427463453017540 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2015-2016 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) module E : sig type OpamStd.Config.E.t += | ALLPARENS of bool option | SKIPVERSIONCHECKS of bool option | STRICT of bool option end (** Configuration options for the format lib (record, global reference and setter) *) type t = private { strict : bool; (** Fail early with errors in OPAM files *) skip_version_checks : bool; (** Ignore mismatching OPAM versions in files *) all_parens : bool; (** Affects the OPAM format printer; for backwards-compatibility *) } type 'a options_fun = ?strict:bool -> ?skip_version_checks:bool -> ?all_parens:bool -> 'a include OpamStd.Config.Sig with type t := t and type 'a options_fun := 'a options_fun opam-2.1.5/src/format/opamRepositoryName.ml0000644000175000017500000000150514427463453017766 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2016 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) include OpamStd.AbstractString let default = of_string "default" opam-2.1.5/src/format/opamPp.ml0000644000175000017500000002020714427463453015365 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2018 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamParserTypes.FullPos open OpamTypesBase open OpamStd.Op type bad_format = pos option * string exception Bad_version of bad_format exception Bad_format of bad_format exception Bad_format_list of bad_format list let bad_format ?pos fmt = Printf.ksprintf (fun str -> raise (Bad_format (pos,str))) fmt let bad_version ?pos fmt = Printf.ksprintf (fun str -> raise (Bad_version (pos,str))) fmt let add_pos pos = function | Bad_format (pos_opt,msg) as e -> if pos_opt = None || pos_opt = Some pos_null then Bad_format (Some pos, msg) else e | Bad_version (pos_opt,msg) as e -> if pos_opt = None || pos_opt = Some pos_null then Bad_version (Some pos, msg) else e | e -> e let rec string_of_bad_format ?file e = match e, file with | Bad_version (None, msg), Some filename | Bad_format (None, msg), Some filename | Bad_version (Some {filename; start = -1, -1 ; stop = -1,-1 }, msg), _ | Bad_format (Some {filename; start = -1, -1 ; stop = -1,-1 }, msg), _ -> Printf.sprintf "In %s:\n%s" filename msg | Bad_version (Some pos, msg), _ | Bad_format (Some pos, msg), _ -> Printf.sprintf "At %s:\n%s" (string_of_pos pos) msg | Bad_version (None, msg), None | Bad_format (None, msg), None -> Printf.sprintf "Input error:\n%s" msg | Bad_format_list bfl, _ -> OpamStd.List.concat_map "\n" (fun bf -> string_of_bad_format ?file (Bad_format bf)) bfl | _ -> Printexc.to_string e let () = Printexc.register_printer @@ function | (Bad_version _ | Bad_format _ | Bad_format_list _ as e) -> Some (string_of_bad_format ?file:None e) | _ -> None type ('a,'b) t = { parse: pos:pos -> 'a -> 'b; print: 'b -> 'a; ppname: string; name_constr: string -> string; } let pp ?(name="") ?(name_constr=fun x -> x) parse print = { parse; print; ppname = name; name_constr; } let of_pair name (simple_parse, print) = pp ~name (fun ~pos:_ -> simple_parse) print (** Utility functions *) exception Unexpected of pos option let unexpected ?pos () = raise (Unexpected pos) (** Basic pp usage *) let parse pp ~pos x = try pp.parse ~pos x with | Bad_version _ | Bad_format _ | Bad_format_list _ as e -> raise (add_pos pos e) | Unexpected (Some pos) -> bad_format ~pos "expected %s" pp.ppname | Unexpected None -> bad_format ~pos "expected %s" pp.ppname | Failure msg -> bad_format ~pos "%s%s" (if pp.ppname <> "" then Printf.sprintf "while expecting %s: " pp.ppname else "") msg | e -> OpamStd.Exn.fatal e; bad_format ~pos "%s%s" (if pp.ppname <> "" then Printf.sprintf "while expecting %s: " pp.ppname else "") (Printexc.to_string e) let print pp x = pp.print x (** Pp combination and transformation *) (** Piping *) let (-|) pp1 pp2 = { parse = (fun ~pos x -> let y = pp1.parse ~pos x in parse pp2 ~pos y ); print = pp1.print @* pp2.print; ppname = (match pp2.ppname with "" -> pp1.ppname | name -> pp1.name_constr name); name_constr = pp1.name_constr @* pp2.name_constr; } let identity = { parse = (fun ~pos:_ x -> x); print = (fun x -> x); ppname = ""; name_constr = (fun x -> x); } let ignore = { parse = (fun ~pos:_ -> OpamStd.Option.none); print = (fun _ -> assert false); ppname = "ignored"; name_constr = (fun _ -> ""); } let check ?name ?(raise=bad_format) ?errmsg f = pp ?name (fun ~pos x -> if not (f x) then match errmsg with | Some m -> raise ~pos "%s" m | None -> unexpected () else x) (fun x -> assert ( f x || (OpamConsole.error "Check failed on value printing%s%s" (match name with Some n -> " at "^n | None -> "") (match errmsg with Some e -> " ("^e^")" | None -> ""); false)); x) let map_pair ?name ?posf1 ?posf2 (pp1: ('a,'b) t) (pp2: ('c,'d) t) = let name = match name with | None -> Printf.sprintf "(%s, %s)" pp1.ppname pp2.ppname | Some n -> n in pp ~name (fun ~pos (a,b) -> let posf1 = OpamStd.Option.default (fun _ -> pos) posf1 in parse pp1 ~pos:(posf1 a) a, let posf2 = OpamStd.Option.default (fun _ -> pos) posf2 in parse pp2 ~pos:(posf2 b) b) (fun (a,b) -> print pp1 a, print pp2 b) let map_fst pp1 = pp (fun ~pos (a,b) -> pp1.parse ~pos a, b) (fun (a, b) -> pp1.print a, b) let map_snd pp1 = pp (fun ~pos (a,b) -> a, pp1.parse ~pos b) (fun (a, b) -> a, pp1.print b) let map_list ?name ?posf pp1 = let name = match name with | None -> pp1.ppname ^ "*" | Some n -> n in pp ~name (fun ~pos l -> let posf = OpamStd.Option.default (fun _ -> pos) posf in List.rev (List.rev_map (fun x -> parse pp1 ~pos:(posf x) x) l)) (List.rev @* List.rev_map (print pp1)) let map_option ?name pp1 = let name = match name with | None -> pp1.ppname ^ "?" | Some n -> n in pp ~name (fun ~pos -> OpamStd.Option.map (parse pp1 ~pos)) (OpamStd.Option.map (print pp1)) let singleton = { parse = (fun ~pos:_ -> function [x] -> x | _ -> unexpected ()); print = (fun x -> [x]); ppname = ""; name_constr = (fun x -> x); } (** Pps from strings *) module type STR = sig type t val of_string: string -> t val to_string: t -> string end let of_module (type a) name m = let module X = (val m: STR with type t = a) in pp ~name (fun ~pos:_ -> X.of_string) X.to_string (** Build tuples from lists *) let (^+) pp1 pp2 = pp ~name:(Printf.sprintf "%s %s" pp1.ppname pp2.ppname) (fun ~pos -> function | x::r -> parse pp1 ~pos x, parse pp2 ~pos r | [] -> unexpected ()) (fun (x,y) -> print pp1 x :: print pp2 y) let last = singleton let opt pp1 = pp ~name:("?"^pp1.ppname) (fun ~pos -> function [] -> None | l -> Some (pp1.parse ~pos l)) (function Some x -> pp1.print x | None -> []) let default d = pp (fun ~pos:_ -> function None -> d | Some x -> x) (fun x -> Some x) let fallback pp1 pp2 = let parse ~pos x = try pp1.parse ~pos x with e -> OpamStd.Exn.fatal e; let bt = Printexc.get_raw_backtrace () in try pp2.parse ~pos x with _ -> Printexc.raise_with_backtrace e bt in { pp1 with parse } module Op = struct let ( -| ) = ( -| ) let ( ^+ ) = ( ^+ ) end (** Pps for file contents (item lists), mostly list of [Variable(...)] fields *) type ('a, 'value) field_parser = ('a * 'value option, 'a) t (** add setter/getter and an accumulator to a pp; useful to use to get/set field records *) let ppacc_opt (* : ('a -> 'b -> 'a) -> ('a -> 'b option) -> ('value, 'b) t -> 'a field_parser *) = fun ?(cleanup = fun ~pos:_ _acc x -> x) set get pp1 -> let parse ~pos = function | acc, Some s -> set (cleanup ~pos acc (pp1.parse ~pos s)) acc | acc, None -> acc in let print s = s, OpamStd.Option.map pp1.print (get s) in { parse; print; ppname = pp1.ppname; name_constr = (fun x -> x); } let ppacc ?cleanup set get pp = ppacc_opt set (fun x -> Some (get x)) ?cleanup pp let ppacc_ignore = { parse = (fun ~pos:_ (acc,_) -> acc); print = (fun s -> s, None); ppname = ""; name_constr = (fun _ -> ""); } let embed set get ppacc = { parse = (fun ~pos (acc, x) -> set (ppacc.parse ~pos (get acc, x)) acc); print = (fun s -> let s1, v = ppacc.print (get s) in set s1 s, v); ppname = ppacc.ppname; name_constr = ppacc.name_constr; } opam-2.1.5/src/format/opamFormat.mli0000644000175000017500000002403014427463453016405 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** OPAM files syntax and conversion tools *) open OpamParserTypes.FullPos open OpamTypes open OpamPp (** Get the position out of a value *) val value_pos: value -> pos (** {3 low-level Pps for the Lines parser ([string list list])} *) type lines = string list list (** Provided an empty element, addition and fold operations with signatures as per Set.S, and a pp from lines to elements, returns a pp parsing from lines *) val lines_set: empty:'set -> add:('elt -> 'set -> 'set) -> fold:(('elt -> lines -> lines) -> 'set -> lines -> lines) -> (string list, 'elt) t -> (lines, 'set) t (** Provided an empty element, addition and fold operations with signatures as per Map.S, and a pp from lines to key, value pairs, returns a pp parsing from lines *) val lines_map : empty:'map -> add:('k -> 'v -> 'map -> 'map) -> fold:(('k -> 'v -> lines -> lines) -> 'map -> lines -> lines) -> (string list, 'k * 'v) t -> (lines, 'map) t (** {3 Pps for the type [value], used by opam-syntax files ([opamfile])} *) module V : sig (** These base converters raise [Unexpected] when not run on the right input (which is then converted to [Bad_format] by the parser. *) val bool : (value, bool) t val int : (value, int) t (** positive or null integer *) val pos_int : (value, int) t val ident : (value, string) t val string : (value, string) t (** Trimmed string *) val string_tr : (value, string) t (** Command arguments, i.e. strings or idents *) val simple_arg : (value, simple_arg) t (** Strings or bools *) val variable_contents : (value, variable_contents) t (** "[a b c]"; also allows just "a" to be parsed as a singleton list *) val list : (value, value list) t (** "(a b c)" *) val group : (value, value list) t (** Options in the [value] type sense, i.e. a value with an optional list of parameters in braces: ["value {op1 op2}"] *) val option : (value, value * value list) t val map_group : (value, 'a) t -> (value, 'a list) t (** An expected list depth may be specified to enable removal of extra brackets (never use [~depth] for an inner list) *) val map_list : ?depth:int -> (value, 'a) t -> (value, 'a list) t (** Normalises to the given list depth when parsing, and removes brackets that can be made implicit when printing *) val list_depth : int -> (value, value) t (** Maps on the two terms of an option constructor. *) val map_option : (value, 'a) t -> (value list, 'b) t -> (value, 'a * 'b) t (** Maps over two options (e.g. [v {op1} {op2}]) *) val map_options_2 : (value, 'a) t -> (value list, 'b) t -> (value list, 'c) t -> (value, 'a * 'b * 'c) t (** Maps over three options (e.g. [v {op1} {op2} {op3}]) *) val map_options_3 : (value, 'a) t -> (value list, 'b) t -> (value list, 'c) t -> (value list, 'd) t -> (value, 'a * 'b * 'c * 'd) t (** A pair is simply a list with two elements in the [value] type *) val map_pair : (value, 'a) t -> (value, 'b) t -> (value, 'a * 'b) t (** A triple is simply a list with three elements in the [value] type *) val map_triple : (value, 'a) t -> (value, 'b) t -> (value, 'c) t -> (value, 'a * 'b * 'c) t val url : (value, url) t (** Specialised url parser when the backend is already known *) val url_with_backend : OpamUrl.backend -> (value, url) t val compiler_version : (value, string) t val filter_ident : (value, name option list * variable * (string * string) option) t val filter : (value list, filter) t (** Arguments in commands (term + optional filter) *) val arg : (value, simple_arg * filter option) t val command : (value, (simple_arg * filter option) list * filter option) t (** Simple dependency constraints *) val constraints : (value, 'a) t -> (value list, (OpamFormula.relop * 'a) OpamFormula.formula) t (** Dependency constraints mixed with filters *) val filtered_constraints : (value, 'version) t -> (value list, 'version filter_or_constraint OpamFormula.formula) t (** Package versions *) val version: (value, version) t (** Package versions as filters, as they may appear in dependency (may be an expanded string or an ident) *) val ext_version: (value, filter) t (** A package name, encoded as a string, but with restrictions *) val pkgname: (value, name) t (** Returns an atom parser [("package" {>= "version"})] from a constraint and a version parser*) val package_atom: (value list, 'a) t -> (value, name * 'a) t (** Takes a parser for constraints. Lists without operator will be understood as conjunctions or disjunctions depending on the first argument. *) val package_formula : [< `Conj | `Disj ] -> (value list, 'a) t -> (value, (name * 'a) OpamFormula.formula) t (** Like [package_formula], but takes the list items directly *) val package_formula_items : [< `Conj | `Disj ] -> (value list, 'a) t -> (value list, (name * 'a) OpamFormula.formula) t (** Environment variable updates syntax *) val env_binding : (value, env_update) t val os_constraint : (value, (bool * string) OpamFormula.formula) t end (** {3 Specific Pps for items lists and fields (opamfile)} *) module I : sig val file : (opamfile, filename * opamfile_item list) t val map_file : (opamfile_item list, 'a) t -> (opamfile, filename * 'a) t val item : (opamfile_item, string * value) t val items : (opamfile_item list, (string * value) list) t (** Suitable for the [fields] [sections] argument, when the sections are anonymous ([section_name = None]) *) val anonymous_section : ('a, 'b) t -> ((string option * 'a) list, 'b) t type ('a, 'value) fields_def = (string * ('a, 'value) field_parser) list (** Parses an item list into a record using a fields_def; errors in a field cause the field to be ignored, and are aggregated into the returned [field, bad_format] list. Errors are ignored when printing back. *) val fields : ?name:string -> empty:'a -> ?sections: ('a, (string option * (opamfile_item list)) list) fields_def -> ?mandatory_fields:string list -> ('a, value) fields_def -> (opamfile_item list, 'a * (string * bad_format) list) t (** Intended to be piped after [fields]. If the errors list is non-empty, this raises [Bad_format_list] if [strict], and otherwise prints warnings for all the errors. The errors are then dropped when parsing, and initialised to empty when printing. [strict] is taken from the global settings if unspecified. [condition] may be added to only show the errors when it returns [true], and only log them otherwise. *) val show_errors : ?name:string -> ?strict:bool -> ?condition:('a -> bool) -> unit -> ('a * (string * bad_format) list, 'a) t (** Intended to be piped after [fields], this processes the given function on the errors, then drops them when parsing. When printing, just sets empty errors. *) val on_errors : ?name:string -> ('a -> string * bad_format -> 'a) -> ('a * (string * bad_format) list, 'a) t (** Partitions items in an opamfile base on a condition on the variable names. If a section is encountered, it is kept in the second list (as filter returning false), unless [section] is true. *) val partition_fields : ?section:bool -> (string -> bool) -> (opamfile_item list, opamfile_item list * opamfile_item list) t (** Partitions items in an opamfile base on a generic condition on the items *) val partition : (opamfile_item -> bool) -> (opamfile_item list, opamfile_item list * opamfile_item list) t (** Parse a single field from a file, return the result and the unchanged item list. The single field is ignored when printing back. *) val field : string -> (pos:pos -> value -> 'a) -> (opamfile_item list, 'a option * opamfile_item list) t (** Parse a single section with the given "kind", towards its name and contents *) val section : string -> (opamfile_item, (string option * opamfile_item list)) t (** Extracts a single item with the given variable name from an item list. The item is removed from the returned item list, and the two are re-combined when printing *) val extract_field : string -> (opamfile_item list, value option * opamfile_item list) t (** Checks the [opam_version] field; otherwise the identity *) val check_opam_version : ?optional:bool -> format_version:opam_version -> ?f:(opam_version -> bool) -> unit -> (opamfile_item list, opamfile_item list) t (** Add [opam-version] field printing at printing, and removes it from parsed fields if [undefined] (default is false) *) val opam_version : ?undefined:bool -> format_version:opam_version -> unit -> (opamfile_item list, opamfile_item list) t (** Signature handling (wip) *) (** A signature is a keyid, an algorithm and the signature proper *) type signature = string * string * string val signature : (value, signature) t exception Invalid_signature of pos * (string * string * string) list option (** Pp for signed files. Will assert fail if attempting to write a file with an invalid signature. *) val signed: check:(signature list -> string -> bool) -> (opamfile_item list, signature list * opamfile_item list) t end opam-2.1.5/src/format/opamFilter.ml0000644000175000017500000005457014427463453016245 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase open OpamStd.Op module OpamParser = OpamParser.FullPos module OpamPrinter = OpamPrinter.FullPos let log ?level fmt = OpamConsole.log "FILTER" ?level fmt let slog = OpamConsole.slog type env = full_variable -> variable_contents option type fident = name option list * variable * (string * string) option let to_string t = let rec aux ?(context=`Or) t = let paren ?(cond=false) f = if cond || OpamFormatConfig.(!r.all_parens) then Printf.sprintf "(%s)" f else f in match t with | FBool b -> string_of_bool b | FString s -> Printf.sprintf "%S" s | FIdent (pkgs,var,converter) -> OpamStd.List.concat_map "+" (function None -> "_" | Some p -> OpamPackage.Name.to_string p) pkgs ^ (if pkgs <> [] then ":" else "") ^ OpamVariable.to_string var ^ (match converter with | Some (it,ifu) -> "?"^it^":"^ifu | None -> "") | FOp(e,s,f) -> paren ~cond:(context <> `Or && context <> `And) (Printf.sprintf "%s %s %s" (aux ~context:`Relop e) (OpamPrinter.relop_kind s) (aux ~context:`Relop f)) | FAnd (e,f) -> paren ~cond:(context <> `Or && context <> `And) (Printf.sprintf "%s & %s" (aux ~context:`And e) (aux ~context:`And f)) | FOr (e,f) -> paren ~cond:(context <> `Or) (Printf.sprintf "%s | %s" (aux e) (aux f)) | FNot e -> paren ~cond:(context = `Relop) (Printf.sprintf "!%s" (aux ~context:`Not e)) | FDefined e -> paren ~cond:(context = `Relop) (Printf.sprintf "?%s" (aux ~context:`Defined e)) | FUndef f -> Printf.sprintf "#undefined(%s)" (aux f) in aux t let rec fold_down_left f acc filter = match filter with | FOp(l,_,r) | FAnd(l,r) | FOr(l,r) -> fold_down_left f (fold_down_left f (f acc filter) l) r | FNot(x) -> fold_down_left f (f acc filter) x | x -> f acc x let rec map_up f = function | FOp (l, op, r) -> f (FOp (map_up f l, op, map_up f r)) | FAnd (l, r) -> f (FAnd (map_up f l, map_up f r)) | FOr (l, r) -> f (FOr (map_up f l, map_up f r)) | FNot x -> f (FNot (map_up f x)) | FUndef x -> f (FUndef (map_up f x)) | (FBool _ | FString _ | FIdent _ | FDefined _) as flt -> f flt (* ["%%"], ["%{xxx}%"], or ["%{xxx"] if unclosed *) let string_interp_regex = let open Re in let notclose = rep (alt [ diff notnl (set "}"); seq [char '}'; alt [diff notnl (set "%"); stop] ] ]) in compile (alt [ str "%%"; seq [str "%{"; group (greedy notclose); opt (group (str "}%"))]; ]) let escape_value = let rex = Re.(compile @@ set "\\\"") in Re.Pcre.substitute ~rex ~subst:(fun s -> "\\"^s) let escape_expansions = Re.replace_string Re.(compile @@ char '%') ~by:"%%" let escape_strings = map_up @@ function | FString s -> FString (escape_expansions s) | flt -> flt let fident_variables = function | [], var, _ -> [OpamVariable.Full.global var] | pkgs, var, _ -> List.map (function | Some n -> OpamVariable.Full.create n var | None -> OpamVariable.Full.self var) pkgs (* extracts variables appearing in interpolations in a string*) let string_variables s = let matches = let rec aux acc pos = try let ss = Re.exec ~pos string_interp_regex s in if Re.Group.test ss 2 then aux (Re.Group.get ss 1 :: acc) (fst (Re.Group.offset ss 0) + String.length (Re.Group.get ss 0)) else aux acc (pos+1) with Not_found -> acc in aux [] 0 in List.fold_left (fun acc s -> try fident_variables (filter_ident_of_string s) @ acc with Failure _ -> acc) [] matches let variables filter = fold_down_left (fun acc -> function | FString s -> string_variables s @ acc | FIdent f -> fident_variables f @ acc | _ -> acc) [] filter (* Some cast functions on values *) let value ?default = function | FBool b -> B b | FString s -> S s | FUndef f -> (match default with | Some d -> d | None -> failwith ("Undefined filter value: "^to_string f)) | e -> raise (Invalid_argument ("filter value: "^to_string e)) let value_string ?default = function | FBool b -> string_of_bool b | FString s -> s | FUndef f -> (match default with | Some d -> d | None -> failwith ("Undefined string filter value: "^to_string f)) | e -> raise (Invalid_argument ("value_string: "^to_string e)) let value_bool ?default = function | FBool b -> b | FString "true" -> true | FString "false" -> false | FUndef f -> (match default with | Some d -> d | None -> failwith ("Undefined boolean filter value: "^to_string f)) | e -> (match default with | Some d -> d | None -> raise (Invalid_argument ("value_bool: "^to_string e))) (* Desugars the "enable" pseudo-variable *) let desugar_fident ((packages,var,converter) as fident) = let enable = OpamVariable.of_string "enable" in if packages <> [] && var = enable && converter = None then packages, OpamVariable.of_string "installed", Some ("enable","disable") else fident (* Resolves an ident to variable contents *) let resolve_ident_raw ?(no_undef_expand=false) env fident = let open OpamStd.Option.Op in let packages,var,converter = desugar_fident fident in let bool_of_value = function | B b -> Some b | S s | L [s] -> (try Some (bool_of_string s) with Invalid_argument _ -> None) | L _ -> None in let resolve name = let var = match name with | Some n -> OpamVariable.Full.create n var | None -> OpamVariable.Full.self var in env var in let value_opt : variable_contents option = match packages with | [] -> env (OpamVariable.Full.global var) | [name] -> resolve name | names -> List.fold_left (fun acc name -> if acc = Some false then acc else match resolve name with | Some (B true) -> acc | v -> v >>= bool_of_value) (Some true) names >>| fun b -> B b in match converter, no_undef_expand with | Some (iftrue, iffalse), false -> (match value_opt >>= bool_of_value with | Some true -> Some (S iftrue) | Some false -> Some (S iffalse) | None -> Some (S iffalse)) | _ -> value_opt (* Resolves [FIdent] to string or bool, using its package and converter specification *) let resolve_ident ?no_undef_expand env fident = match resolve_ident_raw ?no_undef_expand env fident with | Some (B b) -> FBool b | Some (S s) -> FString s | Some (L l) -> FString (String.concat " " l) | None -> FUndef (FIdent fident) (* Resolves ["%{x}%"] string interpolations *) let expand_string_aux ?(partial=false) ?(escape_value=fun x -> x) ?default env text = let default fident = match default, partial with | None, false -> None | Some df, false -> Some (df fident) | None, true -> Some (Printf.sprintf "%%{%s}%%" fident) | Some df, true -> Some (Printf.sprintf "%%{%s}%%" (df fident)) in let env v = if partial then match env v with | Some (S s) -> Some (S (escape_expansions s)) | x -> x else env v in let f g = let str = Re.Group.get g 0 in if str = "%%" then (if partial then "%%" else "%") else if not (OpamStd.String.ends_with ~suffix:"}%" str) then (log "ERR: Unclosed variable replacement in %S\n" str; str) else let fident = String.sub str 2 (String.length str - 4) in resolve_ident ~no_undef_expand:partial env (filter_ident_of_string fident) |> value_string ?default:(default fident) |> escape_value in Re.replace string_interp_regex ~f text let expand_string = expand_string_aux ?escape_value:None let unclosed_expansions text = let re = Re.( compile (alt [ str "%%"; seq [str "%{"; group (greedy (rep (diff notnl (char '}')))); opt (group (str "}%"))]; ]) ) in Re.all re text |> OpamStd.List.filter_map @@ fun gr -> if Re.Group.test gr 1 && not (Re.Group.test gr 2) then Some (Re.Group.offset gr 0, Re.Group.get gr 0) else None let map_variables_in_fident f (_,_,conv as fid) = let vars = fident_variables fid in match List.map f vars with | [] -> assert false | v::vars -> let var_name = OpamVariable.Full.variable v in match OpamVariable.Full.scope v with | OpamVariable.Full.Global -> if vars <> [] then invalid_arg "OpamFilter.map_variables"; [], var_name, conv | OpamVariable.Full.Package _ | OpamVariable.Full.Self -> if (List.exists (fun v -> OpamVariable.Full.variable v <> var_name) vars) then invalid_arg "OpamFilter.map_variables"; List.map (fun v -> match OpamVariable.Full.scope v with | OpamVariable.Full.Package name -> Some name | OpamVariable.Full.Self -> None | OpamVariable.Full.Global -> invalid_arg "OpamFilter.map_variables") (v::vars), var_name, conv let map_variables_in_string f = expand_string ~partial:true ~default:(fun fid_string -> try fid_string |> filter_ident_of_string |> map_variables_in_fident f |> string_of_filter_ident with Failure _ -> fid_string) (fun _ -> None) let map_variables f = map_up @@ function | FIdent fid -> FIdent (map_variables_in_fident f fid) | FString s -> FString (map_variables_in_string f s) | flt -> flt let rec distribute_negations ?(neg=false) = function | FAnd (f1, f2) -> let f1 = distribute_negations ~neg f1 in let f2 = distribute_negations ~neg f2 in if neg then FOr (f1, f2) else FAnd (f1, f2) | FOr (f1, f2) -> let f1 = distribute_negations ~neg f1 in let f2 = distribute_negations ~neg f2 in if neg then FAnd (f1, f2) else FOr (f1, f2) | FBool b -> FBool (if neg then not b else b) | FOp (f1, op, f2) -> FOp (distribute_negations ~neg:false f1, (if neg then OpamFormula.neg_relop op else op), distribute_negations ~neg:false f2) | FNot f -> distribute_negations ~neg:(not neg) f | f -> if neg then FNot f else f let logop1 cstr op = function | FUndef f -> FUndef (cstr f) | e -> try FBool (op (value_bool e)) with Invalid_argument s -> log "ERR: %s" s; FUndef (cstr e) let logop2 cstr op absorb e f = match e, f with | _, FBool x when x = absorb -> FBool x | FBool x, _ when x = absorb -> FBool x | FUndef x, FUndef y | FUndef x, y | x, FUndef y -> FUndef (cstr x y) | f, g -> try FBool (op (value_bool f) (value_bool g)) with Invalid_argument s -> log "ERR: %s" s; FUndef (cstr f g) (* Reduce expressions to values *) let rec reduce_aux ?no_undef_expand ~default_str env = let reduce = reduce ?no_undef_expand ~default_str env in function | FUndef x -> FUndef x | FBool b -> FBool b | FString s -> FString s | FIdent i -> resolve_ident ?no_undef_expand env i | FOp (e,relop,f) -> (match reduce e, reduce f with | FUndef x, FUndef y -> FUndef (FOp (x, relop, y)) | FUndef x, y -> FUndef (FOp (x, relop, escape_strings y)) | x, FUndef y -> FUndef (FOp (escape_strings x, relop, y)) | e,f -> FBool (OpamFormula.check_relop relop (OpamVersionCompare.compare (value_string e) (value_string f)))) | FAnd (e,f) -> logop2 (fun e f -> FAnd (e,f)) (&&) false (reduce e) (reduce f) | FOr (e,f) -> logop2 (fun e f -> FOr (e,f)) (||) true (reduce e) (reduce f) | FNot e -> logop1 (fun e -> FNot e) not (reduce e) | FDefined e -> match reduce e with | FUndef _ -> FBool false | _ -> FBool true and reduce ?no_undef_expand ?(default_str = Some (fun _ -> "")) env e = match reduce_aux ?no_undef_expand ~default_str env e with | FString s -> (try FString (expand_string ?default:default_str env s) with Failure _ -> FUndef (FString (expand_string ~partial:true env s))) | e -> e let eval ?default env e = value ?default (reduce env e) let eval_to_bool ?default env e = value_bool ?default (reduce env e) let opt_eval_to_bool env opt = match opt with | None -> true | Some e -> value_bool ~default:false (reduce env e) let eval_to_string ?default env e = value_string ?default (reduce env e) let partial_eval env flt = match reduce ~no_undef_expand:true ~default_str:None env flt with | FUndef f -> f | f -> escape_strings f let ident_of_var v = (match OpamVariable.Full.scope v with | OpamVariable.Full.Global -> [] | OpamVariable.Full.Self -> [None] | OpamVariable.Full.Package p -> [Some p]), OpamVariable.Full.variable v, None let ident_of_string s = ident_of_var (OpamVariable.Full.of_string s) let ident_value ?default env id = value ?default (resolve_ident env id) let ident_string ?default env id = value_string ?default (resolve_ident env id) let ident_bool ?default env id = value_bool ?default (resolve_ident env id) (* Substitute the file contents *) let expand_interpolations_in_file env file = let f = OpamFilename.of_basename file in let src = OpamFilename.add_extension f "in" in let ic = OpamFilename.open_in_bin src in let oc = OpamFilename.open_out_bin f in (* Determine if the input file parses in opam-file-format *) let is_opam_format = try let _ = OpamParser.channel ic (OpamFilename.to_string src) in true with e -> OpamStd.Exn.fatal e; false in (* Reset the input for processing *) seek_in ic 0; let default _ = "" in let write = output_string oc in let unquoted s = write @@ expand_string ~default env s in let quoted s = write @@ expand_string_aux ~escape_value ~default env s in let process = if is_opam_format then fun () -> OpamInterpLexer.main unquoted quoted (Lexing.from_channel ic) else let rec aux () = match input_line ic with | s -> unquoted s; output_char oc '\n'; aux () | exception End_of_file -> () in aux in process (); close_in ic; close_out oc (* Apply filters and interpolations to package commands *) let arguments env (a,f) = if opt_eval_to_bool env f then match a with | CString s -> [expand_string ~default:(fun _ -> "") env s] | CIdent i -> let fident = filter_ident_of_string i in match resolve_ident_raw env fident with | Some (S s) -> [s] | Some (B b) -> [string_of_bool b] | Some (L sl) -> sl | None -> log "ERR in replacement: undefined ident %S" i; [""] else [] let command env (l, f) = if opt_eval_to_bool env f then match List.concat (List.map (arguments env) l) with | [] -> None | l -> Some l else None let commands env l = OpamStd.List.filter_map (command env) l let single_command env l = List.concat (List.map (arguments env) l) let simple_arg_variables = function | CString s -> string_variables s | CIdent i -> try fident_variables (filter_ident_of_string i) with Failure _ -> [] let filter_opt_variables = function | None -> [] | Some f -> variables f let argument_variables (a,f) = simple_arg_variables a @ filter_opt_variables f let command_variables (l,f) = List.fold_left (fun acc a -> argument_variables a @ acc) (filter_opt_variables f) l let commands_variables l = List.fold_left (fun acc c -> command_variables c @ acc) [] l let rec of_formula atom_f = function | Empty -> FBool true | Atom at -> atom_f at | Block f -> of_formula atom_f f | And (a, b) -> FAnd (of_formula atom_f a, of_formula atom_f b) | Or (a, b) -> FOr (of_formula atom_f a, of_formula atom_f b) let filter_constraints ?default_version ?default env filtered_constraint = OpamFormula.partial_eval (function | Filter flt -> if eval_to_bool ?default env flt then `True else `False | Constraint (relop, v) -> try let v = eval_to_string env v in `Formula (Atom (relop, OpamPackage.Version.of_string v)) with Failure msg -> match default_version with | None -> log "Warn: ignoring version constraint %a: %s" (slog to_string) v msg; `Formula (Empty) | Some v -> `Formula (Atom (relop, v))) filtered_constraint (* { build & "%{skromuk}%" = "flib%" } *) (* { build & "flib%%" = "flib%" } *) let partial_filter_constraints env filtered_constraint = OpamFormula.partial_eval (function | Filter flt -> (match partial_eval env flt with | FBool true -> `True | FBool false -> `False | FUndef f | f -> `Formula (Atom (Filter f))) | Constraint (relop, flt_v) -> (match partial_eval env flt_v with | FBool b -> `Formula (Atom (Constraint (relop, FString (string_of_bool b)))) | FUndef f | f -> `Formula (Atom (Constraint (relop, f))))) filtered_constraint let gen_filter_formula constraints filtered_formula = OpamFormula.map (fun (name, fc) -> match constraints fc with | `True -> Atom (name, Empty) | `False -> Empty | `Formula c -> Atom (name, c)) filtered_formula let filter_formula ?default_version ?default env ff = gen_filter_formula (filter_constraints ?default_version ?default env) ff let partial_filter_formula env ff = gen_filter_formula (partial_filter_constraints env) ff let string_of_filtered_formula = let string_of_constraint = OpamFormula.string_of_formula (function | Constraint (op, FString s) -> Printf.sprintf "%s \"%s\"" (OpamPrinter.relop_kind op) s | Constraint (op, (FIdent _ as v)) -> Printf.sprintf "%s %s" (OpamPrinter.relop_kind op) (to_string v) | Constraint (op, v) -> Printf.sprintf "%s (%s)" (OpamPrinter.relop_kind op) (to_string v) | Filter f -> to_string f) in OpamFormula.string_of_formula (function | n, Empty -> OpamPackage.Name.to_string n | n, c -> let paren = match c with Atom (Constraint _) -> false | _ -> true in Printf.sprintf "%s %s%s%s" (OpamPackage.Name.to_string n) (if paren then "{" else "") (string_of_constraint c) (if paren then "}" else "")) let variables_of_filtered_formula ff = OpamFormula.fold_left (fun acc (_, f) -> OpamFormula.fold_left (fun acc -> function | Constraint _ -> acc | Filter f -> variables f @ acc) acc f) [] ff let deps_var_env ~build ~post ?test ?doc ?dev var = let get_opt = function | Some b -> Some (B b) | None -> invalid_arg "filter_deps" in match OpamVariable.Full.to_string var with | "build" -> Some (B build) | "post" -> Some (B post) | "with-test" -> get_opt test | "with-doc" -> get_opt doc | "dev" -> get_opt dev | _ -> None let filter_deps ~build ~post ?test ?doc ?dev ?default_version ?default deps = filter_formula ?default_version ?default (deps_var_env ~build ~post ?test ?doc ?dev) deps let rec simplify_extended_version_formula ef = let to_pure ef = try Some (OpamFormula.map (function | Constraint (op, FString s) when string_variables s = [] -> Atom (op, OpamPackage.Version.of_string s) | _ -> failwith "Impure") ef) with Failure _ -> None in let to_filtered = OpamFormula.map (fun (op, v) -> Atom (Constraint (op, FString (OpamPackage.Version.to_string v)))) in match to_pure ef with | Some f -> OpamStd.Option.map to_filtered (OpamFormula.simplify_version_formula f) | None -> match ef with | And _ | Or _ -> let conj = match ef with And _ -> true | _ -> false in let l = OpamFormula.(if conj then ands_to_list else ors_to_list) ef in (try let filtered, pure = List.fold_left (fun (filtered, pure) ef1 -> match to_pure ef1 with | Some f -> filtered, f::pure | None -> let ef1 = simplify_extended_version_formula ef1 in match ef1 with | None -> (* Always false *) if conj then failwith "false" else filtered, pure | Some ef1 -> (match to_pure ef1 with | Some f -> filtered, f::pure | None -> ef1::filtered, pure)) ([], []) l in let mk = OpamFormula.(if conj then ands else ors) in match OpamFormula.simplify_version_formula (mk pure) with | None -> if conj then None else Some (mk (List.rev filtered)) | Some pure -> Some (mk (List.rev_append filtered [to_filtered pure])) with Failure _ -> None) | Block ef -> simplify_extended_version_formula ef | atom -> Some atom let atomise_extended = OpamFormula.map (fun (x, c) -> match c with | Empty -> Atom (x, (FBool true, None)) | cs -> let rec aux filters = function | Atom (Filter f) -> Atom (x, (FAnd (f,filters), None)) | Atom (Constraint c) -> Atom (x, (filters, Some c)) | Empty -> (match filters with FBool true -> Empty | f -> Atom (x, (f, None))) | Block f -> aux filters f | And _ as f -> let filters, constraints = let rec split filters conj = function | Atom (Filter f) :: r -> split (FAnd (f,filters)) conj r | cstr :: r -> split filters (cstr::conj) r | [] -> filters, conj in split filters [] (OpamFormula.ands_to_list f) in OpamFormula.ands (List.rev_map (aux filters) constraints) | Or (a, b) -> Or (aux filters a, aux filters b) in aux (FBool true) cs) let sort_filtered_formula compare ff = let f = OpamFormula.sort compare ff in let rec vc_sort = function | Empty -> Empty | Atom (n,vf) -> Atom (n, (OpamStd.Option.default vf (simplify_extended_version_formula vf))) | Block f -> Block (vc_sort f) | And (f,f') -> And (vc_sort f, vc_sort f') | Or (f,f') -> Or (vc_sort f, vc_sort f') in vc_sort f opam-2.1.5/src/format/opamInterpLexer.mll0000644000175000017500000000350314427463453017423 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2016 MetaStack Solutions Ltd. *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) rule main unquoted quoted = parse | [^ '"' '\n' ]+ { unquoted @@ Lexing.lexeme lexbuf; main unquoted quoted lexbuf } | ("\"\"\"" | '"') as quote { unquoted quote; let triple = String.length quote = 3 in string triple unquoted quoted lexbuf } | '\n' { Lexing.new_line lexbuf; unquoted "\n"; main unquoted quoted lexbuf } | eof { () } and string triple unquoted quoted = parse | ( [^ '"' '\\' '\n' ]+ | '\\' [^ '\n' ]? )+ { quoted @@ Lexing.lexeme lexbuf; string triple unquoted quoted lexbuf } | "\"\"\"" { unquoted "\"\"\""; main unquoted quoted lexbuf } | '"' { if triple then begin quoted "\""; string triple unquoted quoted lexbuf end else begin unquoted "\""; main unquoted quoted lexbuf end } | '\n' { Lexing.new_line lexbuf; unquoted "\n"; string triple unquoted quoted lexbuf} | eof { () } opam-2.1.5/src/format/opamPath.mli0000644000175000017500000003050314427463453016053 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Defines the file hierarchy in ~/.opam *) open OpamTypes (** {2 Global paths} *) (** Type of path root *) type t = dirname (** State cache *) val state_cache: t -> filename (** Directory containing state cache *) val state_cache_dir: t -> dirname (** Global lock file for the whole opamroot. Opam should generally read-lock this (e.g. initialisation and format upgrades require a write lock) *) val lock: t -> filename (** Main configuration file: {i $opam/config} *) val config: t -> OpamFile.Config.t OpamFile.t (** The list of configuration files location used by default ({i /etc/opamrc} and {i ~/.opamrc}). More general (lower priority) first. *) val init_config_files: unit -> OpamFile.InitConfig.t OpamFile.t list (** Lock for updates on the main config file (write lock when changes to switches, repositories lists are expected. No lock needed otherwise) *) val config_lock: t -> filename (** Global lock file for the repositories mirrors: {i $opam/repo/lock} *) val repos_lock: t -> filename (** Global config file for the repositories mirrors: {i $opam/repo/repos-config} *) val repos_config: t -> OpamFile.Repos_config.t OpamFile.t (** Init scripts location: {i $opam/opam-init} *) val init: t -> dirname (** Installation dir for configured hooks: ${i $opam/opam-init/hooks} *) val hooks_dir: t -> dirname (** Log dir {i $opam/log} *) val log: t -> dirname (** The directory where global backups are stored *) val backup_dir: t -> dirname (** Backup file for state export *) val backup: t -> switch_selections OpamFile.t (** The prefix for plugin commands (["opam-"]) *) val plugin_prefix : string (** The directory for plugins data {i $opam/plugins} *) val plugins: t -> dirname (** The directory for shared plugin binaries {i $opam/plugins/bin} *) val plugins_bin: t -> dirname (** The globally installed binary of the given plugin {i $opam/plugins/bin/opam-foo} *) val plugin_bin: t -> name -> filename (** The directory for a given plugin's data {i $opam/plugins/$name}. ["bin"] is forbidden. *) val plugin: t -> name -> dirname module type LAYOUT = sig type ctx val root : dirname -> ctx -> dirname val lib_dir : dirname -> ctx -> dirname end (** Switch related paths *) module Switch: sig (** Locations of opam internal dirs and files *) (** The switch prefix: {i $opam/$switch} *) val root: t -> switch -> dirname (** The name of the subdir of the switch prefix where opam data is stored (".opam-switch") *) val meta_dirname: string (** The subdirectory of the prefix where opam data lives: {i $opam/$switch/.opam-switch}*) val meta: t -> switch -> dirname (** lock file: {i $meta/lock} *) val lock: t -> switch -> filename (** The directory where backups are stored for this switch *) val backup_dir: t -> switch -> dirname (** Backup file for state export *) val backup: t -> switch -> switch_selections OpamFile.t (** Switch selections {i $meta/switch-state} *) val selections: t -> switch -> switch_selections OpamFile.t (** Temporary folders used to decompress and compile the corresponding archives: {i $meta/build/$packages} *) val build: t -> switch -> package -> dirname (** Temporary folders used to decompress the corresponding archives, used only for package removal {i $meta/remove/$packages} *) val remove: t -> switch -> package -> dirname (** Temporary folder: {i $meta/build} *) val build_dir: t -> switch -> dirname (** Temporary folder: {i $meta/remove} *) val remove_dir: t -> switch -> dirname (** Installed files for a given package: {i $meta/install/$name.install} *) val install: t -> switch -> name -> OpamFile.Dot_install.t OpamFile.t (** File registering the changes made by the installation of the given package {i $meta/install/$name.changes} *) val changes: t -> switch -> name -> OpamDirTrack.t OpamFile.t (** Installed files: {i $meta/install/} *) val install_dir: t -> switch -> dirname (** Packages to reinstall on next upgrade: {i $meta/reinstall} *) val reinstall: t -> switch -> OpamFile.PkgList.t OpamFile.t (** Configuration folder: {i $meta/config} *) val config_dir: t -> switch -> dirname (** Global config for the switch: {i $meta/switch-config} *) val switch_config: t -> switch -> OpamFile.Switch_config.t OpamFile.t (** Package-specific configuration file for installed packages: {i $meta/config/$name.config} *) val config: t -> switch -> name -> OpamFile.Dot_config.t OpamFile.t (** Clean, uncompressed sources for this switch: {i $meta/sources/} *) val sources_dir: t -> switch -> dirname (** Clean, uncompressed source directory for this package: {i $meta/sources/$name.$version/} *) val sources: t -> switch -> package -> dirname (** Temporary switch-local directory where a by-hash map of extra files may be stored. This is used for switch-imports: {i $meta/extra-files-cache} *) val extra_files_dir: t -> switch -> dirname (** Extra file with the given hash from the temporary switch-import cache: {i $meta/extra-files-cache/HASH} *) val extra_file: t -> switch -> OpamHash.t -> filename (** Mirror of the sources for a given pinned package: {i $meta/sources/$name/} (without version) *) val pinned_package: t -> switch -> name -> dirname (** Cached environment updates. *) val environment: t -> switch -> OpamFile.Environment.t OpamFile.t (** Like [environment], but from the switch prefix dir *) val env_relative_to_prefix: dirname -> OpamFile.Environment.t OpamFile.t (** Directory where the metadata of installed packages is mirrored. {i $meta/packages/} *) val installed_opams: t -> switch -> dirname (** Cache file for the mirrored installed package metadata {i $meta/packages/cache} *) val installed_opams_cache: t -> switch -> filename (** The mirror of the package definition for the given installed package {i $meta/packages/$name.$version/} *) val installed_package_dir: t -> switch -> package -> dirname (** The mirror of the opam file for the given installed package {i $meta/packages/$name.$version/opam} *) val installed_opam: t -> switch -> package -> OpamFile.OPAM.t OpamFile.t (** Mirror of the extra files attached to the package definitions of installed packages {i $meta/packages/$name.$version/files/} *) val installed_opam_files_dir: t -> switch -> package -> dirname (** Locations for the visible part of the installation *) (** Default config *) module Default : sig (** Library path for a given package: {i $prefix/lib/$name} *) val lib: t -> switch -> name -> dirname (** Library path: {i $prefix/lib} *) val lib_dir: t -> switch -> dirname (** DLL paths *) val stublibs: t -> switch -> dirname (** toplevel path: {i $prefix/lib/toplevel} *) val toplevel: t -> switch -> dirname (** Documentation path for a given package: {i $prefix/doc/$name} *) val doc: t -> switch -> name -> dirname (** Documentation path: {i $prefix/doc/} *) val doc_dir: t -> switch -> dirname (** Shared directory: {i $prefix/share} *) val share_dir: t -> switch -> dirname (** Share directory for a given package: {i $prefix/share/$package} *) val share: t -> switch -> name -> dirname (** Etc directory: {i $prefix/etc} *) val etc_dir: t -> switch -> dirname (** Etc directory for a given package: {i $prefix/etc/$package} *) val etc: t -> switch -> name -> dirname (** Man pages path: {i $prefix/man/}. The optional [num] argument will add a {i manN } suffix if specified *) val man_dir: ?num:string -> t -> switch -> dirname (** Installed binaries: {i $prefix/bin} *) val bin: t -> switch -> dirname (** Installed system binaries: {i $prefix/sbin} *) val sbin: t -> switch -> dirname end (** Fuctorised version of Default, for replicating a switch's layout in non-switch contexts *) module DefaultF : functor (L:LAYOUT) -> sig val lib: t -> L.ctx -> name -> dirname val lib_dir: t -> L.ctx -> dirname val stublibs: t -> L.ctx -> dirname val toplevel: t -> L.ctx -> dirname val doc: t -> L.ctx -> name -> dirname val doc_dir: t -> L.ctx -> dirname val share_dir: t -> L.ctx -> dirname val share: t -> L.ctx -> name -> dirname val etc_dir: t -> L.ctx -> dirname val etc: t -> L.ctx -> name -> dirname val man_dir: ?num:string -> t -> L.ctx -> dirname val bin: t -> L.ctx -> dirname val sbin: t -> L.ctx -> dirname end (** Actual config handling the global-config.config indirections *) (** Package-independent dirs *) val get_stdpath: t -> switch -> OpamFile.Switch_config.t -> std_path -> dirname (** Library path: {i $prefix/lib} *) val lib_dir: t -> switch -> OpamFile.Switch_config.t -> dirname (** DLL paths *) val stublibs: t -> switch -> OpamFile.Switch_config.t -> dirname (** toplevel path: {i $prefix/lib/toplevel} *) val toplevel: t -> switch -> OpamFile.Switch_config.t -> dirname (** Documentation path: {i $prefix/doc/} *) val doc_dir: t -> switch -> OpamFile.Switch_config.t -> dirname (** Shared directory: {i $prefix/share} *) val share_dir: t -> switch -> OpamFile.Switch_config.t -> dirname (** Etc directory: {i $prefix/etc} *) val etc_dir: t -> switch -> OpamFile.Switch_config.t -> dirname (** Man pages path: {i $prefix/man/}. The optional [num] argument will add a {i manN } suffix if specified *) val man_dir: ?num:string -> t -> switch -> OpamFile.Switch_config.t -> dirname (** Installed binaries: {i $prefix/bin} *) val bin: t -> switch -> OpamFile.Switch_config.t -> dirname (** Installed system binaries: {i $prefix/sbin} *) val sbin: t -> switch -> OpamFile.Switch_config.t -> dirname (** Package dependent dirs *) (** Library path for a given package: {i $prefix/lib/$name} *) val lib: t -> switch -> OpamFile.Switch_config.t -> name -> dirname (** Documentation path for a given package: {i $prefix/doc/$name} *) val doc: t -> switch -> OpamFile.Switch_config.t -> name -> dirname (** Share directory for a given package: {i $prefix/share/$package} *) val share: t -> switch -> OpamFile.Switch_config.t -> name -> dirname (** Etc directory for a given package: {i $prefix/etc/$package} *) val etc: t -> switch -> OpamFile.Switch_config.t -> name -> dirname module Overlay: sig (** Switch metadata overlay (over the global metadata): {i $meta/overlay/} *) val dir: t -> switch -> dirname (** Switch metadata overlay (over the global metadata): {i $meta/overlay/$name.$version} *) val package: t -> switch -> name -> dirname (** OPAM overlay: {i $meta/overlay/$name.$version/opam} *) val opam: t -> switch -> name -> OpamFile.OPAM.t OpamFile.t (** OPAM temp overlay (for user editing): {i $meta/overlay/$name.$version/opam_} *) val tmp_opam: t -> switch -> name -> OpamFile.OPAM.t OpamFile.t (** URL overlay: {i $meta/overlay/$name.$version/url} *) val url: t -> switch -> name -> OpamFile.URL.t OpamFile.t (** Descr orverlay *) val descr: t -> switch -> name -> OpamFile.Descr.t OpamFile.t (** Files overlay *) val files: t -> switch -> name -> dirname end end (** Location of package-specific files relative to their build directory *) module Builddir: sig (** package.install file: {i $builddir/$name.install} *) val install: dirname -> package -> OpamFile.Dot_install.t OpamFile.t (** package.config file: {i $builddir/$name.config} *) val config: dirname -> package -> OpamFile.Dot_config.t OpamFile.t end opam-2.1.5/src/format/opamTypesBase.ml0000644000175000017500000001443614427463453016714 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamParserTypes.FullPos open OpamTypes include OpamCompat let std_path_of_string = function | "prefix" -> Prefix | "lib" -> Lib | "bin" -> Bin | "sbin" -> Sbin | "share" -> Share | "doc" -> Doc | "etc" -> Etc | "man" -> Man | "toplevel" -> Toplevel | "stublibs" -> Stublibs | _ -> failwith "Wrong standard path" let string_of_std_path = function | Prefix -> "prefix" | Lib -> "lib" | Bin -> "bin" | Sbin -> "sbin" | Share -> "share" | Doc -> "doc" | Etc -> "etc" | Man -> "man" | Toplevel -> "toplevel" | Stublibs -> "stublibs" let all_std_paths = [ Prefix; Lib; Bin; Sbin; Share; Doc; Etc; Man; Toplevel; Stublibs ] let string_of_shell = function | SH_fish -> "fish" | SH_csh -> "csh" | SH_zsh -> "zsh" | SH_sh -> "sh" | SH_bash -> "bash" let file_null = "" let pos_file filename = { filename = OpamFilename.to_string filename; start = -1, -1; stop = -1, -1; } let pos_null = { filename = file_null; start = -1, -1; stop = -1, -1; } let nullify_pos pelem = {pelem; pos = pos_null} (* XXX update *) let pos_best pos1 pos2 = match pos1, pos2 with | { filename = ""; _ }, _ -> pos2 | _, { filename = ""; _ } -> pos1 | { start = (-1,_) ; _ }, _ -> pos2 | _, { start = (-1,_) ; _ } -> pos1 | _, _ -> pos1 (* if f1 = file_null then pos2 else if f2 = file_null then pos1 else if col1 = -1 then pos2 else pos1 *) let string_of_pos pos = let check x = if x >= 0 then string_of_int x else "-" in Printf.sprintf "%s:%s:%s-%s:%s:" pos.filename (check (fst pos.start)) (check (snd pos.start)) (check (fst pos.stop)) (check (snd pos.stop)) let string_of_user_action = function | Query -> "query" | Install -> "install" | Upgrade -> "upgrade" | Reinstall -> "reinstall" | Remove -> "remove" | Switch -> "switch" | Import -> "import" (* Command line arguments *) let env_array l = (* The env list may contain successive bindings of the same variable, make sure to keep only the last *) let bindings = List.fold_left (fun acc (k,v,_) -> OpamStd.String.Map.add k v acc) OpamStd.String.Map.empty l in let a = Array.make (OpamStd.String.Map.cardinal bindings) "" in OpamStd.String.Map.fold (fun k v i -> a.(i) <- String.concat "=" [k;v]; succ i) bindings 0 |> ignore; a let string_of_filter_ident (pkgs,var,converter) = OpamStd.List.concat_map ~nil:"" "+" ~right:":" (function None -> "_" | Some n -> OpamPackage.Name.to_string n) pkgs ^ OpamVariable.to_string var ^ (match converter with | Some (it,ifu) -> "?"^it^":"^ifu | None -> "") let filter_ident_of_string s = match OpamStd.String.rcut_at s ':' with | None -> [], OpamVariable.of_string s, None | Some (p,last) -> let get_names s = List.map (function "_" -> None | s -> Some (OpamPackage.Name.of_string s)) (OpamStd.String.split s '+') in match OpamStd.String.rcut_at p '?' with | None -> get_names p, OpamVariable.of_string last, None | Some (p,val_if_true) -> let converter = Some (val_if_true, last) in match OpamStd.String.rcut_at p ':' with | None -> [], OpamVariable.of_string p, converter | Some (packages,var) -> get_names packages, OpamVariable.of_string var, converter let all_package_flags = [ Pkgflag_LightUninstall; (* Pkgflag_AllSwitches; This has no "official" existence yet and does nothing *) Pkgflag_Verbose; Pkgflag_Plugin; Pkgflag_Compiler; Pkgflag_Conf; ] let string_of_pkg_flag = function | Pkgflag_LightUninstall -> "light-uninstall" | Pkgflag_Verbose -> "verbose" | Pkgflag_Plugin -> "plugin" | Pkgflag_Compiler -> "compiler" | Pkgflag_Conf -> "conf" | Pkgflag_AvoidVersion -> "avoid-version" | Pkgflag_Unknown s -> s let pkg_flag_of_string = function | "light-uninstall" -> Pkgflag_LightUninstall | "verbose" -> Pkgflag_Verbose | "plugin" -> Pkgflag_Plugin | "compiler" -> Pkgflag_Compiler | "conf" -> Pkgflag_Conf | "avoid-version" -> Pkgflag_AvoidVersion | s -> Pkgflag_Unknown s let action_contents = function | `Remove p | `Install p | `Reinstall p | `Build p | `Fetch p -> p | `Change (_,_,p) -> p let full_action_contents = function | `Remove p | `Install p | `Reinstall p | `Build p | `Fetch p -> [p] | `Change (_,p1,p2) -> [p1; p2] let map_atomic_action f = function | `Remove p -> `Remove (f p) | `Install p -> `Install (f p) let map_highlevel_action f = function | #atomic_action as a -> map_atomic_action f a | `Change (direction, p1, p2) -> `Change (direction, f p1, f p2) | `Reinstall p -> `Reinstall (f p) let map_concrete_action f = function | #atomic_action as a -> map_atomic_action f a | `Build p -> `Build (f p) | `Fetch p -> `Fetch (f p) let map_action f = function | #highlevel_action as a -> map_highlevel_action f a | #concrete_action as a -> map_concrete_action f a let string_of_cause to_string = let list_to_string l = match List.map to_string l with | a::b::c::_::_::_ -> Printf.sprintf "%s, %s, %s, etc." a b c | l -> String.concat ", " l in function | Upstream_changes -> "upstream or system changes" | Use pkgs -> Printf.sprintf "uses %s" (list_to_string pkgs) | Required_by pkgs -> Printf.sprintf "required by %s" (list_to_string pkgs) | Conflicts_with pkgs -> Printf.sprintf "conflicts with %s" (list_to_string pkgs) | Requested -> "" | Unknown -> "" let map_success f = function | Success x -> Success (f x) | Conflicts c -> Conflicts c let iter_success f = function | Success x -> f x | Conflicts _ -> () opam-2.1.5/src/format/opamFormat.ml0000644000175000017500000007653714427463453016257 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamParserTypes.FullPos open OpamTypes open OpamTypesBase open OpamStd.Op open OpamPp open OpamPp.Op let item_pos (i: opamfile_item) = i.pos let value_pos (v: value) = v.pos let values_pos = function | [] -> None | x::_ -> Some (value_pos x) let optelem = OpamStd.Option.map (fun x -> x.pelem) let nullposelem = OpamStd.Option.map nullify_pos (** low-level Pps for the Lines parser ([string list list]) *) type lines = string list list let lines_set ~empty ~add ~fold pp1 = pp ~name:(Printf.sprintf "(%s) lines" pp1.ppname) (fun ~pos lines -> List.fold_left (fun (i,acc) -> function | [] -> i + 1, acc | line -> (* XXX POSCHECK *) let pos = { pos with start = i,0 ; stop = i,0 } in i + 1, add (parse pp1 ~pos line) acc) (1, empty) lines |> snd) (fun x -> List.rev (fold (fun v acc -> print pp1 v::acc) x [])) let lines_map ~empty ~add ~fold pp1 = pp ~name:(Printf.sprintf "(%s) lines" pp1.ppname) (fun ~pos lines -> List.fold_left (fun (i,acc) -> function | [] -> i + 1, acc | line -> let pos = { pos with start = i,0 ; stop = i,0 } in (* XXX POSCHECK *) let k,v = parse pp1 ~pos line in i + 1, add k v acc) (1, empty) lines |> snd) (fun x -> List.rev (fold (fun k v acc -> print pp1 (k,v)::acc) x [])) (* let list2 pp1 pp2 = pp ~name:(Printf.sprintf "%s %s" pp1.ppname pp2.ppname) (function [a; b] -> parse pp1 a, parse pp2 b | _ -> unexpected ()) (fun (x,y) -> [print pp1 x; print pp2 y]) *) (** All Pps dealing with the [value] type *) module V = struct (** Low-level Pps *) let bool = pp ~name:"bool" (fun ~pos:_ v -> match v.pelem with Bool b -> b | _ -> unexpected ()) (fun b -> nullify_pos (Bool b)) let int = pp ~name:"int" (fun ~pos:_ v -> match v.pelem with Int i -> i | _ -> unexpected ()) (fun i -> nullify_pos (Int i)) let pos_int = int -| check ~name:"positive-int" (fun i -> i >= 0) let ident = pp ~name:"ident" (fun ~pos:_ v -> match v.pelem with Ident i -> i | _ -> unexpected ()) (fun str -> nullify_pos (Ident str)) let string = pp ~name:"string" (fun ~pos:_ v -> match v.pelem with String s -> s | _ -> unexpected ()) (fun str -> nullify_pos (String str)) let string_tr = string -| pp (fun ~pos:_ -> OpamStd.String.strip) (fun x -> x) let simple_arg = pp ~name:"ident-or-string" (fun ~pos:_ v -> match v.pelem with | Ident i -> CIdent i | String s -> CString s | _ -> unexpected ()) (function | CIdent i -> nullify_pos (Ident i) | CString s -> nullify_pos (String s)) let variable_contents = pp ~name:"string-or-stringlist-or-bool" (fun ~pos:_ v -> match v.pelem with | String s -> S s | Bool b -> B b | List l -> L (List.map (fun v -> match v.pelem with String s -> s | _ -> unexpected ()) l.pelem) | _ -> unexpected ()) (function | S s -> nullify_pos (String s) | B b -> nullify_pos (Bool b) | L l -> nullify_pos (List (nullify_pos (List.map (fun s -> nullify_pos (String s)) l)))) let list = pp ~name:"list" ~name_constr:(Printf.sprintf "[%s]") (fun ~pos:_ v -> match v.pelem with | List l -> l.pelem | _ -> [v]) (fun l -> nullify_pos (List (nullify_pos l))) let group = pp ~name:"group" ~name_constr:(Printf.sprintf "(%s)") (fun ~pos:_ v -> match v.pelem with | Group l -> l.pelem | _ -> [v]) (fun l -> nullify_pos (Group (nullify_pos l))) let option = pp ~name:"option" (fun ~pos:_ v -> match v.pelem with | Option (k,l) -> k, l.pelem | _ -> v, []) (function | (v, []) -> v | (v, l) -> nullify_pos (Option (v, nullify_pos l))) let option_strict = pp ~name:"option" (fun ~pos v -> match v.pelem with | Option (k,l) -> k, l.pelem | _ -> bad_format ~pos "Expected an option") (function (v, l) -> nullify_pos (Option (v, nullify_pos l))) let map_group pp1 = group -| map_list ~posf:value_pos pp1 let list_depth expected_depth = let rec depth v = match v.pelem with | List { pelem = []; _} -> 1 | List { pelem = v::_; _} -> 1 + depth v | Option (v,_) -> depth v | _ -> 0 in let rec wrap n v = if n <= 0 then v else wrap (n-1) (nullify_pos (List (nullify_pos [v]))) in let rec lift n v = if n <= 0 then v else match v.pelem with | List { pelem = [v]; _} -> lift (n-1) v | _ -> v in pp (fun ~pos:_ v -> wrap (expected_depth - depth v) v) (fun v -> lift expected_depth v) let option_depth expected_depth = let rec depth = function | { pelem = Option (v,_); _} -> 1 + depth v | _ -> 0 in let rec wrap n v = if n <= 0 then v else wrap (n-1) (nullify_pos (Option (v, nullify_pos []))) in let rec lift n v = if n <= 0 then v else match v.pelem with | Option (v, {pelem = []; _}) -> lift (n-1) v | _ -> v in pp (fun ~pos:_ v -> wrap (expected_depth - depth v) v) (fun v -> lift expected_depth v) let map_list ?(depth=0) pp1 = list_depth depth -| pp ~name:(Printf.sprintf "[%s]" pp1.ppname) (fun ~pos:_ v -> match v.pelem with | List l -> List.rev @@ List.rev_map (fun v -> parse pp1 ~pos:(value_pos v) v) l.pelem | _ -> unexpected ()) (fun l -> nullify_pos (List (nullify_pos @@ List.rev @@ List.rev_map (print pp1) l))) let map_option_contents pp1 pp2 = map_pair ~name:(Printf.sprintf "%s ?{%s}" pp1.ppname pp2.ppname) ~posf1:value_pos ~posf2:(fun v -> OpamStd.Option.default pos_null (values_pos v)) pp1 pp2 let map_option pp1 pp2 = option -| map_option_contents pp1 pp2 let map_options_2 pp1 pp2 pp3 = option_depth 2 -| option_strict -| map_option_contents (option_strict -| map_option_contents pp1 pp2) pp3 -| pp (fun ~pos:_ ((a,b),c) -> a,b,c) (fun (a,b,c) -> (a,b),c) let map_options_3 pp1 pp2 pp3 pp4 = option_depth 3 -| option_strict -| map_option_contents (option_strict -| map_option_contents (option_strict -| map_option_contents pp1 pp2) pp3) pp4 -| pp (fun ~pos:_ (((a,b),c),d) -> a,b,c,d) (fun (a,b,c,d) -> ((a,b),c),d) let map_pair pp1 pp2 = pp ~name:(Printf.sprintf "[%s %s]" pp1.ppname pp2.ppname) (fun ~pos:_ v -> match v.pelem with | List { pelem = [a; b]; _} -> parse pp1 ~pos:(value_pos a) a, parse pp2 ~pos:(value_pos b) b | _ -> unexpected ()) (fun (a, b) -> nullify_pos @@ List (nullify_pos @@ [pp1.print a; pp2.print b])) let map_triple pp1 pp2 pp3 = pp ~name:(Printf.sprintf "[%s %s %s]" pp1.ppname pp2.ppname pp3.ppname) (fun ~pos:_ v -> match v.pelem with | List { pelem = [a; b; c]; _} -> parse pp1 ~pos:(value_pos a) a, parse pp2 ~pos:(value_pos b) b, parse pp3 ~pos:(value_pos c) c | _ -> unexpected ()) (fun (a, b, c) -> nullify_pos @@ List (nullify_pos @@ [pp1.print a; pp2.print b; pp3.print c])) (** Pps for the [value] type to higher level types *) let url = string -| of_module "url" (module OpamUrl) let url_with_backend backend = string -| pp ~name:"url" (fun ~pos:_ s -> OpamUrl.parse ~backend ~handle_suffix:false s) (fun url -> OpamUrl.to_string url) (* a hack to allow "system" compiler as ident rather than string. For backwards-compat. Deprecated, for migration only *) let compiler_version = let system_compiler = "system" in let parse ~pos:_ = fun v -> match v.pelem with | Ident v when v = system_compiler -> v | String v -> v | _ -> unexpected () in let print v = if v = system_compiler then print ident v else print string v in pp ~name:"compiler-version" parse print let filter_ident = ident -| pp ~name:"filter-ident" (fun ~pos:_ -> filter_ident_of_string) string_of_filter_ident let filter = let rec parse_filter ~pos l = let rec aux = fun v -> match v.pelem with | Bool b -> FBool b | String s -> FString s | Int i -> FString (string_of_int i) | Ident _ -> FIdent (parse ~pos:v.pos filter_ident v) | Group g -> parse_filter ~pos:v.pos g.pelem | Relop (op,e,f) -> FOp (aux e, op.pelem, aux f) | Pfxop ({ pelem = `Not; _}, e) -> FNot (aux e) | Pfxop ({ pelem = `Defined; _}, e) -> FDefined (aux e) | Logop ({ pelem = `And; _}, e, f)-> FAnd (aux e, aux f) | Logop ({ pelem = `Or; _}, e, f)-> FOr (aux e, aux f) | _ -> unexpected () in match l with | [] -> FBool true | [{ pelem = Group { pelem = [] | _::_::_ ; _}; _}] | _::_::_ -> bad_format ~pos "expected a single filter expression" | [{ pelem = Group { pelem = [f]; _}; _}] | [f] -> aux f in let print_filter f = let rec aux ?(context=`Or) f = let group_if ?(cond=false) f = if cond || OpamFormatConfig.(!r.all_parens) then nullify_pos @@ Group (nullify_pos [f]) else f in match f with | FString s -> print string s | FIdent fid -> print filter_ident fid | FBool b -> print bool b | FOp (e,s,f) -> group_if ~cond:(context <> `Or && context <> `And) @@ nullify_pos @@ Relop (nullify_pos s, aux ~context:`Relop e, aux ~context:`Relop f) | FOr (e,f) -> group_if ~cond:(context <> `Or) @@ nullify_pos @@ Logop (nullify_pos `Or, aux ~context:`Or e, aux ~context:`Or f) | FAnd (e,f) -> group_if ~cond:(context <> `Or && context <> `And) @@ nullify_pos @@ Logop (nullify_pos `And, aux ~context:`And e, aux ~context:`And f) | FNot f -> group_if ~cond:(context = `Relop) @@ nullify_pos @@ Pfxop (nullify_pos `Not, aux ~context:`Not f) | FDefined f -> group_if ~cond:(context = `Relop) @@ nullify_pos @@ Pfxop (nullify_pos `Defined, aux ~context:`Defined f) | FUndef _ -> assert false in match f with | FBool true -> [] | f -> [aux f] in pp ~name:"filter-expression" parse_filter print_filter let arg = map_option simple_arg (opt filter) let command = map_option (map_list arg) (opt filter) let constraints version = let rec parse_constraints ~pos:_ l = let rec aux v = match v.pelem with | Prefix_relop (op, v) -> Atom (op.pelem, parse version ~pos:v.pos v) | Logop ({ pelem = `And; _}, l, r) -> And (aux l, aux r) | Logop ({ pelem = `Or; _}, l, r) -> Or (aux l, aux r) | Pfxop ({ pelem = `Not; _}, v) -> OpamFormula.neg (fun (op, s) -> (OpamFormula.neg_relop op, s)) (aux v) | Group g -> Block (parse_constraints ~pos:v.pos g.pelem) | _ -> unexpected ~pos:(value_pos v) () in OpamFormula.ands (List.map aux l) in let rec print_constraints cs = let rec aux ?(in_and=false) cs = let group_if ?(cond=false) f = if cond || OpamFormatConfig.(!r.all_parens) then nullify_pos @@ Group (nullify_pos [f]) else f in match cs with | Empty -> assert false | Atom (r, v) -> group_if @@ nullify_pos @@ Prefix_relop (nullify_pos r, print version v) | And (x, y) -> group_if @@ nullify_pos @@ Logop (nullify_pos `And, aux ~in_and:true x, aux ~in_and:true y) | Or (x, y) -> group_if ~cond:in_and @@ nullify_pos @@ Logop (nullify_pos `Or, aux x, aux y) | Block g -> nullify_pos @@ Group (nullify_pos @@ print_constraints g) in match cs with | Empty -> [] | cs -> [aux cs] in pp ~name:(version.ppname ^ "-constraints") parse_constraints print_constraints let filtered_constraints version = let rec parse_cs ~pos:_ items = let rec aux_parse v = match v.pelem with | Prefix_relop (op, v) -> Atom (Constraint (op.pelem, parse version ~pos:v.pos v)) | Logop ({ pelem = `And; _}, a, b) -> OpamFormula.ands [aux_parse a; aux_parse b] | Logop ({ pelem = `Or; _}, a, b) -> OpamFormula.ors [aux_parse a; aux_parse b] | Group g -> OpamFormula.Block (parse_cs ~pos:v.pos g.pelem) | Pfxop ({ pelem = `Not; _}, v') -> parse_cs ~pos:v.pos [v'] |> OpamFormula.neg (function | Constraint (op, v) -> Constraint (OpamFormula.neg_relop op, v) | Filter f -> Filter (FNot f)) | _ -> Atom (Filter (filter.parse ~pos:(value_pos v) [v])) in OpamFormula.ands (List.map aux_parse items) in let rec print_cs cs = (* form -> val list *) let rec aux ?(in_and=false) cs = let group_if ?(cond=false) f = if cond || OpamFormatConfig.(!r.all_parens) then nullify_pos @@ Group (nullify_pos [f]) else f in match cs with | Empty -> assert false | And (x, y) -> group_if @@ nullify_pos @@ Logop (nullify_pos `And, aux ~in_and:true x, aux ~in_and:true y) | Or (x, y) -> group_if ~cond:in_and @@ nullify_pos @@ Logop (nullify_pos `Or, aux x, aux y) | Block g -> nullify_pos @@ Group (nullify_pos @@ print_cs g) | Atom (Constraint (op,v)) -> group_if @@ nullify_pos @@ Prefix_relop (nullify_pos op, print version v) | Atom (Filter flt) -> (match filter.print flt with | f1::fr -> group_if (List.fold_left (fun a b -> nullify_pos @@ Logop (nullify_pos `And, a, b)) f1 fr) | [] -> nullify_pos @@ Group (nullify_pos [])) in match cs with | Empty -> [] | cs -> [aux cs] in pp ~name:"filtered-constraints" parse_cs print_cs let version = string -| of_module "version" (module OpamPackage.Version) let ext_version = pp ~name:"version-expr" (fun ~pos:_ v -> match v.pelem with | String s -> let _ = try OpamPackage.Version.of_string (OpamFilter.expand_string (fun _ -> Some (S "-")) s) with Failure msg -> bad_format ~pos:v.pos "Invalid version string %S: %s" s msg in FString s | Ident s -> FIdent (filter_ident_of_string s) | _ -> unexpected ()) (function | FString s -> nullify_pos (String s) | FIdent id -> nullify_pos @@ Ident (string_of_filter_ident id) | _ -> assert false) let pkgname = string -| of_module "pkg-name" (module OpamPackage.Name) let package_atom constraints = map_option pkgname constraints (* These two functions are duplicated from [OpamFormula] but we need to have a it here because of a change on [Block] handling: to have a coherent printing, we must not always discard them *) let rec ands_to_list = function | Empty -> [] | And (e,f) -> List.rev_append (rev_ands_to_list e) (ands_to_list f) | x -> [x] and rev_ands_to_list = function | Empty -> [] | And (e,f) -> List.rev_append (ands_to_list f) (rev_ands_to_list e) | x -> [x] let rec ors_to_list = function | Empty -> [] | Or (e,f) | Block (Or (e,f)) -> List.rev_append (rev_ors_to_list e) (ors_to_list f) | x -> [x] and rev_ors_to_list = function | Empty -> [] | Or (e,f) | Block (Or (e,f)) -> List.rev_append (ors_to_list f) (rev_ors_to_list e) | x -> [x] let package_formula_items kind constraints = let split, join = match kind with | `Conj -> ands_to_list, OpamFormula.ands | `Disj -> ors_to_list, OpamFormula.ors in let rec parse_formula ~pos:_ l = let rec aux v = match v.pelem with | String _ | Option (_,_) -> Atom (parse (package_atom constraints) ~pos:v.pos v) | Group g -> Block (parse_formula ~pos:v.pos g.pelem) | Logop ({ pelem = `Or; _}, e1, e2) -> let left = aux e1 in Or (left, aux e2) | Logop ({ pelem = `And; _}, e1, e2) -> let left = aux e1 in And (left, aux e2) | _ -> unexpected ~pos:(value_pos v) () in join (List.map aux l) in let rec print_formula ?(inner=false) f = let rec aux ?(in_and=false) f = let group_if ?(cond=false) f = if cond || OpamFormatConfig.(!r.all_parens) then nullify_pos @@ Group (nullify_pos [f]) else f in match f with | Empty -> assert false | Block f -> nullify_pos @@ Group (nullify_pos @@ print_formula ~inner:true f) | And (e,f) -> group_if @@ nullify_pos @@ Logop (nullify_pos `And, aux ~in_and:true e, aux ~in_and:true f) | Or (e,f) -> group_if ~cond:in_and @@ nullify_pos @@ Logop (nullify_pos `Or, aux e, aux f) | Atom at -> group_if (print (package_atom constraints) at) in let fl = if inner then [f] else split f in List.map (aux ~in_and:false) fl in pp ~name:"pkg-formula" parse_formula print_formula let package_formula kind constraints = list -| package_formula_items kind constraints let env_binding = let parse ~pos:_ v = match v.pelem with | Relop ({ pelem = `Eq;_}, { pelem = Ident i;_}, { pelem = String s;_}) -> i, OpamParserTypes.Eq, s, None | Env_binding ({ pelem = Ident i; _}, op, { pelem = String s; _}) -> i, op.pelem, s, None | _ -> unexpected () in let print (id, op, str, _) = nullify_pos @@ Env_binding (print ident id, nullify_pos op, print string str) in list -| singleton -| pp ~name:"env-binding" parse print (* Only used by the deprecated "os" field *) let os_constraint = let rec parse_osc ~pos:_ l = let rec aux v = match v.pelem with | Group g -> Block (parse_osc ~pos:g.pos g.pelem) | String os -> Atom (true, os) | Logop ({ pelem = `And; _}, l, r) -> And (aux l, aux r) | Logop ({ pelem = `Or; _}, l, r) -> Or (aux l, aux r) | Pfxop ({ pelem = `Not; _}, v) -> OpamFormula.neg (fun (b, s) -> (not b, s)) (aux v) | _ -> unexpected ~pos:(value_pos v) () in OpamFormula.ors (List.map aux l) in let print_osc f = let rec aux = function | Empty -> assert false | Atom (true , os) -> print string os | Atom (false, os) -> nullify_pos @@ Pfxop (nullify_pos `Not, print string os) | Block g -> nullify_pos @@ Group (nullify_pos [aux g]) | And (e,f) -> nullify_pos @@ Logop (nullify_pos `And, aux e, aux f) | Or (e,f) -> nullify_pos @@ Logop (nullify_pos `Or, aux e, aux f) in match f with | Empty -> [] | f -> [aux f] in list -| pp ~name:"os-constraint" parse_osc print_osc end (** Parsers for item lists (standard opam file contents: list of field bindings). *) module I = struct let file = pp ~name:"opam-file" (fun ~pos:_ file -> OpamFilename.of_string file.file_name, file.file_contents) (fun (file_name, file_contents) -> { file_name = OpamFilename.to_string file_name; file_contents }) let map_file pp1 = file -| map_snd pp1 let item = pp ~name:"field-binding" (fun ~pos:_ v -> match v.pelem with | Section (sec) -> bad_format ~pos:v.pos "Unexpected section %s" sec.section_kind.pelem | Variable (k,v) -> k.pelem, v) (fun (k,v) -> nullify_pos @@ Variable (nullify_pos k, v)) let items = map_list ~posf:item_pos item let anonymous_section pp1 = pp ~name:pp1.ppname (fun ~pos -> function | [ None, contents ] -> pp1.parse ~pos contents | [ Some _, _ ] -> bad_format ~pos "Unexpected section title" | [] -> bad_format ~pos "Missing section" | _::_::_ -> bad_format ~pos "Duplicate section") (fun l -> [None, pp1.print l]) let section kind = pp ~name:"file-section" (fun ~pos:_ v -> match v.pelem with | Section ({section_kind; _} as s) when section_kind.pelem = kind -> optelem s.section_name, s.section_items.pelem | Section sec -> bad_format ~pos:v.pos "Unexpected section %s" sec.section_kind.pelem | Variable (k,_) -> bad_format ~pos:v.pos "Unexpected field %s" k.pelem) (fun (name, items) -> nullify_pos @@ Section { section_kind = nullify_pos kind; section_name = nullposelem name; section_items = nullify_pos items }) type ('a, 'value) fields_def = (string * ('a, 'value) field_parser) list let fields ?name ~empty ?(sections=[]) ?(mandatory_fields=[]) ppas = let parse ~pos items = (* For consistency, always read fields in ppa order, ignoring file order. Some parsers may depend on it. *) let module SEM = OpamStd.Map.Make(struct type t = string * string option let compare = compare let to_string (s,o) = s ^ OpamStd.Option.to_string ((^) "^") o let to_json (s,o) = `O (("kind", `String s) :: match o with None -> [] | Some s -> ["name", `String s]) (* these serializers/deserializers are not accessible from the OpamFormat.mli interface, so there are not currently tested -- it's not clear if usage of the SEM functor touches them in any way... *) let of_json = function | `O dict -> begin try match List.assoc "kind" dict with | `String s -> begin let o = if not (List.mem_assoc "name" dict) then None else match List.assoc "name" dict with | `String s -> Some s | _ -> raise Not_found in Some (s, o) end | _ -> raise Not_found with Not_found -> None end | _ -> None end) in (* XXX trasnform field map into set *) let errs, section_map, field_map = List.fold_left (fun (errs, section_map, field_map) it -> match it.pelem with | Section sec -> let k = sec.section_kind.pelem in let v = sec.section_items.pelem in let n = optelem sec.section_name in if List.mem_assoc k sections then try errs, SEM.safe_add (k, n) (pos,v) section_map, field_map with Failure _ -> (k,(Some pos,"Duplicate section "^k)) :: errs, section_map, field_map else (k,(Some pos,"Invalid section "^k)) :: errs, section_map, field_map | Variable (k, v) -> let k = k.pelem in let v = v.pelem in let pos = it.pos in if List.mem_assoc k ppas then try errs, section_map, OpamStd.String.Map.safe_add k (pos,v) field_map with Failure _ -> (k,(Some pos,"Duplicate field "^k)) :: errs, section_map, field_map else (k,(Some pos,"Invalid field "^k))::errs, section_map, field_map) ([], SEM.empty, OpamStd.String.Map.empty) items in let errs, r = List.fold_left (fun (errs,acc) (field,ppa) -> try let pos, v = OpamStd.String.Map.find field field_map in try errs, parse ppa ~pos (acc, Some { pelem = v; pos }) with | Bad_format (pos, msg) -> (field, (pos, msg)) :: errs, acc with Not_found -> (if List.mem field mandatory_fields then (field, (Some pos, "Missing field "^field)) :: errs else errs), acc) (errs, empty) ppas in let errs, r = List.fold_left (fun (errs,acc) (section_kind, ppa) -> let secs = SEM.fold (fun (kind, name) (_, items) acc -> if kind = section_kind then (name, items) :: acc else acc) section_map [] |> List.rev in if secs = [] then errs, acc else try errs, parse ppa ~pos (acc, Some secs) with | Bad_format (pos, msg) -> (section_kind,(pos, msg)) :: errs, acc) (errs, r) sections in r, errs in let print (acc, _) = OpamStd.List.filter_map (fun (field,ppa) -> match snd (ppa.print acc) with | None | Some ({ pelem = List { pelem = []; _}; _} | { pelem = Group { pelem = []; _}; _}) -> None | Some value -> Some (nullify_pos @@ Variable (nullify_pos field, value))) ppas @ (List.flatten @@ List.map (fun (kind, ppa) -> OpamStd.Option.default [] (snd (ppa.print acc)) |> List.map (fun (name, items) -> nullify_pos @@ Section { section_kind = nullify_pos kind; section_name = nullposelem name; section_items = nullify_pos items })) sections) in pp ?name parse print let show_errors ?name ?(strict=OpamFormatConfig.(!r.strict)) ?(condition=fun _ -> true) () = let parse ~pos (t, errs) = let file = pos.filename in if errs = [] then t else if strict then raise (Bad_format_list (List.rev_map snd errs)) else (if condition t then OpamConsole.warning "Errors in %s, some fields have been ignored:\n%s" file (OpamStd.Format.itemize (fun e -> OpamPp.string_of_bad_format (Bad_format e)) (List.rev_map snd errs)) else OpamConsole.log "FORMAT" "File errors in %s, ignored fields: %s" file (OpamStd.List.concat_map "; " (fun e -> OpamPp.string_of_bad_format (Bad_format e)) (List.rev_map snd errs)); t) in let print t = t, [] in pp ?name parse print let on_errors ?name f = let parse ~pos:_ (t, errs) = List.fold_left f t errs in let print t = (t, []) in pp ?name parse print let partition filter = pp (fun ~pos:_ -> List.partition filter) (fun (a,b) -> a @ b) let partition_fields ?(section=false) filter = partition @@ fun v -> match v.pelem with | Variable (k,_) -> filter k.pelem | Section _ -> section let field name parse = pp (fun ~pos items -> match OpamStd.List.filter_map (fun v -> match v.pelem with | Variable (k,v) when k.pelem = name -> Some v | _ -> None) items with | [] -> None, items | _::_::_ -> bad_format ~pos "Duplicate '%s:' field" name | [v] -> Some (parse ~pos v), items) snd let extract_field name = partition_fields ((=) name) -| (map_fst @@ opt @@ singleton -| item -| pp ~name:(Printf.sprintf "'%s:' field" name) (fun ~pos:_ (_,v) -> v) (fun v -> name,v)) let check_opam_version ?(optional=false) ~format_version ?(f=fun v -> OpamVersion.(compare format_version (nopatch v) >= 0)) () = let name = "opam-version" in let opam_v = V.string -| of_module name (module OpamVersion) in let f v = OpamFormatConfig.(!r.skip_version_checks) || match v with | Some v -> f v | None -> optional in let errmsg = Printf.sprintf "unsupported or missing file format version; should be %s or older" (OpamVersion.to_string format_version) in field name (parse opam_v) -| map_fst (check ~name ~raise:OpamPp.bad_version ~errmsg f) -| pp ~name (fun ~pos:_ (_,x) -> x) (fun x -> (* re-extract the field using parse when printing, to check that it is not undefined *) match parse ~pos:pos_null (field name (parse opam_v)) x with | None, _ -> failwith "opam version must be printed" | v, l -> v, l) let opam_version ?(undefined=false) ~format_version () = let name = "opam-version" in pp (fun ~pos:_ items -> if not undefined then items else List.filter (function | { pelem = Variable ({ pelem = fname; _}, { pelem = String _version; _}); _} when fname = name -> (* check opam version already called, we don't need to check that it is the same version *) false | _ -> true) items) (fun items -> let opam_v = V.string -| of_module name (module OpamVersion) in match parse ~pos:pos_null (field name (parse opam_v)) items with | None, items -> let opam_v = nullify_pos @@ Variable (nullify_pos name, nullify_pos @@ String (OpamVersion.to_string format_version)) in opam_v :: items | Some _, items -> items) type signature = string * string * string let signature = V.list -| (V.string ^+ V.string ^+ last -| V.string) -| pp (fun ~pos:_ (a,(b,c)) -> a,b,c) (fun (a,b,c) -> a,(b,c)) exception Invalid_signature of pos * (string*string*string) list option let signed ~check = let module OpamPrinter = OpamPrinter.FullPos in let pp_sig = V.map_list ~depth:2 signature in extract_field "signature" -| pp ~name:"signed-file" (fun ~pos -> function | Some sgs, items -> let sgs = parse ~pos pp_sig sgs in let str = OpamPrinter.Normalise.items items in if not (check sgs str) then raise (Invalid_signature (pos, Some sgs)) else (sgs, items) | None, _ -> raise (Invalid_signature (pos, None))) (fun (sgs, items) -> assert (check sgs (OpamPrinter.Normalise.items items)); Some (print pp_sig sgs), items) end opam-2.1.5/src/format/opamRepositoryName.mli0000644000175000017500000000156114427463453020141 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2016 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** The type for repository names *) include OpamStd.ABSTRACT (** Default repository name *) val default: t opam-2.1.5/src/format/opamSwitch.ml0000644000175000017500000000375614427463453016261 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2018 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) include OpamStd.AbstractString let unset = of_string "#unset#" let is_external s = OpamStd.String.starts_with ~prefix:"." s || OpamStd.String.contains ~sub:Filename.dir_sep s let external_dirname = "_opam" let check s = if String.compare s "" = 0 && let re = Re.(compile @@ seq [ bol; opt @@ seq [ wordc ; char ':'; set "/\\" ]; rep @@ diff any @@ set "<>!`$():"; eol ]) in (try ignore @@ Re.exec re s; true with Not_found -> false) then failwith (Printf.sprintf "Invalid character in switch name %S" s); s let of_string s = check @@ if is_external s then OpamFilename.Dir.(to_string (of_string s)) else s let of_dirname d = let s = OpamFilename.Dir.to_string d in check @@ try let swdir = Unix.readlink (Filename.concat s external_dirname) in let swdir = if Filename.is_relative swdir then Filename.concat s swdir else swdir in let r = OpamSystem.real_path swdir in if Filename.basename r = external_dirname then Filename.dirname r else s with Unix.Unix_error _ -> s let get_root root s = if is_external s then OpamFilename.Dir.of_string (Filename.concat s external_dirname) else OpamFilename.Op.(root / s) opam-2.1.5/src/format/opamFormula.ml0000644000175000017500000004713214427463453016421 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) type relop = [`Eq|`Neq|`Geq|`Gt|`Leq|`Lt] let neg_relop = function | `Eq -> `Neq | `Neq -> `Eq | `Geq -> `Lt | `Gt -> `Leq | `Leq -> `Gt | `Lt -> `Geq let string_of_relop = OpamPrinter.FullPos.relop_kind type version_constraint = relop * OpamPackage.Version.t type atom = OpamPackage.Name.t * version_constraint option let string_of_atom = function | n, None -> OpamPackage.Name.to_string n | n, Some (r,c) -> Printf.sprintf "%s (%s %s)" (OpamPackage.Name.to_string n) (string_of_relop r) (OpamPackage.Version.to_string c) let short_string_of_atom = function | n, None -> OpamPackage.Name.to_string n | n, Some (`Eq,c) -> Printf.sprintf "%s.%s" (OpamPackage.Name.to_string n) (OpamPackage.Version.to_string c) | n, Some (r,c) -> Printf.sprintf "%s%s%s" (OpamPackage.Name.to_string n) (string_of_relop r) (OpamPackage.Version.to_string c) let string_of_atoms atoms = OpamStd.List.concat_map " & " short_string_of_atom atoms let atom_of_string str = let re = lazy Re.(compile @@ whole_string @@ seq [ group @@ rep1 @@ diff any (set ">=<.!"); group @@ alt [ seq [ set "<>"; opt @@ char '=' ]; set "=."; str "!="; ]; group @@ rep1 any; ]) in try let sub = Re.exec (Lazy.force re) str in let sname = Re.Group.get sub 1 in let sop = Re.Group.get sub 2 in let sversion = Re.Group.get sub 3 in let name = OpamPackage.Name.of_string sname in let sop = if sop = "." then "=" else sop in let op = OpamLexer.FullPos.relop sop in let version = OpamPackage.Version.of_string sversion in name, Some (op, version) with Not_found | Failure _ | OpamLexer.Error _ -> OpamPackage.Name.of_string str, None type 'a conjunction = 'a list let string_of_conjunction string_of_atom c = Printf.sprintf "(%s)" (OpamStd.List.concat_map " & " string_of_atom c) type 'a disjunction = 'a list let string_of_disjunction string_of_atom c = Printf.sprintf "(%s)" (OpamStd.List.concat_map " | " string_of_atom c) type 'a cnf = 'a list list let string_of_cnf string_of_atom cnf = let string_of_clause c = let left, right = match c with [_] -> "", "" | _ -> "(", ")" in OpamStd.List.concat_map ~left ~right " | " string_of_atom c in OpamStd.List.concat_map " & " string_of_clause cnf type 'a dnf = 'a list list let string_of_dnf string_of_atom cnf = let string_of_clause c = let left, right = match c with [_] -> "", "" | _ -> "(", ")" in OpamStd.List.concat_map ~left ~right " & " string_of_atom c in OpamStd.List.concat_map " | " string_of_clause cnf type 'a formula = | Empty | Atom of 'a | Block of 'a formula | And of 'a formula * 'a formula | Or of 'a formula * 'a formula let make_and a b = match a, b with | Empty, r | r, Empty -> r | a, b -> And (a, b) let make_or a b = match a, b with | Empty, r | r, Empty -> r (* we're not assuming Empty is true *) | a, b -> Or (a, b) let string_of_formula string_of_a f = let rec aux ?(in_and=false) f = let paren_if ?(cond=false) s = if cond || OpamFormatConfig.(!r.all_parens) then Printf.sprintf "(%s)" s else s in match f with | Empty -> "[]" | Atom a -> paren_if (string_of_a a) | Block x -> Printf.sprintf "(%s)" (aux x) | And(x,y) -> paren_if (Printf.sprintf "%s & %s" (aux ~in_and:true x) (aux ~in_and:true y)) | Or(x,y) -> paren_if ~cond:in_and (Printf.sprintf "%s | %s" (aux x) (aux y)) in aux f let rec map f = function | Empty -> Empty | Atom x -> f x | And(x,y) -> make_and (map f x) (map f y) | Or(x,y) -> make_or (map f x) (map f y) | Block x -> match map f x with | Empty -> Empty | x -> Block x (* Maps top-down *) let rec map_formula f t = let t = f t in match t with | Block x -> Block (map_formula f x) | And(x,y) -> make_and (map_formula f x) (map_formula f y) | Or(x,y) -> make_or (map_formula f x) (map_formula f y) | x -> x let rec map_up_formula f t = let t = match t with | Block x -> f (Block (map_up_formula f x)) | And(x,y) -> f (make_and (map_up_formula f x) (map_up_formula f y)) | Or(x,y) -> f (make_or (map_up_formula f x) (map_up_formula f y)) | Atom x -> f (Atom x) | Empty -> Empty in f t let neg neg_atom = map_formula (function | And(x,y) -> Or(x,y) | Or(x,y) -> And(x,y) | Atom x -> Atom (neg_atom x) | x -> x) let rec iter f = function | Empty -> () | Atom x -> f x | Block x -> iter f x | And(x,y) -> iter f x; iter f y | Or(x,y) -> iter f x; iter f y let rec fold_left f i = function | Empty -> i | Atom x -> f i x | Block x -> fold_left f i x | And(x,y) -> fold_left f (fold_left f i x) y | Or(x,y) -> fold_left f (fold_left f i x) y let rec fold_right f i = function | Empty -> i | Atom x -> f i x | Block x -> fold_right f i x | And(x,y) -> fold_right f (fold_right f i y) x | Or(x,y) -> fold_right f (fold_right f i y) x type version_formula = version_constraint formula type t = (OpamPackage.Name.t * version_formula) formula let rec compare_formula f x y = let rec compare_atom x = function | Empty -> 1 | Atom y -> f x y | Block y -> compare_atom x y | And (y,z) | Or (y,z) -> let r = compare_atom x y in if r <> 0 then r else compare_atom x z in match x, y with | Empty, Empty -> 0 | Empty, _ -> -1 | _ , Empty -> 1 | Atom x, Atom y -> f x y | Atom x, y -> compare_atom x y | x , Atom y -> -1 * (compare_atom y x) | Block x, y | x, Block y -> compare_formula f x y | (And (x,y) | Or (x,y)) as lhs, ((And (x',y') | Or (x',y')) as rhs) -> let l = compare_formula f x x' in if l <> 0 then l else let r = compare_formula f y y' in if r <> 0 then r else (match lhs, rhs with | And _, And _ | Or _, Or _ -> 0 | And _, Or _ -> 1 | Or _, And _ -> -1 | _ -> assert false) let compare_relop op1 op2 = match op1, op2 with | `Lt,`Lt | `Leq,`Leq | `Neq,`Neq | `Eq,`Eq | `Geq,`Geq | `Gt,`Gt -> 0 | `Lt, _ -> -1 | _, `Lt -> 1 | `Leq, _ -> -1 | _, `Leq -> 1 | `Neq, _ -> -1 | _, `Neq -> 1 | `Eq, _ -> -1 | _, `Eq -> 1 | `Geq, _ -> -1 | _, `Geq -> 1 let compare_version_formula = compare_formula (fun (op1,v1) (op2,v2) -> let c = compare v1 v2 in if c <> 0 then c else compare_relop op1 op2) let compare_nc (n1, c1) (n2, c2) = let c = OpamPackage.Name.compare n1 n2 in if c <> 0 then c else compare_version_formula c1 c2 let compare = compare_formula compare_nc let rec eval atom = function | Empty -> true | Atom x -> atom x | Block x -> eval atom x | And(x,y) -> eval atom x && eval atom y | Or(x,y) -> eval atom x || eval atom y let rec partial_eval atom = function | Empty -> `Formula Empty | Atom x -> atom x | And(x,y) -> (match partial_eval atom x, partial_eval atom y with | `False, _ | _, `False -> `False | `True, f | f, `True -> f | `Formula x, `Formula y -> `Formula (And (x,y))) | Or(x,y) -> (match partial_eval atom x, partial_eval atom y with | `True, _ | _, `True -> `True | `False, f | f, `False -> f | `Formula x, `Formula y -> `Formula (Or (x,y))) | Block x -> partial_eval atom x let check_relop relop c = match relop with | `Eq -> c = 0 | `Neq -> c <> 0 | `Geq -> c >= 0 | `Gt -> c > 0 | `Leq -> c <= 0 | `Lt -> c < 0 let eval_relop relop v1 v2 = check_relop relop (OpamPackage.Version.compare v1 v2) let check_version_formula f v = eval (fun (relop, vref) -> eval_relop relop v vref) f let check (name,cstr) package = name = OpamPackage.name package && match cstr with | None -> true | Some (relop, v) -> eval_relop relop (OpamPackage.version package) v let packages_of_atoms ?(disj=false) pkgset atoms = (* Conjunction for constraints over the same name (unless [disj] is specified), but disjunction on the package names *) let ffilter = if disj then List.exists else List.for_all in let by_name = List.fold_left (fun acc (n,_ as atom) -> OpamPackage.Name.Map.update n (fun a -> atom::a) [] acc) OpamPackage.Name.Map.empty atoms in OpamPackage.Name.Map.fold (fun name atoms acc -> OpamPackage.Set.union acc @@ OpamPackage.Set.filter (fun nv -> ffilter (fun a -> check a nv) atoms) (OpamPackage.packages_of_name pkgset name)) by_name OpamPackage.Set.empty let satisfies_depends pkgset f = eval (fun (name, cstr) -> OpamPackage.Set.exists (fun nv -> check_version_formula cstr nv.version) (OpamPackage.packages_of_name pkgset name)) f let to_string t = let string_of_constraint (relop, version) = Printf.sprintf "%s %s" (string_of_relop relop) (OpamPackage.Version.to_string version) in let string_of_pkg = function | n, Empty -> OpamPackage.Name.to_string n | n, (Atom _ as c) -> Printf.sprintf "%s %s" (OpamPackage.Name.to_string n) (string_of_formula string_of_constraint c) | n, c -> Printf.sprintf "%s (%s)" (OpamPackage.Name.to_string n) (string_of_formula string_of_constraint c) in string_of_formula string_of_pkg t (* convert a formula to a CNF *) let cnf_of_formula t = let rec mk_left x y = match y with | Block y -> mk_left x y | And (a,b) -> And (mk_left x a, mk_left x b) | Empty -> x | _ -> Or (x,y) in let rec mk_right x y = match x with | Block x -> mk_right x y | And (a,b) -> And (mk_right a y, mk_right b y) | Empty -> y | _ -> mk_left x y in let rec mk = function | Empty -> Empty | Block x -> mk x | Atom x -> Atom x | And (x,y) -> And (mk x, mk y) | Or (x,y) -> mk_right (mk x) (mk y) in mk t (* convert a formula to DNF *) let dnf_of_formula t = let rec mk_left x y = match y with | Block y -> mk_left x y | Or (a,b) -> Or (mk_left x a, mk_left x b) | _ -> And (x,y) in let rec mk_right x y = match x with | Block x -> mk_right x y | Or (a,b) -> Or (mk_right a y, mk_right b y) | _ -> mk_left x y in let rec mk = function | Empty -> Empty | Block x -> mk x | Atom x -> Atom x | Or (x,y) -> Or (mk x, mk y) | And (x,y) -> mk_right (mk x) (mk y) in mk t let verifies f nv = let name_formula = map (fun ((n, _) as a) -> if n = OpamPackage.name nv then Atom a else Empty) (dnf_of_formula f) in name_formula <> Empty && eval (fun (_name, cstr) -> check_version_formula cstr (OpamPackage.version nv)) name_formula let packages pkgset f = let names = fold_left (fun acc (name, _) -> OpamPackage.Name.Set.add name acc) OpamPackage.Name.Set.empty f in (* dnf allows us to transform the formula into a union of intervals, where ignoring atoms for different package names works. *) let dnf = dnf_of_formula f in OpamPackage.Name.Set.fold (fun name acc -> (* Ignore conjunctions where [name] doesn't appear *) let name_formula = map (fun ((n, _) as a) -> if n = name then Atom a else Empty) dnf in OpamPackage.Set.union acc @@ OpamPackage.Set.filter (fun nv -> let v = OpamPackage.version nv in eval (fun (_name, cstr) -> check_version_formula cstr v) name_formula) (OpamPackage.packages_of_name pkgset name)) names OpamPackage.Set.empty (* Convert a t an atom formula *) let to_atom_formula (t:t): atom formula = map (fun (x, c) -> match c with | Empty -> Atom (x, None) | cs -> map (fun c -> Atom (x, Some c)) cs) t (* Convert an atom formula to a t-formula *) let of_atom_formula (a:atom formula): t = let atom (n, v) = match v with | None -> Atom (n, Empty) | Some (r,v) -> Atom (n, Atom (r,v)) in map atom a let ands l = List.fold_left make_and Empty l let rec ands_to_list = function | Empty -> [] | And (e,f) -> List.rev_append (rev_ands_to_list e) (ands_to_list f) | Block f -> ands_to_list f | x -> [x] and rev_ands_to_list = function | Empty -> [] | Block f -> rev_ands_to_list f | And (e,f) -> List.rev_append (ands_to_list f) (rev_ands_to_list e) | x -> [x] let of_conjunction c = of_atom_formula (ands (List.rev_map (fun x -> Atom x) c)) let ors l = List.fold_left make_or Empty l let rec ors_to_list = function | Empty -> [] | Or (e,f) -> List.rev_append (rev_ors_to_list e) (ors_to_list f) | Block f -> ors_to_list f | x -> [x] and rev_ors_to_list = function | Empty -> [] | Or (e,f) -> List.rev_append (ors_to_list f) (rev_ors_to_list e) | Block f -> rev_ors_to_list f | x -> [x] let is_conjunction t = let rec aux = function | Or _ -> false | And (a,b) -> aux a && aux b | Block a -> aux a | _ -> true in aux t let is_disjunction t = let rec aux = function | And _ -> false | Or (a,b) -> aux a && aux b | Block a -> aux a | _ -> true in aux t let rec sort comp f= match f with | (Empty | Atom _) as f -> f | Block f -> Block (sort comp f) | And _ as f -> ands_to_list f |> List.rev_map (sort comp) |> List.sort (compare_formula comp) |> ands | Or _ as f -> ors_to_list f |> List.rev_map (sort comp) |> List.sort (compare_formula comp) |> ors let atoms t = fold_right (fun accu x -> x::accu) [] (to_atom_formula t) let to_cnf t = let atf = to_atom_formula t in let atoms = fold_right (fun acc a -> a::acc) [] in let conj = rev_ands_to_list atf in if List.for_all is_disjunction conj then List.rev_map atoms conj (* this gives a nice speedup *) else List.rev_map atoms @@ rev_ands_to_list @@ cnf_of_formula atf let to_dnf t = let atf = to_atom_formula t in let atoms = fold_right (fun acc a -> a::acc) [] in let disj = rev_ors_to_list atf in if List.for_all is_conjunction disj then List.rev_map atoms disj else List.rev_map atoms @@ rev_ors_to_list @@ dnf_of_formula atf let to_conjunction t = if is_conjunction t then atoms t else failwith (Printf.sprintf "%s is not a valid conjunction" (to_string t)) let to_disjunction t = if is_disjunction t then atoms t else failwith (Printf.sprintf "%s is not a valid disjunction" (to_string t)) let of_disjunction d = of_atom_formula (ors (List.rev_map (fun x -> Atom x) d)) let get_disjunction_formula version_set cstr = (* rev_ors_to_list cstr |> * List.fold_left *) List.rev_map (fun ff -> match ands_to_list ff with | [] -> assert false | [Atom _] as at -> at | _ -> OpamPackage.Version.Set.filter (check_version_formula ff) version_set |> OpamPackage.Version.Set.elements |> List.map (fun v -> Atom (`Eq, v))) (rev_ors_to_list cstr) |> List.flatten let set_to_disjunction set t = List.map (function | And _ -> failwith (Printf.sprintf "%s is not a valid disjunction" (to_string t)) | Or _ | Block _ | Empty -> assert false | Atom (name, Empty) -> [name, None] | Atom (name, Atom a) -> [name, Some a] | Atom (name, cstr) -> get_disjunction_formula (OpamPackage.versions_of_name set name) cstr |> List.map (function | Atom (relop, v) -> name, Some (relop, v) | _ -> assert false)) (ors_to_list t) |> List.flatten let simplify_ineq_formula vcomp f = let vals = fold_left (fun acc (_op, x) -> x::acc) [] f in let vals = List.sort_uniq vcomp vals in let vals_a = Array.of_list vals in let val_of_int i = vals_a.(i/2) in let int_of_val = let m = List.mapi (fun i v -> v, 2 * i + 1) vals in fun v -> List.assoc v m in (* One integer for each value appearing in f, plus one for each interval *) let rec mk_ranges acc n = if n < 0 then acc else mk_ranges (n::acc) (n-1) in let ranges = mk_ranges [] (2 * Array.length vals_a + 2) in let int_formula = map (fun (op, x) -> Atom (op, int_of_val x)) f in let vals = List.map (fun i -> eval (fun (relop, iref) -> check_relop relop (i - iref)) int_formula, i) ranges in if List.for_all (fun (t, _) -> not t) vals then None else let rec aux = function | (true, _) :: ((true, _) :: _ as r) -> aux r | (false, _) :: ((false, _) :: _ as r) -> aux r | (true, _) :: (false, x) :: ((true, _) :: _ as r) when x mod 2 = 1 -> (`Neq, x) :: aux r | (false, _) :: (true, x) :: ((false, _) :: _ as r) when x mod 2 = 1 -> (`Eq, x) :: aux r | (true, _) :: ((false, x) :: _ as r) -> (if x mod 2 = 1 then `Lt, x else `Leq, x-1) :: aux r | (false, _) :: ((true, x) :: _ as r) -> (if x mod 2 = 1 then `Geq, x else `Gt, x-1) :: aux r | [_] | []-> [] in let rec aux2 = function | (`Geq|`Gt|`Neq as op, i) :: r -> let rec find_upper acc = function | (`Leq|`Lt as op, i) :: r -> ands (List.rev_append acc [Atom (op, val_of_int i)]) :: aux2 r | (`Neq, i) :: r -> find_upper (Atom (`Neq, val_of_int i) :: acc) r | r -> ands (List.rev acc) :: aux2 r in find_upper [Atom (op, val_of_int i)] r | (op, i) :: r -> Atom (op, val_of_int i) :: aux2 r | [] -> [Empty] in Some (ors (aux2 (aux vals))) let simplify_version_formula f = simplify_ineq_formula OpamPackage.Version.compare f (** Takes an ordered list of atoms and a predicate, returns a formula describing the subset of matching atoms *) let gen_formula l f = let l = List.map (fun x -> f x, x) l in let rec aux (t, x as bound) l = match t, l with | true, (false, y) :: (true, _) :: r | false, (true, y) :: (false, _) :: r -> let a = (if t then `Neq else `Eq), y in (match aux bound r with | b :: r -> b :: a :: r | r -> a :: r) | true, (true, _) :: r | false, (false, _) :: r -> aux bound r | true, (false, _ as bound') :: r | false, (true, _ as bound') :: r -> ((if t then `Geq else `Lt), x) :: aux bound' r | _, [] -> [(if t then `Geq else `Lt), x] in let rec aux2 = function | (`Geq|`Neq), _ as a :: r -> let rec find_upper acc = function | `Lt, _ as a :: r -> ands (List.rev_append acc [Atom a]) :: aux2 r | `Neq, _ as a :: r -> find_upper (Atom a :: acc) r | r -> ands (List.rev acc) :: aux2 r in find_upper [Atom a] r | a :: r -> Atom a :: aux2 r | [] -> [Empty] in match l with | [] -> Some Empty | (t, x) :: r -> match aux (t, x) r with | [] -> assert false | [`Geq, _] -> Some Empty | [`Lt, _] -> None | _ :: r -> Some (ors (aux2 r)) let formula_of_version_set set subset = let module S = OpamPackage.Version.Set in match gen_formula (S.elements set) (fun x -> S.mem x subset) with | Some f -> f | None -> invalid_arg "Empty subset" let simplify_version_set set f = let module S = OpamPackage.Version.Set in if S.is_empty set then Empty else let set = fold_left (fun set (_relop, v) -> S.add v set) set f in gen_formula (S.elements set) (check_version_formula f) |> OpamStd.Option.default f opam-2.1.5/src/stubs/0002755000175000017500000000000014427463453013450 5ustar stephstephopam-2.1.5/src/stubs/dune0000644000175000017500000000015114427463453014321 0ustar stephsteph(rule (targets c-flags.sexp) (mode fallback) (action (with-stdout-to %{targets} (echo "()")))) opam-2.1.5/src/stubs/libacl/0002755000175000017500000000000014427463453014676 5ustar stephstephopam-2.1.5/src/stubs/libacl/c-libraries.sexp.in0000644000175000017500000000002514427463453020373 0ustar stephsteph(@CONF_LIBACL_LINK@) opam-2.1.5/src/stubs/libacl/opamlibACL.ml0000644000175000017500000000143314427463453017172 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2020 David Allsopp Ltd. *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) external get_acl_executable_info : string -> int -> int list option = "OPAM_get_acl_executable_info" opam-2.1.5/src/stubs/libacl/opamACL.c0000644000175000017500000001013414427463453016313 0ustar stephsteph/**************************************************************************/ /* */ /* Copyright 2020 David Allsopp Ltd. */ /* */ /* All rights reserved. This file is distributed under the terms of the */ /* GNU Lesser General Public License version 2.1, with the special */ /* exception on linking described in the file LICENSE. */ /* */ /**************************************************************************/ #include #include #include #define CAML_NAME_SPACE #include #include #include #ifndef Val_none #define Val_none Val_int(0) #endif /* OPAM_get_acl_executable_info(file, owner) takes a filename and the uid of * the file's owner (this saves a call to stat on both the OCaml and C sides). * The result is: * None - the process cannot execute file * Some [] - the process can execute file * Some gids - the process can execute file if it is any of these gids */ CAMLprim value OPAM_get_acl_executable_info(value file, value owner) { CAMLparam2(file, owner); CAMLlocal2(result, cell); acl_t acl = acl_get_file(String_val(file), ACL_TYPE_ACCESS); uid_t owner_uid = Int_val(owner); uid_t uid = geteuid(); result = Val_none; if (acl) { acl_entry_t entry; size_t siz; if (acl_get_entry(acl, ACL_FIRST_ENTRY, &entry) == 1) { int mask = 1; int user = 0; do { acl_tag_t tag; acl_permset_t perms; if (acl_get_tag_type(entry, &tag) == 0 && acl_get_permset(entry, &perms) == 0) { void *qualifier = NULL; int executable = acl_get_perm(perms, ACL_EXECUTE); switch(tag) { case ACL_USER: if (executable && (qualifier = acl_get_qualifier(entry))) { uid_t entry_uid = *((uid_t *)qualifier); /* NB ACL_USER entries do not override ACL_USER_OBJ */ if (entry_uid != owner_uid && entry_uid == uid) { /* result = Some [] */ if (!Is_block(result)) { result = caml_alloc_small(1, 0); Field(result, 0) = Val_int(0); } else { caml_modify(&Field(result, 0), Val_int(0)); } user = 1; } } break; case ACL_GROUP: if (!user && executable && (qualifier = acl_get_qualifier(entry))) { gid_t entry_gid = *((gid_t *)qualifier); /* Construct a cons cell */ cell = caml_alloc_small(2, 0); Field(cell, 0) = Val_int(entry_gid); if (Is_block(result)) { /* Put cons cell at head of existing list */ Field(cell, 1) = Field(result, 0); caml_modify(&Field(result, 0), cell); } else { /* result = Some [cell] */ Field(cell, 1) = Val_int(0); result = caml_alloc_small(1, 0); Field(result, 0) = cell; } } break; case ACL_USER_OBJ: case ACL_GROUP_OBJ: /* These have already been done by the stat check */ break; case ACL_MASK: if (!(mask = executable)) { result = Val_none; } break; default: /* ACL_UNDEFINED_TAG or ACL_OTHER */ break; } if (qualifier) acl_free(qualifier); } } while (mask && acl_get_entry(acl, ACL_NEXT_ENTRY, &entry) == 1); } acl_free((void *)acl); } CAMLreturn(result); } opam-2.1.5/src/stubs/libacl/dune-libacl0000644000175000017500000000125314427463453016777 0ustar stephsteph(library (name opam_stubs_libacl) (public_name opam-core.libacl) (synopsis "OCaml Package Manager libacl C stubs") (flags (:standard (:include ../../ocaml-flags-standard.sexp) (:include ../../ocaml-flags-configure.sexp) (:include ../../ocaml-context-flags.sexp))) (modules opamlibACL) (c_names opamACL) (c_flags (:standard (:include ../c-flags.sexp))) (c_library_flags (:include c-libraries.sexp)) (wrapped false)) (rule (targets c-libraries.sexp) (mode fallback) (action (with-stdout-to %{targets} (echo "()")))) opam-2.1.5/src/stubs/c-flags.sexp.in0000644000175000017500000000002014427463453016260 0ustar stephsteph(@CONF_CFLAGS@) opam-2.1.5/src/stubs/win32/0002755000175000017500000000000014427463453014412 5ustar stephstephopam-2.1.5/src/stubs/win32/build-putenv.ml0000644000175000017500000000215214427463453017360 0ustar stephsteph#load "unix.cma" let () = let (prefix, suffix) = let c = open_in Sys.argv.(3) in let prefix = input_line c in let suffix = input_line c in let rec f () = match input_line c with | env -> g env | exception End_of_file -> close_in c and g env = let elt = input_line c in let elt = if elt.[String.length elt - 1] <> ';' then elt ^ ";" else elt in let elt = (* See https://support.microsoft.com/en-us/help/830473 *) let l = String.length elt in if l > 8191 then begin Printf.eprintf "Variable %s has length %d which exceeds the maximum of 8191\n%!" env l; exit 1 end else let current = Unix.getenv env in if String.length elt + String.length current > 8191 then begin Printf.eprintf "Warning: replacing, rather than prepending %s\n%!" env; elt end else elt ^ current in let () = Unix.putenv env elt in f () in f (); (prefix, suffix) in exit (Sys.command (Printf.sprintf "%s%s%s%s" prefix Sys.argv.(1) suffix Sys.argv.(2))) opam-2.1.5/src/stubs/win32/dune-win320000644000175000017500000000204414427463453016226 0ustar stephsteph(library (name opam_stubs_win32) (public_name opam-core.stubs) (synopsis "OCaml Package Manager C stubs") (libraries unix) (flags (:standard (:include ../../ocaml-flags-standard.sexp) (:include ../../ocaml-flags-configure.sexp) (:include ../../ocaml-context-flags.sexp))) (modules opamWin32Stubs) (c_names opamInject opamWindows) (c_flags (:standard (:include ../c-flags.sexp))) (c_library_flags (:standard (:include c-libraries.sexp))) (wrapped false)) (rule (targets opam-putenv.exe) (deps opamInject.c) (action (run ocaml %{dep:build-putenv.ml} %{targets} %{dep:opam-putenv.c} %{dep:cc64}))) (rule (targets cc64) (mode fallback) (action (with-stdout-to %{targets} (echo "")))) (install (section bin) (package opam) (files opam-putenv.exe)) (rule (with-stdout-to c-libraries.sexp (run ocaml %{dep:../../../shell/context_flags.ml} clibs))) opam-2.1.5/src/stubs/win32/opamWin32Stubs.ml0000644000175000017500000000515114427463453017544 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2018 MetaStack Solutions Ltd. *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) external getCurrentProcessID : unit -> int32 = "OPAMW_GetCurrentProcessID" (* Polymorphic parameters below are used as placeholders for types in * OpamStubsTypes - it's not worth the effort of propagating the types here, * even if it does result in some ugly-looking primitives! *) external getStdHandle : 'a -> 'b = "OPAMW_GetStdHandle" external getConsoleScreenBufferInfo : 'a -> 'b = "OPAMW_GetConsoleScreenBufferInfo" external setConsoleTextAttribute : 'a -> int -> unit = "OPAMW_SetConsoleTextAttribute" external fillConsoleOutputCharacter : 'a -> char -> int -> int * int -> bool = "OPAMW_FillConsoleOutputCharacter" external getConsoleMode : 'a -> int = "OPAMW_GetConsoleMode" external setConsoleMode : 'a -> int -> bool = "OPAMW_SetConsoleMode" external getWindowsVersion : unit -> int * int * int * int = "OPAMW_GetWindowsVersion" external isWoW64 : unit -> bool = "OPAMW_IsWoW64" external waitpids : int list -> int -> int * Unix.process_status = "OPAMW_waitpids" external writeRegistry : 'a -> string -> string -> 'b -> 'c -> unit = "OPAMW_WriteRegistry" external getConsoleOutputCP : unit -> int = "OPAMW_GetConsoleOutputCP" external getCurrentConsoleFontEx : 'a -> bool -> 'b = "OPAMW_GetCurrentConsoleFontEx" external create_glyph_checker : string -> 'a * 'a = "OPAMW_CreateGlyphChecker" external delete_glyph_checker : 'a * 'a -> unit = "OPAMW_DeleteGlyphChecker" external has_glyph : 'a * 'a -> Uchar.t -> bool = "OPAMW_HasGlyph" external isWoW64Process : int32 -> bool = "OPAMW_IsWoW64Process" external process_putenv : int32 -> string -> string -> bool = "OPAMW_process_putenv" external shGetFolderPath : int -> 'a -> string = "OPAMW_SHGetFolderPath" external sendMessageTimeout : nativeint -> int -> int -> 'a -> 'b -> 'c -> int * 'd = "OPAMW_SendMessageTimeout_byte" "OPAMW_SendMessageTimeout" external getParentProcessID : int32 -> int32 = "OPAMW_GetParentProcessID" external getConsoleAlias : string -> string -> string = "OPAMW_GetConsoleAlias" opam-2.1.5/src/stubs/win32/opamInject.c0000644000175000017500000001156214427463453016652 0ustar stephsteph/**************************************************************************/ /* */ /* Copyright 2015, 2016, 2017, 2018 MetaStack Solutions Ltd. */ /* */ /* All rights reserved. This file is distributed under the terms of the */ /* GNU Lesser General Public License version 2.1, with the special */ /* exception on linking described in the file LICENSE. */ /* */ /**************************************************************************/ #include /* SetEnvironmentVariable function pointer type */ typedef LRESULT (WINAPI *SETENVIRONMENTVARIABLE)(LPCTSTR,LPCTSTR); /* * Data structure to pass to the remote thread */ typedef struct { SETENVIRONMENTVARIABLE SetEnvironmentVariable; TCHAR lpName[4096]; TCHAR lpValue[4096]; BOOL result; } INJDATA, *PINJDATA; /* * Code to inject into the parent process */ static DWORD WINAPI ThreadFunc (INJDATA *pData) { /* * Call the provided function pointer with its two arguments and return the * result. */ pData->result = pData->SetEnvironmentVariable(pData->lpName, pData->lpValue); return 0; } /* * This is a dummy function used to calculate the code size of ThreadFunc. * This assumes that the linker does not re-order the functions. * If it's a worry, could make the symbols public and use /ORDER * (http://msdn.microsoft.com/en-us/library/00kh39zz.aspx) * Presumably there's a gcc equivalent for mingw. */ static void AfterThreadFunc (void) { return; } char* InjectSetEnvironmentVariable(DWORD pid, const char* key, const char* val) { /* * Open the parent process for code injection */ HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, pid); INJDATA payload = {NULL, "", "", FALSE}; INJDATA* pData; DWORD* pCode; const int codeSize = ((LPBYTE)AfterThreadFunc - (LPBYTE)ThreadFunc); HANDLE hThread; if (!hProcess) return "OPAMW_process_putenv: could not open parent process"; payload.SetEnvironmentVariable = (SETENVIRONMENTVARIABLE)GetProcAddress(GetModuleHandle("kernel32"), "SetEnvironmentVariableA"); /* * Set-up the instruction */ strcpy(payload.lpName, key); strcpy(payload.lpValue, val); /* * Allocate a page in the parent process to hold the instruction and copy the * payload to it. */ pData = (INJDATA*)VirtualAllocEx(hProcess, 0, sizeof(INJDATA), MEM_COMMIT, PAGE_READWRITE); if (!pData) { CloseHandle(hProcess); return "OPAMW_process_putenv: VirtualAllocEx (data) in parent failed"; } if (!WriteProcessMemory(hProcess, pData, &payload, sizeof(INJDATA), NULL)) { VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE); CloseHandle(hProcess); return "OPAMW_process_putenv: could not copy data to parent process"; } /* * Allocate a page in the parent process to hold ThreadFunc and copy the code * there. */ pCode = (PDWORD)VirtualAllocEx(hProcess, 0, codeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!pCode) { VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE); CloseHandle(hProcess); return "OPAMW_process_putenv: VirtualAllocEx (exec) in parent failed"; } if (!WriteProcessMemory(hProcess, pCode, &ThreadFunc, codeSize, NULL)) { VirtualFreeEx(hProcess, pCode, 0, MEM_RELEASE); VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE); CloseHandle(hProcess); return "OPAMW_process_putenv: could not copy code to parent process"; } /* * Start the remote thread */ hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pCode, pData, 0, NULL); if (!hThread) { VirtualFreeEx(hProcess, pCode, 0, MEM_RELEASE); VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE); CloseHandle(hProcess); return "OPAMW_process_putenv: could not start remote thread in parent"; } /* * Wait for the thread to terminate. */ WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); /* * Get the result back */ ReadProcessMemory(hProcess, pData, &payload, sizeof(INJDATA), NULL); /* * Release the memory */ VirtualFreeEx(hProcess, pCode, 0, MEM_RELEASE); VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE); CloseHandle(hProcess); return (payload.result ? NULL : ""); } opam-2.1.5/src/stubs/win32/opam-putenv.c0000644000175000017500000000447514427463453017041 0ustar stephsteph/**************************************************************************/ /* */ /* Copyright 2015, 2016, 2017, 2018 MetaStack Solutions Ltd. */ /* */ /* All rights reserved. This file is distributed under the terms of the */ /* GNU Lesser General Public License version 2.1, with the special */ /* exception on linking described in the file LICENSE. */ /* */ /**************************************************************************/ #include /* * This will be being built for a different architecture, so it's easier just to * #include the code, rather than having to deal with .o(obj) files for * different architectures. */ #include "opamInject.c" /* * This trivially simple utility takes a single PID and then reads CRLF * terminated lines from STDIN. The line ::QUIT causes the program to terminate * otherwise a further line is read and the two lines together form the * key/value pair to be set in the process's environment. * * This utility is always compiled x86 if OPAM is compiled x64 and vice versa * and allows OPAM to manipulate a parent whose architecture differs from its * own. When the architecture matches, OPAM injects the code itself, but * injecting from a 64-bit process to a 32-bit parent is quite hard (and * potentially unstable) and injecting from a 32-bit process to a 64-bit parent * is phenomenally hard! */ int main(int argc, char *argv[], char *envp[]) { if (argc != 2) { printf("Invalid command line: this utility is an internal part of OPAM\n"); } else { DWORD pid = atoi(argv[1]); BOOL running = TRUE; char* key = (char*)malloc(4097); char* value = (char*)malloc(4097); while (running) { if (fgets(key, 4097, stdin)) { if (strcmp(key, "::QUIT\n") && fgets(value, 4097, stdin)) { key[strlen(key) - 1] = value[strlen(value) - 1] = '\0'; InjectSetEnvironmentVariable(pid, key, value); } else { running = FALSE; } } else { running = FALSE; } } free(key); free(value); } } opam-2.1.5/src/stubs/win32/opamWindows.c0000644000175000017500000004574514427463453017102 0ustar stephsteph/**************************************************************************/ /* */ /* Copyright 2015, 2016, 2017, 2018 MetaStack Solutions Ltd. */ /* */ /* All rights reserved. This file is distributed under the terms of the */ /* GNU Lesser General Public License version 2.1, with the special */ /* exception on linking described in the file LICENSE. */ /* */ /**************************************************************************/ #define CAML_NAME_SPACE /* We need the UTF16 conversion functions */ #define CAML_INTERNALS #include #include #include #include #include #include #include #include #include #include /* In a previous incarnation, dummy C stubs were generated for non-Windows * builds. Although this is no longer used, the C sources retain the ability to * be compiled this way. */ #ifdef _WIN32 #include #include #include static struct custom_operations HandleOps = { "org.ocaml.opam.Win32.Handle/1", custom_finalize_default, custom_compare_default, custom_hash_default, custom_serialize_default, custom_deserialize_default }; #define HANDLE_val(v) (*((HANDLE*)Data_custom_val(v))) typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); static LPFN_ISWOW64PROCESS IsWoW64Process = NULL; static inline BOOL has_IsWoW64Process(void) { return (IsWoW64Process || (IsWoW64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process"))); } /* * Taken from otherlibs/win32unix/winwait.c (sadly declared static) * Altered only for CAML_NAME_SPACE */ static value alloc_process_status(HANDLE pid, int status) { value res, st; st = caml_alloc(1, 0); Field(st, 0) = Val_int(status); Begin_root (st); res = caml_alloc_small(2, 0); Field(res, 0) = Val_long((intnat) pid); Field(res, 1) = st; End_roots(); return res; } /* Order must match OpamStubsTypes.registry_root */ static HKEY roots[] = {HKEY_CLASSES_ROOT, HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_USERS}; /* * OPAMW_process_putenv is implemented using Process Injection. * Idea inspired by Bill Stewart's editvar * (see http://www.westmesatech.com/editv.html) * Full technical details at http://www.codeproject.com/Articles/4610/Three-Ways-to-Inject-Your-Code-into-Another-Proces#section_3 */ static char* getProcessInfo(HANDLE hProcessSnapshot, DWORD processId, PROCESSENTRY32 *entry) { entry->dwSize = sizeof(PROCESSENTRY32); if (hProcessSnapshot == INVALID_HANDLE_VALUE) return "getProcessInfo: could not create snapshot"; /* * Locate our process */ if (!Process32First(hProcessSnapshot, entry)) { CloseHandle(hProcessSnapshot); return "getProcessInfo: could not walk process tree"; } else { while (entry->th32ProcessID != processId) { if (!Process32Next(hProcessSnapshot, entry)) { CloseHandle(hProcessSnapshot); return "getProcessInfo: could not find process!"; } } } return NULL; } char* InjectSetEnvironmentVariable(DWORD pid, const char* key, const char* val); #define OPAMreturn CAMLreturn #else #define OPAMreturn(v) CAMLreturn(Val_unit) #endif /* Actual primitives from here */ CAMLprim value OPAMW_GetCurrentProcessID(value unit) { CAMLparam1(unit); OPAMreturn(caml_copy_int32(GetCurrentProcessId())); } CAMLprim value OPAMW_GetStdHandle(value nStdHandle) { CAMLparam1(nStdHandle); #ifdef _WIN32 CAMLlocal1(result); HANDLE hResult; if ((hResult = GetStdHandle(-Int_val(nStdHandle) - 10)) == NULL) caml_raise_not_found(); result = caml_alloc_custom(&HandleOps, sizeof(HANDLE), 0, 1); HANDLE_val(result) = hResult; #endif OPAMreturn(result); } CAMLprim value OPAMW_GetConsoleScreenBufferInfo(value hConsoleOutput) { CAMLparam1(hConsoleOutput); #ifdef _WIN32 CAMLlocal2(result, coord); CONSOLE_SCREEN_BUFFER_INFO buffer; if (!GetConsoleScreenBufferInfo(HANDLE_val(hConsoleOutput), &buffer)) caml_raise_not_found(); result = caml_alloc(5, 0); coord = caml_alloc(2, 0); Store_field(coord, 0, Val_int(buffer.dwSize.X)); Store_field(coord, 1, Val_int(buffer.dwSize.Y)); Store_field(result, 0, coord); coord = caml_alloc(2, 0); Store_field(coord, 0, Val_int(buffer.dwCursorPosition.X)); Store_field(coord, 1, Val_int(buffer.dwCursorPosition.Y)); Store_field(result, 1, coord); Store_field(result, 2, Val_int(buffer.wAttributes)); coord = caml_alloc(4, 0); Store_field(coord, 0, Val_int(buffer.srWindow.Left)); Store_field(coord, 1, Val_int(buffer.srWindow.Top)); Store_field(coord, 2, Val_int(buffer.srWindow.Right)); Store_field(coord, 3, Val_int(buffer.srWindow.Bottom)); Store_field(result, 3, coord); coord = caml_alloc(2, 0); Store_field(coord, 0, Val_int(buffer.dwMaximumWindowSize.X)); Store_field(coord, 1, Val_int(buffer.dwMaximumWindowSize.Y)); Store_field(result, 4, coord); #endif OPAMreturn(result); } CAMLprim value OPAMW_SetConsoleTextAttribute(value hConsoleOutput, value wAttributes) { CAMLparam2(hConsoleOutput, wAttributes); #ifdef _WIN32 if (!SetConsoleTextAttribute(HANDLE_val(hConsoleOutput), Int_val(wAttributes))) caml_failwith("setConsoleTextAttribute"); #endif OPAMreturn(Val_unit); } CAMLprim value OPAMW_FillConsoleOutputCharacter(value vhConsoleOutput, value character, value vnLength, value vdwWriteCoord) { CAMLparam4(vhConsoleOutput, character, vnLength, vdwWriteCoord); #ifdef _WIN32 HANDLE hConsoleOutput = HANDLE_val(vhConsoleOutput); CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo; WCHAR cCharacter = Int_val(character) & 0xFF; DWORD nLength = Int_val(vnLength); COORD dwWriteCoord = {Int_val(Field(vdwWriteCoord, 0)), Int_val(Field(vdwWriteCoord, 1))}; DWORD dwNumberOfCharsWritten; BOOL result = FALSE; if (GetConsoleScreenBufferInfo(hConsoleOutput, &ConsoleScreenBufferInfo)) { while ((result = FillConsoleOutputCharacter(hConsoleOutput, cCharacter, nLength, dwWriteCoord, &dwNumberOfCharsWritten)) && dwNumberOfCharsWritten != nLength) { nLength -= dwNumberOfCharsWritten; dwWriteCoord.X += dwNumberOfCharsWritten; dwWriteCoord.Y += dwWriteCoord.X / ConsoleScreenBufferInfo.dwSize.X; dwWriteCoord.X %= ConsoleScreenBufferInfo.dwSize.X; } } #endif OPAMreturn(Val_bool(result)); } CAMLprim value OPAMW_GetConsoleMode(value hConsoleHandle) { CAMLparam1(hConsoleHandle); #ifdef _WIN32 DWORD dwMode; if (!GetConsoleMode(HANDLE_val(hConsoleHandle), &dwMode)) #endif caml_raise_not_found(); OPAMreturn(Val_int(dwMode)); } CAMLprim value OPAMW_SetConsoleMode(value hConsoleMode, value dwMode) { CAMLparam2(hConsoleMode, dwMode); #ifdef _WIN32 BOOL result = SetConsoleMode(HANDLE_val(hConsoleMode), Int_val(dwMode)); #endif OPAMreturn(Val_bool(result)); } CAMLprim value OPAMW_GetWindowsVersion(value unit) { CAMLparam1(unit); #ifdef _WIN32 CAMLlocal1(result); result = caml_alloc_tuple(4); #if OCAML_VERSION >= 40600 Store_field(result, 0, Val_int(caml_win32_major)); Store_field(result, 1, Val_int(caml_win32_minor)); Store_field(result, 2, Val_int(caml_win32_build)); Store_field(result, 3, Val_int(caml_win32_revision)); #else Store_field(result, 0, Val_int(0)); Store_field(result, 1, Val_int(0)); Store_field(result, 2, Val_int(0)); Store_field(result, 3, Val_int(0)); #endif #endif OPAMreturn(result); } CAMLprim value OPAMW_IsWoW64(value unit) { CAMLparam1(unit); #ifdef _WIN32 BOOL result = FALSE; /* * 32-bit versions may or may not have IsWow64Process (depends on age). * Recommended way is to use GetProcAddress to obtain IsWow64Process, rather * than relying on Windows.h. * See http://msdn.microsoft.com/en-gb/library/windows/desktop/ms684139.aspx */ if (has_IsWoW64Process() && !IsWoW64Process(GetCurrentProcess(), &result)) result = FALSE; #endif OPAMreturn(Val_bool(result)); } /* * Adapted from otherlibs/win32unix/winwait.c win_waitpid */ CAMLprim value OPAMW_waitpids(value vpid_reqs, value vpid_len) { #ifdef _WIN32 int i; DWORD status, retcode; HANDLE pid_req; DWORD err = 0; int len = Int_val(vpid_len); HANDLE *lpHandles = (HANDLE*)malloc(sizeof(HANDLE) * len); value ptr = vpid_reqs; if (lpHandles == NULL) caml_raise_out_of_memory(); for (i = 0; i < len; i++) { lpHandles[i] = (HANDLE)Long_val(Field(ptr, 0)); ptr = Field(ptr, 1); } caml_enter_blocking_section(); retcode = WaitForMultipleObjects(len, lpHandles, FALSE, INFINITE); if (retcode == WAIT_FAILED) err = GetLastError(); caml_leave_blocking_section(); if (err) { win32_maperr(err); uerror("waitpids", Nothing); } pid_req = lpHandles[retcode - WAIT_OBJECT_0]; free(lpHandles); if (! GetExitCodeProcess(pid_req, &status)) { win32_maperr(GetLastError()); uerror("waitpids", Nothing); } /* * NB Unlike in win_waitpid, it's not possible to have status == STILL_ACTIVE */ CloseHandle(pid_req); return alloc_process_status(pid_req, status); #else return Val_unit; #endif } CAMLprim value OPAMW_WriteRegistry(value hKey, value lpSubKey, value lpValueName, value dwType, value lpData) { CAMLparam5(hKey, lpSubKey, lpValueName, dwType, lpData); #ifdef _WIN32 HKEY key; const void* buf = NULL; DWORD cbData = 0; DWORD type = 0; switch (RegOpenKeyEx(roots[Int_val(hKey)], String_val(lpSubKey), 0, KEY_WRITE, &key)) { case ERROR_SUCCESS: { /* Cases match OpamStubsTypes.registry_value */ switch (Int_val(dwType)) { case 0: { buf = String_val(lpData); cbData = strlen(buf) + 1; type = REG_SZ; break; } default: { caml_failwith("OPAMW_WriteRegistry: value not implemented"); break; } } if (RegSetValueEx(key, String_val(lpValueName), 0, type, (LPBYTE)buf, cbData) != ERROR_SUCCESS) { RegCloseKey(key); caml_failwith("RegSetValueEx"); } RegCloseKey(key); break; } case ERROR_FILE_NOT_FOUND: { caml_raise_not_found(); break; } default: { caml_failwith("RegOpenKeyEx"); break; } } #endif OPAMreturn(Val_unit); } CAMLprim value OPAMW_GetConsoleOutputCP(value unit) { CAMLparam1(unit); OPAMreturn(Val_int(GetConsoleOutputCP())); } CAMLprim value OPAMW_GetCurrentConsoleFontEx(value hConsoleOutput, value bMaximumWindow) { CAMLparam2(hConsoleOutput, bMaximumWindow); #ifdef _WIN32 CAMLlocal3(result, coord, name); int len; CONSOLE_FONT_INFOEX fontInfo; fontInfo.cbSize = sizeof(fontInfo); if (GetCurrentConsoleFontEx(HANDLE_val(hConsoleOutput), Bool_val(bMaximumWindow), &fontInfo)) { result = caml_alloc(5, 0); Store_field(result, 0, Val_int(fontInfo.nFont)); coord = caml_alloc(2, 0); Store_field(coord, 0, Val_int(fontInfo.dwFontSize.X)); Store_field(coord, 0, Val_int(fontInfo.dwFontSize.Y)); Store_field(result, 1, coord); Store_field(result, 2, Val_int(fontInfo.FontFamily)); Store_field(result, 3, Val_int(fontInfo.FontWeight)); Store_field(result, 4, caml_copy_string_of_utf16(fontInfo.FaceName)); } else { caml_raise_not_found(); } #endif OPAMreturn(result); } CAMLprim value OPAMW_CreateGlyphChecker(value fontName) { CAMLparam1(fontName); #ifdef _WIN32 CAMLlocal2(result, handle); /* * Any device context will do to load the font, so use the Screen DC. */ HDC hDC = GetDC(NULL); if (hDC) { wchar_t* lpszFace = caml_stat_strdup_to_utf16(String_val(fontName)); HFONT hFont = CreateFontW(0, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, lpszFace); caml_stat_free(lpszFace); if (hFont) { if (SelectObject(hDC, hFont)) { result = caml_alloc_tuple(2); handle = caml_alloc_custom(&HandleOps, sizeof(HANDLE), 0, 1); HANDLE_val(handle) = hDC; Store_field(result, 0, handle); handle = caml_alloc_custom(&HandleOps, sizeof(HANDLE), 0, 1); HANDLE_val(handle) = hFont; Store_field(result, 1, handle); } else { caml_failwith("OPAMW_CheckGlyphs: SelectObject"); } } else { caml_failwith("OPAMW_CheckGlyphs: CreateFontW"); } } else { caml_failwith("OPAMW_CheckGlyphs: GetDC"); } #endif OPAMreturn(result); } CAMLprim value OPAMW_DeleteGlyphChecker(value checker) { CAMLparam1(checker); #ifdef _WIN32 DeleteObject(HANDLE_val(Field(checker, 1))); ReleaseDC(NULL, HANDLE_val(Field(checker, 0))); #endif CAMLreturn(Val_unit); } CAMLprim value OPAMW_HasGlyph(value checker, value scalar) { CAMLparam2(checker, scalar); #ifdef _WIN32 BOOL result = FALSE; HDC hDC = HANDLE_val(Field(checker, 0)); WCHAR test = (WCHAR)Int_val(scalar); WORD index = 0; switch (GetGlyphIndicesW(hDC, &test, 1, &index, GGI_MARK_NONEXISTING_GLYPHS)) { case 1: break; case GDI_ERROR: caml_failwith("OPAMW_CheckGlyphs: GetGlyphIndicesW"); default: caml_failwith("OPAMW_CheckGlyphs: GetGlyphIndicesW (unexpected return)"); } #endif OPAMreturn(Val_bool(index != 0xffff)); } CAMLprim value OPAMW_process_putenv(value pid, value key, value val) { CAMLparam3(pid, key, val); #ifdef _WIN32 CAMLlocal1(res); char* result; /* * MSDN is all over the place as to what the technical limits are for * environment variables (looks like 32KiB for both both name and value) * however there's no need to inject 64KiB data each time - hence 4KiB limit. */ if (caml_string_length(key) > 4095 || caml_string_length(val) > 4095) caml_invalid_argument("Strings too long"); result = InjectSetEnvironmentVariable(Int32_val(pid), String_val(key), String_val(val)); if (result == NULL) { res = Val_true; } else if (strlen(result) == 0) { res = Val_false; } else { caml_failwith(result); } #endif OPAMreturn(res); } CAMLprim value OPAMW_IsWoW64Process(value pid) { CAMLparam1(pid); #ifdef _WIN32 BOOL result = FALSE; if (has_IsWoW64Process()) { HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, Int32_val(pid)); if (hProcess) { if (!IsWoW64Process(hProcess, &result)) result = FALSE; CloseHandle(hProcess); } } #endif OPAMreturn(Val_bool(result)); } /* * Somewhat against my better judgement, wrap SHGetFolderPath rather than * SHGetKnownFolderPath to maintain XP compatibility. OPAM already requires * Windows Vista+ because of GetCurrentConsoleFontEx, but there may be a * workaround for that for XP lusers. */ CAMLprim value OPAMW_SHGetFolderPath(value nFolder, value dwFlags) { CAMLparam2(nFolder, dwFlags); #ifdef _WIN32 CAMLlocal1(result); TCHAR szPath[MAX_PATH]; if (SUCCEEDED(SHGetFolderPath(NULL, Int_val(nFolder), NULL, Int_val(dwFlags), szPath))) result = caml_copy_string(szPath); else caml_failwith("OPAMW_SHGetFolderPath"); #endif OPAMreturn(result); } CAMLprim value OPAMW_SendMessageTimeout(value hWnd, value uTimeout, value fuFlags, value vmsg, value vwParam, value vlParam) { CAMLparam5(hWnd, vmsg, vwParam, vlParam, fuFlags); CAMLxparam1(uTimeout); #ifdef _WIN32 CAMLlocal1(result); DWORD_PTR dwReturnValue; HRESULT lResult; WPARAM wParam; LPARAM lParam; UINT msg; switch (Int_val(vmsg)) { case 0: { msg = WM_SETTINGCHANGE; wParam = Int_val(vwParam); lParam = (LPARAM)String_val(vlParam); break; } default: { caml_failwith("OPAMW_SendMessageTimeout: message not implemented"); break; } } lResult = SendMessageTimeout((HWND)Nativeint_val(hWnd), msg, wParam, lParam, Int_val(fuFlags), Int_val(uTimeout), &dwReturnValue); switch (Int_val(vmsg)) { case 0: { result = caml_alloc(2, 0); Store_field(result, 0, Val_int(lResult)); Store_field(result, 1, Val_int(dwReturnValue)); break; } } #endif OPAMreturn(result); } CAMLprim value OPAMW_SendMessageTimeout_byte(value * v, int n) { return OPAMW_SendMessageTimeout(v[0], v[1], v[2], v[3], v[4], v[5]); } CAMLprim value OPAMW_GetParentProcessID(value processId) { CAMLparam1(processId); #ifdef _WIN32 PROCESSENTRY32 entry; char* msg; /* * Create a Toolhelp Snapshot of running processes */ HANDLE hProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if ((msg = getProcessInfo(hProcessSnapshot, Int32_val(processId), &entry))) caml_failwith(msg); /* * Finished with the snapshot */ CloseHandle(hProcessSnapshot); #endif OPAMreturn(caml_copy_int32(entry.th32ParentProcessID)); } CAMLprim value OPAMW_GetConsoleAlias(value alias, value exeName) { CAMLparam2(alias, exeName); #ifdef _WIN32 CAMLlocal1(result); DWORD nLength = 8192; LPTSTR buffer = (LPTSTR)malloc(nLength); if (!buffer) caml_raise_out_of_memory(); if (GetConsoleAlias((LPTSTR)String_val(alias), buffer, nLength, (LPTSTR)String_val(exeName))) { result = caml_copy_string(buffer); } else { result = caml_copy_string(""); } free(buffer); #endif OPAMreturn(result); } opam-2.1.5/src/solver/0002755000175000017500000000000014427463453013622 5ustar stephstephopam-2.1.5/src/solver/opamCudf.mli0000644000175000017500000002603214427463453016064 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Solver interaction through Cudf, conversion of solver answer to an opam solution *) open OpamTypes [@@@ocaml.warning "-33"] open OpamDoseCompat module Package : sig type t = Cudf.package val equal : t -> t -> bool val compare : t -> t -> int val to_json : t -> OpamJson.t val of_json : OpamJson.t -> t option end (** Cudf sets *) module Set: OpamStd.SET with type elt = Package.t (** Cudf maps *) module Map: OpamStd.MAP with type key = Package.t (** Cudf graph *) module Graph: sig (** Graph of cudf packages *) include module type of Dose_algo.Defaultgraphs.PackageGraph.G (** Build a graph from a CUDF universe. Warning: dependency edges are towards the dependency, which is the reverse of what happens in the action graph. *) val of_universe: Cudf.universe -> t (** Return the transitive closure of [g] *) val transitive_closure: t -> t (** Reverse the direction of all edges *) val mirror: t -> t end (** Computation of differences between universe. Returns the sets of packages to install and remove respectively. *) val diff: Cudf.universe -> Cudf.universe -> (Set.t * Set.t) (** Cudf action graph *) module Action: OpamActionGraph.ACTION with type package = Package.t module ActionGraph: OpamActionGraph.SIG with type package = Package.t (** Abstract type that may be returned in case of conflicts *) type conflict (** Return the transitive closure of dependencies of [set] *) val dependencies: Cudf.universe -> Set.t -> Set.t (** Return the transitive closure of reverse dependencies of [set] *) val reverse_dependencies: Cudf.universe -> Set.t -> Set.t (** Sorts the given packages topolgically (be careful if there are cycles, e.g. if the universe was loaded with [post] dependencies enabled) *) val dependency_sort: Cudf.universe -> Set.t -> Cudf.package list (** Check if a request is satisfiable and return the reasons why not unless [explain] is set to [false] *) val check_request: ?explain:bool -> version_map:int OpamPackage.Map.t -> Cudf.universe -> Cudf_types.vpkg request -> (Cudf.universe, conflict) result (** Compute the final universe state using the external solver. *) val get_final_universe: version_map:int OpamPackage.Map.t -> Cudf.universe -> Cudf_types.vpkg request -> (Cudf.universe, conflict) result (** Compute the list of actions to match the difference between two universe. Remark: the result order is unspecified, ie. need to use [atomic_actions] to get a solution which respects the topological order induced by dependencies. *) val actions_of_diff: (Set.t * Set.t) -> Cudf.package atomic_action list exception Cyclic_actions of Cudf.package action list list (** Computes the actions to process from a solution, from the actions obtained by a simple universe diff. The 'simple' universe should not contain build dependencies and will be used for resolution ; [complete_universe] should include build-deps, it's used to get the dependency ordering of actions. Returns a graph of atomic actions, i.e. only removals and installs. Use [reduce_actions] to reduce it to a graph including reinstall and up/down-grade actions. May raise [Cyclic_actions]. *) val atomic_actions: simple_universe:Cudf.universe -> complete_universe:Cudf.universe -> [< Cudf.package highlevel_action ] list -> ActionGraph.t (** Heuristic to compute the likely cause of all actions in a graph from the set of packages passed in the original request. Assumes a reduced graph. Takes the set of requested package names, and the set of packages marked for reinstall. *) val compute_root_causes: ActionGraph.t -> OpamPackage.Name.Set.t -> OpamPackage.Set.t -> Cudf.package cause Map.t exception Solver_failure of string (** Resolve a CUDF request. The result is either a conflict holding an explanation of the error, or a resulting universe. [~extern] specifies whether the external solver should be used *) val resolve: extern:bool -> version_map:int OpamPackage.Map.t -> Cudf.universe -> Cudf_types.vpkg request -> (Cudf.universe, conflict) result (** Computes a list of actions to proceed from the result of [resolve]. Note however than the action list is not yet complete: the transitive closure of reinstallations is not yet completed, as it requires to fold over the dependency graph in considering the optional dependencies. The first argument specifies a function that will be applied to the starting universe before computation: useful to re-add orphan packages. *) val to_actions: (Cudf.universe -> Cudf.universe) -> Cudf.universe -> (Cudf.universe, conflict) result -> (Cudf.package atomic_action list, conflict) result (** [remove universe name constr] Remove all the packages called [name] satisfying the constraints [constr] in the universe [universe]. *) val remove: Cudf.universe -> Cudf_types.pkgname -> Cudf_types.constr -> Cudf.universe (** Uninstall all the package in the universe. *) val uninstall_all: Cudf.universe -> Cudf.universe (** Install a package in the universe. We don't care about any invariant here (eg. the resulting universe can have multiple versions of the same package installed). *) val install: Cudf.universe -> Cudf.package -> Cudf.universe (** Remove all the versions of a given package, but the one given as argument. *) val remove_all_uninstalled_versions_but: Cudf.universe -> string -> Cudf_types.constr -> Cudf.universe (** Cudf labels for package fields in the cudf format (use for the field Cudf.pkg_extra and with Cudf.lookup_package_property) *) (** the original OPAM package name (as string) *) val s_source: string (** the original OPAM package version (as string) *) val s_source_number: string (** a package to be reinstalled (a bool) *) val s_reinstall: string (** true if this package belongs to the roots ("installed manually") packages *) val s_installed_root: string (** true if the package is pinned to this version *) val s_pinned: string (** the number of versions of the package since this one, cubed *) val s_version_lag: string (** valid cudf name for the dummy package used for enforcing opam's switch invariants *) val opam_invariant_package_name: string (** valid cudf name and version for the dummy package used for enforcing opam's switch invariants *) val opam_invariant_package: string * int val is_opam_invariant: Cudf.package -> bool (** {2 Pretty-printing} *) (** Convert a package constraint to something readable. *) val string_of_vpkgs: Cudf_types.vpkg list -> string val make_conflicts: version_map:int package_map -> Cudf.universe -> Dose_algo.Diagnostic.diagnosis -> ('a, conflict) result val cycle_conflict: version_map:int package_map -> Cudf.universe -> string list list -> ('a, conflict) result type explanation = [ `Conflict of string option * string list * bool | `Missing of string option * string * (OpamPackage.Name.t * OpamFormula.version_formula) OpamFormula.formula ] (** Convert a conflict to something readable by the user. The second argument should return a string explaining the unavailability, or the empty string, when called on an unavailable package (the reason can't be known this deep in the solver) *) val string_of_conflicts: package_set -> (name * OpamFormula.version_formula -> string) -> conflict -> string val string_of_explanations: (name * OpamFormula.version_formula -> string) -> explanation list * string list list -> string (** Returns two lists: - the reasons why the request can't be satisfied with conflict explanations - the cycles in the actions to process (exclusive with the first) *) val conflict_explanations: package_set -> (name * OpamFormula.version_formula -> string) -> conflict -> (string * string list * string list) list * string list val string_of_explanation: (name * OpamFormula.version_formula -> string) -> explanation -> string * string list * string list val conflict_explanations_raw: package_set -> conflict -> explanation list * string list list (** Properly concat a single conflict as returned by [conflict_explanations] for display *) val string_of_conflict: ?start_column:int -> string * string list * string list -> string (** Dumps the given cudf universe to the given channel *) val dump_universe: out_channel -> Cudf.universe -> unit (** Pretty-print atoms *) val string_of_atom: Cudf_types.vpkg -> string (** Pretty-print requests *) val string_of_request: Cudf_types.vpkg request -> string (** Pretty-print the universe *) val string_of_universe: Cudf.universe -> string (** Pretty-print of packages *) val string_of_packages: Cudf.package list -> string (** Convert a cudf package back to an OPAM package *) val cudf2opam: Cudf.package -> package (** Returns the list of packages in a Cudf universe *) val packages: Cudf.universe -> Cudf.package list (** Converts an OPAM request to a Cudf request *) val to_cudf: Cudf.universe -> Cudf_types.vpkg request -> Cudf.preamble * Cudf.universe * Cudf.request module Json: sig open Cudf_types val version_to_json : version OpamJson.encoder val version_of_json : version OpamJson.decoder val relop_to_json : relop OpamJson.encoder val relop_of_json : relop OpamJson.decoder val enum_keep_to_json : enum_keep OpamJson.encoder val enum_keep_of_json : enum_keep OpamJson.decoder val constr_to_json : constr OpamJson.encoder val constr_of_json : constr OpamJson.decoder val vpkg_to_json : vpkg OpamJson.encoder val vpkg_of_json : vpkg OpamJson.decoder val vpkglist_to_json : vpkglist OpamJson.encoder val vpkglist_of_json : vpkglist OpamJson.decoder val veqpkg_to_json : veqpkg OpamJson.encoder val veqpkg_of_json : veqpkg OpamJson.decoder val veqpkglist_to_json : veqpkglist OpamJson.encoder val veqpkglist_of_json : veqpkglist OpamJson.decoder val vpkgformula_to_json : vpkgformula OpamJson.encoder val vpkgformula_of_json : vpkgformula OpamJson.decoder val typedecl1_to_json : typedecl1 OpamJson.encoder val typedecl1_of_json : typedecl1 OpamJson.decoder val typedecl_to_json : typedecl OpamJson.encoder val typedecl_of_json : typedecl OpamJson.decoder val typed_value_to_json : typed_value OpamJson.encoder val typed_value_of_json : typed_value OpamJson.decoder val package_to_json : Cudf.package OpamJson.encoder val package_of_json : Cudf.package OpamJson.decoder end opam-2.1.5/src/solver/opamBuiltinZ3.ml.dummy0000644000175000017500000000204214427463453020002 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCudfSolverSig let name = "builtin-dummy-z3-solver" let is_present () = false let ext = ref None let command_name = None let default_criteria = { crit_default = ""; crit_upgrade = ""; crit_fixup = ""; crit_best_effort_prefix = None; } let call ~criteria:_ ?timeout:_ _cudf = failwith "This opam was compiled without the Z3 solver built in" opam-2.1.5/src/solver/opamSolver.mli0000644000175000017500000001273514427463453016462 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Entry point to the solver, conversion of opam package universes to Cudf, dependencies computation. Front-end to Dose. *) open OpamTypes module Action : OpamActionGraph.ACTION with type package = package module ActionGraph : OpamActionGraph.SIG with type package = package type solution val empty_universe: universe (** {2 Solver} *) (** Convert a request to a string *) val string_of_request: atom request -> string (** Compute statistics about a solution *) val stats: solution -> stats (** Return the new packages in the solution *) val new_packages: solution -> package_set (** Return all packages appearing in the solution *) val all_packages: solution -> package_set (** Pretty-printing of statistics *) val string_of_stats: stats -> string (** Is the solution empty? *) val solution_is_empty: solution -> bool (** Display a solution *) val print_solution: messages:(package -> string list) -> append:(package -> string) -> requested:name_set -> reinstall:package_set -> solution -> unit (** Serialize a solution *) val solution_to_json : solution OpamJson.encoder val solution_of_json : solution OpamJson.decoder (** Computes an opam->cudf version map from a set of package *) val cudf_versions_map: universe -> package_set -> int OpamPackage.Map.t (** Creates a CUDF universe from an OPAM universe, including the given packages. Evaluation of the first 4 arguments is staged. Warning: when [depopts] is [true], the optional dependencies may become strong dependencies. Use [add_invariant] if you expect to call the solver and need the switch invariants to be respected; remember in that case to call [Cudf.remove_package universe OpamCudf.opam_invariant_package] before exporting the results *) val load_cudf_universe: universe -> ?version_map:int package_map -> ?add_invariant:bool -> package_set -> ?depopts:bool -> build:bool -> post:bool -> unit -> Cudf.universe (** Build a request *) val request: ?criteria:solver_criteria -> ?install:atom list -> ?upgrade:atom list -> ?remove:atom list -> unit -> atom request (** Given a description of packages, return a solution preserving the consistency of the initial description. *) val resolve : universe -> orphans:package_set -> atom request -> (solution, OpamCudf.conflict) result (** Returns the graph of atomic actions (rm, inst) from a solution *) val get_atomic_action_graph : solution -> ActionGraph.t (** Keep only the packages that are installable. *) val installable: universe -> package_set (** Like [installable], but within a subset and potentially much faster *) val installable_subset: universe -> package_set -> package_set (** Return the transitive dependency closures of a collection of packages.*) val dependencies : depopts:bool -> build:bool -> post:bool -> installed:bool -> ?unavailable:bool -> universe -> package_set -> package_set (** Same as [dependencies] but for reverse dependencies *) val reverse_dependencies : depopts:bool -> build:bool -> post:bool -> installed:bool -> ?unavailable:bool -> universe -> package_set -> package_set (** Sorts the given package set in topological order (as much as possible, beware of cycles in particular if [post] is [true]) *) val dependency_sort : depopts:bool -> build:bool -> post:bool -> universe -> package_set -> package list module PkgGraph: Graph.Sig.I with type V.t = OpamPackage.t val dependency_graph : depopts:bool -> build:bool -> post:bool -> installed:bool -> ?unavailable:bool -> universe -> PkgGraph.t (** Check the current set of installed packages in a universe for inconsistencies *) val check_for_conflicts : universe -> OpamCudf.conflict option (** Checks the given package set for complete installability ; returns None if they can all be installed together *) val coinstallability_check : universe -> package_set -> OpamCudf.conflict option (** Checks if the given atoms can be honored at the same time in the given universe *) val atom_coinstallability_check : universe -> atom list -> bool (** [coinstallable_subset univ set packages] returns the subset of [packages] which are individually co-installable with [set], i.e. that can be installed if [set] while [set] remains installed. This returns the empty set if [set] is already not coinstallable. *) val coinstallable_subset : universe -> package_set -> package_set -> package_set (** Dumps a cudf file containing all available packages in the given universe, plus version bindings (as '#v2v' comments) for the other ones. *) val dump_universe: universe -> out_channel -> unit (** Filters actions in a solution. Dependents of a removed actions are removed to keep consistency *) val filter_solution: (package -> bool) -> solution -> solution opam-2.1.5/src/solver/opamBuiltinMccs.ml.real0000644000175000017500000000471314427463453020172 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2017-2018 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCudfSolverSig [@@@ocaml.warning "-33"] open OpamDoseCompat let name solver_backend = "builtin-"^Mccs.get_solver_id ~solver:solver_backend () let default_criteria = { crit_default = "-removed,\ -count[avoid-version,changed],\ -count[version-lag,request],\ -count[version-lag,changed],\ -count[missing-depexts,changed],\ -changed"; crit_upgrade = "-removed,\ -count[avoid-version,changed],\ -count[version-lag,solution],\ -count[missing-depexts,changed],\ -new"; crit_fixup = "-changed,\ -count[avoid-version:,true],\ -count[version-lag:,false],\ -count[missing-depexts:,true]"; crit_best_effort_prefix = Some "+count[opam-query:,false],"; } let call solver_backend ext ~criteria ?timeout cudf = let solver = match solver_backend, ext with | `LP _, Some ext -> `LP ext | _ -> solver_backend in match Mccs.resolve_cudf ~solver ~verbose:OpamCoreConfig.(abs !r.debug_level >= 2) ?timeout criteria cudf with | None -> raise Dose_common.CudfSolver.Unsat | Some (preamble, univ) -> Some preamble, univ | exception Mccs.Timeout -> raise (Timeout None) let of_backend backend : (module OpamCudfSolverSig.S) = (module struct let name = name backend let ext = ref None let is_present () = match backend, !ext with | `LP "", None -> false | `LP cmd, None | `LP _, Some cmd -> OpamSystem.resolve_command cmd <> None | _ -> true let command_name = None let default_criteria = default_criteria let call = call backend !ext end) let all_backends = List.map of_backend Mccs.supported_backends opam-2.1.5/src/solver/opamSolverConfig.ml0000644000175000017500000002205714427463453017435 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2015-2018 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) module E = struct type OpamStd.Config.E.t += | BESTEFFORT of bool option | BESTEFFORTPREFIXCRITERIA of string option | CRITERIA of string option | CUDFFILE of string option | CUDFTRIM of string option | DIGDEPTH of int option | EXTERNALSOLVER of string option | FIXUPCRITERIA of string option | NOASPCUD of bool option | PREPRO of bool option | SOLVERALLOWSUBOPTIMAL of bool option | SOLVERTIMEOUT of float option | UPGRADECRITERIA of string option | USEINTERNALSOLVER of bool option | VERSIONLAGPOWER of int option open OpamStd.Config.E let besteffort = value (function BESTEFFORT b -> b | _ -> None) let besteffortprefixcriteria = value (function BESTEFFORTPREFIXCRITERIA s -> s | _ -> None) let criteria = value (function CRITERIA s -> s | _ -> None) let cudffile = value (function CUDFFILE s -> s | _ -> None) let cudftrim = value (function CUDFTRIM s -> s | _ -> None) let digdepth = value (function DIGDEPTH i -> i | _ -> None) let externalsolver = value (function EXTERNALSOLVER s -> s | _ -> None) let fixupcriteria = value (function FIXUPCRITERIA s -> s | _ -> None) let noaspcud = value (function NOASPCUD b -> b | _ -> None) let prepro = value (function PREPRO b -> b | _ -> None) let solverallowsuboptimal = value (function SOLVERALLOWSUBOPTIMAL b -> b | _ -> None) let solvertimeout = value (function SOLVERTIMEOUT f -> f | _ -> None) let useinternalsolver = value (function USEINTERNALSOLVER b -> b | _ -> None) let upgradecriteria = value (function UPGRADECRITERIA s -> s | _ -> None) let versionlagpower = value (function VERSIONLAGPOWER i -> i | _ -> None) end type t = { cudf_file: string option; solver: (module OpamCudfSolver.S) Lazy.t; best_effort: bool; (* The following are options because the default can only be known once the solver is known, so we set it only if no customisation was made *) solver_preferences_default: string option Lazy.t; solver_preferences_upgrade: string option Lazy.t; solver_preferences_fixup: string option Lazy.t; solver_preferences_best_effort_prefix: string option Lazy.t; solver_timeout: float option; solver_allow_suboptimal: bool; cudf_trim: string option; dig_depth: int; preprocess: bool; version_lag_power: int; } type 'a options_fun = ?cudf_file:string option -> ?solver:((module OpamCudfSolver.S) Lazy.t) -> ?best_effort:bool -> ?solver_preferences_default:string option Lazy.t -> ?solver_preferences_upgrade:string option Lazy.t -> ?solver_preferences_fixup:string option Lazy.t -> ?solver_preferences_best_effort_prefix:string option Lazy.t -> ?solver_timeout:float option -> ?solver_allow_suboptimal:bool -> ?cudf_trim:string option -> ?dig_depth:int -> ?preprocess:bool -> ?version_lag_power:int -> 'a let default = let solver = lazy ( OpamCudfSolver.get_solver OpamCudfSolver.default_solver_selection ) in { cudf_file = None; solver; best_effort = false; solver_preferences_default = lazy None; solver_preferences_upgrade = lazy None; solver_preferences_fixup = lazy None; solver_preferences_best_effort_prefix = lazy None; solver_timeout = Some 60.; solver_allow_suboptimal = true; cudf_trim = None; dig_depth = 2; preprocess = true; version_lag_power = 1; } let setk k t ?cudf_file ?solver ?best_effort ?solver_preferences_default ?solver_preferences_upgrade ?solver_preferences_fixup ?solver_preferences_best_effort_prefix ?solver_timeout ?solver_allow_suboptimal ?cudf_trim ?dig_depth ?preprocess ?version_lag_power = let (+) x opt = match opt with Some x -> x | None -> x in k { cudf_file = t.cudf_file + cudf_file; solver = t.solver + solver; best_effort = t.best_effort + best_effort; solver_preferences_default = t.solver_preferences_default + solver_preferences_default; solver_preferences_upgrade = t.solver_preferences_upgrade + solver_preferences_upgrade; solver_preferences_fixup = t.solver_preferences_fixup + solver_preferences_fixup; solver_preferences_best_effort_prefix = t.solver_preferences_best_effort_prefix + solver_preferences_best_effort_prefix; solver_timeout = t.solver_timeout + solver_timeout; solver_allow_suboptimal = t.solver_allow_suboptimal + solver_allow_suboptimal; cudf_trim = t.cudf_trim + cudf_trim; dig_depth = t.dig_depth + dig_depth; preprocess = t.preprocess + preprocess; version_lag_power = t.version_lag_power + version_lag_power; } let set t = setk (fun x () -> x) t let r = ref default let update ?noop:_ = setk (fun cfg () -> r := cfg) !r let with_auto_criteria config = let criteria = lazy ( let module S = (val Lazy.force config.solver) in S.default_criteria ) in set config ~solver_preferences_default: (lazy (match config.solver_preferences_default with | lazy None -> Some (Lazy.force criteria).OpamCudfSolver.crit_default | lazy some -> some)) ~solver_preferences_upgrade: (lazy (match config.solver_preferences_upgrade with | lazy None -> Some (Lazy.force criteria).OpamCudfSolver.crit_upgrade | lazy some -> some)) ~solver_preferences_fixup: (lazy (match config.solver_preferences_fixup with | lazy None -> Some (Lazy.force criteria).OpamCudfSolver.crit_fixup | lazy some -> some)) ~solver_preferences_best_effort_prefix: (lazy (match config.solver_preferences_best_effort_prefix with | lazy None -> (Lazy.force criteria).OpamCudfSolver.crit_best_effort_prefix | lazy some -> some)) () let initk k = let open OpamStd.Option.Op in let solver = let open OpamCudfSolver in match E.externalsolver () with | Some "" -> lazy (get_solver ~internal:true default_solver_selection) | Some s -> lazy (solver_of_string s) | None -> let internal = E.useinternalsolver () ++ E.noaspcud () in lazy (get_solver ?internal default_solver_selection) in let criteria = E.criteria () >>| fun c -> lazy (Some c) in let upgrade_criteria = (E.upgradecriteria () >>| fun c -> lazy (Some c)) ++ criteria in let fixup_criteria = E.fixupcriteria () >>| fun c -> (lazy (Some c)) in let best_effort_prefix_criteria = E.besteffortprefixcriteria () >>| fun c -> (lazy (Some c)) in let solver_timeout = E.solvertimeout () >>| fun f -> if f <= 0. then None else Some f in setk (setk (fun c -> r := with_auto_criteria c; k)) !r ~cudf_file:(E.cudffile ()) ~solver ?best_effort:(E.besteffort ()) ?solver_preferences_default:criteria ?solver_preferences_upgrade:upgrade_criteria ?solver_preferences_fixup:fixup_criteria ?solver_preferences_best_effort_prefix:best_effort_prefix_criteria ?solver_timeout ?solver_allow_suboptimal:(E.solverallowsuboptimal ()) ~cudf_trim:(E.cudftrim ()) ?dig_depth:(E.digdepth ()) ?preprocess:(E.prepro ()) ?version_lag_power:(E.versionlagpower ()) let init ?noop:_ = initk (fun () -> ()) let best_effort = let r = lazy ( !r.best_effort && let crit = match Lazy.force !r.solver_preferences_default with | Some c -> c | None -> failwith "Solver criteria uninitialised" in let pfx = Lazy.force !r.solver_preferences_best_effort_prefix in pfx <> None || OpamStd.String.contains ~sub:"opam-query" crit || (OpamConsole.warning "Your solver configuration does not support --best-effort, the option \ was ignored (you need to specify variable OPAMBESTEFFORTCRITERIA, or \ set your criteria to maximise the count for cudf attribute \ 'opam-query')"; false) ) in fun () -> Lazy.force r let criteria kind = let crit = match kind with | `Default -> !r.solver_preferences_default | `Upgrade -> !r.solver_preferences_upgrade | `Fixup -> !r.solver_preferences_fixup in let str = match Lazy.force crit with | Some c -> c | None -> failwith "Solver criteria uninitialised" in if !r.best_effort then match !r.solver_preferences_best_effort_prefix with | lazy (Some pfx) -> pfx ^ str | lazy None -> str else str let call_solver ~criteria cudf = let module S = (val Lazy.force (!r.solver)) in OpamConsole.log "SOLVER" "Calling solver %s with criteria %s" (OpamCudfSolver.get_name (module S)) criteria; S.call ~criteria ?timeout:(!r.solver_timeout) cudf opam-2.1.5/src/solver/dune0000644000175000017500000000264514427463453014505 0ustar stephsteph(library (name opam_solver) (public_name opam-solver) (synopsis "OCaml Package Manager solver interaction library") (libraries opam-format cudf dose3.algo (select opamDoseCompat.ml from (!dose3.opam -> opamDoseCompat.ml.6) (dose3.dose_src_ext_vendor -> opamDoseCompat.ml.6) ( -> opamDoseCompat.ml.5)) (select opamDoseCompat.mli from (!dose3.opam -> opamDoseCompat.mli.6) (dose3.dose_src_ext_vendor -> opamDoseCompat.mli.6) ( -> opamDoseCompat.mli.5)) (select opamBuiltinMccs.ml from (mccs -> opamBuiltinMccs.ml.real) ( -> opamBuiltinMccs.ml.dummy)) (select opamBuiltinZ3.ml from (z3 -> opamBuiltinZ3.ml.real) ( -> opamBuiltinZ3.ml.dummy)) (select opamBuiltin0install.ml from (opam-0install-cudf -> opamBuiltin0install.ml.real) ( -> opamBuiltin0install.ml.dummy))) (flags (:standard (:include ../ocaml-flags-standard.sexp) (:include ../ocaml-flags-configure.sexp) (:include ../ocaml-context-flags.sexp))) (wrapped false)) (rule (with-stdout-to opamDoseCompat.ml.6 (run echo ""))) (rule (with-stdout-to opamDoseCompat.mli.6 (run echo ""))) opam-2.1.5/src/solver/opamActionGraph.ml0000644000175000017500000003005414427463453017230 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2014-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes module type ACTION = sig type package module Pkg : GenericPackage with type t = package include OpamParallel.VERTEX with type t = package action val to_string: [< t ] -> string val to_aligned_strings: ?append:(package -> string) -> [< t ] list -> string list list module Set: OpamStd.SET with type elt = package action module Map: OpamStd.MAP with type key = package action end let name_of_action = function | `Remove _ -> "remove" | `Install _ -> "install" | `Change (`Up,_,_) -> "upgrade" | `Change (`Down,_,_) -> "downgrade" | `Reinstall _ -> "recompile" | `Build _ -> "build" | `Fetch _ -> "fetch" let symbol_of_action = let open OpamConsole in function | `Remove _ -> utf8_symbol Symbols.circled_division_slash ~alternates:[Symbols.greek_small_letter_lambda] "X" | `Install _ -> utf8_symbol Symbols.asterisk_operator ~alternates:[Symbols.six_pointed_black_star] "*" | `Change (`Up,_,_) -> utf8_symbol Symbols.north_east_arrow ~alternates:[Symbols.upwards_arrow] "U" | `Change (`Down,_,_) -> utf8_symbol Symbols.south_east_arrow ~alternates:[Symbols.downwards_arrow] "D" | `Reinstall _ -> utf8_symbol Symbols.clockwise_open_circle_arrow ~alternates:[Symbols.up_down_arrow] "R" | `Build _ -> utf8_symbol Symbols.greek_small_letter_lambda ~alternates:[Symbols.six_pointed_black_star] "B" | `Fetch _ -> utf8_symbol Symbols.downwards_black_arrow ~alternates:[Symbols.downwards_double_arrow; Symbols.black_down_pointing_triangle] "F" let action_strings ?utf8 a = if utf8 = None && (OpamConsole.utf8 ()) || utf8 = Some true then symbol_of_action a else name_of_action a let action_color c = OpamConsole.colorise (match c with | `Install _ | `Change (`Up,_,_) -> `green | `Remove _ | `Change (`Down,_,_) -> `red | `Reinstall _ -> `yellow | `Build _ | `Fetch _ -> `cyan) module MakeAction (P: GenericPackage) : ACTION with type package = P.t = struct module Pkg = P type package = P.t type t = package action let compare t1 t2 = (* `Install > `Build > `Fetch > `Upgrade > `Reinstall > `Downgrade > `Remove *) match t1,t2 with | `Remove p, `Remove q | `Install p, `Install q | `Reinstall p, `Reinstall q | `Build p, `Build q | `Fetch p, `Fetch q -> P.compare p q | `Change (`Up,p0,p), `Change (`Up,q0,q) | `Change (`Down,p0,p), `Change (`Down,q0,q) -> let c = P.compare p q in if c <> 0 then c else P.compare p0 q0 | `Install _, _ | _, `Remove _ -> 1 | _, `Install _ | `Remove _, _ -> -1 | `Build _, _ | _, `Change (`Down,_,_) -> 1 | _, `Build _ | `Change (`Down,_,_), _ -> -1 | `Fetch _, _ | _, `Reinstall _ -> 1 | _, `Fetch _ | `Reinstall _, _ -> -1 let hash a = Hashtbl.hash (OpamTypesBase.map_action P.hash a) let equal t1 t2 = compare t1 t2 = 0 let to_string a = match a with | `Remove p | `Install p | `Reinstall p | `Build p | `Fetch p -> Printf.sprintf "%s %s" (action_strings a) (P.to_string p) | `Change (_,p0,p) -> Printf.sprintf "%s.%s %s %s" (P.name_to_string p0) (P.version_to_string p0) (action_strings a) (P.version_to_string p) let to_aligned_strings ?(append=(fun _ -> "")) l = List.map (fun a -> let a = (a :> package action) in (if OpamConsole.utf8 () then action_color a (symbol_of_action a) else "-") :: name_of_action a :: OpamConsole.colorise `bold (P.name_to_string (OpamTypesBase.action_contents a)) :: match a with | `Remove p | `Install p | `Reinstall p | `Build p | `Fetch p -> (P.version_to_string p ^ append p) :: [] | `Change (_,p0,p) -> Printf.sprintf "%s to %s" (P.version_to_string p0 ^ append p0) (P.version_to_string p ^ append p) :: []) l let to_json = function | `Remove p -> `O ["remove", P.to_json p] | `Install p -> `O ["install", P.to_json p] | `Change (d, o, p) -> let dir_to_json = function | `Up -> `String "up" | `Down -> `String "down" in `O ["change", `A [dir_to_json d; P.to_json o;P.to_json p]] | `Reinstall p -> `O ["recompile", P.to_json p] | `Build p -> `O ["build", P.to_json p] | `Fetch p -> `O ["fetch", P.to_json p] let of_json = let open OpamStd.Option.Op in function | `O ["remove", p] -> P.of_json p >>= (fun p -> Some (`Remove p)) | `O ["install", p] -> P.of_json p >>= (fun p -> Some (`Install p)) | `O ["change", `A [dj; oj; pj]] -> let json_of_dir = function | `String "up" -> Some `Up | `String "down" -> Some `Down | _ -> None in json_of_dir dj >>= fun d -> P.of_json oj >>= fun o -> P.of_json pj >>= fun p -> Some (`Change(d, o, p)) | `O ["recompile", p] -> P.of_json p >>= (fun p -> Some (`Reinstall p)) | `O ["build", p] -> P.of_json p >>= (fun p -> Some (`Build p)) | `O ["fetch", p] -> P.of_json p >>= (fun p -> Some (`Fetch p)) | _ -> None module O = struct type t = package action let compare = compare let to_string = to_string let to_json = to_json let of_json = of_json end module Set = OpamStd.Set.Make(O) module Map = OpamStd.Map.Make(O) end module type SIG = sig type package include OpamParallel.GRAPH with type V.t = package OpamTypes.action val reduce: t -> t val explicit: ?noop_remove:(package -> bool) -> sources_needed:(package -> bool) -> t -> t val fold_descendants: (V.t -> 'a -> 'a) -> 'a -> t -> V.t -> 'a end module Make (A: ACTION) : SIG with type package = A.package = struct type package = A.package include OpamParallel.MakeGraph(A) module Map = OpamStd.Map.Make (A.Pkg) module Set = OpamStd.Set.Make (A.Pkg) (* Turn concrete actions (only install, remove and build) to higher-level actions (install, remove, up/downgrade, recompile). Builds are removed when they directly precede an install, which should be the case when [explicit] is used. *) let reduce g = let g = copy g in let removals = fold_vertex (fun v acc -> match v with | `Remove p -> OpamStd.String.Map.add (A.Pkg.name_to_string p) p acc | _ -> acc) g OpamStd.String.Map.empty in iter_vertex (function | `Build p as build -> (match fold_succ (fun v _ -> if v = `Install p then Some v else None) g build None with | None -> () | Some inst -> iter_pred (fun pred -> add_edge g pred inst) g build; remove_vertex g build) | _ -> ()) g; let reduced = ref Map.empty in let g = map_vertex (function | `Install p as act -> (try let p0 = OpamStd.String.Map.find (A.Pkg.name_to_string p) removals in let act = match A.Pkg.compare p0 p with | 0 -> `Reinstall p | c -> `Change ((if c < 0 then `Up else `Down), p0, p) in reduced := Map.add p0 act !reduced; act with Not_found -> act) | act -> act) g in Map.iter (fun p act -> let rm_act = `Remove p in iter_pred (fun v -> add_edge g v act) g rm_act; remove_vertex g rm_act ) !reduced; g let same_name p1 p2 = A.Pkg.(name_to_string p1 = name_to_string p2) let compute_closed_predecessors noop_remove g = let closed_g = copy g in transitive_closure closed_g; let closed_packages = (* The set of package that do not have dependencies (in the action graph). *) fold_vertex (fun a acc -> match a with | `Build p -> let pred = (* We ignore predecessors that do not modify the prefix *) List.filter (function | `Remove nv -> not (noop_remove nv) | _ -> true) (pred closed_g a) in if pred = [] then Set.add p acc else acc | _ -> acc) g Set.empty in let dependent_base_packages = fold_vertex (fun a acc -> match a with | `Install p | `Reinstall p | `Change (_,_,p) -> let preds = List.filter (function | `Build q as b -> Set.mem q closed_packages && not (List.exists (function | `Remove r -> same_name p r | _ -> false) (pred closed_g b)) | _ -> false) (pred closed_g a) in OpamStd.String.Map.add (A.Pkg.name_to_string p) preds acc | _ -> acc) g OpamStd.String.Map.empty in function p -> match OpamStd.String.Map.find_opt (A.Pkg.name_to_string p) dependent_base_packages with | None -> [] | Some pred -> pred let explicit ?(noop_remove = (fun _ -> false)) ~sources_needed g0 = let g = copy g0 in (* We insert a "build" action before any "install" action. Except, between the removal and installation of the same package (the removal might be postponed after a succesfull build. *) iter_vertex (fun a -> match a with | `Install p | `Reinstall p | `Change (_,_,p) -> let b = `Build p in iter_pred (function | `Remove p1 when same_name p p1 -> () | pred -> remove_edge g pred a; add_edge g pred b) g0 a; add_edge g b a | `Remove _ -> () | `Build _ | `Fetch _ -> assert false) g0; (* For delaying removal a little bit, for each action "remove A" we add a constraint "build B -> remove A" for transitive predecessors of "A" that do not have dependencies. For adding a little bit more delay, we ignore dependencies that do not modify the prefix (see [OpamAction.noop_remove]) *) let closed_predecessors = compute_closed_predecessors noop_remove g in iter_vertex (function | `Remove p as a -> List.iter (fun b -> add_edge g b a) (closed_predecessors p) | `Install _ | `Reinstall _ | `Change _ | `Build _ | `Fetch _ -> ()) g; (* Add a "fetch" action as a dependency for all "build" and "remove" actions that require it (via [sources_needed]). *) let acc_add_action (acc: vertex list Map.t) (p: A.package) (a: vertex) : vertex list Map.t = let acts = try Map.find p acc with Not_found -> [] in Map.add p (a :: acts) acc in let m = fold_vertex (fun a acc -> match a with | `Build p | `Remove p -> if sources_needed p then acc_add_action acc p a else acc | `Install _ | `Reinstall _ | `Change _ -> acc | `Fetch _ -> assert false ) g Map.empty in Map.iter (fun p acts -> let f = `Fetch p in List.iter (fun a -> add_edge g f a) acts ) m; g let fold_descendants f acc t v = let rec aux seen f acc t v = if A.Set.mem v seen then seen, acc else fold_succ (fun v (seen, acc) -> aux seen f acc t v) t v (A.Set.add v seen, f v acc) in snd (aux A.Set.empty f acc t v) end opam-2.1.5/src/solver/opamCudfSolverSig.ml0000644000175000017500000000246514427463453017555 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2017-2018 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) type criteria_def = { crit_default: string; crit_upgrade: string; crit_fixup: string; crit_best_effort_prefix: string option; } (** Timeout might still return a non-optimal solution *) exception Timeout of (Cudf.preamble option * Cudf.universe) option module type S = sig val name: string (** extra configurable solver parameters *) val ext: string option ref val is_present: unit -> bool val command_name: string option (** None means the solver is built-in *) val default_criteria: criteria_def val call: criteria:string -> ?timeout:float -> Cudf.cudf -> Cudf.preamble option * Cudf.universe end opam-2.1.5/src/solver/opamSolverConfig.mli0000644000175000017500000000527414427463453017610 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2015-2017 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Configuration options for the solver lib (record, global reference, setter, initialisation) *) module E : sig type OpamStd.Config.E.t += | BESTEFFORT of bool option | BESTEFFORTPREFIXCRITERIA of string option | CRITERIA of string option | CUDFFILE of string option | CUDFTRIM of string option | DIGDEPTH of int option | EXTERNALSOLVER of string option | FIXUPCRITERIA of string option | NOASPCUD of bool option | PREPRO of bool option | SOLVERALLOWSUBOPTIMAL of bool option | SOLVERTIMEOUT of float option | UPGRADECRITERIA of string option | USEINTERNALSOLVER of bool option | VERSIONLAGPOWER of int option val externalsolver: unit -> string option end type t = private { cudf_file: string option; solver: (module OpamCudfSolver.S) Lazy.t; best_effort: bool; solver_preferences_default: string option Lazy.t; solver_preferences_upgrade: string option Lazy.t; solver_preferences_fixup: string option Lazy.t; solver_preferences_best_effort_prefix: string option Lazy.t; solver_timeout: float option; solver_allow_suboptimal: bool; cudf_trim: string option; dig_depth: int; preprocess: bool; version_lag_power: int; } type 'a options_fun = ?cudf_file:string option -> ?solver:(module OpamCudfSolver.S) Lazy.t -> ?best_effort:bool -> ?solver_preferences_default:string option Lazy.t -> ?solver_preferences_upgrade:string option Lazy.t -> ?solver_preferences_fixup:string option Lazy.t -> ?solver_preferences_best_effort_prefix:string option Lazy.t -> ?solver_timeout:float option -> ?solver_allow_suboptimal:bool -> ?cudf_trim:string option -> ?dig_depth:int -> ?preprocess:bool -> ?version_lag_power:int -> 'a include OpamStd.Config.Sig with type t := t and type 'a options_fun := 'a options_fun val call_solver: criteria:string -> Cudf.cudf -> Cudf.preamble option * Cudf.universe (** Checks if best_effort was set and is supported *) val best_effort: unit -> bool val criteria: OpamTypes.solver_criteria -> string opam-2.1.5/src/solver/opamBuiltin0install.ml.dummy0000644000175000017500000000206314427463453021237 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2020 Kate Deplaix *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCudfSolverSig let name = "builtin-dummy-0install-solver" let is_present () = false let ext = ref None let command_name = None let default_criteria = { crit_default = ""; crit_upgrade = ""; crit_fixup = ""; crit_best_effort_prefix = None; } let call ~criteria:_ ?timeout:_ _cudf = failwith "This opam was compiled without the opam-0install solver built in" opam-2.1.5/src/solver/opamBuiltinMccs.ml.dummy0000644000175000017500000000215614427463453020401 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2017-2018 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCudfSolverSig module S = struct let name = "builtin-dummy-solver" let is_present () = false let ext = ref None let command_name = None let default_criteria = { crit_default = ""; crit_upgrade = ""; crit_fixup = ""; crit_best_effort_prefix = None; } let call ~criteria:_ ?timeout:_ _cudf = failwith "This opam was compiled without a solver built in" end let all_backends = [ (module S: S) ] opam-2.1.5/src/solver/opamBuiltin0install.mli0000644000175000017500000000003414427463453020252 0ustar stephstephinclude OpamCudfSolverSig.S opam-2.1.5/src/solver/opamDoseCompat.mli.50000644000175000017500000000012214427463453017374 0ustar stephstephmodule Dose_algo : module type of Algo module Dose_common : module type of Common opam-2.1.5/src/solver/opamBuiltin0install.ml.real0000644000175000017500000001117314427463453021031 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2020 Kate Deplaix *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCudfSolverSig [@@@ocaml.warning "-33"] open OpamDoseCompat let log ?level f = OpamConsole.log "0install" ?level f let name = "builtin-0install" let ext = ref None let is_present () = true let command_name = None let default_criteria = { crit_default = ""; crit_upgrade = ""; crit_fixup = ""; crit_best_effort_prefix = None; } let not_relop = function | `Eq -> `Neq | `Neq -> `Eq | `Geq -> `Lt | `Gt -> `Leq | `Leq -> `Gt | `Lt -> `Geq let keep_installed ~drop_installed_packages request pkgname = not drop_installed_packages && not (List.exists (fun (pkg, _) -> String.equal pkg pkgname) request.Cudf.install) && not (List.exists (fun (pkg, _) -> String.equal pkg pkgname) request.Cudf.upgrade) && not (List.exists (fun (pkg, _) -> String.equal pkg pkgname) request.Cudf.remove) let add_spec pkg req c (pkgs, constraints) = let pkgs = (pkg, req) :: pkgs in let constraints = match c with | None -> constraints | Some c -> (pkg, c) :: constraints in (pkgs, constraints) let essential spec (pkg, c) = add_spec pkg `Essential c spec let recommended spec (pkg, c) = add_spec pkg `Recommended c spec let restricts (pkgs, constraints) (pkg, c) = let constraints = match c with | None -> (pkg, (`Lt, 1)) :: (pkg, (`Gt, 1)) :: constraints (* pkg < 1 & pkg > 1 is always false *) | Some (relop, v) -> (pkg, (not_relop relop, v)) :: constraints in (pkgs, constraints) let create_spec ~drop_installed_packages universe request = let spec = ([], []) in let spec = List.fold_left essential spec request.Cudf.install in let spec = List.fold_left essential spec request.Cudf.upgrade in let spec = List.fold_left restricts spec request.Cudf.remove in Cudf.fold_packages_by_name (fun spec pkgname pkgs -> match List.find_opt (fun pkg -> pkg.Cudf.installed) pkgs with | Some {Cudf.keep = `Keep_version; version; _} -> essential spec (pkgname, Some (`Eq, version)) | Some {Cudf.keep = `Keep_package; _} -> essential spec (pkgname, None) | Some {Cudf.keep = `Keep_feature; _} -> assert false (* NOTE: Opam has no support for features *) | Some {Cudf.keep = `Keep_none; _} -> if keep_installed ~drop_installed_packages request pkgname then recommended spec (pkgname, None) else spec | None -> spec ) spec universe let reconstruct_universe universe selections = Opam_0install_cudf.packages_of_result selections |> List.fold_left (fun pkgs (pkg, v) -> let pkg = Cudf.lookup_package universe (pkg, v) in {pkg with was_installed = pkg.installed; installed = true} :: pkgs ) [] |> Cudf.load_universe type options = { drop_installed_packages : bool; prefer_oldest : bool; } let parse_criteria criteria = let default = {drop_installed_packages = false; prefer_oldest = false} in match criteria with | "" -> default | "+removed" -> {drop_installed_packages = true; prefer_oldest = false} | "+count[version-lag,solution]" -> {drop_installed_packages = false; prefer_oldest = true} | "+removed,+count[version-lag,solution]" -> {drop_installed_packages = true; prefer_oldest = true} | _ -> OpamConsole.warning "Criteria '%s' is not supported by the 0install solver" criteria; default let call ~criteria ?timeout:_ (preamble, universe, request) = let {drop_installed_packages; prefer_oldest} = parse_criteria criteria in let timer = OpamConsole.timer () in let pkgs, constraints = create_spec ~drop_installed_packages universe request in let context = Opam_0install_cudf.create ~prefer_oldest ~constraints universe in match Opam_0install_cudf.solve context pkgs with | Ok selections -> let universe = reconstruct_universe universe selections in log "Solution found. Solve took %.2f s" (timer ()); (Some preamble, universe) | Error problem -> log "No solution. Solve took %.2f s" (timer ()); log ~level:3 "%a" (OpamConsole.slog Opam_0install_cudf.diagnostics) problem; raise Dose_common.CudfSolver.Unsat opam-2.1.5/src/solver/opamCudfSolver.mli0000644000175000017500000000350714427463453017261 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2017-2018 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Various implementations of the low-level CUDF resolution, most of them relying on external solvers (aspcud, etc.). Used for calling-back below Dose. *) include module type of struct include OpamCudfSolverSig end module Aspcud : S module Aspcud_old : S module Mccs : S module Packup : S (** The list of supported solvers, in decreasing order of preference *) val default_solver_selection: (module S) list (** Generates a custom solver implementation from a user command. Contains some magic: - if the command matches one of the predefined ones, the default criteria are taken from there - if the command is a singleton and matches, it is expanded similarly from the pre-defined solvers *) val custom_solver : OpamTypes.arg list -> (module S) (** Like [custom_solver], but takes a simple command as a string *) val solver_of_string : string -> (module S) (** Gets the first present solver from the list. Exits with error if none was found. *) val get_solver : ?internal:bool -> (module S) list -> (module S) val has_builtin_solver : unit -> bool (** Gets the full solver name with params *) val get_name : (module S) -> string opam-2.1.5/src/solver/opamBuiltinZ3.ml.real0000644000175000017500000003404214427463453017577 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2017-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCudfSolverSig let log f = OpamConsole.log "Z3" f let name = "builtin-z3" let ext = ref None let is_present () = true let command_name = None let default_criteria = { crit_default = "-removed,\ -count[avoid-version,changed],\ -count[version-lag,request],\ -count[version-lag,changed],\ -count[missing-depexts,changed],\ -changed"; crit_upgrade = "-removed,\ -count[avoid-version,changed],\ -count[version-lag,solution],\ -count[missing-depexts,changed],\ -new"; crit_fixup = "-changed,\ -count[avoid-version,changed],\ -count[version-lag,solution],\ -count[missing-depexts,changed]"; crit_best_effort_prefix = Some "+count[opam-query,solution],"; } let mk_or ctx = function | None -> None | Some [] -> None | Some [p] -> Some p | Some l -> Some (Z3.Boolean.mk_or ctx l) let mk_and ctx = function | None -> None | Some [] -> None | Some [p] -> Some p | Some l -> Some (Z3.Boolean.mk_and ctx l) let ( @^ ) opt l = match opt with | None -> l | Some x -> x :: l let (@@^) o l = match o with | None -> l | Some l1 -> List.rev_append l1 l let xrmap f l = match List.fold_left (fun acc x -> f x @^ acc) [] l with | [] -> None | l -> Some l (* let xmap f l = match xrmap f l with | Some l -> Some (List.rev l) | None -> None *) open OpamStd.Option.Op let def_packages ctx (_preamble, universe, _request) = let syms = Hashtbl.create 2731 in let psym p = Hashtbl.find_opt syms p in let psym_exn p = match psym p with None -> raise Not_found | Some p -> p in (* variable definitions *) Cudf.iter_packages (fun pkg -> Hashtbl.add syms pkg (Z3.Boolean.mk_const_s ctx (Printf.sprintf "%s.%d" pkg.Cudf.package pkg.Cudf.version))) universe; let def_exprs = [] in let def_exprs = (* "keep" flags *) Cudf.fold_packages_by_name (fun e _name pkgs -> let keep = match List.find (fun p -> p.Cudf.keep = `Keep_version) pkgs with | p -> psym p | exception Not_found -> if List.exists (fun p -> p.Cudf.keep = `Keep_package) pkgs then mk_or ctx @@ xrmap psym pkgs else None in keep @^ e) def_exprs universe in let expand_constraint pkg (name, constr) = mk_or ctx (xrmap (fun p -> if Cudf.( =% ) pkg p then None else psym p) (Cudf.lookup_packages universe ~filter:constr name)) in let def_exprs = Cudf.fold_packages (fun e pkg -> let module SM = OpamStd.String.Map in let cudf_depends, cudf_depends_map = List.fold_left (fun (rem, map) -> function | (name, _) :: r as disj when List.for_all (fun (n1, _) -> n1 = name) r -> rem, SM.update name (fun conj -> disj :: conj) [] map | disj -> disj :: rem, map) ([], SM.empty) pkg.Cudf.depends in let depends = xrmap (fun disj -> mk_or ctx @@ xrmap (expand_constraint pkg) disj) cudf_depends @@^ SM.fold (fun name conj e -> (match xrmap psym @@ List.fold_left (fun plist disj -> let r = List.filter (fun p -> List.exists (fun (_, cstr) -> Cudf.version_matches p.Cudf.version cstr) disj) plist in r) (Cudf.lookup_packages universe name) conj with | None -> Some (Z3.Boolean.mk_false ctx) | some -> mk_or ctx some) @^ e) cudf_depends_map [] |> OpamStd.Option.some |> mk_and ctx >>| Z3.Boolean.mk_implies ctx (psym_exn pkg) in let conflicts = mk_or ctx @@ xrmap (expand_constraint pkg) pkg.Cudf.conflicts >>| fun c -> Z3.Boolean.mk_implies ctx (psym_exn pkg) (Z3.Boolean.mk_not ctx c) in depends @^ conflicts @^ e) def_exprs universe in List.rev def_exprs, psym let def_request ctx (_preamble, universe, request) psym = let expand_constraint (name, constr) = mk_or ctx @@ xrmap psym (Cudf.lookup_packages universe ~filter:constr name) in let inst = xrmap expand_constraint request.Cudf.install in let rem = xrmap (fun vpkg -> expand_constraint vpkg >>| Z3.Boolean.mk_not ctx) request.Cudf.remove in let up = xrmap (fun (name, constr) -> match Cudf.get_installed universe name with | [] -> mk_or ctx @@ xrmap psym (Cudf.lookup_packages universe ~filter:constr name) | p::l -> let vmin = List.fold_left (fun vmin p -> max vmin p.Cudf.version) p.Cudf.version l in Cudf.lookup_packages universe ~filter:constr name |> List.filter (fun p -> p.Cudf.version >= vmin) |> xrmap psym |> (* fixme: the spec states that an 'upgrade' request should guarantee that only one version of the package will be installed. Since it's already a constraint in opam, and it's non trivial to encode, we ignore it here. *) mk_or ctx) request.Cudf.upgrade in inst @@^ rem @@^ up @@^ [] let sum ctx (_, universe, _) filter value = let ite filt iftrue iffalse = Z3.Boolean.mk_ite ctx filt (Z3.Arithmetic.Integer.mk_numeral_i ctx iftrue) (Z3.Arithmetic.Integer.mk_numeral_i ctx iffalse) in Cudf.fold_packages (fun e pkg -> match filter pkg with | None -> e | Some filt -> match value pkg with | 0 -> e | n -> if Z3.Boolean.is_not filt then match Z3.Expr.get_args filt with | [filt] -> ite filt 0 n :: e | _ -> assert false else ite filt n 0 :: e) [] universe type filter = Installed | Changed | Removed | New | Upgraded | Downgraded | Requested type property = string option type sign = Plus | Minus type criterion = sign * filter * property let def_criterion ctx opt (preamble, universe, request as cudf) psym (sign, filter, property : criterion) = let filter_f = match filter with | Installed -> fun p -> psym p | Changed -> fun p -> if p.Cudf.installed then psym p >>| Z3.Boolean.mk_not ctx else psym p | Removed -> fun p -> if p.Cudf.installed then mk_or ctx @@ xrmap psym (Cudf.lookup_packages universe p.Cudf.package) >>| Z3.Boolean.mk_not ctx else None | New -> fun p -> if p.Cudf.installed then None else mk_or ctx @@ xrmap psym (Cudf.lookup_packages universe p.Cudf.package) | Upgraded -> fun p -> if p.Cudf.installed then None else (match Cudf.get_installed universe p.Cudf.package with | [] -> None | l when List.for_all (fun p1 -> p1.Cudf.version < p.Cudf.version) l -> psym p | _ -> None) | Downgraded -> fun p -> if p.Cudf.installed then None else (match Cudf.get_installed universe p.Cudf.package with | [] -> None | l when List.exists (fun p1 -> p1.Cudf.version > p.Cudf.version) l -> psym p | _ -> None) | Requested -> fun p -> if List.exists (fun (name, cstr) -> p.Cudf.package = name && Cudf.version_matches p.Cudf.version cstr) request.Cudf.install || List.exists (fun (name, cstr) -> p.Cudf.package = name && Cudf.version_matches p.Cudf.version cstr) request.Cudf.upgrade then psym p else None in let value_f = match property with | None -> fun _ -> 1 | Some prop -> fun p -> match Cudf.lookup_typed_package_property p prop with | `Int n | `Nat n -> n | `Bool true -> 1 | `Bool false -> 0 | _ -> 0 | exception Not_found -> match List.assoc prop preamble.Cudf.property with | `Int (Some n) | `Nat (Some n) -> n | `Bool (Some true) -> 1 | `Bool (Some false) -> 0 | _ -> 0 | exception Not_found -> failwith ("Undefined CUDF property: "^prop) in match sum ctx cudf filter_f value_f with | [] -> None | sum -> OpamStd.Option.some @@ (match sign with Plus -> Z3.Optimize.maximize | Minus -> Z3.Optimize.minimize) opt (Z3.Arithmetic.mk_add ctx sum) let def_criteria ctx opt cudf psym crits = List.map (def_criterion ctx opt cudf psym) crits module Syntax = struct let criterion_of_string (s,params) = let sign = match s.[0] with | '+' -> Plus | '-' -> Minus | c -> failwith (Printf.sprintf "criteria_of_string sign=%c" c) | exception Invalid_argument _ -> failwith "criteria_of_string sign=EOF" in let s = String.sub s 1 (String.length s - 1) in let subset_of_string = function | "new" -> New | "removed" -> Removed | "changed" -> Changed | "up" -> Upgraded | "down" -> Downgraded | "installed" | "solution" -> Installed | "request" -> Requested | s -> failwith ("criteria_of_string subset="^s) in match s, params with | "count", [field; subset] -> sign, subset_of_string subset, Some field | s, [] -> sign, subset_of_string s, None | s, _ -> failwith ("criteria_of_string s="^s) (* let string_of_criterion (sign, filter, property: criterion) = Printf.sprintf "%c%s%s" (match sign with Plus -> '+' | Minus -> '-') (match filter with | Installed -> "installed" | Changed -> "changed" | Removed -> "removed" | New -> "new" | Upgraded -> "up" | Downgraded -> "down" | Requested -> "request") (match property with None -> "" | Some p -> "["^p^"]") *) let criteria_of_string s = let start = ref 0 in let crits = ref [] in let params = ref None in for i = 0 to String.length s - 1 do match s.[i] with | ',' -> let sub = String.sub s !start (i - !start) in start := i + 1; if sub <> "" then (match !params with | None -> crits := (sub, []) :: !crits | Some (name, ps) -> params := Some (name, sub :: ps)) | '[' -> let sub = String.sub s !start (i - !start) in start := i + 1; if !params <> None then failwith "criteria_of_string"; params := Some (sub, []) | ']' -> let sub = String.sub s !start (i - !start) in start := i + 1; (match !params with | None -> failwith "criteria_of_string" | Some (name, ps) -> params := None; crits := (name, List.rev (sub::ps)) :: !crits) | _ -> () done; if !start < String.length s then crits := (String.sub s !start (String.length s - !start), []) :: !crits; if !params <> None then failwith "criteria_of_string"; let r = List.rev_map criterion_of_string !crits in r end let extract_solution_packages universe opt = match Z3.Optimize.get_model opt with | Some model -> Z3.Model.get_const_decls model |> List.fold_left (fun pkgs decl -> match Z3.Model.get_const_interp model decl with | Some p when Z3.Boolean.is_true p -> (match OpamStd.String.cut_at (Z3.Symbol.get_string (Z3.FuncDecl.get_name decl)) '.' with | None -> pkgs | Some (p, v) -> let p = Cudf.lookup_package universe (p, int_of_string v) in {p with Cudf.was_installed = p.installed; Cudf.installed = true} :: pkgs) | _ -> pkgs) [] | None -> failwith "no model ??" let call ~criteria ?timeout (preamble, universe, _ as cudf) = (* try *) log "Generating problem..."; let cfg = match timeout with | None -> [] | Some secs -> ["timeout", string_of_int (int_of_float (1000. *. secs))] in let ctx = Z3.mk_context cfg in let opt = Z3.Optimize.mk_opt ctx in log "Generating package definitions"; let expr, psym = def_packages ctx cudf in Z3.Optimize.add opt expr; log "Generating request"; Z3.Optimize.add opt (def_request ctx cudf psym); log "Generating optimization criteria"; let _objs = def_criteria ctx opt cudf psym (Syntax.criteria_of_string criteria) in log "Resolving..."; match Z3.Optimize.check opt with | UNSATISFIABLE -> log "UNSAT"; raise Dose_common.CudfSolver.Unsat | UNKNOWN -> log "UNKNOWN"; (try let universe = Cudf.load_universe (extract_solution_packages universe opt) in raise (Timeout (Some (Some preamble, universe))) with Failure _ -> raise (Timeout None)) | SATISFIABLE -> log "SAT: extracting model"; let universe = Cudf.load_universe (extract_solution_packages universe opt) in Some preamble, universe (* with * | (Timeout | Dose_common.CudfSolver.Unsat | Failure _) as e -> raise e * | e -> * OpamConsole.error "Z3 error: %s" (Printexc.to_string e); * OpamConsole.errmsg "%s" (Printexc.get_backtrace ()); * raise e *) opam-2.1.5/src/solver/opamSolver.ml0000644000175000017500000007057614427463453016320 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase open OpamPackage.Set.Op [@@@ocaml.warning "-33"] open OpamDoseCompat let log ?level fmt = OpamConsole.log ?level "SOLVER" fmt let slog = OpamConsole.slog module Action = OpamActionGraph.MakeAction(OpamPackage) module ActionGraph = OpamActionGraph.Make(Action) type solution = OpamCudf.ActionGraph.t let empty_universe = { u_packages = OpamPackage.Set.empty; u_installed = OpamPackage.Set.empty; u_available = OpamPackage.Set.empty; u_depends = OpamPackage.Map.empty; u_depopts = OpamPackage.Map.empty; u_conflicts = OpamPackage.Map.empty; u_action = Install; u_installed_roots = OpamPackage.Set.empty; u_pinned = OpamPackage.Set.empty; u_base = OpamPackage.Set.empty; u_invariant = OpamFormula.Empty; u_reinstall = OpamPackage.Set.empty; u_attrs = []; } let is_installed universe (name,_) = OpamPackage.Set.exists (fun pkg -> OpamPackage.name pkg = name ) universe.u_installed let find_installed universe (name, _) = let pkg = OpamPackage.Set.find (fun pkg -> OpamPackage.name pkg = name ) universe.u_installed in OpamPackage.version pkg let is_available universe wish_remove (name, _ as c) = let version = find_installed universe c in OpamPackage.Set.exists (fun pkg -> OpamPackage.name pkg = name && OpamPackage.version pkg = version ) universe.u_available && List.for_all (fun (n, _) -> n <> name) wish_remove let solution_to_json solution = OpamCudf.ActionGraph.to_json solution let solution_of_json json = OpamCudf.ActionGraph.of_json json let cudf_versions_map universe packages = log ~level:3 "cudf_versions_map"; let add_referred_to_packages filt acc refmap = OpamPackage.Map.fold (fun _ deps acc -> List.fold_left (fun acc -> function | n, Some (_, v) -> OpamPackage.Set.add (OpamPackage.create n v) acc | _, None -> acc) acc (OpamFormula.atoms (filt deps))) refmap acc in let filt f = OpamFilter.filter_deps ~build:true ~post:true ~default:false f in let id = fun x -> x in let packages = add_referred_to_packages filt packages universe.u_depends in let packages = add_referred_to_packages filt packages universe.u_depopts in let packages = add_referred_to_packages id packages universe.u_conflicts in let pmap = OpamPackage.to_map packages in OpamPackage.Name.Map.fold (fun name versions acc -> let _, map = OpamPackage.Version.Set.fold (fun version (i,acc) -> let nv = OpamPackage.create name version in i + 1, OpamPackage.Map.add nv i acc) versions (1,acc) in map) pmap OpamPackage.Map.empty let name_to_cudf name = Dose_common.CudfAdd.encode (OpamPackage.Name.to_string name) let constraint_to_cudf version_map name (op,v) = let nv = OpamPackage.create name v in try Some (op, OpamPackage.Map.find nv version_map) with Not_found -> (* The version for comparison doesn't exist: match to the closest existing version according to the direction of the comparison (this shouldn't happen for any constraint in the universe, now that we compute a full version map, but may still happen for user-provided constraints) *) log "Warn: fallback constraint for %s" (OpamFormula.string_of_atom (name, Some (op,v))); let all_versions = OpamPackage.Map.filter (fun nv _ -> nv.name = name) version_map in match op with | `Neq -> None (* Always true *) | `Eq -> (* Always false *) Some (`Gt, OpamPackage.Map.cardinal all_versions) | (`Geq | `Gt | `Leq | `Lt) as op -> let sign, result_op = match op with | `Geq | `Gt -> (fun x -> x), `Geq | `Leq | `Lt -> (fun x -> -x), `Leq in let rev_version_map = OpamPackage.Map.fold (fun nv cv acc -> OpamStd.IntMap.add (sign cv) nv.version acc) all_versions OpamStd.IntMap.empty in let map = OpamStd.IntMap.filter (fun _ v1 -> sign (OpamPackage.Version.compare v v1) < 0) rev_version_map in if OpamStd.IntMap.is_empty map then match result_op with | `Geq -> Some (`Gt, max 1 (OpamPackage.Map.cardinal all_versions)) | `Leq -> Some (`Lt, 1) else Some (result_op, sign (fst (OpamStd.IntMap.min_binding map))) let atom2cudf _universe (version_map : int OpamPackage.Map.t) (name,cstr) = name_to_cudf name, OpamStd.Option.Op.(cstr >>= constraint_to_cudf version_map name) let opam_invariant_package version_map invariant = let depends = OpamFormula.to_atom_formula invariant |> OpamFormula.map (fun at -> Atom (atom2cudf () version_map at)) |> OpamFormula.cnf_of_formula |> OpamFormula.ands_to_list |> List.map (OpamFormula.fold_right (fun acc x -> x::acc) []) in { Cudf. package = OpamCudf.opam_invariant_package_name; version = snd OpamCudf.opam_invariant_package; depends; conflicts = []; provides = []; installed = true; was_installed = true; keep = `Keep_version; pkg_extra = [ OpamCudf.s_source, `String "SWITCH_INVARIANT"; OpamCudf.s_source_number, `String "NULL"; ]; } let lag_function = let rec power n x = if n <= 0 then 1 else x * power (n-1) x in power OpamSolverConfig.(!r.version_lag_power) let opam2cudf universe version_map packages = let set_to_bool_map set = OpamPackage.Set.fold (fun nv -> OpamPackage.Map.add nv true) (packages %% set) OpamPackage.Map.empty in let base_map = OpamPackage.Set.fold (fun nv -> OpamPackage.Map.add nv { Cudf.default_package with Cudf.package = name_to_cudf nv.name; pkg_extra = [ OpamCudf.s_source, `String(OpamPackage.name_to_string nv); OpamCudf.s_source_number, `String(OpamPackage.version_to_string nv); ]; }) packages OpamPackage.Map.empty in let only_packages m = OpamPackage.Map.merge (fun _ -> function None -> fun _ -> None | Some _ -> fun x -> x) base_map m in let installed_map = set_to_bool_map universe.u_installed in let reinstall_map = set_to_bool_map universe.u_reinstall in let installed_root_map = set_to_bool_map universe.u_installed_roots in let pinned_to_current_version_map = set_to_bool_map universe.u_pinned in let avoid_versions = OpamStd.Option.default OpamPackage.Set.empty @@ OpamStd.List.assoc_opt "avoid-version" universe.u_attrs in let version_lag_map = OpamPackage.Name.Map.fold (fun name version_set acc -> let nvers, vs = OpamPackage.Version.Set.fold (fun v (i,acc) -> if OpamPackage.Set.mem (OpamPackage.create name v) avoid_versions then i, acc else i+1, OpamPackage.Version.Map.add v i acc) version_set (0, OpamPackage.Version.Map.empty) in let nvers, vs = (* Place all avoid-versions after normal versions *) (* Not strictly necessary, but gives a better fallback in case the specific criteria for avoided versions are not set *) OpamPackage.Version.Set.fold (fun v (i,acc) -> if OpamPackage.Set.mem (OpamPackage.create name v) avoid_versions then i+1, OpamPackage.Version.Map.add v i acc else i, acc) version_set (nvers, vs) in OpamPackage.Version.Map.fold (fun v i -> let lag = lag_function (nvers - i - 1) in if lag > 0 then OpamPackage.Map.add (OpamPackage.create name v) lag else fun acc -> acc) vs acc) (OpamPackage.to_map packages) OpamPackage.Map.empty in let extras_maps = List.map (fun (label, set) -> OpamPackage.Set.fold (fun nv -> OpamPackage.Map.add nv (label, `Int 1)) (packages %% set) OpamPackage.Map.empty) universe.u_attrs in let add elts f map = OpamPackage.Map.merge (fun nv a b -> match a, b with | Some cp, None -> Some cp | Some cp, Some x -> Some (f nv x cp) | None, _ -> None) map elts in let univ0 = base_map |> add version_map (fun _ version cp -> {cp with Cudf.version}) |> add installed_map (fun _ installed cp -> {cp with Cudf.installed}) |> add reinstall_map (fun _ x cp -> {cp with Cudf.pkg_extra = (OpamCudf.s_reinstall, `Bool x) :: cp.Cudf.pkg_extra}) |> add installed_root_map (fun _ x cp -> {cp with Cudf.pkg_extra = (OpamCudf.s_installed_root, `Bool x) :: cp.Cudf.pkg_extra}) |> add pinned_to_current_version_map (fun _ x cp -> {cp with Cudf.pkg_extra = (OpamCudf.s_pinned, `Bool x) :: cp.Cudf.pkg_extra}) |> add version_lag_map (fun _ x cp -> {cp with Cudf.pkg_extra = (OpamCudf.s_version_lag, `Int x) :: cp.Cudf.pkg_extra}) |> List.fold_right (fun m -> add m (fun _ x cp -> {cp with Cudf.pkg_extra = x :: cp.Cudf.pkg_extra})) extras_maps in let preresolve_deps f = OpamFilter.atomise_extended f |> OpamFormula.map (fun (name, (filter, cstr)) -> let cstr = match cstr with | None -> None | Some (op, FString v) -> let v = OpamPackage.Version.of_string v in constraint_to_cudf version_map name (op, v) | _ -> assert false in Atom (name_to_cudf name, (filter, cstr))) |> OpamFormula.cnf_of_formula in let depends_map = OpamPackage.Map.map preresolve_deps (only_packages universe.u_depends) in let depopts_map = OpamPackage.Map.map preresolve_deps (only_packages universe.u_depopts) in let conflicts_map = OpamPackage.Map.mapi (fun nv conflicts -> (nv.name, None) :: (* prevents install of multiple versions of the same pkg *) OpamFormula.set_to_disjunction universe.u_packages conflicts) (only_packages universe.u_conflicts) in let conflicts_map_resolved = OpamPackage.Map.map (List.rev_map (atom2cudf universe version_map)) conflicts_map in fun ~depopts ~build ~post -> let all_depends_map = if depopts then OpamPackage.Map.union (fun d dopts -> OpamFormula.(ands [d; dopts])) depends_map depopts_map else depends_map in let depends_map_resolved = OpamPackage.Map.map (fun f -> f |> OpamFormula.map (fun (name, (filter, cstr)) -> if OpamFilter.eval_to_bool ~default:false (OpamFilter.deps_var_env ~build ~post) filter then Atom (name, cstr) else Empty) |> OpamFormula.ands_to_list |> List.map (OpamFormula.fold_right (fun acc x -> x::acc) [])) all_depends_map in univ0 |> add depends_map_resolved (fun _ depends cp -> {cp with Cudf.depends}) |> add conflicts_map_resolved (fun _ conflicts cp -> {cp with Cudf.conflicts}) |> OpamPackage.Map.values (* load a cudf universe from an opam one *) let load_cudf_universe opam_universe ?version_map ?(add_invariant=false) opam_packages = let chrono = OpamConsole.timer () in let version_map = match version_map with | Some vm -> vm | None -> cudf_versions_map opam_universe opam_packages in log ~level:3 "Load cudf universe: opam2cudf"; let univ_gen = opam2cudf opam_universe version_map opam_packages in log ~level:3 "Preload of cudf universe: done in %.3fs" (chrono ()); fun ?(depopts=false) ~build ~post () -> log "Load cudf universe (depopts:%a, build:%b, post:%b)" (slog string_of_bool) depopts build post; let chrono = OpamConsole.timer () in let cudf_universe = let cudf_packages = univ_gen ~depopts ~build ~post in let cudf_packages = if add_invariant then opam_invariant_package version_map opam_universe.u_invariant :: cudf_packages else cudf_packages in log ~level:3 "opam2cudf: done in %.3fs" (chrono ()); try Cudf.load_universe cudf_packages with Cudf.Constraint_violation s -> OpamConsole.error_and_exit `Solver_failure "Malformed CUDF universe (%s)" s in log ~level:3 "Secondary load of cudf universe: done in %.3fs" (chrono ()); (* let universe = Dose_algo.Depsolver.trim universe in *) cudf_universe let string_of_request r = let to_string = OpamFormula.string_of_conjunction OpamFormula.string_of_atom in Printf.sprintf "install:%s remove:%s upgrade:%s" (to_string r.wish_install) (to_string r.wish_remove) (to_string r.wish_upgrade) (* Unused? let map_cause f = function | Upstream_changes -> Upstream_changes | Use l -> Use (List.rev_map f l) | Required_by l -> Required_by (List.rev_map f l) | Conflicts_with l -> Conflicts_with (List.rev_map f l) | Requested -> Requested | Unknown -> Unknown *) let cudf_to_opam_graph cudf2opam cudf_graph = let size = OpamCudf.ActionGraph.nb_vertex cudf_graph in let opam_graph = ActionGraph.create ~size () in OpamCudf.ActionGraph.iter_vertex (fun package -> ActionGraph.add_vertex opam_graph (map_action cudf2opam package) ) cudf_graph; OpamCudf.ActionGraph.iter_edges (fun p1 p2 -> ActionGraph.add_edge opam_graph (map_action cudf2opam p1) (map_action cudf2opam p2) ) cudf_graph; opam_graph let map_request f r = let f = List.rev_map f in { wish_install = f r.wish_install; wish_remove = f r.wish_remove; wish_upgrade = f r.wish_upgrade; criteria = r.criteria; extra_attributes = r.extra_attributes; } (* Remove duplicate packages *) (* Add upgrade constraints *) (* Remove constraints in best_effort mode *) let cleanup_request universe (req:atom request) = if OpamSolverConfig.best_effort () then { req with wish_install = []; wish_upgrade = []; } else let wish_install = List.filter (fun (n,_) -> not (List.mem_assoc n req.wish_upgrade)) req.wish_install in let wish_upgrade = List.rev_map (fun (n,c as pkg) -> if c = None && is_installed universe pkg && is_available universe req.wish_remove pkg then n, Some (`Geq, find_installed universe pkg) else pkg ) req.wish_upgrade in { req with wish_install; wish_upgrade } let cycle_conflict ~version_map univ cycles = OpamCudf.cycle_conflict ~version_map univ (List.map (List.map (fun a -> Action.to_string (map_action OpamCudf.cudf2opam a))) cycles) let resolve universe ~orphans request = log "resolve request=%a" (slog string_of_request) request; let all_packages = universe.u_available ++ universe.u_installed ++ orphans in let version_map = cudf_versions_map universe all_packages in let univ_gen = load_cudf_universe universe ~version_map all_packages in let simple_universe, cudf_orphans = let u = univ_gen ~build:true ~post:true () in let cudf_orphans = OpamPackage.Set.fold (fun nv acc -> let cnv = name_to_cudf nv.name, OpamPackage.Map.find nv version_map in let cp = Cudf.lookup_package u cnv in Cudf.remove_package u cnv; cp :: acc) orphans [] in u, cudf_orphans in let add_orphan_packages u = Cudf.load_universe (List.rev_append cudf_orphans (Cudf.get_packages u)) in let request = let extra_attributes = OpamStd.List.sort_nodup compare (List.map fst universe.u_attrs @ request.extra_attributes) in { request with extra_attributes } in let request = cleanup_request universe request in let cudf_request = map_request (atom2cudf universe version_map) request in let resolve u req = try let invariant_pkg = opam_invariant_package version_map universe.u_invariant in Cudf.add_package u invariant_pkg; let resp = OpamCudf.resolve ~extern:true ~version_map u req in Cudf.remove_package u (invariant_pkg.Cudf.package, invariant_pkg.Cudf.version); OpamCudf.to_actions add_orphan_packages u resp with OpamCudf.Solver_failure msg -> OpamConsole.error_and_exit `Solver_failure "%s" msg in match resolve simple_universe cudf_request with | Conflicts _ as c -> c | Success actions -> let simple_universe = univ_gen ~depopts:true ~build:false ~post:false () in let complete_universe = univ_gen ~depopts:true ~build:true ~post:false () in try let atomic_actions = OpamCudf.atomic_actions ~simple_universe ~complete_universe actions in Success atomic_actions with OpamCudf.Cyclic_actions cycles -> cycle_conflict ~version_map complete_universe cycles let get_atomic_action_graph t = cudf_to_opam_graph OpamCudf.cudf2opam t let installable universe = log "trim"; let simple_universe = load_cudf_universe universe ~add_invariant:true universe.u_available ~build:true ~post:true () in let trimmed_universe = (* Dose_algo.Depsolver.trim simple_universe => this can explode memory, we need to specify [~explain:false] *) let open Dose_algo in let open Depsolver in let trimmed_pkgs = ref [] in let callback d = if Dose_algo.Diagnostic.is_solution d then match d.Diagnostic.request with |[p] -> trimmed_pkgs := p::!trimmed_pkgs |_ -> assert false in ignore (univcheck ~callback ~explain:false simple_universe); Cudf.load_universe !trimmed_pkgs in Cudf.fold_packages (fun universe pkg -> if pkg.package = OpamCudf.opam_invariant_package_name then universe else OpamPackage.Set.add (OpamCudf.cudf2opam pkg) universe) OpamPackage.Set.empty trimmed_universe let installable_subset universe packages = log "trim-subset"; let version_map = cudf_versions_map universe universe.u_available in let simple_universe = load_cudf_universe ~build:true ~post:true universe ~version_map ~add_invariant:true universe.u_available () in let cudf_packages = Cudf.get_packages ~filter:(fun p -> p.package <> OpamCudf.opam_invariant_package_name && OpamPackage.Set.mem (OpamCudf.cudf2opam p) packages) simple_universe in let trimmed_universe = (* Dose_algo.Depsolver.trimlist simple_universe with [~explain:false] *) let open Dose_algo in let open Depsolver in let trimmed_pkgs = ref [] in let callback d = if Dose_algo.Diagnostic.is_solution d then match d.Diagnostic.request with |[p] -> trimmed_pkgs := p::!trimmed_pkgs |_ -> assert false in ignore (listcheck ~callback ~explain:false simple_universe cudf_packages); Cudf.load_universe !trimmed_pkgs in Cudf.remove_package trimmed_universe OpamCudf.opam_invariant_package; Cudf.fold_packages (fun universe pkg -> OpamPackage.Set.add (OpamCudf.cudf2opam pkg) universe) OpamPackage.Set.empty trimmed_universe let coinstallable_subset universe set packages = let u_invariant = OpamPackage.Set.fold (fun p acc -> OpamFormula.ands [acc; Atom (p.name, Atom (`Eq, p.version))]) set OpamFormula.Empty in installable_subset {universe with u_invariant} packages module PkgGraph = Graph.Imperative.Digraph.ConcreteBidirectional(OpamPackage) let dependency_graph ~depopts ~build ~post ~installed ?(unavailable=false) universe = let u_packages = if installed then universe.u_installed else if unavailable then universe.u_packages else universe.u_available in let cudf_graph = load_cudf_universe ~depopts ~build ~post universe u_packages () |> OpamCudf.Graph.of_universe in let g = PkgGraph.create ~size:(OpamCudf.Graph.nb_vertex cudf_graph) () in OpamCudf.Graph.iter_vertex (fun v -> PkgGraph.add_vertex g (OpamCudf.cudf2opam v)) cudf_graph; OpamCudf.Graph.iter_edges (fun v1 v2 -> PkgGraph.add_edge g (OpamCudf.cudf2opam v1) (OpamCudf.cudf2opam v2)) cudf_graph; g let filter_dependencies f_direction ~depopts ~build ~post ~installed ?(unavailable=false) universe packages = if OpamPackage.Set.is_empty packages then OpamPackage.Set.empty else let u_packages = packages ++ if installed then universe.u_installed else if unavailable then universe.u_packages else universe.u_available in log ~level:3 "filter_dependencies packages=%a" (slog OpamPackage.Set.to_string) packages; let version_map = cudf_versions_map universe u_packages in let cudf_universe = load_cudf_universe ~depopts ~build ~post universe ~version_map u_packages () in let cudf_packages = OpamCudf.Set.of_list (opam2cudf universe ~depopts ~build ~post version_map packages) in log ~level:3 "filter_dependencies: dependency"; let clos_packages = f_direction cudf_universe cudf_packages in let result = OpamCudf.Set.fold (fun cp -> OpamPackage.Set.add (OpamCudf.cudf2opam cp)) clos_packages OpamPackage.Set.empty in log "filter_dependencies result=%a" (slog OpamPackage.Set.to_string) result; result let dependencies = filter_dependencies OpamCudf.dependencies let reverse_dependencies = filter_dependencies OpamCudf.reverse_dependencies let dependency_sort ~depopts ~build ~post universe packages = let version_map = cudf_versions_map universe universe.u_packages in let cudf_universe = load_cudf_universe ~depopts ~build ~post universe ~version_map universe.u_packages () in let cudf_packages = OpamCudf.Set.of_list (opam2cudf universe ~depopts ~build ~post version_map packages) in List.map OpamCudf.cudf2opam (OpamCudf.dependency_sort cudf_universe cudf_packages) let coinstallability_check universe packages = let version_map = cudf_versions_map universe universe.u_packages in let cudf_universe = load_cudf_universe ~build:true ~post:true ~version_map ~add_invariant:true universe universe.u_packages () in let cudf_packages = opam2cudf universe ~depopts:false ~build:true ~post:true version_map packages in match Dose_algo.Depsolver.edos_coinstall cudf_universe cudf_packages with | { Dose_algo.Diagnostic.result = Dose_algo.Diagnostic.Success _; _ } -> None | { Dose_algo.Diagnostic.result = Dose_algo.Diagnostic.Failure _; _ } as c -> match OpamCudf.make_conflicts ~version_map cudf_universe c with | Conflicts cs -> Some cs | _ -> None let check_for_conflicts universe = coinstallability_check universe universe.u_installed let atom_coinstallability_check universe atoms = let version_map = cudf_versions_map universe universe.u_packages in let check_pkg = { Cudf.default_package with package = "=check_coinstallability"; depends = List.map (fun at -> [atom2cudf () version_map at]) atoms; } in let cudf_universe = Cudf.load_universe (check_pkg :: opam_invariant_package version_map universe.u_invariant :: opam2cudf universe version_map universe.u_available ~depopts:false ~build:true ~post:true) in Dose_algo.Depsolver.edos_install cudf_universe check_pkg |> Dose_algo.Diagnostic.is_solution let new_packages sol = OpamCudf.ActionGraph.fold_vertex (fun action packages -> match action with | `Install p | `Change (_,_,p) -> OpamPackage.Set.add (OpamCudf.cudf2opam p) packages | `Reinstall _ | `Remove _ | `Build _ | `Fetch _ -> packages ) sol OpamPackage.Set.empty let all_packages sol = OpamCudf.ActionGraph.fold_vertex (fun action packages -> List.fold_left (fun packages p -> OpamPackage.Set.add (OpamCudf.cudf2opam p) packages) packages (full_action_contents action)) sol OpamPackage.Set.empty let stats sol = OpamCudf.ActionGraph.fold_vertex (fun action stats -> match action with | `Install _ -> {stats with s_install = stats.s_install+1} | `Change (`Up,_,_) -> {stats with s_upgrade = stats.s_upgrade+1} | `Change (`Down,_,_) -> {stats with s_downgrade = stats.s_downgrade+1} | `Reinstall _ -> {stats with s_reinstall = stats.s_reinstall+1} | `Remove _ -> {stats with s_remove = stats.s_remove+1} | `Build _ | `Fetch _ -> stats) (OpamCudf.ActionGraph.reduce sol) { s_install=0; s_reinstall=0; s_upgrade=0; s_downgrade=0; s_remove=0 } let string_of_stats stats = let utf = (OpamConsole.utf8 ()) in let stats = [ stats.s_install; stats.s_reinstall; stats.s_upgrade; stats.s_downgrade; stats.s_remove; ] in let titles = List.map (fun a -> let s = OpamActionGraph.action_strings a in if utf then OpamActionGraph.action_color a s else s) [`Install (); `Reinstall (); `Change (`Up,(),()); `Change (`Down,(),()); `Remove ()] in let msgs = List.filter (fun (a,_) -> a <> 0) (List.combine stats titles) in if utf then OpamStd.List.concat_map " " (fun (n,t) -> Printf.sprintf "%s %s" t (string_of_int n)) msgs else OpamStd.List.concat_map " | " (fun (n,t) -> Printf.sprintf "%s to %s" (OpamConsole.colorise `yellow (string_of_int n)) t) msgs let solution_is_empty t = OpamCudf.ActionGraph.is_empty t let print_solution ~messages ~append ~requested ~reinstall t = let dump_cudf sfx t = match OpamSolverConfig.(!r.cudf_file) with | None -> () | Some f -> let filename = Printf.sprintf "%s-actions%s.dot" f sfx in let oc = open_out filename in ActionGraph.Dot.output_graph oc (cudf_to_opam_graph OpamCudf.cudf2opam t); close_out oc in dump_cudf "-full" t; let t = OpamCudf.ActionGraph.reduce t in dump_cudf "" t; let causes = OpamCudf.compute_root_causes t requested reinstall in let actions, details = OpamCudf.ActionGraph.Topological.fold (fun a (actions,details) -> let cause = try OpamCudf.Map.find (action_contents a) causes with Not_found -> Unknown in let action = map_action OpamCudf.cudf2opam a in let cudf_name p = OpamPackage.name_to_string (OpamCudf.cudf2opam p) in let cause = string_of_cause cudf_name cause in let messages = match a with | `Install p | `Change (_,_,p) | `Reinstall p -> messages (OpamCudf.cudf2opam p) | `Remove _ | `Build _ | `Fetch _ -> [] in action :: actions, (cause, messages) :: details ) t ([],[]) in let actions, details = List.rev actions, List.rev details in Action.to_aligned_strings ~append actions |> List.map2 (fun (cause, messages) line -> " " :: line @ [if cause = "" then "" else Printf.sprintf "[%s]" cause] @ if messages = [] then [] else [String.concat "\n" messages] ) details |> OpamStd.Format.align_table |> OpamConsole.print_table ~sep:" " stdout let dump_universe universe oc = let version_map = cudf_versions_map universe universe.u_packages in let cudf_univ = load_cudf_universe ~depopts:false ~build:true ~post:true ~version_map universe universe.u_available () in OpamCudf.dump_universe oc cudf_univ; (* Add explicit bindings to retrieve original versions of non-available and non-existing (but referred to) packages *) OpamPackage.Map.iter (fun nv i -> if not (OpamPackage.Set.mem nv universe.u_available) then Printf.fprintf oc "#v2v:%s:%d=%s\n" (OpamPackage.name_to_string nv) i (OpamPackage.version_to_string nv) ) version_map let filter_solution filter t = let t = OpamCudf.ActionGraph.copy t in let rec rm iter_deps v = if OpamCudf.ActionGraph.mem_vertex t v then ( iter_deps (rm iter_deps) t v; OpamCudf.ActionGraph.remove_vertex t v ) in OpamCudf.ActionGraph.iter_vertex (function | `Remove nv as a when not (filter (OpamCudf.cudf2opam nv)) -> rm OpamCudf.ActionGraph.iter_pred a | (`Install nv | `Change (_,_,nv)) as a when not (filter (OpamCudf.cudf2opam nv)) -> rm OpamCudf.ActionGraph.iter_succ a | _ -> ()) t; t let request ?(criteria=`Default) ?(install=[]) ?(upgrade=[]) ?(remove=[]) () = { wish_install = install; wish_upgrade = upgrade; wish_remove = remove; criteria; extra_attributes = []; } opam-2.1.5/src/solver/opamCudf.ml0000644000175000017500000017355014427463453015723 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase [@@@ocaml.warning "-33"] open OpamDoseCompat let log ?level fmt = OpamConsole.log ?level "CUDF" fmt let slog = OpamConsole.slog (* custom cudf field labels *) let s_source = "opam-name" let s_source_number = "opam-version" let s_reinstall = "reinstall" let s_installed_root = "installed-root" let s_pinned = "pinned" let s_version_lag = "version-lag" let opam_invariant_package_name = Dose_common.CudfAdd.encode "=opam-invariant" let opam_invariant_package_version = 1 let opam_invariant_package = opam_invariant_package_name, opam_invariant_package_version let is_opam_invariant p = p.Cudf.package = opam_invariant_package_name let cudf2opam cpkg = if is_opam_invariant cpkg then OpamConsole.error_and_exit `Internal_error "Internal error: tried to access the CUDF opam invariant as an opam \ package"; let sname = Cudf.lookup_package_property cpkg s_source in let name = OpamPackage.Name.of_string sname in let sver = Cudf.lookup_package_property cpkg s_source_number in let version = OpamPackage.Version.of_string sver in OpamPackage.create name version let cudfnv2opam ?version_map ?cudf_universe (name,v) = let nv = match cudf_universe with | None -> None | Some u -> try Some (cudf2opam (Cudf.lookup_package u (name,v))) with Not_found -> None in match nv with | Some nv -> nv | None -> let name = OpamPackage.Name.of_string (Dose_common.CudfAdd.decode name) in match version_map with | Some vmap -> let nvset = OpamPackage.Map.filter (fun nv cv -> nv.name = name && cv = v) vmap in fst (OpamPackage.Map.choose nvset) | None -> raise Not_found let string_of_package p = let installed = if p.Cudf.installed then "installed" else "not-installed" in Printf.sprintf "%s.%d(%s)" p.Cudf.package p.Cudf.version installed let string_of_packages l = OpamStd.List.to_string string_of_package l module Json = struct let (>>=) = OpamStd.Option.Op.(>>=) let int_to_json n : OpamJson.t = `Float (float_of_int n) let int_of_json = function | `Float x -> Some (int_of_float x) | _ -> None let string_to_json s : OpamJson.t = `String s let string_of_json = function | `String s -> Some s | _ -> None let pkgname_to_json name : OpamJson.t = string_to_json name let pkgname_of_json json = string_of_json json let bool_to_json bool : OpamJson.t = `Bool bool let bool_of_json = function | `Bool b -> Some b | _ -> None let list_to_json elem_to_json li : OpamJson.t = `A (List.map elem_to_json li) let list_of_json elem_of_json = function | `A jsons -> begin try let get = function | None -> raise Not_found | Some v -> v in Some (List.map (fun json -> get (elem_of_json json)) jsons) with Not_found -> None end | _ -> None let option_to_json elem_to_json = function | None -> `Null | Some elem -> let json = elem_to_json elem in assert (json <> `Null); json let option_of_json elem_of_json = function | `Null -> Some None | other -> elem_of_json other >>= fun elem -> Some (Some elem) let pair_to_json fst_field fst_to_json snd_field snd_to_json (fst, snd) = `O [(fst_field, fst_to_json fst); (snd_field, snd_to_json snd)] let pair_of_json fst_field fst_of_json snd_field snd_of_json : OpamJson.t -> _ = function | `O dict -> begin try fst_of_json (List.assoc fst_field dict) >>= fun fst -> snd_of_json (List.assoc snd_field dict) >>= fun snd -> Some (fst, snd) with Not_found -> None end | _ -> None let version_to_json n = int_to_json n let version_of_json json = int_of_json json let relop_to_json : Cudf_types.relop -> _ = function | `Eq -> `String "eq" | `Neq -> `String "neq" | `Geq -> `String "geq" | `Gt -> `String "gt" | `Leq -> `String "leq" | `Lt -> `String "lt" let relop_of_json : _ -> Cudf_types.relop option = function | `String "eq" -> Some `Eq | `String "neq" -> Some `Neq | `String "geq" -> Some `Geq | `String "gt" -> Some `Gt | `String "leq" -> Some `Leq | `String "lt" -> Some `Lt | _ -> None let enum_keep_to_json = function | `Keep_version -> `String "keep_version" | `Keep_package -> `String "keep_package" | `Keep_feature -> `String "keep_feature" | `Keep_none -> `String "keep_none" let enum_keep_of_json = function | `String "keep_version" -> Some (`Keep_version) | `String "keep_package" -> Some (`Keep_package) | `String "keep_feature" -> Some (`Keep_feature) | `String "keep_none" -> Some (`Keep_none) | _ -> None let constr_to_json constr = option_to_json (pair_to_json "relop" relop_to_json "version" version_to_json) constr let constr_of_json json = option_of_json (pair_of_json "relop" relop_of_json "version" version_of_json) json let vpkg_to_json v = pair_to_json "pkgname" pkgname_to_json "constr" constr_to_json v let vpkg_of_json json = pair_of_json "pkgname" pkgname_of_json "constr" constr_of_json json let vpkglist_to_json (vpkglist : Cudf_types.vpkglist) = list_to_json vpkg_to_json vpkglist let vpkglist_of_json jsons : Cudf_types.vpkglist option = list_of_json vpkg_of_json jsons let veqpkg_to_json veqpkg = vpkg_to_json (veqpkg :> Cudf_types.vpkg) let veqpkg_of_json json = vpkg_of_json json >>= function | (pkgname, None) -> Some (pkgname, None) | (pkgname, Some (`Eq, version)) -> Some (pkgname, Some (`Eq, version)) | (_pkgname, Some (_, _version)) -> None let veqpkglist_to_json veqpkglist = list_to_json veqpkg_to_json veqpkglist let veqpkglist_of_json jsons = list_of_json veqpkg_of_json jsons let vpkgformula_to_json formula = list_to_json (list_to_json vpkg_to_json) formula let vpkgformula_of_json json = list_of_json (list_of_json vpkg_of_json) json let binding_to_json value_to_json v = pair_to_json "key" string_to_json "value" value_to_json v let binding_of_json value_of_json v = pair_of_json "key" string_of_json "value" value_of_json v let stanza_to_json value_to_json stanza = list_to_json (binding_to_json value_to_json) stanza let stanza_of_json value_of_json json = list_of_json (binding_of_json value_of_json) json let type_schema_to_json tag value_to_json value = pair_to_json "type" string_to_json "default" (option_to_json value_to_json) (tag, value) let rec typedecl1_to_json = function | `Int n -> type_schema_to_json "int" int_to_json n | `Posint n -> type_schema_to_json "posint" int_to_json n | `Nat n -> type_schema_to_json "nat" int_to_json n | `Bool b -> type_schema_to_json "bool" bool_to_json b | `String s -> type_schema_to_json "string" string_to_json s | `Pkgname s -> type_schema_to_json "pkgname" pkgname_to_json s | `Ident s -> type_schema_to_json "ident" string_to_json s | `Enum (enums, v) -> pair_to_json "type" string_to_json "default" (pair_to_json "set" (list_to_json string_to_json) "default" (option_to_json string_to_json)) ("enum", (enums, v)) | `Vpkg v -> type_schema_to_json "vpkg" vpkg_to_json v | `Vpkgformula v -> type_schema_to_json "vpkgformula" vpkgformula_to_json v | `Vpkglist v -> type_schema_to_json "vpkglist" vpkglist_to_json v | `Veqpkg v -> type_schema_to_json "veqpkg" veqpkg_to_json v | `Veqpkglist v -> type_schema_to_json "veqpkglist" veqpkglist_to_json v | `Typedecl td -> type_schema_to_json "typedecl" typedecl_to_json td and typedecl_to_json td = stanza_to_json typedecl1_to_json td let rec typedecl1_of_json json = pair_of_json "type" string_of_json "default" (fun x -> Some x) json >>= fun (tag, json) -> match tag with | "int" -> option_of_json int_of_json json >>= fun x -> Some (`Int x) | "posint" -> option_of_json int_of_json json >>= fun x -> Some (`Posint x) | "nat" -> option_of_json int_of_json json >>= fun x -> Some (`Nat x) | "bool" -> option_of_json bool_of_json json >>= fun x -> Some (`Bool x) | "string" -> option_of_json string_of_json json >>= fun x -> Some (`String x) | "pkgname" -> option_of_json string_of_json json >>= fun x -> Some (`Pkgname x) | "ident" -> option_of_json string_of_json json >>= fun x -> Some (`Ident x) | "enum" -> pair_of_json "set" (list_of_json string_of_json) "default" (option_of_json string_of_json) json >>= fun x -> Some (`Enum x) | "vpkg" -> option_of_json vpkg_of_json json >>= fun x -> Some (`Vpkg x) | "vpkgformula" -> option_of_json vpkgformula_of_json json >>= fun x -> Some (`Vpkgformula x) | "vpkglist" -> option_of_json vpkglist_of_json json >>= fun x -> Some (`Vpkglist x) | "veqpkg" -> option_of_json veqpkg_of_json json >>= fun x -> Some (`Veqpkg x) | "veqpkglist" -> option_of_json veqpkglist_of_json json >>= fun x -> Some (`Veqpkglist x) | "typedecl" -> option_of_json typedecl_of_json json >>= fun x -> Some (`Typedecl x) | _ -> None and typedecl_of_json json = stanza_of_json typedecl1_of_json json let type_tagged_to_json tag value_to_json value = pair_to_json "type" string_to_json "value" value_to_json (tag, value) let typed_value_to_json : Cudf_types.typed_value -> _ = function | `Int n -> type_tagged_to_json "int" int_to_json n | `Posint n -> type_tagged_to_json "posint" int_to_json n | `Nat n -> type_tagged_to_json "nat" int_to_json n | `Bool b -> type_tagged_to_json "bool" bool_to_json b | `String s -> type_tagged_to_json "string" string_to_json s | `Pkgname name -> type_tagged_to_json "pkgname" pkgname_to_json name | `Ident id -> type_tagged_to_json "ident" string_to_json id | `Enum (enums, value) -> type_tagged_to_json "enum" (pair_to_json "set" (list_to_json string_to_json) "choice" string_to_json) (enums, value) | `Vpkg vpkg -> type_tagged_to_json "vpkg" vpkg_to_json vpkg | `Vpkgformula vpkgformula -> type_tagged_to_json "vpkgformula" vpkgformula_to_json vpkgformula | `Vpkglist vpkglist -> type_tagged_to_json "vpkglist" vpkglist_to_json vpkglist | `Veqpkg veqpkg -> type_tagged_to_json "veqpkg" veqpkg_to_json veqpkg | `Veqpkglist veqpkglist -> type_tagged_to_json "veqpkglist" veqpkglist_to_json veqpkglist | `Typedecl typedecl -> type_tagged_to_json "typedecl" typedecl_to_json typedecl let typed_value_of_json json : Cudf_types.typed_value option = pair_of_json "type" string_of_json "value" (fun x -> Some x) json >>= fun (tag, json) -> match tag with | "int" -> int_of_json json >>= fun x -> Some (`Int x) | "posint" -> int_of_json json >>= fun x -> Some (`Posint x) | "nat" -> int_of_json json >>= fun x -> Some (`Nat x) | "bool" -> bool_of_json json >>= fun x -> Some (`Bool x) | "string" -> string_of_json json >>= fun x -> Some (`String x) | "pkgname" -> string_of_json json >>= fun x -> Some (`Pkgname x) | "ident" -> string_of_json json >>= fun x -> Some (`Ident x) | "enum" -> pair_of_json "set" (list_of_json string_of_json) "choice" string_of_json json >>= fun p -> Some (`Enum p) | "vpkg" -> vpkg_of_json json >>= fun x -> Some (`Vpkg x) | "vpkgformula" -> vpkgformula_of_json json >>= fun x -> Some (`Vpkgformula x) | "vpkglist" -> vpkglist_of_json json >>= fun x -> Some (`Vpkglist x) | "veqpkg" -> veqpkg_of_json json >>= fun x -> Some (`Veqpkg x) | "veqpkglist" -> veqpkglist_of_json json >>= fun x -> Some (`Veqpkglist x) | "typedecl" -> typedecl_of_json json >>= fun x -> Some (`Typedecl x) | _ -> None let package_to_json p = `O [ ("name", pkgname_to_json p.Cudf.package); ("version", version_to_json p.Cudf.version); ("depends", vpkgformula_to_json p.Cudf.depends); ("conflicts", vpkglist_to_json p.Cudf.conflicts); ("provides", veqpkglist_to_json p.Cudf.provides); ("installed", bool_to_json p.Cudf.installed); ("was_installed", bool_to_json p.Cudf.was_installed); ("keep", enum_keep_to_json p.Cudf.keep); ("pkg_extra", stanza_to_json typed_value_to_json p.Cudf.pkg_extra); ] let package_of_json = function | `O dict -> begin try pkgname_of_json (List.assoc "name" dict) >>= fun package -> version_of_json (List.assoc "version" dict) >>= fun version -> vpkgformula_of_json (List.assoc "depends" dict) >>= fun depends -> vpkglist_of_json (List.assoc "conflicts" dict) >>= fun conflicts -> veqpkglist_of_json (List.assoc "provides" dict) >>= fun provides -> bool_of_json (List.assoc "installed" dict) >>= fun installed -> bool_of_json (List.assoc "was_installed" dict) >>= fun was_installed -> enum_keep_of_json (List.assoc "keep" dict) >>= fun keep -> stanza_of_json typed_value_of_json (List.assoc "pkg_extra" dict) >>= fun pkg_extra -> Some { Cudf.package = package; version; depends; conflicts; provides; installed; was_installed; keep; pkg_extra; } with Not_found -> None end | _ -> None end let to_json = Json.package_to_json let of_json = Json.package_of_json (* Graph of cudf packages *) module Package = struct type t = Cudf.package include Dose_common.CudfAdd let to_string = string_of_package let name_to_string t = t.Cudf.package let version_to_string t = string_of_int t.Cudf.version let to_json = to_json let of_json = of_json end module Action = OpamActionGraph.MakeAction(Package) module ActionGraph = OpamActionGraph.Make(Action) let string_of_action = Action.to_string let string_of_actions l = OpamStd.List.to_string (fun a -> " - " ^ string_of_action a) l exception Solver_failure of string exception Cyclic_actions of Action.t list list type conflict_case = | Conflict_dep of (unit -> Dose_algo.Diagnostic.reason list) | Conflict_cycle of string list list type conflict = Cudf.universe * int package_map * conflict_case module Map = OpamStd.Map.Make(Package) module Set = OpamStd.Set.Make(Package) let strong_and_weak_deps u deps = (* strong deps are mandatory (constraint appearing in the top conjunction) weak deps correspond to optional occurrences of a package, as part of a disjunction: e.g. in (A>=4 & (B | A<5)), A>=4 is strong, and the other two are weak. In the end we want to retain B and A>=4. *) List.fold_left (fun (strong_deps, weak_deps) l -> let names = List.fold_left (fun acc (n, _) -> OpamStd.String.Map.add n Set.empty acc) OpamStd.String.Map.empty l in let set = List.fold_left (fun acc (n, cstr) -> List.fold_left (fun s x -> Set.add x s) acc (Cudf.lookup_packages ~filter:cstr u n)) Set.empty l in let by_name = Set.fold (fun p -> OpamStd.String.Map.update p.Cudf.package (Set.add p) Set.empty) set names in if OpamStd.String.Map.is_singleton by_name then let name, versions = OpamStd.String.Map.choose by_name in OpamStd.String.Map.update name (Set.inter versions) versions strong_deps, OpamStd.String.Map.remove name weak_deps else let by_name = OpamStd.String.Map.filter (fun name _ -> not (OpamStd.String.Map.mem name strong_deps)) by_name in strong_deps, OpamStd.String.Map.union Set.union weak_deps by_name) (OpamStd.String.Map.empty, OpamStd.String.Map.empty) deps (* From a CUDF dependency CNF, extract the set of packages that can possibly be part of a solution. This is much finer than [Dose_common.CudfAdd.resolve_deps] which doesn't handle conjunctions of versions (see [Graph.of_universe] below) *) let dependency_set u deps = let strong_deps, weak_deps = strong_and_weak_deps u deps in OpamStd.String.Map.fold (fun _ -> Set.union) strong_deps @@ OpamStd.String.Map.fold (fun _ -> Set.union) weak_deps @@ Set.empty (* From a CUDF dependency CNF, extract the set of packages that will necessarily be part of any solution (with a choice among packages of the same name of course) *) let _strong_dependency_set u deps = let strong_deps, _ = strong_and_weak_deps u deps in OpamStd.String.Map.fold (fun _ -> Set.union) strong_deps Set.empty let rec_strong_dependency_map u deps = let module SM = OpamStd.String.Map in let rec aux seen deps = let strong_deps, _ = strong_and_weak_deps u deps in OpamStd.String.Map.fold (fun name ps (seen, acc) -> let seen, common_strong_deps = Set.fold (fun p (seen, acc) -> let seen, dmap = try seen, Map.find p seen with Not_found -> let seen, r = aux (Map.add p SM.empty seen) p.Cudf.depends in Map.add p r seen, r in seen, Some (match acc with | None -> dmap | Some m -> SM.merge (fun _ a b -> match a, b with | Some a, Some b -> Some (Set.union a b) | _ -> None) m dmap)) ps (seen, None) in let strong_deps = SM.add name ps (OpamStd.Option.default SM.empty common_strong_deps) in seen, SM.union Set.inter acc strong_deps) strong_deps (seen, SM.empty) in snd (aux Map.empty deps) let _rec_strong_dependency_set u deps = OpamStd.String.Map.fold (fun _ -> Set.union) (rec_strong_dependency_map u deps) Set.empty module Graph = struct module PG = struct include Dose_algo.Defaultgraphs.PackageGraph.G let succ g v = try succ g v with e -> OpamStd.Exn.fatal e; [] end module PO = Dose_algo.Defaultgraphs.GraphOper (PG) module Topo = Graph.Topological.Make (PG) let of_universe u = (* {[Dose_algo.Defaultgraphs.PackageGraph.dependency_graph u]} -> doesn't handle conjunctive dependencies correctly (e.g. (a>3 & a<=4) is considered as (a>3 | a<=4) and results in extra edges). Here we handle the fact that a conjunction with the same pkgname is an intersection, while a conjunction between different names is an union *) let t = OpamConsole.timer () in let g = PG.create ~size:(Cudf.universe_size u) () in let iter_deps f deps = (* List.iter (fun d -> List.iter f (Dose_common.CudfAdd.resolve_deps u d)) deps *) Set.iter f (dependency_set u deps) in Cudf.iter_packages (fun p -> PG.add_vertex g p; iter_deps (PG.add_edge g p) p.Cudf.depends) u; log ~level:3 "Graph generation: %.3f" (t ()); g let output g filename = let fd = open_out (filename ^ ".dot") in Dose_algo.Defaultgraphs.PackageGraph.DotPrinter.output_graph fd g; close_out fd let transitive_closure g = PO.O.add_transitive_closure g let linearize g pkgs = Topo.fold (fun p acc -> if Set.mem p pkgs then p::acc else acc) g [] let mirror = PO.O.mirror include PG end (** Special package used by Dose internally, should generally be filtered out *) let dose_dummy_request = Dose_algo.Depsolver.dummy_request.Cudf.package let is_artefact cpkg = is_opam_invariant cpkg || cpkg.Cudf.package = dose_dummy_request let dependencies universe packages = Set.fixpoint (fun p -> dependency_set universe p.Cudf.depends) packages (* similar to Dose_algo.Depsolver.dependency_closure but with finer results on version sets *) let reverse_dependencies universe packages = let graph = Graph.of_universe universe in Set.fixpoint (fun p -> Set.of_list (Graph.pred graph p)) packages (* similar to Dose_algo.Depsolver.reverse_dependency_closure but more reliable *) let dependency_sort universe packages = let graph = Graph.of_universe universe in Graph.linearize graph packages |> List.rev let string_of_atom (p, c) = let const = function | None -> "" | Some (r,v) -> Printf.sprintf " (%s %d)" (OpamPrinter.FullPos.relop_kind r) v in Printf.sprintf "%s%s" p (const c) let string_of_vpkgs constr = let constr = List.sort (fun (a,_) (b,_) -> String.compare a b) constr in OpamFormula.string_of_conjunction string_of_atom constr let string_of_universe u = string_of_packages (List.sort Dose_common.CudfAdd.compare (Cudf.get_packages u)) let vpkg2atom cudfnv2opam (name,cstr) = match cstr with | None -> OpamPackage.Name.of_string (Dose_common.CudfAdd.decode name), None | Some (relop,v) -> let nv = cudfnv2opam (name,v) in nv.name, Some (relop, nv.version) (* Should be unneeded now that we pass a full version_map along [{ log "Could not find corresponding version in cudf universe: %a" (slog string_of_atom) (name,cstr); let candidates = Cudf.lookup_packages cudf_universe name in let solutions = Cudf.lookup_packages ~filter:cstr cudf_universe name in let module OVS = OpamPackage.Version.Set in let to_version_set l = OVS.of_list (List.map (fun p -> OpamPackage.version (cudf2opam p)) l) in let solutions = to_version_set solutions in let others = OVS.Op.(to_version_set candidates -- solutions) in OpamPackage.Name.of_string (Dose_common.CudfAdd.decode name), match relop, OVS.is_empty solutions, OVS.is_empty others with | _, true, true -> None | `Leq, false, _ | `Lt, false, true -> Some (`Leq, OVS.max_elt solutions) | `Lt, _, false | `Leq, true, false -> Some (`Lt, OVS.min_elt others) | `Geq, false, _ | `Gt, false, true -> Some (`Geq, OVS.min_elt solutions) | `Gt, _, false | `Geq, true, false -> Some (`Gt, OVS.max_elt others) | `Eq, false, _ -> Some (`Eq, OVS.choose solutions) | `Eq, true, _ -> Some (`Eq, OpamPackage.Version.of_string "") | `Neq, false, true -> None | `Neq, _, false -> Some (`Neq, OVS.choose others) }] *) let conflict_empty ~version_map univ = Conflicts (univ, version_map, Conflict_dep (fun () -> [])) let make_conflicts ~version_map univ = function | {Dose_algo.Diagnostic.result = Dose_algo.Diagnostic.Failure f; _} -> Conflicts (univ, version_map, Conflict_dep f) | {Dose_algo.Diagnostic.result = Dose_algo.Diagnostic.Success _; _} -> raise (Invalid_argument "make_conflicts") let cycle_conflict ~version_map univ cycle = Conflicts (univ, version_map, Conflict_cycle cycle) let arrow_concat sl = let arrow = Printf.sprintf " %s " (OpamConsole.utf8_symbol OpamConsole.Symbols.rightwards_arrow "->") in String.concat (OpamConsole.colorise `yellow arrow) sl let formula_of_vpkgl cudfnv2opam all_packages vpkgl = let atoms = List.map (fun vp -> try vpkg2atom cudfnv2opam vp with Not_found -> OpamPackage.Name.of_string (Dose_common.CudfAdd.decode (fst vp)), None) vpkgl in let names = OpamStd.List.sort_nodup compare (List.map fst atoms) in let by_name = List.map (fun name -> let formula = OpamFormula.ors (List.map (function | n, Some atom when n = name -> Atom atom | _ -> Empty) atoms) in let all_versions = OpamPackage.versions_of_name all_packages name in let formula = OpamFormula.simplify_version_set all_versions formula in Atom (name, formula)) names in OpamFormula.ors by_name (* - Conflict message handling machinery - *) (* chain sets: sets of package lists *) module ChainSet = struct include OpamStd.Set.Make (struct type t = Package.t list let rec compare t1 t2 = match t1, t2 with | [], [] -> 0 | [], _ -> -1 | _, [] -> 1 | p1::r1, p2::r2 -> match Package.compare p1 p2 with 0 -> compare r1 r2 | n -> n let to_string t = arrow_concat (List.rev_map Package.to_string t) let to_json t = Json.list_to_json Package.to_json t let of_json j = Json.list_of_json Package.of_json j end) (** Turns a set of lists into a list of sets *) let rec transpose cs = let hds, tls = fold (fun c (hds, tls) -> match c with | hd::tl -> Set.add hd hds, add tl tls | [] -> hds, tls) cs (Set.empty, empty) in if Set.is_empty hds then [] else hds :: transpose tls (** cs1 precludes cs2 if it contains a list that is prefix to all elements of cs2 *) let precludes cs1 cs2 = let rec list_is_prefix pfx l = match pfx, l with | [], _ -> true | a::r1, b::r2 when Package.equal a b -> list_is_prefix r1 r2 | _ -> false in exists (fun pfx -> for_all (fun l -> list_is_prefix pfx l) cs2) cs1 let length cs = fold (fun l acc -> min (List.length l) acc) cs max_int end type explanation = [ `Conflict of string option * string list * bool | `Missing of string option * string * (OpamPackage.Name.t * OpamFormula.version_formula) OpamFormula.formula ] let extract_explanations packages cudfnv2opam reasons : explanation list = log "Conflict reporting"; let open Dose_algo.Diagnostic in let module CS = ChainSet in (* Definitions and printers *) let all_opam = let add p set = if is_artefact p then set else OpamPackage.Set.add (cudf2opam p) set in List.fold_left (fun acc -> function | Conflict (l, r, _) -> add l @@ add r @@ acc | Dependency (l, _, rs) -> List.fold_left (fun acc p -> add p acc) (add l acc) rs | Missing (p, _) -> add p acc) OpamPackage.Set.empty reasons in let print_set pkgs = if Set.exists is_artefact pkgs then if Set.exists is_opam_invariant pkgs then "(invariant)" else "(request)" else let nvs = OpamPackage.to_map @@ Set.fold (fun p s -> OpamPackage.Set.add (cudf2opam p) s) pkgs OpamPackage.Set.empty in let strs = OpamPackage.Name.Map.mapi (fun name versions -> let all_versions = OpamPackage.versions_of_name all_opam name in let formula = OpamFormula.formula_of_version_set all_versions versions in OpamFormula.to_string (Atom (name, formula))) nvs in String.concat ", " (OpamPackage.Name.Map.values strs) in let cs_to_string ?(hl_last=true) cs = let rec aux vpkgl = function | [] -> [] | pkgs :: r -> let vpkgl1 = List.fold_left (fun acc -> function | Dependency (p1, vpl, _) when Set.mem p1 pkgs -> List.rev_append vpl acc | _ -> acc) [] reasons in if Set.exists is_artefact pkgs then if Set.exists is_opam_invariant pkgs then Printf.sprintf "(invariant)" :: aux vpkgl1 r else if r = [] then ["(request)"] else aux vpkgl1 r (* request *) else if vpkgl = [] then print_set pkgs :: aux vpkgl1 r else let f = let vpkgl = List.filter (fun (n, _) -> Set.exists (fun p -> p.package = n) pkgs) vpkgl in (* TODO: We should aim to use what does give us not guess the formula *) (* Dose is precise enough from what i'm seeing *) formula_of_vpkgl cudfnv2opam packages vpkgl in let s = OpamFormula.to_string f in (if hl_last && r = [] then OpamConsole.colorise' [`red;`bold] s else s) :: aux vpkgl1 r in arrow_concat (aux [] (CS.transpose (CS.map List.rev cs))) in let get t x = try Hashtbl.find t x with Not_found -> Set.empty in let add_set t l set = match Hashtbl.find t l with | exception Not_found -> Hashtbl.add t l set | s -> Hashtbl.replace t l (Set.union set s) in (* Gather all data in hashtables *) let ct = Hashtbl.create 53 in let deps = Hashtbl.create 53 in let rdeps = Hashtbl.create 53 in let missing = Hashtbl.create 53 in List.iter (function | Conflict (l, r, (_pkgname, _constr)) -> add_set ct l (Set.singleton r); add_set ct r (Set.singleton l); | Dependency (l, _, rs) -> add_set deps l (Set.of_list rs); List.iter (fun r -> add_set rdeps r (Set.singleton l)) rs | Missing (p, deps) -> Hashtbl.add missing p deps) reasons; (* Get paths from the conflicts to requested or invariant packages *) let roots = let add_artefacts set = Hashtbl.fold (fun p _ acc -> if is_artefact p then Set.add p acc else acc) set in Set.empty |> add_artefacts deps |> add_artefacts missing |> add_artefacts ct in let _seen, ct_chains = (* get a covering tree from the roots to all reachable packages. *) let rec aux seen ct_chains = Map.fold (fun pkg parent_chain (seen, ct_chains) -> if Set.mem pkg seen then (seen, ct_chains) else let dependencies = get deps pkg in let seen = Set.add pkg seen in Set.fold (fun dep (seen, ct_chains) -> let chain = CS.map (fun c -> dep :: c) parent_chain in let ct_chains = Map.update dep (CS.union chain) CS.empty ct_chains in aux seen ct_chains ) dependencies (seen, ct_chains) ) ct_chains (seen, ct_chains) in let init_chains = Set.fold (fun p -> Map.add p (CS.singleton [p])) roots Map.empty in aux Set.empty init_chains in let ct_chains = (* We keep only shortest chains. *) (* TODO: choose is probably not the right thing here. *) (* e.g. if two lists have the size, we should probably have both. *) Map.map (fun x -> CS.singleton (CS.choose x)) ct_chains in let reasons = (* order "reasons" by most interesting first: version conflicts then package then missing + shortest chains first *) let clen p = try CS.length (Map.find p ct_chains) with Not_found -> 0 in let version_conflict = function | Conflict (l, r, _) -> l.Cudf.package = r.Cudf.package | _ -> false in let cmp a b = match a, b with | Conflict (l1, r1, _), Conflict (l2, r2, _) -> let va = version_conflict a and vb = version_conflict b in if va && not vb then -1 else if vb && not va then 1 else (match compare (clen l1 + clen r1) (clen l2 + clen r2) with | 0 -> (match Package.compare l1 l2 with | 0 -> Package.compare r1 r2 | n -> n) | n -> n) | _, Conflict _ -> 1 | Conflict _, _ -> -1 | Missing (p1, _), Missing (p2, _) -> (match compare (clen p1) (clen p2) with | 0 -> Package.compare p1 p2 | n -> n) | _, Missing _ -> 1 | Missing _, _ -> -1 | Dependency _, Dependency _ -> 0 (* we don't care anymore *) in List.sort_uniq cmp reasons in let has_invariant p = let chain_has_invariant cs = CS.exists (List.exists is_opam_invariant) cs in try chain_has_invariant (Map.find p ct_chains) with Not_found -> false in let explanations, _remaining_ct_chains = List.fold_left (fun (explanations, ct_chains) re -> let cst ?hl_last ct_chains p = let chains = Map.find p ct_chains in Map.filter (fun _ c -> not (CS.precludes chains c)) ct_chains, cs_to_string ?hl_last chains in try match re with | Conflict (l, r, _) -> let ct_chains, csl = cst ct_chains l in let ct_chains, csr = cst ct_chains r in let msg1 = if l.Cudf.package = r.Cudf.package then Some (Package.name_to_string l) else None in let msg2 = List.sort_uniq compare [csl; csr] in let msg3 = (has_invariant l || has_invariant r) && not (List.exists (function `Conflict (_,_,has_invariant) -> has_invariant | _ -> false) explanations) in let msg = `Conflict (msg1, msg2, msg3) in if List.mem msg explanations then raise Not_found else msg :: explanations, ct_chains | Missing (p, deps) -> let ct_chains, csp = cst ~hl_last:false ct_chains p in let fdeps = formula_of_vpkgl cudfnv2opam packages deps in let sdeps = OpamFormula.to_string fdeps in let msg = `Missing (Some csp, sdeps, fdeps) in if List.mem msg explanations then raise Not_found else msg :: explanations, ct_chains | Dependency _ -> explanations, ct_chains with Not_found -> explanations, ct_chains) ([], ct_chains) reasons in let same_depexts sdeps fdeps = List.for_all (function | `Missing (_, sdeps', fdeps') -> sdeps = sdeps' && fdeps = fdeps' | _ -> false) in match explanations with | `Missing (_, sdeps, fdeps) :: rest when same_depexts sdeps fdeps rest -> [`Missing (None, sdeps, fdeps)] | _ -> explanations let strings_of_cycles cycles = List.map arrow_concat cycles let string_of_conflict ?(start_column=0) (msg1, msg2, msg3) = let width = OpamStd.Sys.terminal_columns () - start_column - 2 in OpamStd.Format.reformat ~start_column ~indent:2 msg1 ^ OpamStd.List.concat_map ~left:"\n- " ~nil:"" "\n- " (fun s -> OpamStd.Format.reformat ~indent:2 ~width s) msg2 ^ OpamStd.List.concat_map ~left:"\n" ~nil:"" "\n" (fun s -> OpamStd.Format.reformat ~indent:2 ~width s) msg3 let conflict_explanations_raw packages = function | univ, version_map, Conflict_dep reasons -> let r = reasons () in let cudfnv2opam = cudfnv2opam ~cudf_universe:univ ~version_map in List.rev (extract_explanations packages cudfnv2opam r), [] | _univ, _version_map, Conflict_cycle cycles -> [], cycles let string_of_explanation unav_reasons = function | `Conflict (kind, packages, has_invariant) -> let msg1 = let format_package_name p = Printf.sprintf "No agreement on the version of %s:" (OpamConsole.colorise `bold p) in OpamStd.Option.map_default format_package_name "Incompatible packages:" kind and msg3 = if has_invariant then ["You can temporarily relax the switch invariant with \ `--update-invariant'"] else [] in (msg1, packages, msg3) | `Missing (csp, sdeps, fdeps) -> let sdeps = OpamConsole.colorise' [`red;`bold] sdeps in let msg1 = "Missing dependency:" and msg2 = OpamStd.Option.map_default (fun csp -> arrow_concat [csp; sdeps]) sdeps csp and msg3 = OpamFormula.fold_right (fun a x -> unav_reasons x::a) [] fdeps in (msg1, [msg2], msg3) let conflict_explanations packages unav_reasons = function | univ, version_map, Conflict_dep reasons -> let r = reasons () in let cudfnv2opam = cudfnv2opam ~cudf_universe:univ ~version_map in let explanations = extract_explanations packages cudfnv2opam r in List.rev_map (string_of_explanation unav_reasons) explanations, [] | _univ, _version_map, Conflict_cycle cycles -> [], strings_of_cycles cycles let string_of_explanations unav_reasons (cflts, cycles) = let cflts = List.map (string_of_explanation unav_reasons) cflts in let cycles = strings_of_cycles cycles in let b = Buffer.create 1024 in let pr_items b l = Buffer.add_string b (OpamStd.Format.itemize (fun s -> s) l) in if cycles <> [] then Printf.bprintf b "The actions to process have cyclic dependencies:\n%a" pr_items cycles; if cflts <> [] then Buffer.add_string b (OpamStd.Format.itemize ~bullet:(OpamConsole.colorise `red " * ") (string_of_conflict ~start_column:4) cflts); if cflts = [] && cycles = [] then (* No explanation found *) Printf.bprintf b "Sorry, no solution found: \ there seems to be a problem with your request.\n"; Buffer.add_string b "\n"; Buffer.contents b let string_of_conflicts packages unav_reasons conflict = string_of_explanations unav_reasons (conflict_explanations_raw packages conflict) let check flag p = try Cudf.lookup_typed_package_property p flag = `Bool true with Not_found -> false let need_reinstall = check s_reinstall (* let is_installed_root = check s_installed_root let is_pinned = check s_pinned *) let default_preamble = let l = [ (s_source, `String None); (s_source_number, `String None); (s_reinstall, `Bool (Some false)); (s_installed_root, `Bool (Some false)); (s_pinned, `Bool (Some false)); (s_version_lag, `Nat (Some 0)); ] in Dose_common.CudfAdd.add_properties Cudf.default_preamble l let remove universe name constr = let filter p = p.Cudf.package <> name || not (Cudf.version_matches p.Cudf.version constr) in let packages = Cudf.get_packages ~filter universe in Cudf.load_universe packages let uninstall_all universe = let packages = Cudf.get_packages universe in let packages = List.rev_map (fun p -> { p with Cudf.installed = false }) packages in Cudf.load_universe packages let install universe package = let p = Cudf.lookup_package universe (package.Cudf.package, package.Cudf.version) in let p = { p with Cudf.installed = true } in let packages = let filter p = p.Cudf.package <> package.Cudf.package || p.Cudf.version <> package.Cudf.version in Cudf.get_packages ~filter universe in Cudf.load_universe (p :: packages) let remove_all_uninstalled_versions_but universe name constr = let filter p = p.Cudf.installed || p.Cudf.package <> name || Cudf.version_matches p.Cudf.version constr in let packages = Cudf.get_packages ~filter universe in Cudf.load_universe packages let to_cudf univ req = ( Dose_common.CudfAdd.add_properties default_preamble (List.map (fun s -> s, `Int (Some 0)) req.extra_attributes), univ, { Cudf.request_id = "opam"; install = req.wish_install; remove = req.wish_remove; upgrade = req.wish_upgrade; req_extra = [] } ) let string_of_request r = Printf.sprintf "install:%s remove:%s upgrade:%s" (string_of_vpkgs r.wish_install) (string_of_vpkgs r.wish_remove) (string_of_vpkgs r.wish_upgrade) let solver_calls = ref 0 let dump_universe oc univ = Cudf_printer.pp_cudf oc (default_preamble, univ, Cudf.default_request) let dump_cudf_request ~version_map (_, univ,_ as cudf) criteria = function | None -> None | Some f -> ignore ( version_map: int OpamPackage.Map.t ); incr solver_calls; let filename = Printf.sprintf "%s-%d.cudf" f !solver_calls in let oc = open_out filename in let module Solver = (val OpamSolverConfig.(Lazy.force !r.solver)) in Printf.fprintf oc "# Solver: %s\n" (OpamCudfSolver.get_name (module Solver)); Printf.fprintf oc "# Criteria: %s\n" criteria; Cudf_printer.pp_cudf oc cudf; OpamPackage.Map.iter (fun (pkg:OpamPackage.t) (vnum: int) -> let name = OpamPackage.name_to_string pkg in let version = OpamPackage.version_to_string pkg in Printf.fprintf oc "#v2v:%s:%d=%s\n" name vnum version; ) version_map; close_out oc; Graph.output (Graph.of_universe univ) f; Some filename let dump_cudf_error ~version_map univ req = let cudf_file = match OpamSolverConfig.(!r.cudf_file) with | Some f -> f | None -> let (/) = Filename.concat in OpamCoreConfig.(!r.log_dir) / ("solver-error-"^string_of_int (OpamStubs.getpid())) in match dump_cudf_request (to_cudf univ req) ~version_map (OpamSolverConfig.criteria req.criteria) (Some cudf_file) with | Some f -> f | None -> assert false let preprocess_cudf_request (props, univ, creq) criteria = let chrono = OpamConsole.timer () in let univ0 = univ in let do_trimming = match OpamSolverConfig.(!r.cudf_trim) with | Some "simple" -> Some false | b -> match OpamStd.Option.Op.(b >>= OpamStd.Config.bool_of_string) with | Some false -> None | Some true -> Some true | None -> (* Full trimming is only correct when there is no maximisation criteria, so automatically set it to true in this case *) let neg_crit_re = Re.(seq [char '-'; rep1 (diff any (set ",[(")); opt (seq [set "[("; rep1 (diff any (set ")]")); set ")]"])]) in let all_neg_re = Re.(whole_string (seq [rep (seq [neg_crit_re; char ',']); neg_crit_re])) in Some (Re.execp (Re.compile all_neg_re) criteria) in let univ = let open Set.Op in let vpkg2set vp = Set.of_list (Dose_common.CudfAdd.resolve_deps univ vp) in let to_install = vpkg2set creq.Cudf.install ++ Set.of_list (Cudf.lookup_packages univ opam_invariant_package_name) in let to_install_formula = List.map (fun x -> [x]) @@ (opam_invariant_package_name, None) :: creq.Cudf.install @ creq.Cudf.upgrade in let to_map set = Set.fold (fun p -> OpamStd.String.Map.update p.Cudf.package (Set.add p) Set.empty) set OpamStd.String.Map.empty in let packages = match do_trimming with | None -> Set.of_list (Cudf.get_packages univ) | Some false -> (* "simple" trimming *) let strong_deps_cone = rec_strong_dependency_map univ to_install_formula in (* only limit visible versions of packages appearing in strong_deps_cone *) let filter p = p.Cudf.installed || match OpamStd.String.Map.find_opt p.Cudf.package strong_deps_cone with | Some ps -> Set.mem p ps | None -> true in Set.of_list (Cudf.get_packages ~filter univ) | Some true -> (* "full" trimming *) let strong_deps_cone = rec_strong_dependency_map univ to_install_formula in (* limit visibility to only "possibly interesting" packages; this includes all installed packages, including their other versions (the changes to installed packages may need up/downgrades). *) let interesting_set = List.fold_left (fun acc p -> let name = p.Cudf.package in if OpamStd.String.Map.mem name strong_deps_cone then acc else acc ++ Set.of_list (Cudf.lookup_packages univ name)) (OpamStd.String.Map.fold (fun _ -> Set.union) strong_deps_cone Set.empty) (Cudf.get_packages ~filter:(fun p -> p.Cudf.installed) univ) in (* we will also need all the weak dependencies of all these packages *) Set.fixpoint (fun p -> Set.filter (fun d -> not (OpamStd.String.Map.mem d.Cudf.package strong_deps_cone)) (dependency_set univ p.Cudf.depends)) interesting_set in let direct_conflicts p = let base_conflicts = Set.filter (fun q -> q.Cudf.package <> p.Cudf.package) (vpkg2set p.Cudf.conflicts) in (* Dependencies not matching constraints are also conflicts *) List.fold_left (fun acc -> function | (n, c) :: disj when List.for_all (fun (m, _) -> m = n) disj -> let coset = function | Some (op, v) -> let filter = Some (OpamFormula.neg_relop op, v) in Set.of_list (Cudf.lookup_packages ~filter univ n) | None -> Set.empty in acc ++ List.fold_left (fun acc (_, c) -> acc %% coset c) (coset c) disj | _ -> acc) base_conflicts p.Cudf.depends in let cache = Hashtbl.create 513 in let cache_direct = Hashtbl.create 513 in (* Don't explore deeper than that for transitive conflicts *) let max_dig_depth = OpamSolverConfig.(!r.dig_depth) in let rec transitive_conflicts seen p = try Hashtbl.find cache p with Not_found -> let direct = try Hashtbl.find cache_direct p with Not_found -> let conflicts = direct_conflicts p in Hashtbl.add cache_direct p conflicts; conflicts in if Set.mem p seen || Set.cardinal seen >= max_dig_depth - 1 then direct else let seen = Set.add p seen in let conflicts = direct ++ List.fold_left (fun acc disj -> acc ++ Set.map_reduce ~default:Set.empty (transitive_conflicts seen) Set.inter (vpkg2set disj)) Set.empty p.Cudf.depends in Hashtbl.add cache p conflicts; conflicts in let conflicts = OpamStd.String.Map.fold (fun _ ps acc -> acc ++ Set.map_reduce ~default:Set.empty (transitive_conflicts Set.empty) Set.inter ps) (to_map to_install) Set.empty in log "Conflicts: %a (%a) pkgs to remove" (slog OpamStd.Op.(string_of_int @* Set.cardinal)) conflicts (slog OpamStd.Op.(string_of_int @* Set.cardinal)) (conflicts %% packages); Cudf.load_universe (Set.elements (packages -- conflicts)) in log "Preprocess cudf request (trimming: %s): from %d to %d packages in %.2fs" (match do_trimming with None -> "none" | Some false -> "simple" | Some true -> "full") (Cudf.universe_size univ0) (Cudf.universe_size univ) (chrono ()); props, univ, creq exception Timeout of Dose_algo.Depsolver.solver_result option let call_external_solver ~version_map univ req = let cudf_request = to_cudf univ req in if Cudf.universe_size univ > 0 then let criteria = OpamSolverConfig.criteria req.criteria in let chrono = OpamConsole.timer () in ignore (dump_cudf_request ~version_map cudf_request criteria OpamSolverConfig.(!r.cudf_file)); (* Wrap a return of exn Timeout through Depsolver *) let check_request_using ~call_solver ~explain req = let timed_out = ref false in let call_solver args = try call_solver args with | OpamCudfSolver.Timeout (Some s) -> timed_out := true; s | OpamCudfSolver.Timeout None -> raise (Timeout None) in let r = Dose_algo.Depsolver.check_request_using ~call_solver ~explain req in if !timed_out then raise (Timeout (Some r)) else r in try let cudf_request = if not OpamSolverConfig.(!r.preprocess) then cudf_request else preprocess_cudf_request cudf_request criteria in let r = check_request_using ~call_solver:(OpamSolverConfig.call_solver ~criteria) ~explain:true cudf_request in log "Solver call done in %.3fs" (chrono ()); r with | Timeout (Some sol) -> log "Solver call TIMED OUT with solution after %.3fs" (chrono ()); OpamConsole.warning "Resolution of the installation set timed out, so the following \ solution might not be optimal.\n\ You may want to make your request more precise, increase the value \ of OPAMSOLVERTIMEOUT (currently %.1fs), or try a different solver." OpamSolverConfig.(OpamStd.Option.default 0. !r.solver_timeout); sol | Timeout None -> let msg = Printf.sprintf "Sorry, resolution of the request timed out.\n\ Try to specify a more precise request, use a different solver, or \ increase the allowed time by setting OPAMSOLVERTIMEOUT to a bigger \ value (currently, it is set to %.1f seconds)." OpamSolverConfig.(OpamStd.Option.default 0. !r.solver_timeout) in raise (Solver_failure msg) | Failure msg -> let msg = Printf.sprintf "Solver failure: %s\nThis may be due to bad settings (solver or \ solver criteria) or a broken solver solver installation. Check \ $OPAMROOT/config, and the --solver and --criteria options." msg in raise (Solver_failure msg) | e -> OpamStd.Exn.fatal e; let msg = Printf.sprintf "Solver failed: %s" (Printexc.to_string e) in raise (Solver_failure msg) else Dose_algo.Depsolver.Sat(None,Cudf.load_universe []) let check_request ?(explain=true) ~version_map univ req = match Dose_algo.Depsolver.check_request ~explain (to_cudf univ req) with | Dose_algo.Depsolver.Unsat (Some ({Dose_algo.Diagnostic.result = Dose_algo.Diagnostic.Failure _; _} as r)) -> make_conflicts ~version_map univ r | Dose_algo.Depsolver.Sat (_,u) -> Success (remove u dose_dummy_request None) | Dose_algo.Depsolver.Error msg -> let f = dump_cudf_error ~version_map univ req in let msg = Printf.sprintf "Internal solver failed with %s Request saved to %S" msg f in raise (Solver_failure msg) | Dose_algo.Depsolver.Unsat _ -> (* normally when [explain] = false *) conflict_empty ~version_map univ (* Return the universe in which the system has to go *) let get_final_universe ~version_map univ req = let fail msg = let f = dump_cudf_error ~version_map univ req in let msg = Printf.sprintf "External solver failed with %s Request saved to %S" msg f in raise (Solver_failure msg) in match call_external_solver ~version_map univ req with | Dose_algo.Depsolver.Sat (_,u) -> Success (remove u dose_dummy_request None) | Dose_algo.Depsolver.Error "(CRASH) Solution file is empty" -> (* XXX Is this still needed with latest dose? *) Success (Cudf.load_universe []) | Dose_algo.Depsolver.Error str -> fail str | Dose_algo.Depsolver.Unsat r -> let msg = Printf.sprintf "The solver (%s) pretends there is no solution while that's apparently \ false.\n\ This is likely an issue with the solver interface, please try a \ different solver and report if you were using a supported one." (let module Solver = (val OpamSolverConfig.(Lazy.force !r.solver)) in Solver.name) in match r with | Some ({Dose_algo.Diagnostic.result = Dose_algo.Diagnostic.Failure _; _} as r) -> OpamConsole.error "%s" msg; make_conflicts ~version_map univ r | Some {Dose_algo.Diagnostic.result = Dose_algo.Diagnostic.Success _; _} | None -> raise (Solver_failure msg) let diff univ sol = let before = Set.of_list (Cudf.get_packages ~filter:(fun p -> p.Cudf.installed) univ) in let after = Set.of_list (Cudf.get_packages ~filter:(fun p -> p.Cudf.installed) sol) in let open Set.Op in let reinstall = Set.filter need_reinstall after in let install = after -- before ++ reinstall in let remove = before -- after ++ reinstall in install, remove (* Transform a diff from current to final state into a list of actions. At this point, we don't know about the root causes of the actions, they will be computed later. *) let actions_of_diff (install, remove) = let actions = [] in let actions = Set.fold (fun p acc -> `Install p :: acc) install actions in let actions = Set.fold (fun p acc -> `Remove p :: acc) remove actions in actions let resolve ~extern ~version_map universe request = log "resolve request=%a" (slog string_of_request) request; let resp = match check_request ~version_map universe request with | Success _ when extern -> get_final_universe ~version_map universe request | resp -> resp in let cleanup univ = Cudf.remove_package univ opam_invariant_package in let () = match resp with | Success univ -> cleanup univ | Conflicts (univ, _, _) -> cleanup univ in resp let to_actions f universe result = let aux u1 u2 = let diff = diff (f u1) u2 in actions_of_diff diff in map_success (aux universe) result let create_graph filter universe = let pkgs = Cudf.get_packages ~filter universe in let u = Cudf.load_universe pkgs in Graph.of_universe u let find_cycles g = let open ActionGraph in let roots = fold_vertex (fun v acc -> if in_degree g v = 0 then v::acc else acc) g [] in let roots = if roots = [] then fold_vertex (fun v acc -> v::acc) g [] else roots in let rec prefix_find acc v = function | x::_ when x = v -> Some (x::acc) | x::r -> prefix_find (x::acc) v r | [] -> None in let seen = Hashtbl.create 17 in let rec follow v path = match prefix_find [] v path with | Some cycle -> Hashtbl.add seen v (); [cycle@[v]] | None -> if Hashtbl.mem seen v then [] else let path = v::path in Hashtbl.add seen v (); List.fold_left (fun acc s -> follow s path @ acc) [] (succ g v) in List.fold_left (fun cycles root -> follow root [] @ cycles ) [] roots (* Compute the original causes of the actions, from the original set of packages in the user request. In the restricted dependency graph, for each action we find the closest package belonging to the user request and print out the closest neighbour that gets there. This way, if a -> b -> c and the user requests a to be installed, we can print: - install a - install b [required by a] - intall c [required by b] *) let compute_root_causes g requested reinstall = let module StringSet = OpamStd.String.Set in let requested_pkgnames = OpamPackage.Name.Set.fold (fun n s -> StringSet.add (Dose_common.CudfAdd.encode (OpamPackage.Name.to_string n)) s) requested StringSet.empty in let reinstall_pkgnames = OpamPackage.Set.fold (fun nv s -> StringSet.add (Dose_common.CudfAdd.encode (OpamPackage.name_to_string nv)) s) reinstall StringSet.empty in let actions = ActionGraph.fold_vertex (fun a acc -> Map.add (action_contents a) a acc) g Map.empty in let requested_actions = Map.filter (fun pkg _ -> StringSet.mem pkg.Cudf.package requested_pkgnames) actions in let merge_causes (c1,depth1) (c2,depth2) = (* When we found several causes explaining the same action, only keep the most likely one *) if c2 = Unknown || depth1 < depth2 then c1, depth1 else if c1 = Unknown || depth2 < depth1 then c2, depth2 else let (@) = List.fold_left (fun l a -> if List.mem a l then l else a::l) in match c1, c2 with | Required_by a, Required_by b -> Required_by (a @ b), depth1 | Use a, Use b -> Use (a @ b), depth1 | Conflicts_with a, Conflicts_with b -> Conflicts_with (a @ b), depth1 | Requested, a | a, Requested | Unknown, a | a, Unknown | Upstream_changes , a | a, Upstream_changes -> a, depth1 | _, c -> c, depth1 in let direct_cause consequence order cause = (* Investigate the reason of action [consequence], that was possibly triggered by [cause], where the actions are ordered as [consequence] [order] [cause]. *) match consequence, order, cause with | (`Install _ | `Change _), `Before, (`Install p | `Change (_,_,p)) -> (* Prerequisite *) Required_by [p] | `Change _, `After, (`Install p | `Change (_,_,p)) -> (* Change caused by change in dependencies *) Use [p] | `Reinstall _, `After, a -> (* Reinstall caused by action on deps *) Use [action_contents a] | (`Remove _ | `Change _ ), `Before, `Remove p -> (* Removal or change caused by the removal of a dependency *) Use [p] | `Remove _, `Before, (`Install p | `Change (_,_,p) | `Reinstall p) -> (* Removal caused by conflict *) Conflicts_with [p] | (`Install _ | `Change _), `Before, `Reinstall p -> (* New dependency of p? *) Required_by [p] | `Change _, _, _ -> (* The only remaining cause for changes is upstream *) Upstream_changes | (`Install _ | `Remove _), `After, _ -> (* Nothing can cause these actions after itself *) Unknown | (`Install _ | `Reinstall _), `Before, _ -> (* An install or reinstall doesn't cause any other actions on its dependendants *) Unknown | `Build _, _, _ | _, _, `Build _ -> assert false | `Fetch _, _, _ | _, _, `Fetch _ -> assert false (* XXX CHECK *) in let get_causes acc roots = let rec aux seen depth pkgname causes = if depth > 100 then (OpamConsole.error "Internal error computing action causes: sorry, please report."; causes) else let action = Map.find pkgname actions in let seen = Set.add pkgname seen in let propagate causes actions direction = List.fold_left (fun causes act -> let p = action_contents act in if Set.mem p seen then causes else let cause = direct_cause act direction action in if cause = Unknown then causes else try Map.add p (merge_causes (cause,depth) (Map.find p causes)) causes with Not_found -> aux seen (depth + 1) p (Map.add p (cause,depth) causes) ) causes actions in let causes = propagate causes (ActionGraph.pred g action) `Before in let causes = propagate causes (ActionGraph.succ g action) `After in causes in let start = Map.fold (fun k _ acc -> Set.add k acc) roots Set.empty in let acc = Map.union (fun a _ -> a) acc roots in Set.fold (aux start 1) start acc in (* Compute the roots of the action given a condition *) let make_roots causes base_cause f = ActionGraph.fold_vertex (fun act acc -> if Map.mem (action_contents act) causes then acc else if f act then Map.add (action_contents act) (base_cause,0) acc else acc) g Map.empty in let causes = Map.empty in let causes = let roots = if Map.is_empty requested_actions then (* Assume a global upgrade *) make_roots causes Requested (function | `Change (`Up,_,_) -> true | _ -> false) else (Map.map (fun _ -> Requested, 0) requested_actions) in get_causes causes roots in let causes = (* Compute causes for remaining upgrades (maybe these could be removed from the actions altogether since they are unrelated to the request?) *) let roots = make_roots causes Unknown (function | `Change _ as act -> List.for_all (function `Change _ -> false | _ -> true) (ActionGraph.pred g act) | _ -> false) in get_causes causes roots in let causes = (* Compute causes for marked reinstalls *) let roots = make_roots causes Upstream_changes (function | `Reinstall p -> (* need_reinstall p is not available here *) StringSet.mem p.Cudf.package reinstall_pkgnames | _ -> false) in get_causes causes roots in Map.map fst causes (* Compute a full solution from a set of root actions. This means adding all required reinstallations and computing the graph of dependency of required actions *) let atomic_actions ~simple_universe ~complete_universe root_actions = log ~level:2 "graph_of_actions root_actions=%a" (slog string_of_actions) root_actions; let to_remove, to_install = List.fold_left (fun (rm,inst) a -> match a with | `Change (_,p1,p2) -> Set.add p1 rm, Set.add p2 inst | `Install p -> rm, Set.add p inst | `Reinstall p -> Set.add p rm, Set.add p inst | `Remove p -> Set.add p rm, inst) (Set.empty, Set.empty) root_actions in (* transitively add recompilations *) let to_remove, to_install = let packages = Set.union to_remove to_install in let package_graph = let filter p = p.Cudf.installed || Set.mem p packages in Graph.mirror (create_graph filter simple_universe) in Graph.Topo.fold (fun p (rm,inst) -> let actionned p = Set.mem p rm || Set.mem p inst in if not (actionned p) && List.exists actionned (Graph.pred package_graph p) then Set.add p rm, Set.add p inst else rm, inst) package_graph (to_remove, to_install) in let pkggraph set = create_graph (fun p -> Set.mem p set) complete_universe in (* Build the graph of atomic actions: Removals or installs *) let g = ActionGraph.create () in Set.iter (fun p -> ActionGraph.add_vertex g (`Remove p)) to_remove; Set.iter (fun p -> ActionGraph.add_vertex g (`Install (p))) to_install; (* reinstalls and upgrades: remove first *) Set.iter (fun p1 -> try let p2 = Set.find (fun p2 -> p1.Cudf.package = p2.Cudf.package) to_install in ActionGraph.add_edge g (`Remove p1) (`Install (p2)) with Not_found -> ()) to_remove; (* uninstall order *) Graph.iter_edges (fun p1 p2 -> ActionGraph.add_edge g (`Remove p1) (`Remove p2) ) (pkggraph to_remove); (* install order *) Graph.iter_edges (fun p1 p2 -> if Set.mem p1 to_install then let cause = if Set.mem p2 to_install then `Install ( p2) else `Remove p2 in ActionGraph.add_edge g cause (`Install ( p1)) ) (pkggraph (Set.union to_install to_remove)); (* conflicts *) let conflicts_graph = let filter p = Set.mem p to_remove || Set.mem p to_install in Dose_algo.Defaultgraphs.PackageGraph.conflict_graph (Cudf.load_universe (Cudf.get_packages ~filter complete_universe)) in Dose_algo.Defaultgraphs.PackageGraph.UG.iter_edges (fun p1 p2 -> if Set.mem p1 to_remove && Set.mem p2 to_install then ActionGraph.add_edge g (`Remove p1) (`Install ( p2)) else if Set.mem p2 to_remove && Set.mem p1 to_install then ActionGraph.add_edge g (`Remove p2) (`Install ( p1))) conflicts_graph; (* check for cycles *) match find_cycles g with | [] -> g | cycles -> raise (Cyclic_actions cycles) let packages u = Cudf.get_packages u opam-2.1.5/src/solver/opamCudfSolver.ml0000644000175000017500000002332014427463453017103 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2017-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes [@@@ocaml.warning "-33"] open OpamDoseCompat include OpamCudfSolverSig let default_compat_criteria = { crit_default = "-removed,-notuptodate,-changed"; crit_upgrade = "-removed,-notuptodate,-changed"; crit_fixup = "-changed,-notuptodate"; crit_best_effort_prefix = None; } module type ExternalArg = sig val name: string val is_present: bool Lazy.t val command_name: string val command_args: OpamTypes.arg list val default_criteria: criteria_def end let call_external_solver command ~criteria ?timeout (_, universe,_ as cudf) = let solver_in = OpamFilename.of_string (OpamSystem.temp_file "solver-in") in let solver_out = OpamFilename.of_string (OpamSystem.temp_file "solver-out") in try let _ = let oc = OpamFilename.open_out solver_in in Cudf_printer.pp_cudf oc cudf; close_out oc in let () = let cmd = OpamFilter.single_command (fun v -> if not (OpamVariable.Full.is_global v) then None else match OpamVariable.to_string (OpamVariable.Full.variable v) with | "input" -> Some (S (OpamFilename.to_string solver_in)) | "output" -> Some (S (OpamFilename.to_string solver_out)) | "criteria" -> Some (S criteria) | "timeout" -> Some (S (string_of_float (OpamStd.Option.default 0. timeout))) | _ -> None) command in OpamSystem.command ~verbose:(OpamCoreConfig.(abs !r.debug_level >= 2)) cmd in OpamFilename.remove solver_in; if not (OpamFilename.exists solver_out) then raise (Dose_common.CudfSolver.Error "no output") else if (let ic = OpamFilename.open_in solver_out in try let i = input_line ic in close_in ic; i = "FAIL" with End_of_file -> close_in ic; false) then raise Dose_common.CudfSolver.Unsat else let r = Cudf_parser.load_solution_from_file (OpamFilename.to_string solver_out) universe in OpamFilename.remove solver_out; r with e -> OpamStd.Exn.finalise e @@ fun () -> OpamFilename.remove solver_in; OpamFilename.remove solver_out module External (E: ExternalArg) : S = struct let name = E.name let ext = ref None let is_present () = Lazy.force E.is_present let command_name = Some E.command_name let default_criteria = E.default_criteria let call = call_external_solver ((CString E.command_name, None) :: E.command_args) end module Aspcud_def = struct let name = "aspcud" let command_name = "aspcud" let is_present = lazy ( match OpamSystem.resolve_command command_name with | None -> false | Some cmd -> try match OpamSystem.read_command_output ~verbose:false ~allow_stdin:false [cmd; "-v"] with | [] -> false | s::_ -> match OpamStd.String.split s ' ' with | "aspcud"::_::v::_ when OpamVersionCompare.compare v "1.9" >= 0 -> OpamConsole.log "SOLVER" "Solver is aspcud >= 1.9: using latest version criteria"; true | _ -> false with OpamSystem.Process_error _ -> false ) let command_args = [ CIdent "input", None; CIdent "output", None; CIdent "criteria", None ] let default_criteria = { crit_default = "-count(removed),\ -sum(solution,avoid-version),\ -sum(request,version-lag),\ -count(down),\ -sum(solution,version-lag),\ -count(changed),\ -sum(solution,missing-depexts)"; crit_upgrade = "-count(down),\ -count(removed),\ -sum(solution,avoid-version),\ -sum(solution,version-lag),\ -sum(solution,missing-depexts),\ -count(new)"; crit_fixup = "-count(changed),\ -count[avoid-version:,true],\ -notuptodate(solution),\ -sum(solution,version-lag),\ -count[missing-depexts:,true]"; crit_best_effort_prefix = Some "+sum(solution,opam-query),"; } end module Aspcud = External(Aspcud_def) module Aspcud_old_def = struct let name = "aspcud-old" let command_name = Aspcud_def.command_name let is_present = lazy (OpamSystem.resolve_command command_name <> None) let command_args = Aspcud_def.command_args let default_criteria = default_compat_criteria end module Aspcud_old = External(Aspcud_old_def) module Mccs_def = struct let name = "mccs" let command_name = "mccs" let is_present = lazy (OpamSystem.resolve_command command_name <> None) let command_args = [ CString "-i", None; CIdent "input", None; CString "-o", None; CIdent "output", None; CString "-lexagregate[%{criteria}%]", None; ] let default_criteria = { crit_default = "-removed,\ -count[avoid-version:,true],\ -count[version-lag:,true],\ -changed,\ -count[version-lag:,false],\ -count[missing-depexts:,true],\ -new"; crit_upgrade = "-removed,\ -count[avoid-version:,true],\ -count[version-lag:,false],\ -count[missing-depexts:,true],\ -new"; crit_fixup = "-changed,\ -count[avoid-version:,true],\ -count[version-lag:,false],\ -count[missing-depexts:,true]"; crit_best_effort_prefix = Some "+count[opam-query:,false],"; } end module Mccs = External(Mccs_def) module Packup_def = struct let name = "packup" let command_name = "packup" let is_present = lazy (OpamSystem.resolve_command command_name <> None) let command_args = [ CIdent "input", None; CIdent "output", None; CString "-u", None; CIdent "criteria", None; ] let default_criteria = default_compat_criteria end module Packup = External(Packup_def) let make_custom_solver name args criteria = (module (External (struct let command_name = name let name = name ^ "-custom" let is_present = lazy true let command_args = args let default_criteria = criteria end)) : S) let default_solver_selection = OpamBuiltinMccs.all_backends @ [ (module OpamBuiltinZ3: S); (module OpamBuiltin0install: S); (module Aspcud: S); (module Mccs: S); (module Aspcud_old: S); (module Packup: S); ] let extract_solver_param name = if OpamStd.String.ends_with ~suffix:")" name then match OpamStd.String.cut_at name '(' with | Some (xname, ext2) -> xname, Some (OpamStd.String.remove_suffix ~suffix:")" ext2) | None -> name, None else name, None let custom_solver cmd = match cmd with | [ CIdent name, _ ] | [ CString name, _ ] -> (try let xname, ext = extract_solver_param name in List.find (fun (module S: S) -> let n, _ = extract_solver_param S.name in (n = xname || n = Filename.basename xname || S.command_name = Some name) && (if ext <> None then S.ext := ext; S.is_present ())) default_solver_selection with Not_found -> OpamConsole.error_and_exit `Configuration_error "No installed solver matching the selected '%s' found" name) | ((CIdent name | CString name), _) :: args -> let criteria = try let corresponding_module = List.find (fun (module S: S) -> S.command_name = Some (Filename.basename name) && S.is_present ()) default_solver_selection in let module S = (val corresponding_module) in S.default_criteria with Not_found -> default_compat_criteria in make_custom_solver name args criteria | _ -> OpamConsole.error_and_exit `Configuration_error "Invalid custom solver command specified." let solver_of_string s = let args = OpamStd.String.split s ' ' in (custom_solver (List.map (fun a -> OpamTypes.CString a, None) args)) let has_builtin_solver () = List.exists (fun (module S: S) -> S.command_name = None && S.is_present ()) default_solver_selection let get_solver ?internal l = try List.find (fun (module S: S) -> (internal = None || internal = Some (S.command_name = None)) && S.is_present ()) l with Not_found -> OpamConsole.error_and_exit `Configuration_error "No available solver found. Make sure your solver configuration is \ correct. %s" (if has_builtin_solver () then "You can enforce use of the built-in solver with \ `--use-internal-solver'." else "This opam has been compiled without a built-in solver, so you need \ to install and configure an external one. See \ http://opam.ocaml.org/doc/Install.html#ExternalSolvers for details.") let get_name (module S: S) = let name, ext0 = extract_solver_param S.name in match !S.ext, ext0 with | Some e, _ | None, Some e -> Printf.sprintf "%s(%s)" name e | None, None -> name opam-2.1.5/src/solver/opamActionGraph.mli0000644000175000017500000000576414427463453017413 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2014-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Handles graphs of actions (package changes), based on ocamlgraph *) open OpamTypes module type ACTION = sig type package module Pkg: GenericPackage with type t = package include OpamParallel.VERTEX with type t = package action val to_string: [< t ] -> string val to_aligned_strings: ?append:(package -> string) -> [< t ] list -> string list list module Set: OpamStd.SET with type elt = package action module Map: OpamStd.MAP with type key = package action end module MakeAction (P: GenericPackage) : ACTION with type package = P.t and type t = P.t OpamTypes.action module type SIG = sig type package include OpamParallel.GRAPH with type V.t = package OpamTypes.action (** Reduces a graph of atomic or concrete actions (only removals, installs and builds) by turning removal+install to reinstalls or up/down-grades, best for display. Dependency ordering won't be as accurate though, as there is no proper ordering of (reinstall a, reinstall b) if b depends on a. The resulting graph contains at most one action per package name. There is no guarantee however that the resulting graph is acyclic. *) val reduce: t -> t (** Expand install actions, adding a build action preceding them. The argument [noop_remove] is a function that should return `true` for package where the `remove` action is known not to modify the filesystem (such as `conf-*` package). The argument [sources_needed] is a function that should return `true` for packages that require fetching sources (packages that do not require it are typically up-to-date pins or "in-place" builds). *) val explicit: ?noop_remove:(package -> bool) -> sources_needed:(package -> bool) -> t -> t (** Folds on all recursive successors of the given action, including itself, depth-first. *) val fold_descendants: (V.t -> 'a -> 'a) -> 'a -> t -> V.t -> 'a end module Make (A: ACTION) : SIG with type package = A.package (** Some messages that may be used for displaying actions. Single utf8 chars if the corresponding option is set, otherwise words. *) val action_strings: ?utf8:bool -> 'a action -> string (** Colorise string according to the action *) val action_color: 'a action -> string -> string opam-2.1.5/src/solver/opamBuiltinMccs.mli0000644000175000017500000000135214427463453017415 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2017-2018 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) val all_backends: (module OpamCudfSolverSig.S) list opam-2.1.5/src/solver/opamDoseCompat.ml.50000644000175000017500000000006414427463453017230 0ustar stephstephmodule Dose_algo = Algo module Dose_common = Common opam-2.1.5/src/solver/opamBuiltinZ3.mli0000644000175000017500000000003414427463453017020 0ustar stephstephinclude OpamCudfSolverSig.S opam-2.1.5/src/client/0002755000175000017500000000000014427463453013566 5ustar stephstephopam-2.1.5/src/client/opamSwitchCommand.mli0000644000175000017500000000765614427463453017722 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Functions handling the "opam switch" subcommand *) open OpamTypes open OpamStateTypes (** Creates and configures a new switch. The given [global_state] is unlocked once done. [update_config] sets the switch as current globally, unless it is external. [post] can be used to run guarded operations after the switch creation (cleanup will be proposed to the user if they fail). You probably want to call [install_compiler] there. *) val create: rw global_state -> rt:'a repos_state -> ?synopsis:string -> ?repos:repository_name list -> update_config:bool -> invariant:formula -> switch -> (rw switch_state -> 'ret * rw switch_state) -> 'ret * rw switch_state (** Used to initially install a compiler's base packages, according to its invariant. [ask] triggers prompting the user as for normal installs; defaults to [false]. *) val install_compiler: ?additional_installs:atom list -> ?deps_only:bool -> ?ask:bool -> rw switch_state -> rw switch_state (** Import a file which contains the packages to install. *) val import: rw switch_state -> OpamFile.SwitchExport.t OpamFile.t option -> rw switch_state (** Export a file which contains the installed packages. If [full] is specified and true, export metadata of all installed packages (excluding overlay files) as part of the export. The export will be extended with a map of all extra-files. If [freeze] is specified and true, VCS urls will be frozen to the specific commit ID. If [None] is provided as file argument, the export is done to stdout. *) val export: 'a repos_state -> ?freeze:bool -> ?full:bool -> ?switch:switch -> OpamFile.SwitchExport.t OpamFile.t option -> unit (** Remove the given compiler switch, and returns the updated state (unchanged in case [confirm] is [true] and the user didn't confirm) *) val remove: rw global_state -> ?confirm:bool -> switch -> rw global_state (** Changes the currently active switch *) val switch: 'a lock -> rw global_state -> switch -> unit (** Reinstall the given compiler switch. *) val reinstall: rw switch_state -> rw switch_state (** Updates the switch invariant and the associated config files, and writes the config file unless [show] or [dry_run] are activated globally. Low-level function, see [set_invariant] for the user-facing function. *) val set_invariant_raw: rw switch_state -> formula -> rw switch_state (** Sets the packages configured as the current switch compiler base, after some checks and messages. *) val set_invariant: ?force:bool -> rw switch_state -> formula -> rw switch_state (** Display the current compiler switch. *) val show: unit -> unit (** List all the available compiler switches. *) val list: 'a global_state -> print_short:bool -> unit (** Returns all available compiler packages from a repo state *) val get_compiler_packages: ?repos:repository_name list -> 'a repos_state -> package_set (** Guess a real compiler spec from a list of strings, which may refer to packages with optional version constraints, or just versions. This uses some heuristics. *) val guess_compiler_invariant: ?repos:repository_name list -> 'a repos_state -> string list -> OpamFormula.t opam-2.1.5/src/client/opamAuxCommands.mli0000644000175000017500000001251114427463453017363 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2017-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Some command helpers, and auxiliary opam management functions used by the CLI *) open OpamTypes open OpamStateTypes (** Gets the file changes done in the installation of the given packages in the given switch, and copies the corresponding files to the same relative paths below the given prefix ; files that are not current according to the recorded package changes print warnings and aren't copied. *) val copy_files_to_destdir: 'a switch_state -> dirname -> package_set -> unit (** Removes all files that may have been installed by [copy_files_to_destdir]; it's more aggressive than [OpamDirTrack.revert] and doesn't check if the files are current. *) val remove_files_from_destdir: 'a switch_state -> dirname -> package_set -> unit (** If the URL points to a local, version-controlled directory, qualify it by suffixing `#current-branch` if no branch/tag/hash was specified. *) val url_with_local_branch: url -> url (** From an in-source opam file, return the corresponding package name if it can be found, and the corresponding source directory *) val name_and_dir_of_opam_file: filename -> name option * dirname (** From a directory, retrieve its opam files and returns packages name, opam file and subpath option *) val opams_of_dir: ?recurse:bool -> ?subpath:string -> OpamFilename.Dir.t -> (name * OpamFile.OPAM.t OpamFile.t * string option) list (** Like [opam_of_dirs], but changes the pinning_url if needed. If given [url] is local dir with vcs backend, and opam files not versioned, its pinning url is changed to rsync path-pin. If [ame_kind the_new_url] returns true, package information (name, opam file, new_url, subpath) are added to the returned list, otherwise it is discarded. *) val opams_of_dir_w_target: ?recurse:bool -> ?subpath:string -> ?same_kind:(OpamUrl.t -> bool) -> OpamUrl.t -> OpamFilename.Dir.t -> (name * OpamFile.OPAM.t OpamFile.t * OpamUrl.t * string option) list (** Resolves the opam files and directories in the list to package name and location, and returns the corresponding pinnings and atoms. May fail and exit if package names for provided [`Filename] could not be inferred, or if the same package name appears multiple times. *) val resolve_locals: ?quiet:bool -> ?recurse:bool -> ?subpath:string -> [ `Atom of atom | `Filename of filename | `Dirname of dirname ] list -> (name * OpamUrl.t * string option * OpamFile.OPAM.t OpamFile.t) list * atom list (** Resolves the opam files and directories in the list to package name and location, according to what is currently pinned, and returns the corresponding list of atoms. Prints warnings for directories where nothing is pinned, or opam files corresponding to no pinned package. *) val resolve_locals_pinned: 'a switch_state -> ?recurse:bool -> ?subpath:string -> [ `Atom of atom | `Dirname of dirname ] list -> atom list (** Resolves the opam files in the list to package name and location, pins the corresponding packages accordingly if necessary, otherwise updates them, and returns the resolved atom list. With [simulate], don't do the pinnings but return the switch state with the package definitions that would have been obtained if pinning. Also synchronises the specified directories, that is, unpins any package pinned there but not current (no more corresponding opam file). This also handles [pin-depends:] of the local packages. That part is done even if [simulate] is [true]. *) val autopin: rw switch_state -> ?simulate:bool -> ?quiet:bool -> ?recurse:bool -> ?subpath:string -> [ `Atom of atom | `Filename of filename | `Dirname of dirname ] list -> rw switch_state * atom list (** The read-only version of [autopin ~simulate:true]: this doesn't require a write-locked switch, and doesn't update the local packages. [for_view] will result in the switch state containing more accurate information to be displayed to the user, but should never be flushed to disk because ; without that option, the state can safely be worked with and will just contain the proper package definitions *) val simulate_autopin: 'a switch_state -> ?quiet:bool -> ?for_view:bool -> ?recurse:bool -> ?subpath:string -> [ `Atom of atom | `Filename of filename | `Dirname of dirname ] list -> 'a switch_state * atom list (* Check sandboxing script call. If it errors or unattended output, disable sandboxing by removing [OpamInitDefaults.sandbox_wrappers] commands in config file. Only one script is checked (init script default one), and tested on an `echo SUCCESS' call. *) val check_and_revert_sandboxing: OpamPath.t -> OpamFile.Config.t -> OpamFile.Config.t opam-2.1.5/src/client/opamMain.mli0000644000175000017500000000144414427463453016033 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2017 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** opam main CLI entry point *) opam-2.1.5/src/client/opamAdminCheck.mli0000644000175000017500000000335014427463453017133 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2017-2018 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes (** Analyses a given package universe, and returns [uninstallable_roots,uninstallable]. The first is a subset of the second, where internal dependents have been removed. *) val installability_check: universe -> package_set * package_set (** Analyses a universe for dependency cycles. Returns the set of packages involved, and the cycles (reduced to formula lists) *) val cycle_check: universe -> package_set * formula list list (** Runs checks on the repository at the given repository. Returns [all_packages], [uninstallable_roots], [uninstallable], [cycle_packages], [obsolete_packages]. If the corresponding option was disabled, the returned sets are empty. *) val check: quiet:bool -> installability:bool -> cycles:bool -> obsolete:bool -> ignore_test:bool -> dirname -> package_set * package_set * package_set * package_set * package_set (** Returns a subset of "obsolete" packages, i.e. packages for which a strictly better version exists *) val get_obsolete: universe -> OpamFile.OPAM.t package_map -> package_set opam-2.1.5/src/client/opamSolution.mli0000644000175000017500000001064014427463453016761 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Interface with the solver, processing of full solutions through actions *) open OpamTypes open OpamStateTypes (** Resolve an user request *) val resolve: 'a switch_state -> user_action -> orphans:package_set -> ?reinstall:package_set -> requested:name_set -> atom request -> (OpamSolver.solution, OpamCudf.conflict) result (** Apply a solution returned by the solver. If [ask] is not specified, prompts the user whenever the solution isn't obvious from the request. [add_roots] defaults to the set of newly installed packages that are part of [requested]. If [force_remove] is true, modified files are not kept.*) val apply: ?ask:bool -> rw switch_state -> requested:OpamPackage.Name.Set.t -> ?add_roots:OpamPackage.Name.Set.t -> ?assume_built:bool -> ?download_only:bool -> ?force_remove:bool -> OpamSolver.solution -> rw switch_state * solution_result (** Call the solver to get a solution and then call [apply]. If [ask] is not specified, prompts the user whenever the solution isn't obvious from the request. [add_roots] defaults to the set of newly installed packages that are part of [requested]. If [force_remove] is true, modified files are not kept. *) val resolve_and_apply: ?ask:bool -> rw switch_state -> user_action -> orphans:package_set -> ?reinstall:package_set -> requested:OpamPackage.Name.Set.t -> ?add_roots:OpamPackage.Name.Set.t -> ?assume_built:bool -> ?download_only:bool -> ?force_remove:bool -> atom request -> rw switch_state * (solution_result, OpamCudf.conflict) result (** Raise an error if no solution is found or in case of error. Unless [quiet] is set, print a message indicating that nothing was done on an empty solution. *) val check_solution: ?quiet:bool -> 'a switch_state -> (solution_result, 'conflict) result -> unit (* Install external dependencies of the given package set, according the depext configuration. If [confirm] is false, install commands are directly launched, without asking user (used by the `--depext-only` option). If [force_depext] is true, it overrides [OpamFile.Config.depext] value. *) val install_depexts: ?force_depext:bool -> ?confirm:bool -> rw switch_state -> package_set -> rw switch_state (** {2 Atoms} *) (** Return an atom with a strict version constraint *) val eq_atom: name -> version -> atom (** Return a simple atom, with no version constraint, from a package*) val atom_of_package: package -> atom (** Returns an atom with a strict version constraint from a package *) val eq_atom_of_package: package -> atom (** Return a list of simple atoms (ie. with no version constraints) from a set of packages *) val atoms_of_packages: package_set -> atom list (** Return a list of constrained atoms from a set of packages *) val eq_atoms_of_packages: package_set -> atom list (** Checks that the atoms can possibly be verified (individually) in a package set. Displays an error and exits otherwise. [permissive] just changes the error message. *) val check_availability: ?permissive: bool -> 'a switch_state -> OpamPackage.Set.t -> atom list -> unit (** Matches package names to their existing counterparts, up to capitalisation. If no match exists, returns the name unchanged. *) val fuzzy_name: 'a switch_state -> name -> name (** Takes a "raw" list of atoms (from the user), and match it to existing packages. Match packages with the wrong capitalisation, and raises errors on non-existing packages, and unavailable ones unless [permissive] is set. Exits with a message on error. *) val sanitize_atom_list: ?permissive: bool -> 'a switch_state -> atom list -> atom list (** {2 Stats} *) val sum: stats -> int opam-2.1.5/src/client/opamRepositoryCommand.ml0000644000175000017500000002540314427463453020455 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamStateTypes open OpamStd.Op let log fmt = OpamConsole.log "REPOSITORY" fmt let update_global_selection gt update_fun = let repos = OpamFile.Config.repositories gt.config in let config = OpamFile.Config.with_repositories (update_fun repos) gt.config in let gt = { gt with config } in OpamGlobalState.write gt; gt let update_selection gt ~global ~switches update_fun = List.iter (OpamSwitchState.update_repositories gt update_fun) switches; if global then (* ensure all unselected switches aren't modified by changing the default *) (List.iter (fun sw -> if not (List.mem sw switches) then OpamSwitchState.update_repositories gt (fun r -> r) sw) (OpamFile.Config.installed_switches gt.config); let (), gt = OpamGlobalState.with_write_lock gt @@ fun gt -> (), update_global_selection gt update_fun in gt) else gt let update_repos_config rt repositories = (* Remove cached opam files for changed or removed repos *) let repo_opams = OpamRepositoryName.Map.filter (fun name _ -> OpamRepositoryName.Map.find_opt name rt.repositories = OpamRepositoryName.Map.find_opt name repositories) rt.repo_opams in let rt = { rt with repositories; repo_opams } in OpamRepositoryState.Cache.remove (); OpamRepositoryState.write_config rt; rt let add rt name url trust_anchors = log "repository-add"; let root = rt.repos_global.root in let repo_exists = OpamStd.Option.of_Not_found (OpamRepositoryName.Map.find name) rt.repositories in match repo_exists with | Some r when r.repo_url = url && (trust_anchors = r.repo_trust || trust_anchors = None) -> rt | Some r -> OpamConsole.error_and_exit `Bad_arguments "Repository %s is already set up%s. To change that, use 'opam \ repository set-url %s %s'." (OpamRepositoryName.to_string name) (if r.repo_url <> url then " and points to "^OpamUrl.to_string r.repo_url else match r.repo_trust with | None -> " without trust anchors" | Some ta -> Printf.sprintf " with trust anchors %s and quorum %d" (OpamStd.List.concat_map ~nil:"()" "," String.escaped ta.fingerprints) ta.quorum) (OpamRepositoryName.to_string name) (OpamUrl.to_string url) | None -> let repo = { repo_name = name; repo_url = url; repo_trust = trust_anchors; } in if OpamFilename.exists_dir (OpamRepositoryPath.root root name) || OpamFilename.exists (OpamRepositoryPath.tar root name) then OpamConsole.error_and_exit `Bad_arguments "Invalid repository name, %s exists" (OpamFilename.Dir.to_string (OpamRepositoryPath.root root name)); if url.OpamUrl.backend = `rsync && OpamUrl.local_dir url <> None && OpamUrl.local_dir (OpamRepositoryPath.Remote.packages_url url) = None && not (OpamConsole.confirm "%S doesn't contain a \"packages\" directory.\n\ Is it really the directory of your repo?" (OpamUrl.to_string url)) then OpamStd.Sys.exit_because `Aborted; update_repos_config rt (OpamRepositoryName.Map.add name repo rt.repositories) let remove rt name = log "repository-remove"; let rt = update_repos_config rt (OpamRepositoryName.Map.remove name rt.repositories) in OpamRepositoryState.Cache.save rt; OpamFilename.rmdir (OpamRepositoryPath.root rt.repos_global.root name); OpamFilename.remove (OpamRepositoryPath.tar rt.repos_global.root name); rt let set_url rt name url trust_anchors = log "repository-set-url"; let repo = try OpamRepositoryName.Map.find name rt.repositories with Not_found -> OpamConsole.error_and_exit `Not_found "No repository %s found" (OpamRepositoryName.to_string name); in OpamFilename.cleandir (OpamRepositoryPath.root rt.repos_global.root name); OpamFilename.remove (OpamRepositoryPath.tar rt.repos_global.root name); let repo = { repo with repo_url = url; repo_trust = trust_anchors; } in OpamRepositoryState.remove_from_repos_tmp rt name; update_repos_config rt (OpamRepositoryName.Map.add name repo rt.repositories) let print_selection rt ~short repos_list = if short then List.iter (fun r -> OpamConsole.msg "%s\n" (OpamRepositoryName.to_string r)) repos_list else List.mapi (fun i name -> [ Printf.sprintf "%2d" (i+1); OpamRepositoryName.to_string name |> OpamConsole.colorise `bold; try let r = OpamRepositoryName.Map.find name rt.repositories in if r.repo_url = OpamUrl.empty then "-" else OpamUrl.to_string r.repo_url |> OpamConsole.colorise `underline with Not_found -> "not found" |> OpamConsole.colorise `red ]) repos_list |> OpamStd.Format.align_table |> OpamConsole.print_table stdout ~sep:" " let switch_repos rt sw = let switch_config = OpamStateConfig.Switch.safe_load ~lock_kind:`Lock_read rt.repos_global sw in match switch_config.OpamFile.Switch_config.repos with | None -> OpamGlobalState.repos_list rt.repos_global | Some rl -> rl let list rt ~global ~switches ~short = if global then (let repos = OpamGlobalState.repos_list rt.repos_global in if not short then OpamConsole.header_msg "Default repository configuration (for newly created switches)"; print_selection rt ~short repos); List.iter (fun sw -> if not short then OpamConsole.header_msg "Repository configuration for switch %s" (OpamSwitch.to_string sw); print_selection rt ~short (switch_repos rt sw)) switches let list_all rt ~short = log "repository-list"; if short then OpamRepositoryName.Map.iter (fun r _ -> OpamConsole.msg "%s\n" (OpamRepositoryName.to_string r)) rt.repositories else let repos_switches, _ = let repos = OpamGlobalState.repos_list rt.repos_global in let n_repos = List.length repos in List.fold_left (fun (acc,i) repo -> OpamRepositoryName.Map.add repo [None, (i, n_repos)] acc, i + 1) (OpamRepositoryName.Map.empty, 1) repos in let repos_switches = List.fold_left (fun acc sw -> let repos = switch_repos rt sw in let n_repos = List.length repos in let acc,_ = List.fold_left (fun (acc,i) repo -> OpamRepositoryName.Map.update repo (fun s -> (Some sw, (i, n_repos))::s) [] acc, i + 1) (acc,1) repos in acc) repos_switches (OpamFile.Config.installed_switches rt.repos_global.config) in let cols = List.map (OpamConsole.colorise `blue) ["# Repository"; "# Url"; "# Switches(rank)"] in let lines = OpamRepositoryName.Map.mapi (fun name repo -> [ OpamRepositoryName.to_string name |> OpamConsole.colorise `bold; OpamUrl.to_string repo.repo_url; OpamStd.List.concat_map " " (fun (sw,(i, n)) -> OpamStd.Option.to_string ~none:"" OpamSwitch.to_string sw ^ (if n = 1 then "" else Printf.sprintf "(%d/%d)" i n |> OpamConsole.colorise `yellow)) (List.rev (try OpamRepositoryName.Map.find name repos_switches with Not_found -> [])); ]) rt.repositories in cols :: OpamRepositoryName.Map.values lines |> OpamStd.Format.align_table |> OpamConsole.print_table stdout ~sep:" " let update_with_auto_upgrade rt repo_names = let repos = List.map (OpamRepositoryState.get_repo rt) repo_names in let failed, rt = OpamUpdate.repositories rt repos in let failed = List.map (fun r -> r.repo_name) failed in if OpamFormatConfig.(!r.skip_version_checks) || OpamClientConfig.(!r.no_auto_upgrade) then failed, rt else let rt, done_upgrade = List.fold_left (fun (rt, done_upgrade) r -> if List.mem r.repo_name failed then rt, done_upgrade else let def = OpamRepositoryName.Map.find r.repo_name rt.repos_definitions in let need_upgrade = match OpamFile.Repo.opam_version def with | None -> OpamConsole.note "Repository at %s doesn't define its version, assuming it's 1.2." (OpamUrl.to_string r.repo_url); true | Some v when OpamVersion.compare v OpamAdminRepoUpgrade.upgradeto_version < 0 -> true | _ -> false in if need_upgrade then (if not done_upgrade then (OpamConsole.header_msg "Upgrading repositories from older opam format"; OpamRepositoryState.Cache.remove ()); OpamConsole.msg "Upgrading repository \"%s\"...\n" (OpamRepositoryName.to_string r.repo_name); let open OpamProcess.Job.Op in let repo_root = OpamRepositoryState.get_repo_root rt r in OpamAdminRepoUpgrade.do_upgrade repo_root; OpamProcess.Job.run (OpamFilename.make_tar_gz_job (OpamRepositoryPath.tar rt.repos_global.root r.repo_name) repo_root @@| function | Some e -> Printf.ksprintf failwith "Failed to regenerate local repository archive: %s" (Printexc.to_string e) | None -> ()); let def = OpamFile.Repo.safe_read (OpamRepositoryPath.repo repo_root) |> OpamFile.Repo.with_root_url r.repo_url in let opams = OpamRepositoryState.load_opams_from_dir r.repo_name repo_root in let rt = { rt with repos_definitions = OpamRepositoryName.Map.add r.repo_name def rt.repos_definitions; repo_opams = OpamRepositoryName.Map.add r.repo_name opams rt.repo_opams; } in rt, true) else rt, done_upgrade) (rt, false) repos in if done_upgrade then OpamRepositoryState.Cache.save rt; failed, rt opam-2.1.5/src/client/opamAdminCommand.mli0000644000175000017500000000165014427463453017475 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2017 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) val admin_command_doc: string type command = unit Cmdliner.Term.t * Cmdliner.Term.info val get_cmdliner_parser: OpamCLIVersion.Sourced.t -> command * command list opam-2.1.5/src/client/dune0000644000175000017500000000556314427463453014453 0ustar stephsteph(library (name opam_client) (public_name opam-client) (synopsis "OCaml Package Manager client and CLI library") (modules (:standard \ opamMain get_git_version)) (libraries opam-state opam-solver opam-repository re base64 cmdliner (select opamBase64Compat.ml from (!dose3.opam -> opamBase64Compat.ml.6) (dose3.dose_src_ext_vendor -> opamBase64Compat.ml.6) ( -> opamBase64Compat.ml.5)) (select opamBase64Compat.mli from (!dose3.opam -> opamBase64Compat.mli.6) (dose3.dose_src_ext_vendor -> opamBase64Compat.mli.6) ( -> opamBase64Compat.mli.5))) (flags (:standard (:include ../ocaml-flags-standard.sexp) (:include ../ocaml-flags-configure.sexp) (:include ../ocaml-context-flags.sexp))) (wrapped false)) (rule (with-stdout-to opamBase64Compat.ml.6 (run echo ""))) (rule (with-stdout-to opamBase64Compat.mli.6 (run echo ""))) (executable (name opamMain) ; This name needs to be updated in doc/man/dune if changed (public_name opam) (package opam) (modules opamMain) (flags (:standard (:include ../ocaml-flags-standard.sexp) (:include ../ocaml-flags-configure.sexp) (:include ../ocaml-context-flags.sexp) (:include linking.sexp))) (libraries opam-client (select link-opam-manifest from (opam-client.manifest -> pull-manifest) ( -> dummy) ))) (rule (with-stdout-to dummy (echo ""))) (rule (targets pull-manifest) (deps (:obj ../manifest/opam-manifest.o)) (action (progn (system "cp %{obj} opam-manifest.o 2> %{null} || copy %{obj} opam-manifest.o") (with-stdout-to %{targets} (echo ""))))) (rule (targets git-sha) (deps (universe)) (action (ignore-stderr (with-stdout-to %{targets} (system "git rev-parse --quiet --verify HEAD || echo ."))))) (rule (targets git-describe) (deps (universe)) (action (ignore-stderr (with-stdout-to %{targets} (system "git describe --exact HEAD || echo [dev]"))))) (rule (targets no-git-version) (mode fallback) (action (copy git-sha %{targets}))) (rule (with-stdout-to get_git_version.ml (echo "print_string @@ \ let v = \"%{read-lines:no-git-version}\" in \ let w = \"%{read-lines:git-describe}\" in \ if v = \"\" || v = \".\" || w <> \"[dev]\" then \ \"let version = None\" \ else \ \"let version = Some \\\"\" ^ v ^ \"\\\"\""))) (rule (with-stdout-to opamGitVersion.ml (run ocaml %{dep:get_git_version.ml}))) (rule (targets linking.sexp) (mode fallback) (action (with-stdout-to %{targets} (echo "()")))) opam-2.1.5/src/client/opamBase64Compat.mli.50000644000175000017500000000023014427463453017472 0ustar stephstephmodule Base64 : sig val decode_exn : ?alphabet:string -> string -> string val encode_string : ?pad:bool -> ?alphabet:string -> string -> string end opam-2.1.5/src/client/opamClientConfig.ml0000644000175000017500000002117214427463453017342 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2015-2020 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) module E = struct type OpamStd.Config.E.t += | ASSUMEDEPEXTS of bool option | AUTOREMOVE of bool option | CLI of string option | DROPWORKINGDIR of bool option | EDITOR of string option | FAKE of bool option | IGNOREPINDEPENDS of bool option | INPLACEBUILD of bool option | JSON of string option | KEEPBUILDDIR of bool option | NOAGGREGATE of bool option | NOAUTOUPGRADE of bool option | NOSELFUPGRADE of string option | PINKINDAUTO of bool option | REUSEBUILDDIR of bool option | ROOTISOK of bool option | SHOW of bool option | SKIPUPDATE of bool option | STATS of bool option | WORKINGDIR of bool option open OpamStd.Config.E let assumedepexts = value (function ASSUMEDEPEXTS b -> b | _ -> None) let autoremove = value (function AUTOREMOVE b -> b | _ -> None) let cli = value (function CLI s -> s | _ -> None) let dropworkingdir = value (function DROPWORKINGDIR b -> b | _ -> None) let editor = value (function EDITOR s -> s | _ -> None) let fake = value (function FAKE b -> b | _ -> None) let ignorepindepends = value (function IGNOREPINDEPENDS b -> b | _ -> None) let inplacebuild = value (function INPLACEBUILD b -> b | _ -> None) let json = value (function JSON s -> s | _ -> None) let keepbuilddir = value (function KEEPBUILDDIR b -> b | _ -> None) let noaggregate = value (function NOAGGREGATE b -> b | _ -> None) let noautoupgrade = value (function NOAUTOUPGRADE b -> b | _ -> None) let noselfupgrade = value (function NOSELFUPGRADE s -> s | _ -> None) let pinkindauto = value (function PINKINDAUTO b -> b | _ -> None) let reusebuilddir = value (function REUSEBUILDDIR b -> b | _ -> None) let rootisok = value (function ROOTISOK b -> b | _ -> None) let show = value (function SHOW b -> b | _ -> None) let skipupdate = value (function SKIPUPDATE b -> b | _ -> None) let stats = value (function STATS b -> b | _ -> None) let workingdir = value (function WORKINGDIR b -> b | _ -> None) end type t = { print_stats: bool; pin_kind_auto: bool; autoremove: bool; editor: string; keep_build_dir: bool; reuse_build_dir: bool; inplace_build: bool; working_dir: bool; drop_working_dir: bool; ignore_pin_depends: bool; show: bool; fake: bool; skip_dev_update: bool; json_out: string option; root_is_ok: bool; no_auto_upgrade: bool; assume_depexts: bool; cli: OpamCLIVersion.t; scrubbed_environment_variables: string list; } let default = { print_stats = false; pin_kind_auto = true; autoremove = false; editor = "nano"; keep_build_dir = false; reuse_build_dir = false; inplace_build = false; working_dir = false; drop_working_dir = false; ignore_pin_depends = false; show = false; fake = false; skip_dev_update = false; json_out = None; root_is_ok = false; no_auto_upgrade = false; assume_depexts = false; cli = OpamCLIVersion.current; scrubbed_environment_variables = []; } type 'a options_fun = ?print_stats:bool -> ?pin_kind_auto:bool -> ?autoremove:bool -> ?editor:string -> ?keep_build_dir:bool -> ?reuse_build_dir:bool -> ?inplace_build:bool -> ?working_dir:bool -> ?drop_working_dir:bool -> ?ignore_pin_depends:bool -> ?show:bool -> ?fake:bool -> ?skip_dev_update:bool -> ?json_out:string option -> ?root_is_ok:bool -> ?no_auto_upgrade:bool -> ?assume_depexts:bool -> ?cli:OpamCLIVersion.t -> ?scrubbed_environment_variables:string list -> 'a let setk k t ?print_stats ?pin_kind_auto ?autoremove ?editor ?keep_build_dir ?reuse_build_dir ?inplace_build ?working_dir ?drop_working_dir ?ignore_pin_depends ?show ?fake ?skip_dev_update ?json_out ?root_is_ok ?no_auto_upgrade ?assume_depexts ?cli ?scrubbed_environment_variables = let (+) x opt = match opt with Some x -> x | None -> x in k { print_stats = t.print_stats + print_stats; pin_kind_auto = t.pin_kind_auto + pin_kind_auto; autoremove = t.autoremove + autoremove; editor = t.editor + editor; keep_build_dir = t.keep_build_dir + keep_build_dir; reuse_build_dir = t.reuse_build_dir + reuse_build_dir; inplace_build = t.inplace_build + inplace_build; working_dir = t.working_dir + working_dir; drop_working_dir = t.drop_working_dir + drop_working_dir; ignore_pin_depends = t.ignore_pin_depends + ignore_pin_depends; show = t.show + show; fake = t.fake + fake; skip_dev_update = t.skip_dev_update + skip_dev_update; json_out = t.json_out + json_out; root_is_ok = t.root_is_ok + root_is_ok; no_auto_upgrade = t.no_auto_upgrade + no_auto_upgrade; assume_depexts = t.assume_depexts + assume_depexts; cli = t.cli + cli; scrubbed_environment_variables = t.scrubbed_environment_variables + scrubbed_environment_variables } let set t = setk (fun x () -> x) t let r = ref default let update ?noop:_ = setk (fun cfg () -> r := cfg) !r let initk k = let open OpamStd.Option.Op in Random.self_init (); let editor = E.editor () ++ OpamStd.Env.(getopt "VISUAL" ++ getopt "EDITOR") in setk (setk (fun c -> r := c; k)) !r ?print_stats:(E.stats ()) ?pin_kind_auto:(E.pinkindauto ()) ?autoremove:(E.autoremove ()) ?editor ?keep_build_dir:(E.keepbuilddir ()) ?reuse_build_dir:(E.reusebuilddir ()) ?inplace_build:(E.inplacebuild ()) ?working_dir:(E.workingdir ()) ?drop_working_dir:(E.dropworkingdir ()) ?ignore_pin_depends:(E.ignorepindepends ()) ?show:(E.show ()) ?fake:(E.fake ()) ?skip_dev_update:(E.skipupdate ()) ?json_out:(E.json () >>| function "" -> None | s -> Some s) ?root_is_ok:(E.rootisok ()) ?no_auto_upgrade:(E.noautoupgrade ()) ?assume_depexts:(E.assumedepexts ()) ?cli:None ?scrubbed_environment_variables:None let init ?noop:_ = initk (fun () -> ()) let search_files = ["findlib"] open OpamStd.Op let opam_init ?root_dir ?strict ?solver = let open OpamStd.Option.Op in (* (i) get root dir *) let root = OpamStateConfig.opamroot ?root_dir () in (* (ii) load conf file and set defaults *) (* the init for OpamFormat is done in advance since (a) it has an effect on loading the global config (b) the global config has no effect on it *) OpamFormatConfig.initk ?strict @@ fun ?log_dir -> let config = OpamStateConfig.load_defaults ~lock_kind:`Lock_read root in let initialised = config <> None in (* !X fixme: don't drop the loaded config file to reload it afterwards (when loading the global_state) like that... *) let solver = if solver = None && OpamSolverConfig.E.externalsolver () = None then (* fixme: in order to not revert config file solver value, we need to check it here *) (config >>= OpamFile.Config.solver >>| fun s -> lazy (OpamCudfSolver.custom_solver s)) else solver in begin match config with | None -> () | Some conf -> let criteria kind = let c = OpamFile.Config.criteria conf in try Some (List.assoc kind c) with Not_found -> None in OpamSolverConfig.update ?solver ?solver_preferences_default:(criteria `Default >>| fun s-> lazy(Some s)) ?solver_preferences_upgrade:(criteria `Upgrade >>| fun s-> lazy(Some s)) ?solver_preferences_fixup:(criteria `Fixup >>| fun s -> lazy (Some s)) ?solver_preferences_best_effort_prefix: (OpamFile.Config.best_effort_prefix conf >>| fun s -> lazy (Some s)) (); OpamStateConfig.update () end; (* (iii) load from env and options using OpamXxxConfig.init *) let log_dir = OpamStd.Option.map OpamFilename.Dir.to_string @@ if log_dir = None && initialised && OpamCoreConfig.E.logs () = None then (* fixme: in order to not revert [OPAMLOGS] value, we need to check it here *) Some (OpamPath.log root) else log_dir in (fun () -> ()) |> OpamCoreConfig.initk ?log_dir |> OpamRepositoryConfig.initk |> OpamSolverConfig.initk ?solver |> OpamStateConfig.initk ~root_dir:root |> initk opam-2.1.5/src/client/opamArg.mli0000644000175000017500000002543114427463453015662 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Command-line argument parsers and helpers *) open OpamTypes open Cmdliner (** {2 Helpers and argument constructors} *) (** {3 CLI versioning} *) (* Type of the validity of a flag *) type validity val cli2_0: OpamCLIVersion.t val cli2_1: OpamCLIVersion.t (* [cli_from since] validity flag since [since], and no removal version *) val cli_from: OpamCLIVersion.t -> validity (* [cli_between since until ?replaced] a validity flags introduced in [since], removed in [until], [replaced] is the replacement helper message *) val cli_between: OpamCLIVersion.t -> ?default:bool -> ?replaced:string -> OpamCLIVersion.t -> validity (* Original cli options : [validity] from 2.0 and no removal. No new options should use this. *) val cli_original: validity (** {3 Common helphers} *) (* Helpers function takes [cli] as first argument, which is the requested cli (via [--cli] or [OPAMCLI]), and a [validity] argument, the validity of the flag. All arguments must be defined using [mk_*] function, they embed cli validation. *) val mk_flag: cli:OpamCLIVersion.Sourced.t -> validity -> ?section:string -> string list -> string -> bool Term.t (* Deprecate and replace a [flags]. Constructs a [vflag] with the deprecated option and the new one *) val mk_flag_replaced: cli:OpamCLIVersion.Sourced.t -> ?section:string -> (validity * string list) list -> string -> bool Term.t val mk_opt: cli:OpamCLIVersion.Sourced.t -> validity -> ?section:string -> ?vopt:'a -> string list -> string -> string -> 'a Arg.converter -> 'a -> 'a Term.t val mk_opt_all: cli:OpamCLIVersion.Sourced.t -> validity -> ?section:string -> ?vopt:'a -> ?default:'a list -> string list -> string -> string -> 'a Arg.converter -> 'a list Term.t val mk_vflag: cli:OpamCLIVersion.Sourced.t -> ?section:string -> 'a -> (validity * 'a * string list * string) list -> 'a Term.t val mk_vflag_all: cli:OpamCLIVersion.Sourced.t -> ?section:string -> ?default:'a list -> (validity * 'a * string list * string) list -> 'a list Term.t (* Escaped Windows directory separator. To use instead of [Filename.dir_sep] for manpage strings *) val dir_sep: string (* Escape Windows path *) val escape_path: string -> string (** {2 Flags} *) (** --short *) val print_short_flag: OpamCLIVersion.Sourced.t -> validity -> bool Term.t (** --shell *) val shell_opt: OpamCLIVersion.Sourced.t -> validity -> shell option Term.t (** --dot-profile *) val dot_profile_flag: OpamCLIVersion.Sourced.t -> validity -> filename option Term.t (** --http/ --git/ --local *) val repo_kind_flag: OpamCLIVersion.Sourced.t -> validity -> OpamUrl.backend option Term.t (** --jobs *) val jobs_flag: OpamCLIVersion.Sourced.t -> validity -> int option Term.t (** package names *) val name_list: name list Term.t (** parameters *) val param_list: string list Term.t (** package list with optional constraints *) val atom_list: OpamFormula.atom list Term.t (** package list with optional constraints *) val nonempty_atom_list: OpamFormula.atom list Term.t val atom_or_local_list: [ `Atom of atom | `Filename of filename | `Dirname of dirname ] list Term.t val atom_or_dir_list: [ `Atom of atom | `Dirname of dirname ] list Term.t (** Generic argument list builder *) val arg_list: string -> string -> 'a Arg.converter -> 'a list Term.t (** Generic argument list builder *) val nonempty_arg_list: string -> string -> 'a Arg.converter -> 'a list Term.t (** Confirmation level enum *) val confirm_enum: (validity * string * OpamStd.Config.answer) list (** {3 Global options} *) (** Type for global options *) type global_options = { debug_level: int option; verbose: int; quiet : bool; color : OpamStd.Config.when_ option; opt_switch : string option; confirm_level : OpamStd.Config.answer option; yes: bool option; strict : bool; opt_root : dirname option; git_version : bool; external_solver : string option; use_internal_solver : bool; cudf_file : string option; solver_preferences : string option; best_effort: bool; safe_mode : bool; json : string option; no_auto_upgrade : bool; working_dir : bool; ignore_pin_depends : bool; cli : OpamCLIVersion.t; } (** Global options *) val global_options: OpamCLIVersion.Sourced.t -> global_options Term.t (** Apply global options *) val apply_global_options: OpamCLIVersion.Sourced.t -> global_options -> unit (** {3 Build options} *) (** Abstract type for build options *) type build_options val man_build_option_section: Manpage.block list (** Build options *) val build_options: OpamCLIVersion.Sourced.t -> build_options Term.t (** Install and reinstall options *) val assume_built: OpamCLIVersion.Sourced.t -> bool Term.t (* Options common to all path based/related commands, e.g. (un)pin, upgrade, remove, (re)install Disabled *) val recurse: OpamCLIVersion.Sourced.t -> bool Term.t val subpath: OpamCLIVersion.Sourced.t -> string option Term.t (** Applly build options *) val apply_build_options: OpamCLIVersion.Sourced.t -> build_options -> unit (** Lock options *) val locked: ?section:string -> OpamCLIVersion.Sourced.t -> bool Term.t val lock_suffix: ?section:string -> OpamCLIVersion.Sourced.t -> string Term.t (** {3 Package listing and filtering options} *) (** Man section name *) val package_selection_section: string (** Build a package selection filter *) val package_selection: OpamCLIVersion.Sourced.t -> OpamListCommand.selector list Term.t (** Man section name *) val package_listing_section: string (** Package selection filter based on the current state of packages (installed, available, etc.) *) val package_listing: OpamCLIVersion.Sourced.t -> (force_all_versions:bool -> OpamListCommand.package_listing_format) Term.t (** {3 Converters} *) (** Repository name converter *) val repository_name: repository_name Arg.converter (** URL converter *) val url: url Arg.converter (** Filename converter *) val filename: filename Arg.converter (** Filename converter also accepting "-" for stdin/stdout *) val existing_filename_or_dash: filename option Arg.converter (** Dirnam converter *) val dirname: dirname Arg.converter val existing_filename_dirname_or_dash: OpamFilename.generic_file option Arg.converter val positive_integer: int Arg.converter (** Package name converter *) val package_name: name Arg.converter (** Package version converter *) val package_version: version Arg.converter (** [name{.version}] (or [name=version]) *) val package: (name * version option) Arg.converter (** [name.version] (or [name=version]) *) val package_with_version: package Arg.converter (** [name{(.|=|!=|>|<|>=|<=)version}] converter*) val atom: atom Arg.converter (** Accepts [atom] but also (explicit) file and directory names *) val atom_or_local: [ `Atom of atom | `Filename of filename | `Dirname of dirname ] Arg.converter val atom_or_dir: [ `Atom of atom | `Dirname of dirname ] Arg.converter (** Formula, in the same format as [depends:] in opam files *) val dep_formula: formula Arg.converter (** [var=value,...] argument *) val variable_bindings: (OpamVariable.t * string) list Arg.converter (** Warnings string ["+3..10-4"] *) val warn_selector: (int * bool) list Arg.converter val opamlist_columns: OpamListCommand.output_format list Arg.converter (** {2 Subcommands} *) type 'a subcommand = validity * string * 'a * string list * string (** A subcommand [cmds, v, args, doc] is the subcommand [cmd], using the documentation [doc] and the list of documentation parameters [args]. If the subcommand is selected, return [v] value. *) type 'a subcommands = 'a subcommand list val mk_subcommands: cli:OpamCLIVersion.Sourced.t -> 'a subcommands -> 'a option Term.t * string list Term.t (** [subcommands cmds] are the terms [cmd] and [params]. [cmd] parses which sub-commands in [cmds] is selected and [params] parses the remaining of the command-line parameters as a list of strings. *) type 'a default = [> `default of string] as 'a (* unused (** Enumeration with a default command *) val enum_with_default: (string * 'a default) list -> 'a Arg.converter *) val mk_subcommands_with_default: cli:OpamCLIVersion.Sourced.t -> 'a default subcommands -> 'a option Term.t * string list Term.t (** Same as {!mk_subcommand} but use the default value if no sub-command is selected. *) val bad_subcommand: cli:OpamCLIVersion.Sourced.t -> 'a default subcommands -> (string * 'a option * string list) -> 'b Term.ret (** [bad_subcommand cmds cmd] is a command return value denoting a parsing error of sub-commands. *) val mk_subdoc : cli:OpamCLIVersion.Sourced.t -> ?defaults:(string * string) list -> 'a subcommands -> Manpage.block list (** [mk_subdoc cmds] is the documentation block for [cmds]. *) val make_command_alias: cli:OpamCLIVersion.Sourced.t -> 'a Term.t * Term.info -> ?options:string -> string -> 'a Term.t * Term.info (** Create an alias for an existing command. [options] can be used to add extra options after the original command in the doc (eg like `unpin` is an alias for `pin remove`). *) (** {2 Commands} *) (* All commands must be defined using [mk_command] and [mk_command_ret] for prior cli validation. *) type command = unit Term.t * Term.info val mk_command: cli:OpamCLIVersion.Sourced.t -> validity -> string -> doc:string -> man:Manpage.block list -> (unit -> unit) Term.t -> command (* [mk_command cli validity name doc man term] is the command [name] with its [doc] and [man], and using [term]. Its [validity] is checked at runtime against requested [cli], updates its documentation and errors if not valid. *) val mk_command_ret: cli:OpamCLIVersion.Sourced.t -> validity -> string -> doc:string -> man:Manpage.block list -> (unit -> unit Term.ret) Term.t -> command (* Same as {!mk_command} but [term] returns a [Cmdliner.Term.ret] *) (** {2 Documentation} *) val global_option_section: string val help_sections: OpamCLIVersion.Sourced.t -> Manpage.block list (** {2 Environment variables} *) val preinit_opam_env_variables: unit -> unit val init_opam_env_variabes: OpamCLIVersion.Sourced.t -> unit val scrubbed_environment_variables: string list opam-2.1.5/src/client/opamCliMain.mli0000644000175000017500000000321714427463453016463 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2020 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Handles calling opam plugins (à la git). E.g. [opam publish] runs [opam-publish] from PATH, with specific addition of OpamPath.plugins_bin and the current switch bin directory). Note that this does load some configuration and env, but only handles a leading [--yes] argument. @raise InvalidCLI *) val check_and_run_external_commands: unit -> OpamCLIVersion.Sourced.t * string list (** Handles flushing buffers and catching exceptions from the main call, including special cases like [OpamStd.Sys.Exec] that is expected to do a [Unix.exec], but after all proper cleanup has been done. *) val main_catch_all: (unit -> unit) -> unit (** Handling of debug JSON output, according to [OpamClientConfig.json_out] *) val json_out: unit -> unit (** [run default command_list] runs command-line argument parsing and processing of the command *) val run: unit -> unit (** Default entry point with handling of debug finalisers *) val main: unit -> unit opam-2.1.5/src/client/opamAction.mli0000644000175000017500000000674314427463453016373 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2018 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Handles concrete actions on packages, like installations and removals *) open OpamTypes open OpamStateTypes (** [download t pkg] downloads the source of the package [pkg] into its locally cached source dir. Returns [Some (short_errmsg option, long_errmsg)] on error, [None] on success. See {!OpamTypes.Not_available}. This doesn't update dev packages that already have a locally cached source. *) val download_package: rw switch_state -> package -> (string option * string) option OpamProcess.job (** [prepare_package_source t pkg dir] updates the given source [dir] with the extra downloads, overlays and patches from the package's metadata applied. *) val prepare_package_source: rw switch_state -> package -> dirname -> exn option OpamProcess.job (** [prepare_package_build env opam pkg dir] is a lower level version of `prepare_package_source`, without requiring a switch and without handling extra downloads. *) val prepare_package_build: OpamFilter.env -> OpamFile.OPAM.t -> package -> dirname -> exn option OpamProcess.job (** [build_package t build_dir pkg] builds the package [pkg] within [build_dir]. Returns [None] on success, [Some exn] on error. See {!download_package} and {!prepare_package_source} for the previous steps. *) val build_package: rw switch_state -> ?test:bool -> ?doc:bool -> dirname -> package -> exn option OpamProcess.job (** [install_package t pkg] installs an already built package. Returns [None] on success, [Some exn] on error. Do not update OPAM's metadata. See {!build_package} to build the package. *) val install_package: rw switch_state -> ?test:bool -> ?doc:bool -> ?build_dir:dirname -> package -> (OpamFile.Dot_config.t option, exn) OpamCompat.Either.t OpamProcess.job (** Find out if the package source is needed for uninstall *) val removal_needs_download: 'a switch_state -> package -> bool (** Removes a package. If [changes] is unspecified, it is read from the package's change file. if [force] is specified, remove files marked as added in [changes] even if the files have been modified since. *) val remove_package: rw switch_state -> ?silent:bool -> ?changes:OpamDirTrack.t -> ?force:bool -> ?build_dir:dirname -> package -> unit OpamProcess.job (** Returns [true] whenever [remove_package] is a no-op. *) val noop_remove_package: rw switch_state -> package -> bool (** Removes auxiliary files related to a package, after checking that they're not needed *) val cleanup_package_artefacts: rw switch_state -> package -> unit (** Compute the set of packages which will need to be downloaded to apply a solution. Takes a graph of atomic actions. *) val sources_needed: 'a switch_state -> OpamSolver.ActionGraph.t -> package_set opam-2.1.5/src/client/opamArg.ml0000644000175000017500000020446014427463453015512 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase open Cmdliner open OpamStd.Op include OpamArgTools (** Utils *) let when_enum = [ "always", `Always; "never", `Never; "auto", `Auto ] |> List.map (fun (s,v) -> cli_original, s, v) let confirm_enum = [ cli_from cli2_1, "ask", `ask; cli_from cli2_1, "no", `all_no; cli_from cli2_1, "yes", `all_yes; cli_from cli2_1, "unsafe-yes", `unsafe_yes; ] (* Windows directory separators need to be escaped for manpages *) let dir_sep, escape_path = match Filename.dir_sep with | "\\" -> let esc = "\\\\" in esc, fun p -> OpamStd.List.concat_map esc (fun x -> x) (OpamStd.String.split_delim p '\\') | ds -> ds, fun x -> x (** Opam environment variables *) (* Environment variables that need to be initialised before config init, see [OpamCliMain.run]. *) let preinit_environment_variables = let open OpamStd.Config in let core = let open OpamCoreConfig.E in [ "DEBUG", (fun v -> DEBUG (env_int v)), "see options `--debug' and `--debug-level'."; "YES", (fun v -> YES (env_bool v)), "see options `--yes' and `--confirm-level`. \ $(b,OPAMYES) has has priority over $(b,OPAMNO) and is \ ignored if $(b,OPAMCONFIRMLEVEL) is set."; ] in let client = let open OpamClientConfig.E in [ "CLI", (fun v -> CLI (env_string v)), "see option `--cli'."; "NOSELFUPGRADE",(fun v -> NOSELFUPGRADE (env_string v)), "see option `--no-self-upgrade'"; "ROOTISOK", (fun v -> ROOTISOK (env_bool v)), "don't complain when running as root."; ] in core @ client let preinit_opam_env_variables, doc_opam_env_variables_pre = let preinit () = OpamStd.Config.E.updates @@ List.map (fun (var, cons, _doc) -> cons var) preinit_environment_variables in let doc = List.map (fun (var, _cons, doc) -> `P (Printf.sprintf "$(i,OPAM%s) %s" var doc)) preinit_environment_variables in preinit, doc (* Environment variables with their doc and their validity OPAMVAR_var and OPAMPACKAGE_var are defined and documented static in [help_sections]. *) let environment_variables = let open OpamStd.Config in let core = let open OpamCoreConfig.E in [ "COLOR", cli_original, (fun v -> COLOR (env_when v)), "when set to $(i,always) or $(i,never), sets a default value for the \ `--color' option."; "CONFIRMLEVEL", cli_from cli2_1, (fun v -> CONFIRMLEVEL (env_answer v)), "see option `--confirm-level`. \ $(b,OPAMCONFIRMLEVEL) has priority over $(b,OPAMYES) \ and $(b,OPAMNO)."; "DEBUGSECTIONS", cli_from cli2_1, (fun v -> DEBUGSECTIONS (env_sections v)), "if set, limits debug messages to the space-separated list of \ sections. Sections can optionally have a specific debug level (for \ example, $(b,CLIENT:2) or $(b,CLIENT CUDF:2)), but otherwise use \ `--debug-level'."; "ERRLOGLEN", cli_original, (fun v -> ERRLOGLEN (env_int v)), "sets the number of log lines printed when a sub-process fails. 0 to \ print all."; "KEEPLOGS", cli_original, (fun v -> KEEPLOGS (env_bool v)), "tells opam to not remove some temporary command logs and some \ backups. This skips some finalisers and may also help to get more \ reliable backtraces."; "LOGS", cli_original, (fun v -> LOGS (env_string v)), ("$(i,logdir) sets log directory, default is a temporary directory in \ " ^ (if Sys.win32 then "%TEMP%" else "/tmp")); "MERGEOUT", cli_original, (fun v -> MERGEOUT (env_bool v)), "merge process outputs, stderr on stdout."; "NO", cli_original, (fun v -> NO (env_bool v)), "answer no to any question asked, see options `--no` and `--confirm-level`. \ $(b,OPAMNO) is ignored if either $(b,OPAMCONFIRMLEVEL) or $(b,OPAMYES) \ is set."; "PRECISETRACKING", cli_original, (fun v -> PRECISETRACKING (env_bool v)), "fine grain tracking of directories."; "SAFE", cli_original, (fun v -> SAFE (env_bool v)), "see option `--safe'."; "STATUSLINE", cli_original, (fun v -> STATUSLINE (env_when v)), ("display a dynamic status line showing what's currently going on on \ the terminal. (one of "^string_of_enum when_enum^")"); "USEOPENSSL", cli_original, (fun v -> USEOPENSSL (env_bool v)), "force openssl use for hash computing."; "UTF8", cli_original, (fun v -> UTF8 (env_when_ext v)), (Printf.sprintf "use UTF8 characters in output (one of %s). By default \ `auto', which is determined from the locale)." (string_of_enum when_enum)); "UTF8MSGS", cli_original, (fun v -> UTF8MSGS (env_bool v)), "use extended UTF8 characters (camels) in opam messages. Implies \ $(i,OPAMUTF8). This is set by default on OSX only."; "VERBOSE", cli_original, (fun v -> VERBOSE (env_level v)), "see option `--verbose'."; ] in let format = let open OpamFormatConfig.E in [ "ALLPARENS", cli_original, (fun v -> ALLPARENS (env_bool v)), "surround all filters with parenthesis."; "SKIPVERSIONCHECKS", cli_original, (fun v -> SKIPVERSIONCHECKS (env_bool v)), "bypasses some version checks. Unsafe, for compatibility testing only."; "STRICT", cli_original, (fun v -> STRICT (env_bool v)), "fail on inconsistencies (file reading, switch import, etc.)."; ] in let solver = let open OpamSolverConfig.E in [ "BESTEFFORT", cli_original, (fun v -> BESTEFFORT (env_bool v)), "see option `--best-effort'."; "BESTEFFORTPREFIXCRITERIA", cli_original, (fun v -> BESTEFFORTPREFIXCRITERIA (env_string v)), "sets the string that must be prepended to the criteria when the \ `--best-effort' option is set, and is expected to maximise the \ `opam-query' property in the solution."; "CRITERIA", cli_original, (fun v -> CRITERIA (env_string v)), "specifies user $(i,preferences) for dependency solving. The default \ value depends on the solver version, use `config report' to know the \ current setting. See also option --criteria."; "CUDFFILE", cli_original, (fun v -> CUDFFILE (env_string v)), "save the cudf graph to $(i,file)-actions-explicit.dot."; "CUDFTRIM", cli_original, (fun v -> CUDFTRIM (env_string v)), "controls the filtering of unrelated packages during CUDF preprocessing."; "DIGDEPTH", cli_original, (fun v -> DIGDEPTH (env_int v)), "defines how aggressive the lookup for conflicts during CUDF \ preprocessing is."; "EXTERNALSOLVER", cli_original, (fun v -> EXTERNALSOLVER (env_string v)), "see option `--solver'."; "FIXUPCRITERIA", cli_original, (fun v -> FIXUPCRITERIA (env_string v)), "same as $(i,OPAMUPGRADECRITERIA), but specific to fixup."; "NOASPCUD", cli_original, (fun v -> NOASPCUD (env_bool v)), "Deprecated."; "PREPRO", cli_original, (fun v -> PREPRO (env_bool v)), "set this to false to disable CUDF preprocessing. Less efficient, but \ might help debugging solver issue."; "SOLVERALLOWSUBOPTIMAL", cli_from cli2_1, (fun v -> SOLVERALLOWSUBOPTIMAL (env_bool v)), "(default `true') allows some solvers to still return a solution when \ they reach timeout; while the solution remains assured to be \ consistent, there is no guarantee in this case that it fits the \ expected optimisation criteria. If `true', opam willcontinue with a \ warning, if `false' a timeout is an error. Currently only \ the builtin-z3 backend handles this degraded case."; "SOLVERTIMEOUT", cli_original, (fun v -> SOLVERTIMEOUT (env_float v)), (Printf.sprintf "change the time allowance of the solver. Default is %.1f, set to 0 \ for unlimited. Note that all solvers may not support this option." (OpamStd.Option.default 0. OpamSolverConfig.(default.solver_timeout))); "UPGRADECRITERIA", cli_original, (fun v -> UPGRADECRITERIA (env_string v)), "specifies user $(i,preferences) for dependency solving when performing \ an upgrade. Overrides $(i,OPAMCRITERIA) in upgrades if both are set. \ See also option --criteria."; "USEINTERNALSOLVER", cli_original, (fun v -> USEINTERNALSOLVER (env_bool v)), "see option `--use-internal-solver'."; "VERSIONLAGPOWER", cli_original, (fun v -> VERSIONLAGPOWER (env_int v)), "do not use."; ] in let repository = let open OpamRepositoryConfig.E in [ "CURL", cli_original, (fun v -> CURL (env_string v)), "can be used to select a given 'curl' program. See $(i,OPAMFETCH) for \ more options."; "FETCH", cli_original, (fun v -> FETCH (env_string v)), "specifies how to download files: either `wget', `curl' or a custom \ command where variables $(b,%{url}%), $(b,%{out}%), $(b,%{retry}%), \ $(b,%{compress}%) and $(b,%{checksum}%) will be replaced. Overrides the \ 'download-command' value from the main config file."; "NOCHECKSUMS", cli_original, (fun v -> NOCHECKSUMS (env_bool v)), "enables option --no-checksums when available."; "REQUIRECHECKSUMS", cli_original, (fun v -> REQUIRECHECKSUMS (env_bool v)), "Enables option `--require-checksums' when available \ (e.g. for `opam install')."; "RETRIES", cli_original, (fun v -> RETRIES (env_int v)), "sets the number of tries before failing downloads."; "VALIDATIONHOOK", cli_original, (fun v -> VALIDATIONHOOK (env_string v)), "if set, uses the `%{hook%}' command to validate \ an opam repository update."; ] in let state = let open OpamStateConfig.E in [ "BUILDDOC", cli_between cli2_0 cli2_1, (fun v -> BUILDDOC (env_bool v)), "see option `--build-doc'."; "BUILDTEST", cli_between cli2_0 cli2_1, (fun v -> BUILDTEST (env_bool v)), "see option `--build-test'."; "DOWNLOADJOBS", cli_original, (fun v -> DOWNLOADJOBS (env_int v)), "sets the maximum number of simultaneous downloads."; "DRYRUN", cli_original, (fun v -> DRYRUN (env_bool v)), "see option `--dry-run'."; "IGNORECONSTRAINTS", cli_original, (fun v -> IGNORECONSTRAINTS (env_string v)), "see install option `--ignore-constraints-on'."; "JOBS", cli_original, (fun v -> JOBS (env_int v)), "sets the maximum number of parallel workers to run."; "LOCKED", cli_original, (fun v -> LOCKED (env_string v)), "combination of `--locked' and `--lock-suffix' options."; "MAKECMD", cli_original, (fun v -> MAKECMD (env_string v)), "set the system make command to use."; "NODEPEXTS", cli_from cli2_1, (fun v -> NODEPEXTS (env_bool v)), "disables system dependencies handling, see option `--no-depexts'."; "NOENVNOTICE", cli_original, (fun v -> NOENVNOTICE (env_bool v)), "Internal."; "ROOT", cli_original, (fun v -> ROOT (env_string v)), "see option `--root'. This is automatically set \ by `opam env --root=DIR --set-root'."; "SWITCH", cli_original, (fun v -> SWITCH (env_string v)), "see option `--switch'. Automatically set \ by `opam env --switch=SWITCH --set-switch'."; "UNLOCKBASE", cli_original, (fun v -> UNLOCKBASE (env_bool v)), "see install option `--unlock-base'."; "WITHDOC", cli_original, (fun v -> WITHDOC (env_bool v)), "see install option `--with-doc'."; "WITHTEST", cli_original, (fun v -> WITHTEST (env_bool v)), "see install option `--with-test."; ] in let client = let open OpamClientConfig.E in [ "ASSUMEDEPEXTS", cli_from cli2_1, (fun v -> ASSUMEDEPEXTS (env_bool v)), "see option `--assume-depexts'."; "AUTOREMOVE", cli_original, (fun v -> AUTOREMOVE (env_bool v)), "see remove option `--auto-remove'."; "DROPWORKINGDIR", cli_from cli2_1, (fun v -> DROPWORKINGDIR (env_bool v)), "overrides packages previously updated with $(b,--working-dir) on \ update. Without this variable set, opam would keep them unchanged \ unless explicitly named on the command-line."; "EDITOR", cli_original, (fun v -> EDITOR (env_string v)), "sets the editor to use for opam file editing, overrides $(i,\\$EDITOR) \ and $(i,\\$VISUAL)."; "FAKE", cli_original, (fun v -> FAKE (env_bool v)), "see option `--fake'."; "IGNOREPINDEPENDS", cli_original, (fun v -> IGNOREPINDEPENDS (env_bool v)), "see option `--ignore-pin-depends'."; "INPLACEBUILD", cli_original, (fun v -> INPLACEBUILD (env_bool v)), "see option `--inplace-build'."; "JSON", cli_original, (fun v -> JSON (env_string v)), "log json output to the given file \ (use character `%' to index the files)."; "KEEPBUILDDIR", cli_original, (fun v -> KEEPBUILDDIR (env_bool v)), "see install option `--keep-build-dir'."; "NOAUTOUPGRADE", cli_original, (fun v -> NOAUTOUPGRADE (env_bool v)), "disables automatic internal upgrade of repositories in an earlier \ format to the current one, on 'update' or 'init'."; "NOAGGREGATE", cli_original, (fun v -> NOAGGREGATE (env_bool v)), "with `opam admin check', don't aggregate packages."; "PINKINDAUTO", cli_original, (fun v -> PINKINDAUTO (env_bool v)), "sets whether version control systems should be detected when pinning \ to a local path. Enabled by default since 1.3.0."; "REUSEBUILDDIR", cli_original, (fun v -> REUSEBUILDDIR (env_bool v)), "see option `--reuse-build-dir'."; "SHOW", cli_original, (fun v -> SHOW (env_bool v)), "see option `--show'."; "SKIPUPDATE", cli_original, (fun v -> SKIPUPDATE (env_bool v)), "see option `--skip-updates'."; "STATS", cli_original, (fun v -> STATS (env_bool v)), "display stats at the end of command."; "WORKINGDIR", cli_original, (fun v -> WORKINGDIR (env_bool v)), "see option `--working-dir'."; ] in core @ format @ solver @ repository @ state @ client let scrubbed_environment_variables = let f (name, validity, _, _) = if is_original_cli validity then None else Some ("OPAM" ^ name) in OpamStd.List.filter_map f environment_variables let doc_opam_env_variables, init_opam_env_variabes = env_with_cli environment_variables (** Help sections common to all commands *) let global_option_section = Manpage.s_common_options let help_sections cli = [ `S global_option_section; `P "These options are common to all commands."; `S Manpage.s_environment; `P "Opam makes use of the environment variables listed here. Boolean \ variables should be set to \"0\", \"no\", \"false\" or the empty \ string to disable, \"1\", \"yes\" or \"true\" to enable."; ] @ List.sort compare (doc_opam_env_variables_pre @ doc_opam_env_variables cli) @ [ `P "$(i,OPAMVAR_var) overrides the contents of the variable $(i,var) when \ substituting `%{var}%` strings in `opam` files."; `P "$(i,OPAMVAR_package_var) overrides the contents of the variable \ $(i,package:var) when substituting `%{package:var}%` strings in \ `opam` files."; `S "CLI VERSION"; `P "All scripts and programmatic invocations of opam should use `--cli' in \ order to ensure that they work seamlessly with future versions of the \ opam client. Additionally, blog posts or other documentation can \ benefit, as it prevents information from becoming stale."; `P (Printf.sprintf "Although opam only supports roots ($(i,~%s.opam%s)) for the current \ version, it does provide backwards compatibility for its \ command-line interface." dir_sep dir_sep); `P "Since CLI version support was only added in opam 2.1, use $(i,OPAMCLI) \ to select 2.0 support (as opam 2.0 will just ignore it), \ and `--cli=2.1' for 2.1 (or later) versions, since an environment variable \ controlling the parsing of syntax is brittle. To this end, opam \ displays a warning if $(i,OPAMCLI) specifies a valid version other \ than 2.0, and also if `--cli=2.0' is specified."; `P "The command-line version is selected by using the `--cli' option or \ the $(i,OPAMCLI) environment variable. `--cli' may be specified more\ than once, where the last instance takes precedence. $(i,OPAMCLI) is \ only inspected if `--cli' is not given."; `S Manpage.s_exit_status; `P "As an exception to the following, the `exec' command returns 127 if the \ command was not found or couldn't be executed, and the command's exit \ value otherwise." ] @ List.map (fun (reason, code) -> `I (string_of_int code, match reason with | `Success -> "Success, or true for boolean queries." | `False -> "False. Returned when a boolean return value is expected, e.g. when \ running with $(b,--check), or for queries like $(b,opam lint)." | `Bad_arguments -> "Bad command-line arguments, or command-line arguments pointing to \ an invalid context (e.g. file not following the expected format)." | `Not_found -> "Not found. You requested something (package, version, repository, \ etc.) that couldn't be found." | `Aborted -> "Aborted. The operation required confirmation, which wasn't given." | `Locked -> "Could not acquire the locks required for the operation." | `No_solution -> "There is no solution to the user request. This can be caused by \ asking to install two incompatible packages, for example." | `File_error -> "Error in package definition, or other metadata files. Using \ $(b,--strict) raises this error more often." | `Package_operation_error -> "Package script error. Some package operations were unsuccessful. \ This may be an error in the packages or an incompatibility with \ your system. This can be a partial error." | `Sync_error -> "Sync error. Could not fetch some remotes from the network. This can \ be a partial error." | `Configuration_error -> "Configuration error. Opam or system configuration doesn't allow \ operation, and needs fixing." | `Solver_failure -> "Solver failure. The solver failed to return a sound answer. It can \ be due to a broken external solver, or an error in solver \ configuration." | `Internal_error -> "Internal error. Something went wrong, likely due to a bug in opam \ itself." | `User_interrupt -> "User interrupt. SIGINT was received, generally due to the user \ pressing Ctrl-C." )) OpamStd.Sys.exit_codes @ [ `S "FURTHER DOCUMENTATION"; `P (Printf.sprintf "See https://opam.ocaml.org/doc."); `S Manpage.s_authors; `P "Vincent Bernardoff "; `Noblank; `P "Raja Boujbel "; `Noblank; `P "Roberto Di Cosmo "; `Noblank; `P "Thomas Gazagnaire "; `Noblank; `P "Louis Gesbert "; `Noblank; `P "Fabrice Le Fessant "; `Noblank; `P "Anil Madhavapeddy "; `Noblank; `P "Guillem Rieu "; `Noblank; `P "Ralf Treinen "; `Noblank; `P "Frederic Tuong "; `S Manpage.s_bugs; `P "Check bug reports at https://github.com/ocaml/opam/issues."; ] (** Global options *) type global_options = { debug_level: int option; verbose: int; quiet : bool; color : OpamStd.Config.when_ option; opt_switch : string option; confirm_level : OpamStd.Config.answer option; yes: bool option; strict : bool; opt_root : dirname option; git_version : bool; external_solver : string option; use_internal_solver : bool; cudf_file : string option; solver_preferences : string option; best_effort : bool; safe_mode : bool; json : string option; no_auto_upgrade : bool; working_dir : bool; ignore_pin_depends : bool; cli : OpamCLIVersion.t; } (* The --cli passed by cmdliner is ignored (it's only there for --help) *) let create_global_options git_version debug debug_level verbose quiet color opt_switch yes confirm_level strict opt_root external_solver use_internal_solver cudf_file solver_preferences best_effort safe_mode json no_auto_upgrade working_dir ignore_pin_depends d_no_aspcud _ = if d_no_aspcud then OpamConsole.warning "Option %s is deprecated, ignoring it." (OpamConsole.colorise `bold "--no-aspcud"); let debug_level = OpamStd.Option.Op.( debug_level >>+ fun () -> if debug then Some 1 else None ) in let get_last l = match List.rev l with [] -> None | x::_ -> Some x in let yes = get_last yes in let confirm_level = get_last confirm_level in let verbose = List.length verbose in let cli = OpamCLIVersion.current in { git_version; debug_level; verbose; quiet; color; opt_switch; confirm_level; yes; strict; opt_root; external_solver; use_internal_solver; cudf_file; solver_preferences; best_effort; safe_mode; json; no_auto_upgrade; working_dir; ignore_pin_depends; cli } let apply_global_options cli o = if o.git_version then ( begin match OpamGitVersion.version with | None -> () | Some v -> OpamConsole.msg "%s\n" v end; OpamStd.Sys.exit_because `Success ); let open OpamStd.Option.Op in let flag f = if f then Some true else None in let some x = match x with None -> None | some -> Some some in let solver = if o.use_internal_solver then Some (lazy (OpamCudfSolver.get_solver ~internal:true OpamCudfSolver.default_solver_selection)) else o.external_solver >>| fun s -> lazy (OpamCudfSolver.solver_of_string s) in let solver_prefs = o.solver_preferences >>| fun p -> lazy (Some p) in let yes = OpamStd.Option.(map some o.yes) in init_opam_env_variabes cli; OpamClientConfig.opam_init (* - format options - *) ?strict:(flag o.strict) (* ?skip_version_checks:bool *) (* ?all_parens:bool *) (* - core options - *) ?debug_level:(if o.safe_mode then Some 0 else o.debug_level) ?verbose_level:(if o.quiet then Some 0 else if o.verbose = 0 then None else Some o.verbose) ?color:o.color (* ?utf8:[ `Extended | `Always | `Never | `Auto ] *) (* ?disp_status_line:[ `Always | `Never | `Auto ] *) ?confirm_level:o.confirm_level ?yes ?safe_mode:(flag o.safe_mode) (* ?lock_retries:int *) (* ?log_dir:OpamTypes.dirname *) (* ?keep_log_dir:bool *) (* - repository options - *) (* ?download_tool:(OpamTypes.arg list * dl_tool_kind) Lazy.t *) (* ?retries:int *) (* ?force_checksums:bool option *) (* - solver options *) ?cudf_file:(some o.cudf_file) ?solver ?best_effort:(flag o.best_effort) ?solver_preferences_default:solver_prefs ?solver_preferences_upgrade:solver_prefs ?solver_preferences_fixup:solver_prefs (* ?solver_preferences_best_effort_prefix: *) (* - state options - *) ?root_dir:o.opt_root ?current_switch:(o.opt_switch >>| OpamSwitch.of_string) ?switch_from:(o.opt_switch >>| fun _ -> `Command_line) (* ?jobs: int *) (* ?dl_jobs: int *) (* ?keep_build_dir:bool *) (* ?build_test:bool *) (* ?build_doc:bool *) (* ?show:bool *) (* ?dryrun:bool *) (* ?fake:bool *) (* ?makecmd:string Lazy.t *) (* ?ignore_constraints_on:name_set *) (* ?skip_dev_update:bool *) ?json_out:OpamStd.Option.Op.(o.json >>| function "" -> None | s -> Some s) (* ?root_is_ok:bool *) ?no_auto_upgrade:(flag o.no_auto_upgrade) (* - client options - *) ?working_dir:(flag o.working_dir) ?ignore_pin_depends:(flag o.ignore_pin_depends) (* ?print_stats:bool *) (* ?sync_archives:bool *) (* ?pin_kind_auto:bool *) (* ?autoremove:bool *) (* ?editor:string *) ~cli:o.cli (); if OpamClientConfig.(!r.json_out <> None) then ( OpamJson.append "opam-version" (`String OpamVersion.(to_string (full ()))); OpamJson.append "command-line" (`A (List.map (fun s -> `String s) (Array.to_list Sys.argv))) ) (** Build options *) type build_options = { keep_build_dir: bool; reuse_build_dir: bool; inplace_build : bool; make : string option; no_checksums : bool; req_checksums : bool; build_test : bool; build_doc : bool; show : bool; dryrun : bool; fake : bool; skip_update : bool; jobs : int option; ignore_constraints_on: name list option; unlock_base : bool; locked : bool; lock_suffix : string; assume_depexts: bool; no_depexts : bool; } let create_build_options keep_build_dir reuse_build_dir inplace_build make no_checksums req_checksums build_test build_doc show dryrun skip_update fake jobs ignore_constraints_on unlock_base locked lock_suffix assume_depexts no_depexts = { keep_build_dir; reuse_build_dir; inplace_build; make; no_checksums; req_checksums; build_test; build_doc; show; dryrun; skip_update; fake; jobs; ignore_constraints_on; unlock_base; locked; lock_suffix; assume_depexts; no_depexts; } let apply_build_options cli b = let open OpamStd.Option.Op in let flag f = if f then Some true else None in OpamRepositoryConfig.update (* ?download_tool:(OpamTypes.arg list * dl_tool_kind) Lazy.t *) (* ?retries:int *) ?force_checksums:(if b.req_checksums then Some (Some true) else if b.no_checksums then Some (Some false) else None) (); OpamStateConfig.update (* ?root: -- handled globally *) ?jobs:(b.jobs >>| fun j -> lazy j) (* ?dl_jobs:int *) (* ?no_base_packages:(flag o.no_base_packages) -- handled globally *) ?build_test:(flag b.build_test) ?build_doc:(flag b.build_doc) ?dryrun:(flag b.dryrun) ?makecmd:(b.make >>| fun m -> lazy m) ?ignore_constraints_on: (b.ignore_constraints_on >>| OpamPackage.Name.Set.of_list) ?unlock_base:(flag b.unlock_base) ?locked:(if b.locked then Some (Some b.lock_suffix) else None) ?no_depexts:(flag (b.no_depexts || OpamCLIVersion.Op.(cli @= cli2_0))) (); OpamClientConfig.update ?keep_build_dir:(flag b.keep_build_dir) ?reuse_build_dir:(flag b.reuse_build_dir) ?inplace_build:(flag b.inplace_build) ?show:(flag b.show) ?fake:(flag b.fake) ?skip_dev_update:(flag b.skip_update) ?assume_depexts:(flag (b.assume_depexts || b.no_depexts)) ~scrubbed_environment_variables () (** Converters *) let pr_str = Format.pp_print_string let repository_name = let parse str = `Ok (OpamRepositoryName.of_string str) in let print ppf name = pr_str ppf (OpamRepositoryName.to_string name) in parse, print let url = let parse str = match OpamUrl.parse_opt ~from_file:false str with | Some url -> `Ok url | None -> `Error ("malformed url "^str) in let print ppf url = pr_str ppf (OpamUrl.to_string url) in parse, print let filename = let parse str = `Ok (OpamFilename.of_string str) in let print ppf filename = pr_str ppf (OpamFilename.to_string filename) in parse, print let existing_filename_or_dash = let parse str = if str = "-" then `Ok None else let f = OpamFilename.of_string str in if OpamFilename.exists f then `Ok (Some f) else `Error (Printf.sprintf "File %s not found" (OpamFilename.to_string f)) in let print ppf filename = pr_str ppf OpamStd.Option.Op.((filename >>| OpamFilename.to_string) +! "-") in parse, print let dirname = let parse str = `Ok (OpamFilename.Dir.of_string str) in let print ppf dir = pr_str ppf (escape_path (OpamFilename.prettify_dir dir)) in parse, print let existing_filename_dirname_or_dash = let parse str = if str = "-" then `Ok None else match OpamFilename.opt_file (OpamFilename.of_string str) with | Some f -> `Ok (Some (OpamFilename.F f)) | None -> match OpamFilename.opt_dir (OpamFilename.Dir.of_string str) with | Some d -> `Ok (Some (OpamFilename.D d)) | None -> `Error (Printf.sprintf "File or directory %s not found" str) in let print ppf gf = pr_str ppf @@ match gf with | None -> "-" | Some (OpamFilename.D d) -> OpamFilename.Dir.to_string d | Some (OpamFilename.F f) -> OpamFilename.to_string f in parse, print let _subpath_conv = (fun str -> `Ok (OpamStd.String.remove_prefix ~prefix:"./" str)), pr_str let package_name = let parse str = try `Ok (OpamPackage.Name.of_string str) with Failure msg -> `Error msg in let print ppf pkg = pr_str ppf (OpamPackage.Name.to_string pkg) in parse, print let package_version = let parse str = try `Ok (OpamPackage.Version.of_string str) with Failure msg -> `Error msg in let print ppf ver = pr_str ppf (OpamPackage.Version.to_string ver) in parse, print let positive_integer : int Arg.converter = let (parser, printer) = Arg.int in let parser s = match parser s with | `Error _ -> `Error "expected a strictly positive integer" | `Ok n as r -> if n <= 0 then `Error "expected a positive integer" else r in (parser, printer) (* name * version option *) let package = let parse str = let re = Re.(compile @@ seq [ bos; group @@ rep1 @@ diff any (set ">=<.!"); opt @@ seq [ set ".="; group @@ rep1 any ]; eos; ]) in try let sub = Re.exec re str in let name = OpamPackage.Name.of_string (Re.Group.get sub 1) in let version_opt = try Some (OpamPackage.Version.of_string (Re.Group.get sub 2)) with Not_found -> None in `Ok (name, version_opt) with Not_found | Failure _ -> `Error "bad package format" in let print ppf (name, version_opt) = match version_opt with | None -> pr_str ppf (OpamPackage.Name.to_string name) | Some v -> pr_str ppf (OpamPackage.Name.to_string name ^"."^ OpamPackage.Version.to_string v) in parse, print let package_with_version = let parse str = match fst package str with | `Ok (n, Some v) -> `Ok (OpamPackage.create n v) | `Ok (_, None) -> `Error "missing package version" | `Error e -> `Error e in let print ppf nv = pr_str ppf (OpamPackage.to_string nv) in parse, print (* name * version constraint *) let atom = let parse str = try `Ok (OpamFormula.atom_of_string str) with Failure msg -> `Error msg in let print ppf atom = pr_str ppf (OpamFormula.short_string_of_atom atom) in parse, print let atom_or_local = let parse str = if OpamStd.String.contains ~sub:Filename.dir_sep str || OpamStd.String.starts_with ~prefix:"." str then if OpamFilename.(exists (of_string str)) then `Ok (`Filename (OpamFilename.of_string str)) else if OpamFilename.(exists_dir (Dir.of_string str)) then `Ok (`Dirname (OpamFilename.Dir.of_string str)) else `Error (Printf.sprintf "Not a valid package specification or existing file or \ directory: %s" str) else match fst atom str with | `Ok at -> `Ok (`Atom at) | `Error e -> `Error e in let print ppf = function | `Filename f -> pr_str ppf (OpamFilename.to_string f) | `Dirname d -> pr_str ppf (OpamFilename.Dir.to_string d) | `Atom a -> snd atom ppf a in parse, print let atom_or_dir = let parse str = match fst atom_or_local str with | `Ok (`Filename _) -> `Error (Printf.sprintf "Not a valid package specification or existing directory: %s" str) | `Ok (`Atom _ | `Dirname _ as atom_or_dir) -> `Ok (atom_or_dir) | `Error e -> `Error e in let print ppf = snd atom_or_local ppf in parse, print let dep_formula = let module OpamParser = OpamParser.FullPos in let module OpamPrinter = OpamPrinter.FullPos in let pp = OpamFormat.V.(package_formula `Conj (constraints version)) in let parse str = try let v = OpamParser.value_from_string str "" in `Ok (OpamPp.parse pp ~pos:pos_null v) with e -> OpamStd.Exn.fatal e; `Error (Printexc.to_string e) in let print ppf f = pr_str ppf (OpamPrinter.value (OpamPp.print pp f)) in parse, print let variable_bindings = let parse str = try OpamStd.String.split str ',' |> List.map (fun s -> match OpamStd.String.cut_at s '=' with | Some (a, b) -> OpamVariable.of_string a, b | None -> Printf.ksprintf failwith "%S is not a binding" s) |> fun bnds -> `Ok bnds with Failure e -> `Error e in let print ppf x = List.map (fun (a,b) -> Printf.sprintf "%s=%s" (OpamVariable.to_string a) b) x |> String.concat "," |> pr_str ppf in parse, print let warn_selector = let parse str = let sep = Re.(compile (set "+-")) in let sel = Re.(compile @@ seq [bos; group (rep1 digit); opt @@ seq [str ".."; group (rep1 digit)]; eos]) in let rec seq i j = if i = j then [i] else if i < j then i :: seq (i+1) j else j :: seq (j+1) i in let rec aux acc = function | `Delim d :: `Text n :: r -> let nums = let g = Re.exec sel n in let i = int_of_string (Re.Group.get g 1) in try seq i (int_of_string (Re.Group.get g 2)) with Not_found -> [i] in let enabled = Re.Group.get d 0 = "+" in let acc = List.fold_left (fun acc n -> (n, enabled) :: acc) acc nums in aux acc r | [] -> acc | _ -> raise Not_found in try `Ok (List.rev (aux [] (Re.split_full sep str))) with Not_found -> `Error "Expected a warning string, e.g. '--warn=-10..21+12-36'" in let print ppf warns = pr_str ppf @@ OpamStd.List.concat_map "" (fun (num,enable) -> Printf.sprintf "%c%d" (if enable then '+' else '-') num) warns in parse, print let _selector = let parse str = let r = List.fold_left (fun (plus, minus) elem -> match OpamStd.String.sub_at 1 elem with | "+" as prefix -> (OpamStd.String.remove_prefix ~prefix elem)::plus, minus | "-" as prefix -> plus, (OpamStd.String.remove_prefix ~prefix elem)::minus | _ -> elem::plus, minus) ([],[]) (OpamStd.String.split str ',') in `Ok r in let print ppf (plus,minus) = let concat c = OpamStd.List.concat_map ~nil:"" "," (fun x -> c^x) in pr_str ppf @@ Printf.sprintf "%s,%s" (concat "+" plus) (concat "-" minus) in parse, print (* unused let enum_with_default sl: 'a Arg.converter = let parse, print = Arg.enum sl in let parse s = match parse s with | `Ok _ as x -> x | _ -> `Ok (`default s) in parse, print *) let opamlist_column = let parse str = if OpamStd.String.ends_with ~suffix:":" str then let fld = OpamStd.String.remove_suffix ~suffix:":" str in `Ok (OpamListCommand.Field fld) else try List.find (function (OpamListCommand.Field _), _ -> false | _, name -> name = str) OpamListCommand.field_names |> fun (f, _) -> `Ok f with Not_found -> `Error (Printf.sprintf "No known printer for column %s. If you meant an opam file \ field, use '%s:' instead (with a trailing colon)." str str) in let print ppf field = Format.pp_print_string ppf (OpamListCommand.string_of_field field) in parse, print let opamlist_columns = let field_re = (* max paren nesting 1, obviously *) Re.(compile @@ seq [ start; group @@ seq [ rep @@ diff any (set ",("); opt @@ seq [char '('; rep (diff any (char ')')); char ')']; ]; alt [char ','; stop]; ]) in let parse str = try let rec aux pos = if pos = String.length str then [] else let g = Re.exec ~pos field_re str in Re.Group.get g 1 :: aux (Re.Group.stop g 0) in let fields = aux 0 in List.fold_left (function | `Error _ as e -> fun _ -> e | `Ok acc -> fun str -> match fst opamlist_column str with | `Ok f -> `Ok (acc @ [f]) | `Error _ as e -> e) (`Ok []) fields with Not_found -> `Error (Printf.sprintf "Invalid columns specification: '%s'." str) in let print ppf cols = let rec aux = function | x::(_::_) as r -> snd opamlist_column ppf x; Format.pp_print_char ppf ','; aux r | [x] -> snd opamlist_column ppf x | [] -> () in aux cols in parse, print let term_info ~cli title ~doc ~man = let man = man @ help_sections cli in Term.info ~sdocs:global_option_section ~docs:Manpage.s_commands ~doc ~man title let mk_command ~cli validity name ~doc ~man = mk_command ~cli validity term_info name ~doc ~man let mk_command_ret ~cli validity name ~doc ~man = mk_command_ret ~cli validity term_info name ~doc ~man let make_command_alias ~cli cmd ?(options="") name = let term, info = cmd in let orig = Term.name info in let doc = Printf.sprintf "An alias for $(b,%s%s)." orig options in let man = [ `S Manpage.s_description; `P (Printf.sprintf "$(mname)$(b, %s) is an alias for $(mname)$(b, %s%s)." name orig options); `P (Printf.sprintf "See $(mname)$(b, %s --help) for details." orig); `S Manpage.s_options; ] @ help_sections cli in term, Term.info name ~docs:"COMMAND ALIASES" ~sdocs:global_option_section ~doc ~man let arg_list name doc kind = let doc = Arg.info ~docv:name ~doc [] in Arg.(value & pos_all kind [] & doc) let nonempty_arg_list name doc kind = let doc = Arg.info ~docv:name ~doc [] in Arg.(non_empty & pos_all kind [] & doc) (** Common flags *) let print_short_flag cli validity = mk_flag ~cli validity ["s";"short"] "Output raw lists of names, one per line, skipping any details." let shell_opt cli validity = let enum = [ "bash",SH_bash; "sh",SH_sh; "csh",SH_csh; "zsh",SH_zsh; "fish",SH_fish; ] |> List.map (fun (s,v) -> cli_original, s, v) in mk_enum_opt ~cli validity ["shell"] "SHELL" enum (Printf.sprintf "Sets the configuration mode for opam environment appropriate for \ $(docv). One of %s. Guessed from the parent processes and the \\$SHELL \ variable by default." (string_of_enum enum)) let dot_profile_flag cli validity = mk_opt ~cli validity ["dot-profile"] "FILENAME" (Printf.sprintf "Name of the configuration file to update instead of \ $(i,~%s.profile) or $(i,~%s.zshrc) based on shell detection." dir_sep dir_sep) (Arg.some filename) None let repo_kind_flag cli validity = let main_kinds = [ "http" , `http; "local", `rsync; "git" , `git; "darcs", `darcs; "hg" , `hg; ] |> List.map (fun (s,v) -> cli_original, s, v) in let aliases_kinds = [ "wget" , `http; "curl" , `http; "rsync", `rsync; ] |> List.map (fun (s,v) -> cli_original, s, v) in mk_enum_opt ~cli validity ["k";"kind"] "KIND" (main_kinds @ aliases_kinds) (Printf.sprintf "Specify the kind of the repository to be used (%s)." (string_of_enum main_kinds)) let jobs_flag cli validity = mk_opt ~cli validity ["j";"jobs"] "JOBS" "Set the maximal number of concurrent jobs to use. The default value is \ calculated from the number of cores. You can also set it using the \ $(b,\\$OPAMJOBS) environment variable." Arg.(some positive_integer) None let name_list = arg_list "PACKAGES" "List of package names." package_name let atom_list = arg_list "PACKAGES" "List of package names, with an optional version or constraint, \ e.g `pkg', `pkg.1.0' or `pkg>=0.5'." atom let atom_or_local_list = arg_list "PACKAGES" (Printf.sprintf "List of package names, with an optional version or constraint, e.g `pkg', \ `pkg.1.0' or `pkg>=0.5' ; or files or directory names containing package \ description, with explicit directory (e.g. `.%sfoo.opam' or `.')" dir_sep) atom_or_local let atom_or_dir_list = arg_list "PACKAGES" (Printf.sprintf "List of package names, with an optional version or constraint, e.g `pkg', \ `pkg.1.0' or `pkg>=0.5' ; or directory names containing package \ description, with explicit directory (e.g. `.%ssrcdir' or `.')" dir_sep) atom_or_dir let nonempty_atom_list = nonempty_arg_list "PACKAGES" "List of package names, with an optional version or constraint, \ e.g `pkg', `pkg.1.0' or `pkg>=0.5'." atom let param_list = arg_list "PARAMS" "List of parameters." Arg.string (* Options common to all commands *) let global_options cli = let section = global_option_section in let git_version = mk_flag ~cli cli_original ~section ["git-version"] "Print the git version of opam, if set (i.e. you are using a development \ version), and exit." in let debug = mk_flag ~cli cli_original ~section ["debug"] "Print debug message to stderr. \ This is equivalent to setting $(b,\\$OPAMDEBUG) to \"true\"." in let debug_level = mk_opt ~cli cli_original ~section ["debug-level"] "LEVEL" "Like $(b,--debug), but allows specifying the debug level ($(b,--debug) \ sets it to 1). Equivalent to setting $(b,\\$OPAMDEBUG) to a positive \ integer." Arg.(some int) None in let verbose = Arg.(value & flag_all & info ~docs:section ["v";"verbose"] ~doc: "Be more verbose. One $(b,-v) shows all package commands, repeat to \ also display commands called internally (e.g. $(i,tar), $(i,curl), \ $(i,patch) etc.) Repeating $(i,n) times is equivalent to setting \ $(b,\\$OPAMVERBOSE) to \"$(i,n)\".") in let quiet = mk_flag ~cli cli_original ~section ["q";"quiet"] "Disables $(b,--verbose)." in let color = mk_enum_opt ~cli cli_original ~section ["color"] "WHEN" when_enum (Printf.sprintf "Colorize the output. $(docv) must be %s." (string_of_enum when_enum)) in (* The --cli option is pre-processed, because it has to be able to appear before sub-commands. The one here is present only for --help. *) let cli_arg = mk_opt ~cli cli_original ~section ["cli"] "MAJOR.MINOR" "Use the command-line interface syntax and semantics of $(docv). \ Intended for any persistent use of opam (scripts, blog posts, etc.), \ any version of opam in the same MAJOR series will behave as for the \ specified MINOR release. The flag was not available in opam 2.0, so to \ select the 2.0 CLI, set the $(b,OPAMCLI) environment variable to \ $(i,2.0) instead of using this parameter." Arg.string (OpamCLIVersion.to_string OpamCLIVersion.current) in let switch = mk_opt ~cli cli_original ~section ["switch"] "SWITCH" "Use $(docv) as the current compiler switch. \ This is equivalent to setting $(b,\\$OPAMSWITCH) to $(i,SWITCH)." Arg.(some string) None in let yes = mk_vflag_all ~cli [ cli_original, true, ["y";"yes"], "Answer yes to all opam yes/no questions without prompting. \ See also $(b,--confirm-level). \ This is equivalent to setting $(b,\\$OPAMYES) to \"true\"."; cli_from cli2_1, false, ["no"], "Answer no to all opam yes/no questions without prompting. \ See also $(b,--confirm-level). \ This is equivalent to setting $(b,\\$OPAMNO) to \"true\"."; ] in let confirm_level = mk_enum_opt_all ~cli (cli_from cli2_1) ~section ["confirm-level"] "LEVEL" confirm_enum (Printf.sprintf "Confirmation level, $(docv) must be %s. Can be specified more than \ once. If $(b,--yes) or $(b,--no) are also given, the value of the \ last $(b,--confirm-level) is taken into account. This is equivalent \ to setting $(b, \\$OPAMCONFIRMLEVEL)`." (string_of_enum confirm_enum)) in let strict = mk_flag ~cli cli_original ~section ["strict"] "Fail whenever an error is found in a package definition \ or a configuration file. The default is to continue silently \ if possible." in let root = mk_opt ~cli cli_original ~section ["root"] "ROOT" "Use $(docv) as the current root path. \ This is equivalent to setting $(b,\\$OPAMROOT) to $(i,ROOT)." Arg.(some dirname) None in let d_no_aspcud = mk_flag ~cli (cli_between cli2_0 cli2_1) ~section ["no-aspcud"] "Deprecated" in let use_internal_solver = mk_flag ~cli cli_original ~section ["use-internal-solver"] "Disable any external solver, and use the built-in one (this requires \ that opam has been compiled with a built-in solver). This is equivalent \ to setting $(b,\\$OPAMNOASPCUD) or $(b,\\$OPAMUSEINTERNALSOLVER)." in let external_solver = mk_opt ~cli cli_original ~section ["solver"] "CMD" (Printf.sprintf "Specify the CUDF solver to use for resolving package installation \ problems. This is either a predefined solver (this version of opam \ supports %s), or a custom command that should contain the variables \ %%{input}%%, %%{output}%%, %%{criteria}%%, and optionally \ %%{timeout}%%. This is equivalent to setting $(b,\\$OPAMEXTERNALSOLVER)." (OpamStd.List.concat_map ", " (fun (module S : OpamCudfSolver.S) -> S.name) (OpamCudfSolver.default_solver_selection))) Arg.(some string) None in let solver_preferences = mk_opt ~cli cli_original ~section ["criteria"] "CRITERIA" ("Specify user $(i,preferences) for dependency solving for this run. \ Overrides both $(b,\\$OPAMCRITERIA) and $(b,\\$OPAMUPGRADECRITERIA). \ For details on the supported language, and the external solvers available, see \ $(i, http://opam.ocaml.org/doc/External_solvers.html). \ A general guide to using solver preferences can be found at \ $(i, http://www.dicosmo.org/Articles/usercriteria.pdf).") Arg.(some string) None in let cudf_file = mk_opt ~cli cli_original ~section ["cudf"] "FILENAME" "Debug option: Save the CUDF requests sent to the solver to \ $(docv)-.cudf." Arg.(some string) None in let best_effort = mk_flag ~cli cli_original ~section ["best-effort"] "Don't fail if all requested packages can't be installed: try to install \ as many as possible. Note that not all external solvers may support \ this option (recent versions of $(i,aspcud) or $(i,mccs) should). This \ is equivalent to setting $(b,\\$OPAMBESTEFFORT) environment variable." in let safe_mode = mk_flag ~cli cli_original ~section ["readonly"; "safe"] "Make sure nothing will be automatically updated or rewritten. Useful \ for calling from completion scripts, for example. Will fail whenever \ such an operation is needed ; also avoids waiting for locks, skips \ interactive questions and overrides the $(b,\\$OPAMDEBUG) variable. \ This is equivalent to set environment variable $(b,\\$OPAMSAFE)." in let json_flag = mk_opt ~cli cli_original ~section ["json"] "FILENAME" "Save the results of the opam run in a computer-readable file. If the \ filename contains the character `%', it will be replaced by an index \ that doesn't overwrite an existing file. Similar to setting the \ $(b,\\$OPAMJSON) variable." Arg.(some string) None in let no_auto_upgrade = mk_flag ~cli cli_original ~section ["no-auto-upgrade"] "When configuring or updating a repository that is written for an \ earlier opam version (1.2), opam internally converts it to the current \ format. This disables this behaviour. Note that repositories should \ define their format version in a 'repo' file at their root, or they \ will be assumed to be in the older format. It is, in any case, \ preferable to upgrade the repositories manually using $(i,opam admin \ upgrade [--mirror URL]) when possible." in let working_dir = mk_flag ~cli cli_original ~section ["working-dir"; "w"] "Whenever updating packages that are bound to a local, \ version-controlled directory, update to the current working state of \ their source instead of the last committed state, or the ref they are \ pointing to. As source directory is copied as it is, if it isn't clean \ it may result on a opam build failure.\ This only affects packages explicitly listed on the command-line.\ It can also be set with $(b,\\$OPAMWORKINGDIR). " in let ignore_pin_depends = mk_flag ~cli cli_original ~section ["ignore-pin-depends"] "Ignore extra pins required by packages that get pinned, either manually \ through $(i,opam pin) or through $(i,opam install DIR). This is \ equivalent to setting $(b,IGNOREPINDEPENDS=true)." in Term.(const create_global_options $git_version $debug $debug_level $verbose $quiet $color $switch $yes $confirm_level $strict $root $external_solver $use_internal_solver $cudf_file $solver_preferences $best_effort $safe_mode $json_flag $no_auto_upgrade $working_dir $ignore_pin_depends $d_no_aspcud $cli_arg) (* lock options *) let locked ?(section=Manpage.s_options) cli = mk_flag ~cli cli_original ~section ["locked"] "In commands that use opam files found from pinned sources, if a variant \ of the file with an added .$(i,locked) extension is found (e.g. \ $(b,foo.opam.locked) besides $(b,foo.opam)), that will be used instead. \ This is typically useful to offer a more specific set of dependencies \ and reproduce similar build contexts, hence the name. The $(i, lock)\ option can be used to generate such files, based on the versions \ of the dependencies currently installed on the host. This is equivalent \ to setting the $(b,\\$OPAMLOCKED) environment variable. Note that this \ option doesn't generally affect already pinned packages." let lock_suffix ?(section=Manpage.s_options) cli = mk_opt ~cli (cli_from cli2_1) ~section ["lock-suffix"] "SUFFIX" "Set locked files suffix to $(i,SUFFIX)." Arg.(string) ("locked") (* Options common to all build commands *) let build_option_section = "PACKAGE BUILD OPTIONS" let man_build_option_section = [ `S build_option_section; ] let build_options cli = let section = build_option_section in let keep_build_dir = mk_flag ~cli cli_original ~section ["b";"keep-build-dir"] "Keep the build directories after compiling packages. \ This is equivalent to setting $(b,\\$OPAMKEEPBUILDDIR) to \"true\"." in let reuse_build_dir = mk_flag ~cli cli_original ~section ["reuse-build-dir"] "Reuse existing build directories (kept by using $(b,--keep-build-dir)), \ instead of compiling from a fresh clone of the source. This can be \ faster, but also lead to failures if the build systems of the packages \ don't handle upgrades of dependencies well. This is equivalent to \ setting $(b,\\$OPAMREUSEBUILDDIR) to \"true\"." in let inplace_build = mk_flag ~cli cli_original ~section ["inplace-build"] "When compiling a package which has its source bound to a local \ directory, process the build and install actions directly in that \ directory, rather than in a clean copy handled by opam. This only \ affects packages that are explicitly listed on the command-line. \ This is equivalent to setting $(b,\\$OPAMINPLACEBUILD) to \"true\"." in let no_checksums = mk_flag ~cli cli_original ~section ["no-checksums"] "Do not verify the checksum of downloaded archives.\ This is equivalent to setting $(b,\\$OPAMNOCHECKSUMS) to \"true\"." in let req_checksums = mk_flag ~cli cli_original ~section ["require-checksums"] "Reject the installation of packages that don't provide a checksum for the upstream archives. \ This is equivalent to setting $(b,\\$OPAMREQUIRECHECKSUMS) to \"true\"." in let build_test = mk_flag_replaced ~cli ~section [ cli_between cli2_0 cli2_1 ~replaced:"--with-test", ["build-test"]; cli_original, ["t";"with-test"]; ] "Build and $(b,run) the package unit-tests. This only affects packages \ listed on the command-line. This is equivalent to setting \ $(b,\\$OPAMWITHTEST) (or the deprecated $(b,\\$OPAMBUILDTEST)) to \ \"true\"." in let build_doc = mk_flag_replaced ~cli ~section [ cli_between cli2_0 cli2_1 ~replaced:"--with-doc", ["build-doc"]; cli_original, ["d";"with-doc"]; ] "Build the package documentation. This only affects packages listed on \ the command-line. This is equivalent to setting $(b,\\$OPAMWITHDOC) \ (or the deprecated $(b,\\$OPAMBUILDDOC)) to \"true\"." in let make = mk_opt ~cli (cli_between cli2_0 cli2_1 ~replaced:"opam config set[-global] make MAKE") ~section ["m";"make"] "MAKE" "Use $(docv) as the default 'make' command. Has no effect if the \ $(i,make) variable is defined." Arg.(some string) None in let show = mk_flag ~cli cli_original ~section ["show-actions"] "Call the solver and display the actions. Don't perform any changes. \ This is equivalent to setting $(b,\\$OPAMSHOW)." in let dryrun = mk_flag ~cli cli_original ~section ["dry-run"] "Simulate the command, but don't actually perform any changes. This also \ can be set with environment variable $(b,\\$OPAMDEBUG)." in let skip_update = mk_flag ~cli cli_original ~section ["skip-updates"] "When running an install, upgrade or reinstall on source-pinned \ packages, they are normally updated from their origin first. This flag \ disables that behaviour and will keep them to their version in cache. \ This is equivalent to setting $(b,\\$OPAMSKIPUPDATE)." in let fake = mk_flag ~cli cli_original ~section ["fake"] "This option registers the actions into the opam database, without \ actually performing them. \ WARNING: This option is dangerous and likely to break your opam \ environment. You probably want $(b,--dry-run). You've been $(i,warned)." in let ignore_constraints_on = mk_opt ~cli cli_original ~section ["ignore-constraints-on"] "PACKAGES" "Forces opam to ignore version constraints on all dependencies to the \ listed packages. This can be used to test compatibility, but expect \ builds to break when using this. Note that version constraints on \ optional dependencies and conflicts are unaffected. This is equivalent \ to setting $(b,\\$OPAMIGNORECONSTRAINTS)." Arg.(some (list package_name)) None ~vopt:(Some []) in let unlock_base = mk_flag_replaced ~cli ~section [ cli_between cli2_0 cli2_1 ~replaced:"--update-invariant", ["unlock-base"]; cli_from cli2_1, ["update-invariant"] ] "Allow changes to the packages set as switch base (typically, the main \ compiler). Use with caution. This is equivalent to setting the \ $(b,\\$OPAMUNLOCKBASE) environment variable" in let locked = locked cli ~section in let lock_suffix = lock_suffix cli ~section in let assume_depexts = mk_flag ~cli (cli_from cli2_1) ~section ["assume-depexts"] "Skip the installation step for any missing system packages, and attempt \ to proceed with compilation of the opam packages anyway. If the \ installation is successful, opam won't prompt again about these system \ packages. Only meaningful if external dependency handling is enabled." in let no_depexts = mk_flag ~cli (cli_from cli2_1) ~section ["no-depexts"] "Temporarily disables handling of external dependencies. This can be \ used if a package is not available on your system package manager, but \ you installed the required dependency by hand. Implies \ $(b,--assume-depexts), and stores the exceptions upon success as well." in Term.(const create_build_options $keep_build_dir $reuse_build_dir $inplace_build $make $no_checksums $req_checksums $build_test $build_doc $show $dryrun $skip_update $fake $jobs_flag cli cli_original $ignore_constraints_on $unlock_base $locked $lock_suffix $assume_depexts $no_depexts) (* Option common to install commands *) let assume_built cli = mk_flag ~cli cli_original ["assume-built"] "For use on locally-pinned packages: assume they have already \ been correctly built, and only run their installation \ instructions, directly from their source directory. This \ skips the build instructions and can be useful to install \ packages that are being worked on. Implies $(i,--inplace-build). \ No locally-pinned packages will be skipped." (* Options common to all path based/related commands, e.g. (un)pin, upgrade, remove, (re)install. Disabled *) let recurse _cli = Term.const false (* mk_flag ~cli (cli_from cli2_2) ["recursive"] "Allow recursive lookups of (b,*.opam) files. Cf. $(i,--subpath) also." *) let subpath _cli = Term.const None (* mk_opt ~cli (cli_from cli2_2) ["subpath"] "PATH" "$(b,*.opam) files are retrieved from the given sub directory instead of \ top directory. Sources are then taken from the targeted sub directory, \ internally only this subdirectory is copied/fetched. It can be combined \ with $(i,--recursive) to have a recursive lookup on the subpath." Arg.(some subpath_conv) None *) let package_selection_section = "PACKAGE SELECTION OPTIONS" let package_selection cli = let section = package_selection_section in let depends_on = mk_opt_all ~cli cli_original ["depends-on"] "PACKAGES" ~section "List only packages that depend on one of (comma-separated) $(b,PACKAGES)." Arg.(list atom) in let required_by = mk_opt_all ~cli cli_original ["required-by"] "PACKAGES" ~section "List only the dependencies of (comma-separated) $(b,PACKAGES)." Arg.(list atom) in let conflicts_with = mk_opt_all ~cli cli_original ["conflicts-with"] "PACKAGES" ~section "List packages that have declared conflicts with at least one of the \ given list. This includes conflicts defined from the packages in the \ list, from the other package, or by a common $(b,conflict-class:) \ field." Arg.(list package_with_version) in let coinstallable_with = mk_opt_all ~cli cli_original ["coinstallable-with"] "PACKAGES" ~section "Only list packages that are compatible with all of $(b,PACKAGES)." Arg.(list package_with_version) in let resolve = mk_opt_all ~cli cli_original ["resolve"] "PACKAGES" ~section "Restrict to a solution to install (comma-separated) $(docv), $(i,i.e.) \ a consistent set of packages including those. This is subtly different \ from `--required-by --recursive`, which is more predictable and can't \ fail, but lists all dependencies independently without ensuring \ consistency. \ Without `--installed`, the answer is self-contained and independent of \ the current installation. With `--installed', it's computed from the \ set of currently installed packages. \ `--no-switch` further makes the solution independent from the \ currently pinned packages, architecture, and compiler version. \ The combination with `--depopts' is not supported." Arg.(list atom) in let recursive = mk_flag ~cli cli_original ["recursive"] ~section "With `--depends-on' and `--required-by', display all transitive \ dependencies rather than just direct dependencies." in let depopts = mk_flag ~cli cli_original ["depopts"] ~section "Include optional dependencies in dependency requests." in let nobuild = mk_flag ~cli cli_original ["nobuild"] ~section "Exclude build dependencies (they are included by default)." in let post = mk_flag ~cli cli_original ["post"] ~section "Include dependencies tagged as $(i,post)." in let dev = mk_flag ~cli cli_original ["dev"] ~section "Include development packages in dependencies." in let doc_flag = mk_flag ~cli cli_original ["doc";"with-doc"] ~section "Include doc-only dependencies." in let test = mk_flag ~cli cli_original ["t";"test";"with-test"] ~section "Include test-only dependencies." in let field_match = mk_opt_all ~cli cli_original ["field-match"] "FIELD:PATTERN" ~section "Filter packages with a match for $(i,PATTERN) on the given $(i,FIELD)" Arg.(pair ~sep:':' string string) in let has_flag = mk_opt_all ~cli cli_original ["has-flag"] "FLAG" ~section ("Only include packages which have the given flag set. \ Package flags are one of: "^ (OpamStd.List.concat_map " " (Printf.sprintf "$(b,%s)" @* string_of_pkg_flag) all_package_flags)) ((fun s -> match pkg_flag_of_string s with | Pkgflag_Unknown s -> `Error ("Invalid package flag "^s^", must be one of "^ OpamStd.List.concat_map " " string_of_pkg_flag all_package_flags) | f -> `Ok f), fun fmt flag -> Format.pp_print_string fmt (string_of_pkg_flag flag)) in let has_tag = mk_opt_all ~cli cli_original ["has-tag"] "TAG" ~section "Only includes packages which have the given tag set" Arg.string in let filter depends_on required_by conflicts_with coinstallable_with resolve recursive depopts nobuild post dev doc_flag test field_match has_flag has_tag = let dependency_toggles = { OpamListCommand. recursive; depopts; build = not nobuild; post; test; doc = doc_flag; dev } in List.map (fun flag -> OpamListCommand.Flag flag) has_flag @ List.map (fun tag -> OpamListCommand.Tag tag) has_tag @ List.map (fun (field,patt) -> OpamListCommand.Pattern ({OpamListCommand.default_pattern_selector with OpamListCommand.fields = [field]}, patt)) field_match @ List.map (fun deps -> OpamListCommand.Depends_on (dependency_toggles, deps)) depends_on @ List.map (fun rdeps -> OpamListCommand.Required_by (dependency_toggles, rdeps)) required_by @ List.map (fun pkgs -> OpamListCommand.Conflicts_with pkgs) conflicts_with @ List.map (fun deps -> OpamListCommand.Solution (dependency_toggles, deps)) resolve @ List.map (fun pkgs -> OpamListCommand.Coinstallable_with (dependency_toggles, pkgs)) coinstallable_with in Term.(const filter $ depends_on $ required_by $ conflicts_with $ coinstallable_with $ resolve $ recursive $ depopts $ nobuild $ post $ dev $ doc_flag $ test $ field_match $ has_flag $ has_tag) let package_listing_section = "OUTPUT FORMAT OPTIONS" let package_listing cli = let section = package_listing_section in let all_versions = mk_flag ~cli cli_original ["all-versions";"V"] ~section "Normally, when multiple versions of a package match, only one is shown \ in the output (the installed one, the pinned-to one, or, failing that, \ the highest one available or the highest one). This flag disables this \ behaviour and shows all matching versions. This also changes the \ default display format to include package versions instead of just \ package names (including when --short is set). This is automatically \ turned on when a single non-pattern package name is provided on the \ command-line." in let print_short = mk_flag ~cli cli_original ["short";"s"] ~section "Don't print a header, and sets the default columns to $(b,name) only. \ If you need package versions included, use $(b,--columns=package) \ instead" in let sort = mk_flag ~cli cli_original ["sort";"S"] ~section "Sort the packages in dependency order (i.e. an order in which they \ could be individually installed.)" in let columns = mk_opt ~cli cli_original ["columns"] "COLUMNS" ~section (Printf.sprintf "Select the columns to display among: %s.\n\ The default is $(b,name) when $(i,--short) is present \ and %s otherwise." (OpamStd.List.concat_map ", " (fun (_,f) -> Printf.sprintf "$(b,%s)" f) OpamListCommand.raw_field_names) (OpamStd.List.concat_map ", " (fun f -> Printf.sprintf "$(b,%s)" (OpamListCommand.string_of_field f)) OpamListCommand.default_list_format)) Arg.(some & opamlist_columns) None in let normalise = mk_flag ~cli cli_original ["normalise"] ~section "Print the values of opam fields normalised" in let wrap = mk_flag ~cli cli_original ["wrap"] ~section "Wrap long lines, the default being to truncate when displaying on a \ terminal, or to keep as is otherwise" in let separator = mk_opt ~cli cli_original ["separator"] "STRING" ~section "Set the column-separator string" Arg.string " " in let format all_versions short sort columns normalise wrap separator = fun ~force_all_versions -> let all_versions = force_all_versions || all_versions in let columns = match columns with | Some c -> c | None -> let cols = if short then [OpamListCommand.Name] else OpamListCommand.default_list_format in if all_versions then List.map (function | OpamListCommand.Name -> OpamListCommand.Package | c -> c) cols else cols in { OpamListCommand. short; header = not short; columns; all_versions; wrap = if wrap then Some (`Wrap "\\ ") else Some `Truncate; separator; value_printer = if normalise then `Normalised else `Normal; order = if sort then `Dependency else `Standard; } in Term.(const format $ all_versions $ print_short $ sort $ columns $ normalise $ wrap $ separator) opam-2.1.5/src/client/opamLockCommand.mli0000644000175000017500000000243714427463453017341 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Functions handling the "opam lock" command *) open OpamTypes open OpamStateTypes (** Select packages to lock. If a package have at least one of its direct dependencies not installed in the switch, it is dropped. Returns the state with non present packages pinned, and kept packages. *) val select_packages: [ `Atom of atom | `Filename of filename | `Dirname of dirname ] list -> 'a switch_state -> 'a switch_state * package_set (** Returns the locked opam file, according its depends, depopts, and pins. *) val lock_opam: ?only_direct:bool -> 'a switch_state -> OpamFile.OPAM.t -> OpamFile.OPAM.t opam-2.1.5/src/client/opamSwitchCommand.ml0000644000175000017500000007102414427463453017537 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamStateTypes open OpamPackage.Set.Op open OpamStd.Op [@@@ocaml.warning "-33"] open OpamBase64Compat module S = OpamFile.SwitchSelections let log fmt = OpamConsole.log "SWITCH" fmt let slog = OpamConsole.slog let list gt ~print_short = log "list"; let gt = OpamGlobalState.fix_switch_list gt in if print_short then List.iter (OpamConsole.msg "%s\n" @* OpamSwitch.to_string) (List.sort compare (OpamFile.Config.installed_switches gt.config)) else let installed_switches = OpamGlobalState.fold_switches (fun sw sel acc -> let opams = OpamPackage.Set.fold (fun nv acc -> match OpamFile.OPAM.read_opt (OpamPath.Switch.installed_opam gt.root sw nv) with | Some opam -> OpamPackage.Map.add nv opam acc | None -> acc) sel.sel_compiler OpamPackage.Map.empty in let ifempty default m = if OpamPackage.Map.is_empty m then default else m in let comp = OpamPackage.Map.filter (fun nv _ -> OpamPackage.Set.mem nv sel.sel_roots) opams |> ifempty opams in let comp = OpamPackage.Map.filter (fun _ opam -> OpamFile.OPAM.has_flag Pkgflag_Compiler opam) comp |> ifempty comp in let conf = OpamStateConfig.Switch.read_opt ~lock_kind:`Lock_read gt sw in let descr = match conf with | Some c -> c.OpamFile.Switch_config.synopsis | None -> OpamConsole.colorise `red "Missing config file" in OpamSwitch.Map.add sw (OpamPackage.keys comp, descr) acc) gt OpamSwitch.Map.empty in let list = OpamSwitch.Map.bindings installed_switches in let table = List.map (OpamConsole.colorise `blue) ["#"; "switch"; "compiler"; "description" ] :: List.map (fun (switch, (packages, descr)) -> let current = Some switch = OpamStateConfig.get_switch_opt () in List.map (if current then OpamConsole.colorise `bold else fun s -> s) [ if current then OpamConsole.(utf8_symbol Symbols.rightwards_arrow "->") else ""; OpamSwitch.to_string switch; OpamStd.List.concat_map "," (OpamConsole.colorise `yellow @* OpamPackage.to_string) (OpamPackage.Set.elements packages); descr ]) list in OpamConsole.print_table stdout ~sep:" " (OpamStd.Format.align_table table); match OpamStateConfig.get_switch_opt (), OpamStateConfig.(!r.switch_from) with | None, _ when OpamFile.Config.installed_switches gt.config <> [] -> OpamConsole.note "No switch is currently set, you should use 'opam switch ' \ to set an active switch" | Some switch, `Env -> let sys = OpamFile.Config.switch gt.config in if not (OpamGlobalState.switch_exists gt switch) then (OpamConsole.msg "\n"; OpamConsole.warning "The OPAMSWITCH variable does not point to a valid switch: %S" (OpamSwitch.to_string switch)) else if sys <> Some switch then (OpamConsole.msg "\n"; OpamConsole.note "Current switch is set locally through the OPAMSWITCH variable.\n\ The current global system switch is %s." (OpamStd.Option.to_string ~none:"unset" (fun s -> OpamConsole.colorise `bold (OpamSwitch.to_string s)) sys)) else (match OpamStateConfig.get_current_switch_from_cwd gt.root with | None -> () | Some sw -> OpamConsole.msg "\n"; OpamConsole.note "Current switch is set globally and through the OPAMSWITCH variable.\n\ Thus, the local switch found at %s was ignored." (OpamConsole.colorise `bold (OpamSwitch.to_string sw))) | Some switch, `Default when not (OpamGlobalState.switch_exists gt switch) -> OpamConsole.msg "\n"; OpamConsole.warning "The currently selected switch (%S) is invalid.\n%s" (OpamSwitch.to_string switch) (if OpamSwitch.is_external switch then "Stale '_opam' directory or link ?" else "Fix the selection with 'opam switch set SWITCH'.") | Some switch, `Default when OpamSwitch.is_external switch -> OpamConsole.msg "\n"; OpamConsole.note "Current switch has been selected based on the current directory.\n\ The current global system switch is %s." (OpamStd.Option.to_string ~none:"unset" (fun s -> OpamConsole.colorise `bold (OpamSwitch.to_string s)) (OpamFile.Config.switch gt.config)); if not (OpamEnv.is_up_to_date_switch gt.root switch) then OpamConsole.warning "The environment is not in sync with the current switch.\n\ You should run: %s" (OpamEnv.eval_string gt (Some switch)) | Some switch, `Default -> if not (OpamEnv.is_up_to_date_switch gt.root switch) then (OpamConsole.msg "\n"; OpamConsole.warning "The environment is not in sync with the current switch.\n\ You should run: %s" (OpamEnv.eval_string gt (Some switch))) | _ -> () let clear_switch ?(keep_debug=false) (gt: rw global_state) switch = let module C = OpamFile.Config in let config = gt.config in let config = C.with_installed_switches (List.filter ((<>) switch) (C.installed_switches config)) config in let config = if C.switch config = Some switch then C.with_switch_opt None config else config in let gt = { gt with config } in OpamGlobalState.write gt; let comp_dir = OpamPath.Switch.root gt.root switch in if keep_debug && (OpamClientConfig.(!r.keep_build_dir) || (OpamConsole.debug ())) then (OpamConsole.note "Keeping %s despite errors (debug mode), \ you may want to remove it by hand" (OpamFilename.Dir.to_string comp_dir); gt) else try OpamFilename.rmdir comp_dir; gt with OpamSystem.Internal_error _ -> gt let remove gt ?(confirm = true) switch = log "remove switch=%a" (slog OpamSwitch.to_string) switch; if not (OpamGlobalState.switch_exists gt switch) then ( OpamConsole.msg "The compiler switch %s does not exist.\n" (OpamSwitch.to_string switch); OpamStd.Sys.exit_because `Not_found; ); if not confirm || OpamConsole.confirm "Switch %s and all its packages will be wiped. Are you sure?" (OpamSwitch.to_string switch) then clear_switch gt switch else gt let set_invariant_raw st invariant = let switch_config = {st.switch_config with invariant = Some invariant} in let st = {st with switch_invariant = invariant; switch_config } in if not (OpamStateConfig.(!r.dryrun) || OpamClientConfig.(!r.show)) then OpamSwitchAction.install_switch_config st.switch_global.root st.switch switch_config; st let install_compiler ?(additional_installs=[]) ?(deps_only=false) ?(ask=false) t = let invariant = t.switch_invariant in if invariant = OpamFormula.Empty && additional_installs = [] then begin (if not OpamClientConfig.(!r.show) && not OpamStateConfig.(!r.dryrun) then OpamFile.Environment.write (OpamPath.Switch.environment t.switch_global.root t.switch) (OpamEnv.compute_updates t); OpamEnv.check_and_print_env_warning t); t end else let () = OpamRepositoryState.check_last_update () in let atoms = OpamFormula.atoms invariant in let names_of_atoms at = OpamPackage.Name.Set.of_list (List.map fst at) in let comp_roots = names_of_atoms atoms in let add_names = names_of_atoms additional_installs in let roots = OpamPackage.Name.Set.union comp_roots add_names in OpamConsole.header_msg "Installing new switch packages"; OpamConsole.msg "Switch invariant: %s\n" (OpamFileTools.dep_formula_to_string invariant); let solution = OpamSolution.resolve t Switch ~orphans:OpamPackage.Set.empty ~requested:roots (OpamSolver.request ~install:additional_installs ()) in let solution = match solution with | Success s -> s | Conflicts cs -> OpamConsole.error "Could not determine which packages to install for this switch:"; OpamConsole.errmsg "%s\n" (OpamCudf.string_of_conflicts t.packages (OpamSwitchState.unavailable_reason t) cs); OpamStd.Sys.exit_because `No_solution in let () = match OpamSolver.stats solution with | { s_install = _; s_reinstall = 0; s_upgrade = 0; s_downgrade=0; s_remove = 0 } -> () | stats -> OpamConsole.error_and_exit `No_solution "Inconsistent resolution of packages:\n%s" (OpamSolver.string_of_stats stats) in let to_install_pkgs = OpamSolver.new_packages solution in let base_comp = OpamPackage.packages_of_names to_install_pkgs comp_roots in let has_comp_flag = let is_comp nv = try OpamFile.OPAM.has_flag Pkgflag_Compiler (OpamSwitchState.opam t nv) with Not_found -> false in (* Packages with the Compiler flag, or with a direct dependency with that flag (just for the warning) *) OpamPackage.Set.filter (fun nv -> is_comp nv || OpamPackage.Set.exists is_comp (OpamFormula.packages t.packages (OpamPackageVar.all_depends ~filter_default:true t (OpamSwitchState.opam t nv)))) base_comp in if invariant = OpamFormula.Empty then OpamConsole.note "No invariant was set, you may want to use `opam switch set-invariant' \ to keep a stable compiler version on upgrades." else if OpamPackage.Set.is_empty has_comp_flag then OpamConsole.note "Packages %s don't have the 'compiler' flag set (nor any of their \ direct dependencies).\n\ You may want to use `opam switch set-invariant' to keep a stable \ compiler version on upgrades." (OpamStd.List.concat_map ", " OpamPackage.to_string (OpamPackage.Set.elements base_comp)); let t = if t.switch_config.OpamFile.Switch_config.synopsis = "" then let synopsis = match OpamPackage.Set.elements base_comp with | [] -> OpamSwitch.to_string t.switch | [pkg] -> let open OpamStd.Option.Op in (OpamSwitchState.opam_opt t pkg >>= OpamFile.OPAM.synopsis) +! OpamPackage.to_string pkg | pkgs -> OpamStd.List.concat_map " " OpamPackage.to_string pkgs in let switch_config = { t.switch_config with OpamFile.Switch_config.synopsis } in if not (OpamStateConfig.(!r.dryrun) || OpamClientConfig.(!r.show)) then OpamSwitchAction.install_switch_config t.switch_global.root t.switch switch_config; { t with switch_config } else t in let t = { t with compiler_packages = base_comp } in let solution = if deps_only then OpamSolver.filter_solution (fun nv -> not (OpamPackage.Name.Set.mem nv.name add_names)) solution else solution in let t, result = OpamSolution.apply t ~ask:(OpamClientConfig.(!r.show) || ask) ~requested:roots ~add_roots:roots solution in OpamSolution.check_solution ~quiet:OpamClientConfig.(not !r.show) t (Success result); t let create gt ~rt ?synopsis ?repos ~update_config ~invariant switch post = let update_config = update_config && not (OpamSwitch.is_external switch) in let comp_dir = OpamPath.Switch.root gt.root switch in let simulate = OpamStateConfig.(!r.dryrun) || OpamClientConfig.(!r.show) in if OpamGlobalState.switch_exists gt switch then OpamConsole.error_and_exit `Bad_arguments "There already is an installed switch named %s" (OpamSwitch.to_string switch); if Sys.file_exists (OpamFilename.Dir.to_string comp_dir) then OpamConsole.error_and_exit `Bad_arguments "Directory %S already exists, please choose a different name" (OpamFilename.Dir.to_string comp_dir); let gt, st = if not simulate then let gt = OpamSwitchAction.create_empty_switch gt ?synopsis ?repos ~invariant switch in let rt = ({ rt with repos_global = (gt :> unlocked global_state) } :> unlocked repos_state) in gt, OpamSwitchState.load `Lock_write gt rt switch else let rt = (rt :> unlocked repos_state) in let st = OpamSwitchState.load_virtual ?repos_list:repos gt rt in let switch_config = OpamSwitchAction.gen_switch_config gt.root ?repos switch ~invariant in let st = { st with switch_invariant = invariant } in let available_packages = lazy (OpamSwitchState.compute_available_packages gt switch switch_config ~pinned:OpamPackage.Set.empty ~opams:st.opams) in gt, { st with switch; switch_config; available_packages } in match post st with | ret, st -> let st = if update_config && not simulate then OpamSwitchAction.set_current_switch gt st else st in OpamGlobalState.drop gt; ret, st | exception e when not simulate -> let () = try OpamStd.Exn.fatal e with e -> OpamStd.Exn.finalise e @@ fun () -> OpamConsole.warning "Switch %s left partially installed" (OpamSwitch.to_string st.switch) in OpamStd.Exn.finalise e @@ fun () -> let gt, st = if OpamConsole.confirm "Switch initialisation failed: clean up? \ ('n' will leave the switch partially installed)" then clear_switch gt st.switch, st else if update_config && not simulate then gt, OpamSwitchAction.set_current_switch gt st else gt, st in OpamSwitchState.drop st; OpamGlobalState.drop gt let switch lock gt switch = log "switch switch=%a" (slog OpamSwitch.to_string) switch; if OpamGlobalState.switch_exists gt switch then OpamRepositoryState.with_ `Lock_none gt @@ fun rt -> let st = OpamSwitchState.load lock gt rt switch in let st = if OpamStateConfig.(!r.dryrun) || OpamClientConfig.(!r.show) then st else OpamSwitchAction.set_current_switch gt st in OpamEnv.check_and_print_env_warning st else let installed_switches = OpamFile.Config.installed_switches gt.config in OpamConsole.error_and_exit `Not_found "No switch %s is currently installed. Did you mean \ 'opam switch create %s'?\n\ Installed switches are:\n%s" (OpamSwitch.to_string switch) (OpamSwitch.to_string switch) (OpamStd.Format.itemize OpamSwitch.to_string installed_switches) let import_t ?ask importfile t = log "import switch"; let extra_files = importfile.OpamFile.SwitchExport.extra_files in let xfiles_dir = OpamPath.Switch.extra_files_dir t.switch_global.root t.switch in OpamHash.Map.iter (fun hash content -> let value = Base64.decode_exn content in let my = OpamHash.compute_from_string ~kind:(OpamHash.kind hash) value in if OpamHash.contents my = OpamHash.contents hash then let dst = let base = OpamFilename.Base.of_string (OpamHash.contents hash) in OpamFilename.create xfiles_dir base in OpamFilename.write dst value else failwith "Bad hash for inline extra-files") extra_files; let import_sel = importfile.OpamFile.SwitchExport.selections in let import_opams = importfile.OpamFile.SwitchExport.overlays in let opams = OpamPackage.Name.Map.fold (fun name opam opams -> let nv = OpamPackage.create name (OpamFile.OPAM.version opam) in OpamPackage.Map.add nv opam opams) import_opams t.opams in let packages = t.packages ++ OpamPackage.keys opams in let pinned = let names = OpamPackage.names_of_packages import_sel.sel_pinned in OpamPackage.Set.filter (fun nv -> not (OpamPackage.Name.Set.mem nv.name names)) t.pinned ++ import_sel.sel_pinned in let available = OpamSwitchState.compute_available_packages t.switch_global t.switch t.switch_config ~pinned ~opams in let compiler_packages, to_install = if OpamPackage.Set.is_empty t.compiler_packages then import_sel.sel_compiler %% available, import_sel.sel_installed else t.compiler_packages, import_sel.sel_installed -- import_sel.sel_compiler in let t = { t with available_packages = lazy available; packages; compiler_packages; pinned; opams; } in let unavailable_version, unavailable = let available_names = OpamPackage.names_of_packages available in OpamPackage.Set.partition (fun nv -> OpamPackage.Name.Set.mem nv.name available_names) (to_install -- available) in if not (OpamPackage.Set.is_empty unavailable_version) then OpamConsole.warning "These packages aren't available at the specified versions, \ version constraints have been discarded:\n%s" (OpamStd.Format.itemize OpamPackage.to_string (OpamPackage.Set.elements unavailable_version)); if not (OpamPackage.Set.is_empty unavailable) then OpamConsole.warning "These packages are unavailable, they have been ignored from \ the import file:\n%s" (OpamStd.Format.itemize OpamPackage.to_string (OpamPackage.Set.elements unavailable)); let t, solution = let to_import = OpamSolution.eq_atoms_of_packages (to_install %% available) @ OpamSolution.atoms_of_packages unavailable_version in let add_roots = OpamPackage.names_of_packages import_sel.sel_roots in OpamSolution.resolve_and_apply ?ask t Import ~requested:(OpamPackage.Name.Set.of_list @@ List.map fst to_import) ~add_roots ~orphans:OpamPackage.Set.empty { wish_install = to_import; wish_remove = []; wish_upgrade = []; criteria = `Default; extra_attributes = []; } in OpamSolution.check_solution t solution; OpamFilename.rmdir xfiles_dir; if not (OpamStateConfig.(!r.dryrun) || OpamClientConfig.(!r.show)) then begin (* Put imported overlays in place *) OpamPackage.Set.iter (fun nv -> match OpamPackage.Name.Map.find_opt nv.name import_opams with | None -> () | Some opam -> OpamFilename.rmdir (OpamPath.Switch.Overlay.package t.switch_global.root t.switch nv.name); OpamFile.OPAM.write (OpamPath.Switch.Overlay.opam t.switch_global.root t.switch nv.name) opam) pinned; (* Save new pinnings *) let sel = OpamSwitchState.load_selections t.switch_global t.switch in S.write (OpamPath.Switch.selections t.switch_global.root t.switch) { sel with sel_pinned = pinned } end; t let freeze_opam src_dir nv opam = match OpamFile.OPAM.url opam with | None -> opam | Some url -> let url_t = OpamFile.URL.url url in match url_t.backend with | #OpamUrl.version_control -> (match OpamProcess.Job.run (OpamRepository.revision (src_dir nv) url_t) with | None -> OpamConsole.error_and_exit `Not_found "Unable to retrieve %s url revision: %s, \ it can't be exported with --freeze." (OpamPackage.to_string nv) (OpamUrl.to_string url_t) | Some hash -> OpamFile.OPAM.with_url (OpamFile.URL.with_url { url_t with hash = Some (OpamPackage.Version.to_string hash) } url) opam) | `http -> (match OpamFile.URL.checksum url with | [] -> OpamConsole.error_and_exit `Not_found "%s url doesn't have an associated checksum, \ it can't be exported with --freeze." (OpamPackage.Name.to_string nv.name) | _ -> opam) | `rsync -> OpamConsole.error_and_exit `Not_found "%s is path pinned, it can't be exported with --freeze." (OpamPackage.Name.to_string nv.name) let export rt ?(freeze=false) ?(full=false) ?(switch=OpamStateConfig.get_switch ()) filename = let root = OpamStateConfig.(!r.root_dir) in let export = OpamFilename.with_flock `Lock_none (OpamPath.Switch.lock root switch) @@ fun _ -> let selections = OpamStateConfig.Switch.safe_read_selections ~lock_kind:`Lock_none rt.repos_global switch in let opams = let read_opams read pkgs = let src_dir nv = if OpamPackage.Set.mem nv selections.sel_pinned then OpamPath.Switch.pinned_package root switch nv.name else OpamPath.Switch.sources root switch nv in OpamPackage.Set.fold (fun nv map -> match read nv with | Some opam -> let opam = if not freeze then opam else freeze_opam src_dir nv opam in OpamPackage.Map.add nv opam map | None -> map) pkgs OpamPackage.Map.empty in let overlays = read_opams (fun nv -> OpamFileTools.read_opam (OpamPath.Switch.Overlay.package root switch nv.name)) selections.sel_pinned in if not full then overlays else OpamPackage.Map.union (fun a _ -> a) overlays @@ read_opams (fun nv -> OpamFile.OPAM.read_opt (OpamPath.Switch.installed_opam root switch nv)) (selections.sel_installed -- selections.sel_pinned) in let overlays = OpamPackage.Map.fold (fun nv opam nmap -> OpamPackage.Name.Map.add nv.name opam nmap) opams OpamPackage.Name.Map.empty in let extra_files = let repos_roots = OpamRepositoryState.get_root rt in OpamPackage.Map.fold (fun nv opam hmap -> match OpamFile.OPAM.get_extra_files ~repos_roots opam with | [] -> hmap | files -> let hmap, err = List.fold_left (fun (hmap,err) (file, base, hash) -> if OpamFilename.exists file && OpamHash.check_file (OpamFilename.to_string file) hash then let value = Base64.encode_string (OpamFilename.read file) in OpamHash.Map.add hash value hmap, err else hmap, base::err) (hmap,[]) files in if err <> [] then OpamConsole.warning "Invalid hash%s, ignoring package %s extra-file%s: %s" (match err with | [_] -> "" | _ -> "es") (OpamPackage.to_string nv) (match err with | [_] -> "" | _ -> "s") (OpamStd.Format.pretty_list (List.map OpamFilename.Base.to_string err)); hmap) opams OpamHash.Map.empty in { OpamFile.SwitchExport.selections; extra_files; overlays } in match filename with | None -> OpamFile.SwitchExport.write_to_channel stdout export | Some f -> OpamFile.SwitchExport.write f export let show () = OpamConsole.msg "%s\n" (OpamSwitch.to_string (OpamStateConfig.get_switch ())) let reinstall init_st = let switch = init_st.switch in log "reinstall switch=%a" (slog OpamSwitch.to_string) switch; let gt = init_st.switch_global in let switch_root = OpamPath.Switch.root gt.root switch in let opam_subdir = OpamPath.Switch.meta gt.root switch in let pkg_dirs = List.filter ((<>) opam_subdir) (OpamFilename.dirs switch_root) in List.iter OpamFilename.cleandir pkg_dirs; List.iter OpamFilename.remove (OpamFilename.files switch_root); OpamFilename.cleandir (OpamPath.Switch.config_dir gt.root switch); OpamFilename.cleandir (OpamPath.Switch.installed_opams gt.root switch); let st = { init_st with installed = OpamPackage.Set.empty; installed_roots = OpamPackage.Set.empty; reinstall = lazy OpamPackage.Set.empty; } in import_t { OpamFile.SwitchExport. selections = OpamSwitchState.selections init_st; extra_files = OpamHash.Map.empty; overlays = OpamPackage.Name.Map.empty; } st let import st filename = let import_str = match filename with | None -> OpamSystem.string_of_channel stdin | Some f -> OpamFilename.read (OpamFile.filename f) in let importfile = try OpamFile.SwitchExport.read_from_string ?filename import_str with OpamPp.Bad_format _ as e -> log "Error loading export file, trying the old file format"; try let selections = OpamFile.LegacyState.read_from_string import_str in { OpamFile.SwitchExport.selections; extra_files = OpamHash.Map.empty; overlays = OpamPackage.Name.Map.empty } with e1 -> OpamStd.Exn.fatal e1; raise e in import_t importfile st let set_invariant ?(force=false) st invariant = let satisfied = OpamFormula.satisfies_depends st.installed invariant in let names = OpamPackage.Name.Set.of_list (List.map fst (OpamFormula.atoms invariant)) in let name_unknown = OpamPackage.Name.Set.filter (fun n -> not (OpamPackage.has_name st.packages n)) names in if not (OpamPackage.Name.Set.is_empty name_unknown) then (if satisfied || force then OpamConsole.warning else OpamConsole.error_and_exit `Not_found) "No packages by these names found: %s" (OpamStd.List.concat_map ", " OpamPackage.Name.to_string (OpamPackage.Name.Set.elements name_unknown)); let packages = OpamFormula.packages st.installed invariant in let not_comp = OpamPackage.Set.filter (fun nv -> match OpamSwitchState.opam_opt st nv with | Some opam -> not (OpamFile.OPAM.has_flag Pkgflag_Compiler opam) | None -> false) packages in if not (OpamPackage.Set.is_empty not_comp) then OpamConsole.warning "Packages %s don't have the 'compiler' flag set." (OpamStd.Format.pretty_list (List.map OpamPackage.Name.to_string (OpamPackage.Name.Set.elements (OpamPackage.names_of_packages not_comp)))); set_invariant_raw st invariant let get_compiler_packages ?repos rt = let repos = match repos with | None -> OpamGlobalState.repos_list rt.repos_global | Some r -> r in let package_index = OpamRepositoryState.build_index rt repos in OpamPackage.Map.filter (fun _ opam -> OpamFile.OPAM.has_flag Pkgflag_Compiler opam && OpamFilter.eval_to_bool ~default:false (OpamPackageVar.resolve_global rt.repos_global) (OpamFile.OPAM.available opam)) package_index |> OpamPackage.keys let guess_compiler_invariant ?repos rt strings = let repos = match repos with | None -> OpamGlobalState.repos_list rt.repos_global | Some r -> r in let opams = OpamRepositoryState.build_index rt repos in let packages = OpamPackage.keys opams in let compiler_packages = OpamPackage.Map.filter (fun _ -> OpamFile.OPAM.has_flag Pkgflag_Compiler) opams |> OpamPackage.keys in let invariant = List.fold_left (fun acc str -> try let (name, _) as atom = OpamFormula.atom_of_string str in if OpamPackage.Set.exists (OpamFormula.check atom) (OpamPackage.packages_of_name packages name) then OpamFormula.ands [acc; Atom atom] else raise Not_found with Failure _ | Not_found -> try let v = OpamPackage.Version.of_string str in let candidates = OpamPackage.Set.filter (fun nv -> nv.version = v) compiler_packages in if OpamPackage.Set.is_empty candidates then raise Not_found else let disj = OpamPackage.Set.fold (fun nv acc -> OpamFormula.ors [acc; Atom (OpamSolution.eq_atom_of_package nv)]) candidates OpamFormula.Empty in OpamFormula.ands [acc; disj] with | Failure _ -> OpamConsole.error_and_exit `Bad_arguments "Invalid package specification or version %S" str | Not_found -> OpamConsole.error_and_exit `Not_found "No compiler matching `%s' found, use `opam switch list-available' \ to see what is available, or use `--packages' to select packages \ explicitly." str) OpamFormula.Empty strings in OpamFormula.of_atom_formula invariant opam-2.1.5/src/client/opamArgTools.mli0000644000175000017500000000777714427463453016720 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2021 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** CLI version helpers *) (* Defines Cmdliner optional argument function-helpers, with the cli version. *) open Cmdliner type validity val cli_from: OpamCLIVersion.t -> validity val cli_between: OpamCLIVersion.t -> ?default:bool -> ?replaced:string -> OpamCLIVersion.t -> validity val cli_original: validity val cli2_0: OpamCLIVersion.t val cli2_1: OpamCLIVersion.t val mk_flag: cli:OpamCLIVersion.Sourced.t -> validity -> ?section:string -> string list -> string -> bool Term.t val mk_flag_replaced: cli:OpamCLIVersion.Sourced.t -> ?section:string -> (validity * string list) list -> string -> bool Term.t val mk_opt: cli:OpamCLIVersion.Sourced.t -> validity -> ?section:string -> ?vopt:'a -> string list -> string -> string -> 'a Arg.converter -> 'a -> 'a Term.t val mk_opt_all: cli:OpamCLIVersion.Sourced.t -> validity -> ?section:string -> ?vopt:'a -> ?default:'a list -> string list -> string -> string -> 'a Arg.converter -> 'a list Term.t val mk_vflag: cli:OpamCLIVersion.Sourced.t -> ?section:string -> 'a -> (validity * 'a * string list * string) list -> 'a Term.t val mk_vflag_all: cli:OpamCLIVersion.Sourced.t -> ?section:string -> ?default:'a list -> (validity * 'a * string list * string) list -> 'a list Term.t val mk_enum_opt: cli:OpamCLIVersion.Sourced.t -> validity -> ?section:string -> string list -> string -> (validity * string * 'a) list -> string -> 'a option Term.t (** [opt_all] with enums. Check each flag content cli, purge non corresponding ones from the final result. If after purge the resulting list is empty (all removed or newer flag contents), it raises an error ; otherwise only display warnings on wrong cli contents. *) val mk_enum_opt_all: cli:OpamCLIVersion.Sourced.t -> validity -> ?section:string -> string list -> string -> (validity * string * 'a) list -> string -> 'a list Term.t val string_of_enum: (validity * string * 'a) list -> string type 'a subcommand = validity * string * 'a * string list * string type 'a subcommands = 'a subcommand list val mk_subcommands: cli:OpamCLIVersion.Sourced.t -> 'a subcommands -> 'a option Term.t * string list Term.t type 'a default = [> `default of string] as 'a val mk_subcommands_with_default: cli:OpamCLIVersion.Sourced.t -> 'a default subcommands -> 'a option Term.t * string list Term.t val bad_subcommand: cli:OpamCLIVersion.Sourced.t -> 'a default subcommands -> (string * 'a option * string list) -> 'b Term.ret val mk_subdoc : cli:OpamCLIVersion.Sourced.t -> ?defaults:(string * string) list -> 'a subcommands -> Manpage.block list type command = unit Term.t * Term.info val mk_command: cli:OpamCLIVersion.Sourced.t -> validity -> (cli:OpamCLIVersion.Sourced.t -> string -> doc:string -> man:Manpage.block list -> Term.info) -> string -> doc:string -> man:Manpage.block list -> (unit -> unit) Term.t -> command val mk_command_ret: cli:OpamCLIVersion.Sourced.t -> validity -> (cli:OpamCLIVersion.Sourced.t -> string -> doc:string -> man:Manpage.block list -> Term.info) -> string -> doc:string -> man:Manpage.block list -> (unit -> unit Term.ret) Term.t -> command val env_with_cli: (string * validity * (string -> OpamStd.Config.E.t) * string) list -> (OpamCLIVersion.Sourced.t -> Manpage.block list) * (OpamCLIVersion.Sourced.t -> unit) val is_original_cli: validity -> bool opam-2.1.5/src/client/opamCLIVersion.ml0000644000175000017500000000503214427463453016750 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2020 David Allsopp Ltd. *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCompat type t = int * int let supported_versions = [(2, 0); (2, 1)] let is_supported v = List.mem v supported_versions let of_string s = match String.index s '.' with | i when s.[0] <> '0' && (i >= String.length s - 2 || s.[i + 1] <> '0') -> begin try Scanf.sscanf s "%u.%u%!" (fun major minor -> (major, minor)) with Scanf.Scan_failure _ -> failwith "OpamVersion.CLI.of_string" end | exception Not_found -> failwith "OpamVersion.CLI.of_string" | _ -> failwith "OpamVersion.CLI.of_string" let current = of_string @@ OpamVersion.(to_string current_nopatch) (* This line is checked on CI to ensure that default cli version matches release opam version *) let default = (2,0) let of_string_opt s = try Some (of_string s) with Failure _ -> None let to_string (major, minor) = Printf.sprintf "%d.%d" major minor let to_json v = `String (to_string v) let of_json = function | `String x -> of_string_opt x | _ -> None let ( >= ) = Stdlib.( >= ) let ( < ) = Stdlib.( < ) let compare = Stdlib.compare let previous cli = let f previous version = if version > previous && cli > version then version else previous in let zero = (0, 0) in let previous = List.fold_left f zero supported_versions in if previous = zero then raise Not_found else previous (* CLI version extended with provenance *) module Sourced = struct type nonrec t = t * OpamStateTypes.provenance let current = current, `Default let env s = OpamStd.Option.Op.(s >>= of_string_opt >>| (fun c -> c, `Env)) end module Op = struct let ( @>= ) (c,_) = Stdlib.( >= ) c let ( @< ) (c,_) = Stdlib.( < ) c let ( @= ) (c,_) = Stdlib.( = ) c end module O = struct type nonrec t = t let to_string = to_string let to_json = to_json let of_json = of_json let compare = compare end module Set = OpamStd.Set.Make(O) module Map = OpamStd.Map.Make(O) opam-2.1.5/src/client/opamGitVersion.mli0000644000175000017500000000167414427463453017245 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2014-2016 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** (generated) Current git version of OPAM *) (** This is defined only at the client lib level to avoid triggering full recompilations all the time *) val version: string option opam-2.1.5/src/client/opamLockCommand.ml0000644000175000017500000002612414427463453017167 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes let select_packages atom_locs st = let st, atoms = OpamAuxCommands.simulate_autopin ~quiet:true ~for_view:true st atom_locs in let packages = OpamFormula.packages_of_atoms OpamPackage.Set.Op.(st.packages ++ st.installed) atoms in if OpamPackage.Set.is_empty packages then OpamConsole.error_and_exit `Not_found "No package matching %s" (OpamFormula.string_of_atoms atoms) else (let names = OpamPackage.names_of_packages packages in let missing = OpamStd.List.filter_map (fun (n,vc) -> if OpamPackage.Name.Set.mem n names then None else Some (n,vc)) atoms in if missing <> [] then OpamConsole.error "No package matching %s" (OpamFormula.string_of_atoms missing); (* we keep only one version of each package, the pinned or installed one, the latest version otherwise ; and the one that have their dependencies \ installed *) let packages = OpamPackage.Name.Set.fold (fun name acc -> let pkgs = OpamPackage.packages_of_name packages name in let pkg, is_pinned = let open OpamPackage.Set.Op in let pinned = pkgs %% st.pinned in if OpamPackage.Set.is_empty pinned then pkgs %% st.installed, false else pinned, true in let nv = match OpamPackage.Set.elements pkg with | [nv] -> nv | _ -> (let nv = OpamPackage.Set.max_elt pkgs in OpamConsole.note "Package %s is not installed nor pinned, generating lock \ file for its latest version %s" (OpamConsole.colorise `underline (OpamPackage.Name.to_string name)) (OpamConsole.colorise `underline (OpamPackage.version_to_string nv)); nv) in let opam = if is_pinned then let open OpamStd.Option.Op in match OpamSwitchState.opam st nv |> OpamFile.OPAM.url >>| OpamFile.URL.url >>= OpamUrl.local_dir >>= OpamPinned.find_opam_file_in_source name >>| OpamFile.OPAM.read with | Some opam -> (* we add the name/version because of an [OpamFile.OPAM.package] in all depends *) let opam = if OpamFile.OPAM.name_opt opam = None then OpamFile.OPAM.with_name name opam else opam in if OpamFile.OPAM.version_opt opam = None then OpamFile.OPAM.with_version (OpamPackage.version nv) opam else opam | None -> OpamSwitchState.opam st nv else OpamSwitchState.opam st nv in let atoms = OpamFormula.atoms (OpamPackageVar.all_depends ~depopts:false st opam) in let missing = List.filter (fun (n,vc) -> let pkgs = (OpamPackage.packages_of_name st.installed n) in OpamPackage.Set.is_empty pkgs || OpamPackage.Set.fold (fun nv satisf -> satisf || not (OpamFormula.check (n,vc) nv)) pkgs false) atoms in if missing <> [] then (OpamConsole.error "Skipping %s, dependencies are not satisfied in this switch, \ not installed packages are:\n%s" (OpamPackage.to_string nv) (OpamStd.Format.itemize OpamFormula.string_of_atom missing); acc) else OpamPackage.Set.add nv acc) names OpamPackage.Set.empty in st, packages) let get_git_url url nv dir = let module VCS = (val OpamRepository.find_backend_by_kind url.OpamUrl.backend) in let open OpamProcess.Job.Op in OpamProcess.Job.run @@ VCS.get_remote_url ?hash:url.OpamUrl.hash dir @@| function | Some u -> (if u.OpamUrl.hash = None then OpamConsole.warning "Referenced git branch for %s is not available in remote: %s, \ use default branch instead." (OpamConsole.colorise `underline (OpamPackage.to_string nv)) (OpamUrl.to_string u); Some u) | _ -> (OpamConsole.error "Can't retrieve remote informations for %s" (OpamPackage.to_string nv); None) let lock_opam ?(only_direct=false) st opam = let nv = OpamFile.OPAM.package opam in let univ = OpamSwitchState.universe st ~requested:(OpamPackage.Name.Set.singleton nv.name) Query in (* Depends *) let all_depends = OpamSolver.dependencies ~depopts:true ~build:true ~post:true ~installed:true univ (OpamPackage.Set.singleton nv) |> OpamPackage.Set.remove nv in let depends = if only_direct then let names = OpamFilter.filter_formula ~default:true (fun _ -> None) (OpamFile.OPAM.depends opam) |> OpamFormula.fold_left (fun acc (n,_) -> OpamPackage.Name.Set.add n acc) OpamPackage.Name.Set.empty in OpamPackage.packages_of_names all_depends names else all_depends in let map_of_set x set = OpamPackage.Map.of_list (List.map (fun nv -> nv, x) (OpamPackage.Set.elements set)) in let depends_map = map_of_set `version depends in (* others: dev, test, doc *) let open OpamPackage.Set.Op in let select ?(build=false) ?(test=false) ?(doc=false) ?(dev=false) ?(default=false) ?(post=false) () = OpamFormula.packages st.packages (OpamFilter.filter_deps ~build ~test ~doc ~dev ~default ~post (OpamFile.OPAM.depends opam)) in let default = select () in let select_depends typ selection = let depends = selection -- default in let installed = depends %% st.installed in let uninstalled = OpamPackage.(Name.Set.diff (names_of_packages depends) (names_of_packages installed)) in if OpamPackage.Name.Set.is_empty uninstalled then let depends_map = map_of_set `other installed in if only_direct then depends_map else (OpamSolver.dependencies ~depopts:false ~build:true ~post:true ~installed:true univ installed -- all_depends) |> map_of_set (`other_dep typ) |> OpamPackage.Map.union (fun _v _o -> `other_dep typ) depends_map else (OpamConsole.msg "Not all dependencies are satisfied, won't include them\n"; OpamPackage.Map.empty) in (* variables are set here as a string *) let dev_depends_map = select_depends "dev" (select ~dev:true ~build:true () -- select ~build:true ()) in let test_depends_map = select_depends "with-test" (select ~test:true ()) in let doc_depends_map = select_depends "with-doc" (select ~doc:true ()) in let depends = let f a b = match a,b with | _, (`other_dep _ as ot) | (`other_dep _ as ot), _ -> ot | _, `other | `other, _ -> `other | `version, `version -> `version in OpamPackage.Map.( depends_map |> union f dev_depends_map |> union f test_depends_map |> union f doc_depends_map ) in (* formulas *) let filters = OpamFormula.fold_left (fun acc form -> let n, vc = form in OpamPackage.Name.Map.add n vc acc) OpamPackage.Name.Map.empty (OpamFile.OPAM.depends opam) in let depends_formula = OpamFormula.ands (List.rev (OpamPackage.Map.fold (fun nv cst acc -> let filter = let cst_v = Atom ( Constraint (`Eq, FString (OpamPackage.version_to_string nv))) in match cst with | `version -> cst_v | `other_dep typ -> And (cst_v, Atom (Filter (FIdent ([], OpamVariable.of_string typ, None)))) | `other -> let orig_deps_formula = OpamPackage.Name.Map.find (OpamPackage.name nv) filters in let new_formula = OpamFormula.map (function | Constraint _ -> cst_v | Filter _ as f -> Atom f ) orig_deps_formula in if new_formula = orig_deps_formula then And (cst_v, new_formula) else new_formula in Atom (nv.name, filter)::acc) depends [])) in (* keep installed depopts in depends and set as conflicting uninstalled ones *) let all_depopts = OpamFormula.packages st.packages (OpamFilter.filter_deps ~build:true ~test:true ~doc:true ~dev:true ~default:true ~post:false (OpamFile.OPAM.depopts opam)) in let installed_depopts = OpamPackage.Set.inter all_depopts st.installed in let uninstalled_depopts = OpamPackage.(Name.Set.diff (names_of_packages all_depopts) (names_of_packages installed_depopts)) in let conflicts = OpamFormula.ors (OpamFile.OPAM.conflicts opam :: List.map (fun n -> Atom (n, Empty)) (OpamPackage.Name.Set.elements uninstalled_depopts)) in let pin_depends = OpamPackage.Set.fold (fun nv acc -> if not (OpamSwitchState.is_pinned st nv.name) then acc else match OpamSwitchState.primary_url st nv with | None -> acc | Some u -> match OpamUrl.local_dir u with | Some d -> let local_warn () = OpamConsole.warning "Dependency %s is pinned to local target %s" (OpamPackage.to_string nv) (OpamUrl.to_string u); acc in (match u.OpamUrl.backend with | #OpamUrl.version_control -> (match get_git_url u nv d with | Some resolved_u -> OpamConsole.note "Local pin %s resolved to %s" (OpamUrl.to_string u) (OpamUrl.to_string resolved_u); (nv, resolved_u) :: acc | None -> local_warn ()) | _ -> local_warn ()) | None -> (nv, u) :: acc) all_depends [] |> List.rev in opam |> OpamFile.OPAM.with_depopts OpamFormula.Empty |> OpamFile.OPAM.with_depends depends_formula |> OpamFile.OPAM.with_conflicts conflicts |> OpamFile.OPAM.with_pin_depends pin_depends opam-2.1.5/src/client/opamListCommand.mli0000644000175000017500000001452114427463453017361 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Functions handling the "opam list" subcommand *) open OpamParserTypes.FullPos open OpamTypes open OpamStateTypes (** Switches to determine what to include when querying (reverse) dependencies *) type dependency_toggles = { recursive: bool; depopts: bool; build: bool; post: bool; test: bool; doc: bool; dev: bool; } val default_dependency_toggles: dependency_toggles type pattern_selector = { case_sensitive: bool; exact: bool; glob: bool; fields: string list; ext_fields: bool; (** Match on raw strings in [x-foo] fields *) } val default_pattern_selector: pattern_selector (** Package selectors used to filter the set of packages *) type selector = | Any | Installed | Root | Compiler | Available | Installable | Pinned | Depends_on of dependency_toggles * atom list | Required_by of dependency_toggles * atom list | Conflicts_with of package list | Coinstallable_with of dependency_toggles * package list | Solution of dependency_toggles * atom list | Pattern of pattern_selector * string | Atoms of atom list | Flag of package_flag | Tag of string | From_repository of repository_name list | Owns_file of filename (** Applies a formula of selectors to filter the package from a given switch state *) val filter: base:package_set -> 'a switch_state -> selector OpamFormula.formula -> package_set (** Or-filter on package patterns (NAME or NAME.VERSION) *) val pattern_selector: string list -> selector OpamFormula.formula (** Get the aggregated active external dependencies of the given packages *) val get_depexts: 'a switch_state -> package_set -> OpamSysPkg.Set.t (** Lists the given aggregated active external dependencies of the given packages *) val print_depexts: OpamSysPkg.Set.t -> unit (** Element of package information to be printed. Fixme: should be part of the run-time man! *) type output_format = | Name (** Name without version *) | Version (** Version of the currently looked-at package *) | Package (** [name.version] *) | Synopsis (** One-line package description *) | Synopsis_or_target (** Pinning target if pinned, synopsis otherwise *) | Description (** The package description, excluding synopsis *) | Field of string (** The value of the given opam-file field *) | Raw_field of string (** The raw value of the given opam-file field *) | Installed_version (** Installed version or "--" if none *) | Pinning_target (** Empty string if not pinned *) | Source_hash (** The VC-reported ident of current version, for dev packages. Empty if not available *) | Raw (** The full contents of the opam file (reformatted) *) | All_installed_versions (** List of the installed versions in all switches with the corresponding switches in brackets *) | Available_versions (** List of the available versions (currently installed one in bold if color enabled) *) | All_versions (** List of the existing package versions (installed, installed in current switch and unavailable colored specifically if color enabled) *) | Repository (** The repository the package was found in (may be empty for pinned packages) *) | Installed_files (** The list of files that the installed package added to the system *) | VC_ref (** The version-control branch or tag the package url is bound to, if any *) | Depexts (** The external dependencies *) val default_list_format: output_format list (** Gets either the current switch state, if a switch is selected, or a virtual state corresponding to the configured repos *) val get_switch_state: 'a global_state -> 'a repos_state -> unlocked switch_state (** For documentation, includes a dummy ':' for the [Field] format. Used for the --columns argument. *) val raw_field_names: (output_format * string) list (** For documentation, includes a dummy ':' and '' for the [Field] format. Used for the --field argument. *) val field_names: (output_format * string) list val string_of_field: ?raw:bool -> output_format -> string val field_of_string: raw:bool -> string -> output_format type package_listing_format = { short: bool; header: bool; columns: output_format list; all_versions: bool; wrap: [`Wrap of string | `Truncate | `None] option; separator: string; value_printer: [`Normal | `Pretty | `Normalised]; order: [`Standard | `Dependency | `Custom of package -> package -> int]; } val default_package_listing_format: package_listing_format (** Outputs a list of packages as a table according to the formatting options. [normalise] supersedes [prettify] and uses a canonical way of displaying package definition file fields. [prettify] uses a nicer to read format for the package definition file fields. *) val display: 'a switch_state -> package_listing_format -> package_set -> unit (** Display a general summary of a collection of packages. *) val info: 'a switch_state -> fields:string list -> raw:bool -> where:bool -> ?normalise:bool -> ?show_empty:bool -> ?all_versions:bool -> ?sort:bool -> atom list -> unit (** Prints the value of an opam field in a shortened way (with [prettify] -- the default -- puts lists of strings in a format that is easier to read *) val mini_field_printer: ?prettify:bool -> ?normalise:bool -> value -> string val string_of_formula: selector OpamFormula.formula -> string opam-2.1.5/src/client/opamArgTools.ml0000644000175000017500000005413114427463453016531 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2021 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamStd.Op open Cmdliner open OpamCLIVersion.Op let cli2_0 = OpamCLIVersion.of_string "2.0" let cli2_1 = OpamCLIVersion.of_string "2.1" type 'b validity_and_content = { valid: OpamCLIVersion.t; removed: (OpamCLIVersion.t * string option) option; content: 'b; default: bool; } type 'a content = Valid of 'a | Removed of 'a type 'a contented_validity = 'a content validity_and_content type validity = unit validity_and_content let elem_of_vr = function Valid e | Removed e -> e let contented_validity (validity:validity) content : 'a contented_validity = match validity.removed with | None -> { validity with content = Valid content} | Some _ -> { validity with content = Removed content} let is_original_cli validity = OpamCLIVersion.compare validity.valid cli2_0 = 0 let cli_from valid = { valid ; removed = None; content = (); default = false } let cli_between since ?(default=false) ?replaced removal = if since >= removal then OpamConsole.error_and_exit `Internal_error "An option can't be added in %s and removed in %s" (OpamCLIVersion.to_string since) (OpamCLIVersion.to_string removal); { valid = since ; removed = Some (removal, replaced); content = (); default } let cli_original = cli_from cli2_0 let bold = OpamConsole.colorise `bold let string_of_sourced_cli (c,_) = OpamCLIVersion.to_string c let string_of_cli_option cli = if cli = cli2_0 then Printf.sprintf "set %s environment variable to %s" (bold "OPAMCLI") (bold "2.0") else Printf.sprintf "use --cli=%s" (bold @@ OpamCLIVersion.to_string cli) let update_doc_w_cli doc ~cli = function | { valid = c ; removed = None; _} -> if cli @< c then Printf.sprintf "(Since $(b,%s)) %s" (OpamCLIVersion.to_string c) doc else doc | { removed = Some (since, instead); _} -> if cli @< since then doc else Printf.sprintf "Removed in $(b,%s)%s" (OpamCLIVersion.to_string since) (match instead with | Some instead -> Printf.sprintf ", use $(i,%s) instead." instead | None -> ".") (* Error messages *) type target = | Flags of string list | Option of string | Verbatim of string let get_long_form flags = List.fold_left (fun (lgth,long) f -> let flgth = String.length f in if flgth > lgth then (flgth, f) else (lgth, long)) (0,"") flags |> snd let string_of_target = function | Flags flags -> bold "--"^get_long_form flags | Option o -> bold o | Verbatim s -> s let newer_flag_msg cli valid_since target = Printf.sprintf "%s was added in version %s of the opam CLI, \ but version %s has been requested, which is older." target (OpamCLIVersion.to_string valid_since) (string_of_sourced_cli cli) let newer_flag_error cli valid_since targets = let target = string_of_target targets in let msg = newer_flag_msg cli valid_since target in `Error (false, msg) let previously_str removal instead = let previous = string_of_cli_option (OpamCLIVersion.previous removal) in match instead with | Some ist -> Printf.sprintf ". Use %s instead or %s" (bold ist) previous | None -> Printf.sprintf ", %s" previous let older_flag_msg cli removal instead target = Printf.sprintf "%s was removed in version %s of the opam CLI, \ but version %s has been requested%s." target (OpamCLIVersion.to_string removal) (string_of_sourced_cli cli) (previously_str removal instead) let older_flag_error cli removal instead targets = let target = string_of_target targets in let msg = older_flag_msg cli removal instead target in `Error (false, msg) let deprecated_warning removal instead targets = let target = string_of_target targets in OpamConsole.warning "%s was deprecated in version %s of the opam CLI%s." target (OpamCLIVersion.to_string removal) (previously_str removal instead) (* Cli version check *) let cond_new cli c = cli @< c let cond_removed cli removal = cli @>= removal let check_cli_validity_t ~newer ~default_cli ~older ~valid ?(cond=fun x -> x) cli = function | { removed = None ; valid = c; _ } when cond (cond_new cli c) -> newer c | { removed = Some (removal, instead); default = true; _ } when (snd cli = `Default) && OpamCLIVersion.default < removal -> (* default cli case : we dont even check if the condition is required *) default_cli removal instead | { removed = Some (removal, instead); _ } when cond (cond_removed cli removal) -> older removal instead | _ -> valid () let check_cli_validity cli validity ?cond elem targets = check_cli_validity_t cli validity ?cond ~newer:(fun c -> newer_flag_error cli c targets) ~default_cli:(fun removal instead -> deprecated_warning removal instead targets; `Ok elem) ~older:(fun removal instead -> older_flag_error cli removal instead targets) ~valid:(fun () -> `Ok elem) let term_cli_check ~check arg = Term.(ret ((const check) $ (Arg.value arg))) (* Arguments *) let mk_flag ~cli validity ?section flags doc = let doc = update_doc_w_cli doc ~cli validity in let doc = Arg.info ?docs:section ~doc flags in let check elem = check_cli_validity cli validity ~cond:(fun c -> c && elem) elem (Flags flags) in term_cli_check ~check Arg.(flag & doc) let mk_opt ~cli validity ?section ?vopt flags value doc kind default = let doc = update_doc_w_cli doc ~cli validity in let doc = Arg.info ?docs:section ~docv:value ~doc flags in let check elem = check_cli_validity cli validity ~cond:(fun c -> c && default <> elem) elem (Flags flags) in term_cli_check ~check Arg.(opt ?vopt kind default & doc) let mk_opt_all ~cli validity ?section ?vopt ?(default=[]) flags value doc kind = let doc = update_doc_w_cli doc ~cli validity in let doc = Arg.info ?docs:section ~docv:value ~doc flags in let check elem = check_cli_validity cli validity ~cond:(fun c -> c && default <> elem) elem (Flags flags) in term_cli_check ~check Arg.(opt_all ?vopt kind default & doc) let mk_vflag ~cli ?section default flags = let flags = List.map (fun (v,c,f,d) -> contented_validity v c, f, d) flags in let info_flags = List.map (fun (validity, flag, doc) -> let doc = update_doc_w_cli doc ~cli validity in validity.content, Arg.info ?docs:section flag ~doc) flags in let check elem = match OpamStd.List.find_opt (fun (validity, _, _) -> validity.content = elem) flags with | Some (validity, flags, _) -> check_cli_validity cli validity (elem_of_vr elem) (Flags flags) | None -> `Ok (elem_of_vr elem) in term_cli_check ~check Arg.(vflag (Valid default) info_flags) let mk_flag_replaced ~cli ?section flags doc = let flags = List.map (fun (c,f) -> c, true, f, doc) flags in mk_vflag ~cli ?section false flags let mk_vflag_all ~cli ?section ?(default=[]) flags = let flags = List.map (fun (v,c,f,d) -> contented_validity v c, f, d) flags in let info_flags = List.map (fun (validity, flag, doc) -> let doc = update_doc_w_cli doc ~cli validity in validity.content, Arg.info ?docs:section flag ~doc) flags in let check selected = let newer_cli, older_cli = List.fold_left (fun (newer_cli,older_cli as acc) elem -> match OpamStd.List.find_opt (fun (validity, _, _) -> validity.content = elem) flags with | Some (validity, flags, _) -> check_cli_validity_t cli validity ~newer:(fun c -> (flags, c)::newer_cli, older_cli) ~default_cli:(fun _ _ -> acc) ~older:(fun removal instead -> newer_cli, (flags, (removal, instead))::older_cli) ~valid:(fun () -> acc) | None -> acc) ([],[]) selected in let max_cli clis = OpamCLIVersion.to_string @@ match clis with | [] -> assert false | c::cl -> List.fold_left max c cl in let string_of_options options = OpamStd.Format.pretty_list (List.map (fun o -> string_of_target (Flags o)) options) in match newer_cli, older_cli with | [], [] -> `Ok (List.map elem_of_vr selected) | [flags, c], [] -> newer_flag_error cli c (Flags flags) | [], [flags, (c, instead)] -> older_flag_error cli c instead (Flags flags) | _::_, []-> let options, clis = List.split newer_cli in let msg = Printf.sprintf "%s can only be used with at least version %s of the opam \ CLI, but version %s has been requested." (string_of_options options) (max_cli clis) (string_of_sourced_cli cli) in `Error (false, msg) | [], _::_-> let options, clis = List.split older_cli in let clis = List.split clis |> fst in let in_all = match clis with | c::cs when List.for_all ((=) c) cs -> Some c | _ -> None in let msg = Printf.sprintf "%s %swere all removed by version %s of the opam CLI, \ but version %s has been requested." (string_of_options options) (OpamStd.Option.to_string (OpamCLIVersion.to_string @> Printf.sprintf "were all in %s, and ") in_all) (max_cli clis) (string_of_sourced_cli cli) in `Error (false, msg) | _,_ -> let newer, nclis = List.split newer_cli in let older, rclis_ist = List.split older_cli in let rclis, insteads = List.split rclis_ist in let msg = if List.for_all ((<>) None) insteads then Printf.sprintf "This combination of options is not possible: %s require \ at least version %s of the opam CLI and the newer %s \ flags must be used for %s respectively!" (string_of_options newer) (max_cli nclis) (string_of_options older) (OpamStd.Format.pretty_list (List.map (function Some f -> f | None -> assert false) insteads)) else Printf.sprintf "This combination of options is not possible: %s require \ at least version %s of the opam CLI but %s were all \ removed by version %s of the opam CLI!" (string_of_options newer) (max_cli nclis) (string_of_options older) (max_cli rclis) in `Error (false, msg) in let default = List.map (fun x -> Valid x) default in term_cli_check ~check Arg.(vflag_all default info_flags) let string_of_enum enum = Arg.doc_alts_enum (List.map (fun (_, s, v) -> s,v) enum) let mk_enum_opt ~cli validity ?section flags value states doc = let doc = update_doc_w_cli doc ~cli validity in let doc = Arg.info ?docs:section ~docv:value ~doc flags in let check elem = (* first check validity of flag *) let flag_validity = check_cli_validity cli validity ~cond:(fun c -> c && elem <> None) elem (Flags flags) in (* then check validity of the argument *) match flag_validity with | `Ok (Some elem) -> let validity, str, _ = List.find (fun (_,_,v) -> v = elem) states in check_cli_validity cli validity (Some elem) (Verbatim (Printf.sprintf "the %s option for %s" (bold str) (bold "--"^get_long_form flags))) | _ -> flag_validity in let states = List.map (fun (_, s, v) -> s,v) states in term_cli_check ~check Arg.(opt (some (enum states)) None & doc) let mk_enum_opt_all ~cli validity ?section flags value states doc = let doc = update_doc_w_cli doc ~cli validity in let doc = Arg.info ?docs:section ~docv:value ~doc flags in let check elems = (* first check validity of flag *) let flag_validity = check_cli_validity cli validity ~cond:(fun c -> c && elems <> []) elems (Flags flags) in (* then check validity of the argument *) match flag_validity with | `Error _ -> flag_validity | `Ok elems -> let newer_cli, older_cli, valid = List.fold_left (fun (newer_cli,older_cli,valid) elem -> let (validity, str, _) = List.find (fun (_,_,v) -> v = elem) states in check_cli_validity_t cli validity ~newer:(fun c -> (str, c)::newer_cli, older_cli, valid) ~default_cli:(fun _ _ -> newer_cli, older_cli, elem::valid) ~older:(fun removal instead -> newer_cli, (str, (removal, instead))::older_cli, valid) ~valid:(fun () -> newer_cli, older_cli, elem::valid)) ([],[],[]) elems in let max_cli clis = OpamCLIVersion.to_string @@ match clis with | [] -> assert false | c::cl -> List.fold_left max c cl in let long_form_flags = "--"^get_long_form flags in let to_str states = Printf.sprintf "the option%s %s for %s" (match states with [_] -> "s" | _ -> "") (bold @@ OpamStd.Format.pretty_list states) (bold long_form_flags) in match newer_cli, older_cli, List.rev valid with | [], [], elems -> `Ok elems | [str, c], [], [] -> newer_flag_error cli c (Verbatim (to_str [str])) | [str, c], [], elems -> (OpamConsole.warning "%s" (newer_flag_msg cli c (to_str [str])); `Ok elems) | [], [str, (c, instead)], [] -> older_flag_error cli c instead (Verbatim (to_str [str])) | [], [str, (c, instead)], elems -> (OpamConsole.warning "%s" (older_flag_msg cli c instead (to_str [str])); `Ok elems) | _::_, [], elems -> let states, clis = List.split newer_cli in let msg = Printf.sprintf "%s can only be used with at least version %s of the opam \ CLI, but version %s has been requested." (to_str states) (max_cli clis) (string_of_sourced_cli cli) in if elems = [] then `Error (false, msg) else (OpamConsole.warning "%s" msg; `Ok elems) | [], _::_, elems-> let states, clis = List.split older_cli in let clis = List.split clis |> fst in let in_all = match clis with | c::cs when List.for_all ((=) c) cs -> Some c | _ -> None in let msg = Printf.sprintf "%s %swere all removed by version %s of the opam CLI, \ but version %s has been requested." (to_str states) (OpamStd.Option.to_string (OpamCLIVersion.to_string @> Printf.sprintf "were all in %s, and ") in_all) (max_cli clis) (string_of_sourced_cli cli) in if elems = [] then `Error (false, msg) else (OpamConsole.warning "%s" msg; `Ok elems) | _, _, elems -> let newer, nclis = List.split newer_cli in let older, rclis_ist = List.split older_cli in let rclis, insteads = List.split rclis_ist in let msg = if List.for_all ((<>) None) insteads then Printf.sprintf "This combination of %s options is not possible: %s require \ at least version %s of the opam CLI and the newer %s \ flags must be used for %s respectively!" (bold long_form_flags) (bold @@ OpamStd.Format.pretty_list newer) (max_cli nclis) (bold @@ OpamStd.Format.pretty_list older) (OpamStd.Format.pretty_list (List.map (function Some f -> f | None -> assert false) insteads)) else Printf.sprintf "This combination of %s options is not possible: %s require \ at least version %s of the opam CLI but %s were all \ removed by version %s of the opam CLI!" (bold long_form_flags) (bold @@ OpamStd.Format.pretty_list newer) (max_cli nclis) (bold @@ OpamStd.Format.pretty_list older) (max_cli rclis) in if elems = [] then `Error (false, msg) else (OpamConsole.warning "%s" msg; `Ok elems) in let states = List.map (fun (_, s, v) -> s,v) states in term_cli_check ~check Arg.(opt_all (enum states) [] & doc) (* Subcommands *) type 'a subcommand = validity * string * 'a * string list * string type 'a subcommands = 'a subcommand list let mk_subdoc ~cli ?(defaults=[]) commands = let bold s = Printf.sprintf "$(b,%s)" s in let it s = Printf.sprintf "$(i,%s)" s in `S Manpage.s_commands :: (List.map (function | "", name -> `P (Printf.sprintf "Without argument, defaults to %s." (bold name)) | arg, default -> `I (it arg, Printf.sprintf "With a %s argument, defaults to %s %s." (it arg) (bold default) (it arg)) ) defaults) @ List.map (fun (validity, c, _, args,d) -> let cmds = bold c ^ " " ^ OpamStd.List.concat_map " " it args in let d = update_doc_w_cli d ~cli validity in `I (cmds, d) ) commands let mk_subcommands_aux ~cli my_enum commands = let commands = List.map (fun (v,n,c,a,d) -> contented_validity v c, n, a, d) commands in let command = let doc = Arg.info ~docv:"COMMAND" [] in let scommand = List.rev_map (fun (v,f,_,_) -> f,v.content) commands in let check = function | None -> `Ok None | Some elem -> match OpamStd.List.find_opt (fun (validity, _, _, _) -> validity.content = elem) commands with | Some (validity, sbcmd, _,_) -> check_cli_validity cli validity (Some (elem_of_vr elem)) (Option sbcmd) | None -> `Ok (Some (elem_of_vr elem)) in term_cli_check ~check Arg.(pos 0 (some & my_enum scommand) None & doc) in let params = let doc = Arg.info ~doc:"Optional parameters." [] in Arg.(value & pos_right 0 string [] & doc) in command, params let mk_subcommands ~cli commands = mk_subcommands_aux ~cli Arg.enum commands type 'a default = [> `default of string] as 'a let mk_subcommands_with_default ~cli commands = let enum_with_default_valrem sl = let parse, print = Arg.enum sl in let parse s = match parse s with | `Ok x -> `Ok (x) | _ -> `Ok (Valid (`default s)) in parse, print in mk_subcommands_aux ~cli enum_with_default_valrem commands let bad_subcommand ~cli subcommands (command, usersubcommand, userparams) = match usersubcommand with | None -> `Error (false, Printf.sprintf "Missing subcommand. Valid subcommands are %s." (OpamStd.Format.pretty_list (OpamStd.List.filter_map (fun (validity,sb,_,_,_) -> match validity with | {valid = c; removed = None; _} when cli @>= c -> None | {removed = Some (c,_); _} when cli @< c -> None | _ -> Some sb) subcommands))) | Some (`default cmd) -> `Error (true, Printf.sprintf "Invalid %s subcommand %S" command cmd) | Some usersubcommand -> let exe = Filename.basename Sys.executable_name in match List.find_all (fun (_,_,cmd,_,_) -> cmd = usersubcommand) subcommands with | [ _, name, _, args, _doc] -> let usage = Printf.sprintf "%s %s [OPTION]... %s %s" exe command name (String.concat " " args) in if List.length userparams < List.length args then `Error (false, Printf.sprintf "%s: Missing argument.\nUsage: %s\n" exe usage) else `Error (false, Printf.sprintf "%s: Too many arguments.\nUsage: %s\n" exe usage) | _ -> `Error (true, Printf.sprintf "Invalid %s subcommand" command) (* Commands *) type command = unit Term.t * Term.info (* As [term_info] is defined later, we need to have it as argument *) let mk_command ~cli validity term_info name ~doc ~man cmd = let doc = update_doc_w_cli doc ~cli validity in let info = term_info ~cli name ~doc ~man in let check = check_cli_validity cli validity () (Option name) |> Term.const |> Term.ret in Term.(cmd $ check), info let mk_command_ret ~cli validity term_info name ~doc ~man cmd = let doc = update_doc_w_cli doc ~cli validity in let info = term_info ~cli name ~doc ~man in let check = check_cli_validity cli validity () (Option name) |> Term.const |> Term.ret in Term.(ret (cmd $ check)), info (* Environment variables *) let check_cli_env_validity cli validity var cons = let is_defined () = OpamStd.Config.env (fun x -> x) var <> None in let ovar = "OPAM"^var in match validity with | { removed = None ; valid = c; _ } when cond_new cli c -> if is_defined () then OpamConsole.warning "%s was ignored because CLI %s \ was requested and it was introduced in %s." ovar (string_of_sourced_cli cli) (OpamCLIVersion.to_string c); None | { removed = Some (removal, instead); _ } when cond_removed cli removal -> if is_defined () then OpamConsole.warning "%s was ignored because CLI %s \ was requested and it was removed in %s%s." ovar (string_of_sourced_cli cli) (OpamCLIVersion.to_string removal) (previously_str removal instead); None | _ -> Some (cons var) let env_with_cli environment = let doc_env cli = List.map (fun (var, validity, _cons, doc) -> let doc = update_doc_w_cli doc ~cli validity in `P (Printf.sprintf "$(i,OPAM%s) %s" var doc)) environment in let init_env cli = OpamStd.List.filter_map (fun (var, validity, cons, _doc) -> check_cli_env_validity cli validity var cons) environment |> OpamStd.Config.E.updates in doc_env, init_env opam-2.1.5/src/client/opamClientConfig.mli0000644000175000017500000001177314427463453017521 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2015-2020 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Configuration options for the client lib (record, global reference, setter, initialisation), plus helper for global setup *) module E: sig type OpamStd.Config.E.t += | ASSUMEDEPEXTS of bool option | AUTOREMOVE of bool option | CLI of string option | DROPWORKINGDIR of bool option | EDITOR of string option | FAKE of bool option | IGNOREPINDEPENDS of bool option | INPLACEBUILD of bool option | JSON of string option | KEEPBUILDDIR of bool option | NOAGGREGATE of bool option | NOAUTOUPGRADE of bool option | NOSELFUPGRADE of string option | PINKINDAUTO of bool option | REUSEBUILDDIR of bool option | ROOTISOK of bool option | SHOW of bool option | SKIPUPDATE of bool option | STATS of bool option | WORKINGDIR of bool option val cli: unit -> string option val rootisok: unit -> bool option val noaggregate: unit -> bool option val noselfupgrade: unit -> string option end type t = private { print_stats: bool; pin_kind_auto: bool; autoremove: bool; editor: string; keep_build_dir: bool; reuse_build_dir: bool; inplace_build: bool; working_dir: bool; drop_working_dir: bool; ignore_pin_depends: bool; show: bool; fake: bool; skip_dev_update: bool; json_out: string option; root_is_ok: bool; no_auto_upgrade: bool; assume_depexts: bool; cli: OpamCLIVersion.t; scrubbed_environment_variables: string list; } type 'a options_fun = ?print_stats:bool -> ?pin_kind_auto:bool -> ?autoremove:bool -> ?editor:string -> ?keep_build_dir:bool -> ?reuse_build_dir:bool -> ?inplace_build:bool -> ?working_dir:bool -> ?drop_working_dir:bool -> ?ignore_pin_depends:bool -> ?show:bool -> ?fake:bool -> ?skip_dev_update:bool -> ?json_out:string option -> ?root_is_ok:bool -> ?no_auto_upgrade:bool -> ?assume_depexts:bool -> ?cli:OpamCLIVersion.t -> ?scrubbed_environment_variables:string list -> 'a (* constraint 'a = 'b -> 'c *) include OpamStd.Config.Sig with type t := t and type 'a options_fun := 'a options_fun (** Extra files included in [opam search] *) val search_files: string list (** Load the global configuration file (opamroot/config) and initialise all opam sub-libraries, overriding the given arguments *) val opam_init: ?root_dir:OpamTypes.dirname -> ?strict:bool -> ?solver:(module OpamCudfSolver.S) Lazy.t -> ?skip_version_checks:bool -> ?all_parens:bool -> ?log_dir:OpamTypes.dirname -> ?print_stats:bool -> ?pin_kind_auto:bool -> ?autoremove:bool -> ?editor:string -> ?keep_build_dir:bool -> ?reuse_build_dir:bool -> ?inplace_build:bool -> ?working_dir:bool -> ?drop_working_dir:bool -> ?ignore_pin_depends:bool -> ?show:bool -> ?fake:bool -> ?skip_dev_update:bool -> ?json_out:string option -> ?root_is_ok:bool -> ?no_auto_upgrade:bool -> ?assume_depexts:bool -> ?cli:OpamCLIVersion.t -> ?scrubbed_environment_variables:string list -> ?current_switch:OpamSwitch.t -> ?switch_from:OpamStateTypes.provenance -> ?jobs:int Lazy.t -> ?dl_jobs:int -> ?build_test:bool -> ?build_doc:bool -> ?dryrun:bool -> ?makecmd:string Lazy.t -> ?ignore_constraints_on:OpamPackage.Name.Set.t -> ?unlock_base:bool -> ?no_env_notice:bool -> ?locked:string option -> ?no_depexts:bool -> ?cudf_file:string option -> ?best_effort:bool -> ?solver_preferences_default:string option Lazy.t -> ?solver_preferences_upgrade:string option Lazy.t -> ?solver_preferences_fixup:string option Lazy.t -> ?solver_preferences_best_effort_prefix: string option Lazy.t -> ?solver_timeout:float option -> ?solver_allow_suboptimal:bool -> ?cudf_trim:string option -> ?dig_depth:int -> ?preprocess:bool -> ?version_lag_power:int -> ?download_tool:(OpamTypes.arg list * OpamRepositoryConfig.dl_tool_kind) Lazy.t -> ?validation_hook:OpamTypes.arg list option -> ?retries:int -> ?force_checksums:bool option -> ?debug_level:int -> ?debug_sections:OpamStd.Config.sections -> ?verbose_level:OpamStd.Config.level -> ?color:OpamStd.Config.when_ -> ?utf8:OpamStd.Config.when_ext -> ?disp_status_line:OpamStd.Config.when_ -> ?confirm_level:OpamStd.Config.answer -> ?yes:bool option -> ?safe_mode:bool -> ?keep_log_dir:bool -> ?errlog_length:int -> ?merged_output:bool -> ?use_openssl:bool -> ?precise_tracking:bool -> unit -> unit opam-2.1.5/src/client/opamClient.ml0000644000175000017500000017524414427463453016226 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamStateTypes open OpamStd.Op open OpamPackage.Set.Op let log fmt = OpamConsole.log "CLIENT" fmt let slog = OpamConsole.slog (* When packages are removed from upstream, they normally disappear from the 'available' packages set and can't be seen by the solver anymore. This is a problem for several reasons, so we compute the set of orphan packages here: - they are checked for conflicts with the user request - they are re-added to the universe if (transitively) unrelated to the request (the [changes] parameter) This function separates full orphans (no version of the package available anymore) from orphan versions, because they have a different impact on the request (needs version change VS needs uninstall). Orphan packages include both installed packages that are no longer available, and packages that are "invalidated", i.e. their system dependencies are no longer up-to-date: in this case they might still be available for reinstall.. See also check_conflicts. *) let orphans ?changes ?(transitive=false) t = let all = t.packages ++ t.installed in let available = Lazy.force t.available_packages in let allnames = OpamPackage.names_of_packages all in let invalidated = Lazy.force t.invalidated in let universe = OpamSwitchState.universe t ~requested:OpamPackage.Name.Set.empty Reinstall in (* Basic definition of orphan packages *) let orphans = t.installed -- available in log "Base orphans: %a" (slog OpamPackage.Set.to_string) orphans; (* Restriction to the request-related packages *) let changes = match changes with | None -> None | Some ch -> Some (OpamPackage.Name.Set.fold (fun name ch -> try OpamPackage.Set.add (OpamPackage.package_of_name t.installed name) ch with Not_found -> ch) (OpamPackage.names_of_packages ch) ch) in let orphans = match changes with | None -> orphans | Some ch -> if OpamPackage.Set.is_empty orphans then orphans else let recompile_cone = OpamSolver.reverse_dependencies ~depopts:true ~installed:true ~unavailable:true ~build:true ~post:false universe ch in orphans %% recompile_cone in (* invalidated packages forbid changes of their reverse dependencies, while basic orphans do not *) let orphans = orphans ++ invalidated in (* Pinned versions of packages remain always available *) let orphans = orphans -- OpamPinned.packages t in (* Splits between full orphans (no version left) and partial ones *) let full_partition orphans = let orphan_names = (* names for which there is no available version left *) OpamPackage.Name.Set.diff allnames (OpamPackage.names_of_packages (available -- orphans)) in OpamPackage.Set.partition (fun nv -> OpamPackage.Name.Set.mem nv.name orphan_names) orphans in let full_orphans, orphan_versions = full_partition orphans in (* Closure *) let full_orphans, orphan_versions = if not transitive then full_orphans, orphan_versions else let rec add_trans full_orphans orphan_versions = (* fixpoint to check all packages with no available version *) let new_orphans = OpamSolver.reverse_dependencies ~depopts:false ~installed:false ~unavailable:true ~build:true ~post:false universe full_orphans in let full, versions = full_partition (new_orphans++orphan_versions) in if OpamPackage.Set.equal full_orphans full then full, versions else add_trans full versions in add_trans full_orphans orphan_versions in (* Installed packages outside the set of changes are otherwise safe: re-add them to the universe *) let t = if changes = None then t else let available_packages = lazy (available ++ (t.installed -- orphans)) in { t with available_packages } in log "Orphans: (changes: %a, transitive: %b) -> full %a, versions %a" (slog @@ OpamStd.Option.to_string OpamPackage.Set.to_string) changes transitive (slog @@ OpamPackage.Name.Set.to_string @* OpamPackage.names_of_packages) full_orphans (slog OpamPackage.Set.to_string) orphan_versions; t, full_orphans, orphan_versions (* Splits a list of atoms into the installed and uninstalled ones*) let get_installed_atoms t atoms = List.fold_left (fun (packages, not_installed) atom -> try let nv = OpamPackage.Set.find (OpamFormula.check atom) t.installed in nv :: packages, not_installed with Not_found -> packages, atom :: not_installed) ([],[]) atoms (* Check atoms for pinned packages, and update them. Returns the state that may have been reloaded if there were changes *) let update_dev_packages_t ?(only_installed=false) atoms t = OpamRepositoryState.check_last_update (); if OpamClientConfig.(!r.skip_dev_update) then t else let working_dir = OpamClientConfig.(!r.working_dir || !r.inplace_build) in let to_update = List.fold_left (fun to_update (name,_) -> try let nv = OpamPackage.package_of_name t.pinned name in if OpamSwitchState.is_dev_package t nv && ( not only_installed || OpamPackage.Set.exists (fun nv -> nv.name = name) t.installed ) then OpamPackage.Set.add nv to_update else to_update with Not_found -> to_update) OpamPackage.Set.empty atoms in if OpamPackage.Set.is_empty to_update then t else ( OpamConsole.header_msg "Synchronising pinned packages"; try let working_dir = if working_dir then Some (OpamSwitchState.packages_of_atoms t atoms) else None in let _success, t, _pkgs = OpamUpdate.dev_packages t ?working_dir to_update in OpamConsole.msg "\n"; t with e -> OpamStd.Exn.fatal e; OpamConsole.msg "\n"; t ) let compute_upgrade_t ?(strict_upgrade=true) ?(auto_install=false) ?(only_installed=false) ~all atoms t = let names = OpamPackage.Name.Set.of_list (List.rev_map fst atoms) in let atoms = List.map (function | (n,None) when strict_upgrade -> (* force strict upgrade for unchanged, non dev or pinned packages (strict update makes no sense for pinned packages which have a fixed version) *) (try let nv = OpamSwitchState.find_installed_package_by_name t n in if OpamSwitchState.is_dev_package t nv || OpamPackage.has_name t.pinned n || OpamPackage.Set.mem nv (Lazy.force t.reinstall) then (n, None) else let atom = (n, Some (`Gt, nv.version)) in if OpamPackage.Set.exists (fun nv -> OpamFormula.check atom nv && (not (OpamFile.OPAM.has_flag Pkgflag_AvoidVersion (OpamSwitchState.opam t nv)) || OpamSwitchState.can_upgrade_to_avoid_version (OpamPackage.name nv) t)) (Lazy.force t.available_packages) then atom else (n, None) with Not_found -> (n,None)) | atom -> atom ) atoms in let requested_installed, not_installed = List.fold_left (fun (packages, not_installed) (n,_ as atom) -> try let nv = OpamPackage.Set.find (fun nv -> nv.name = n) t.installed in OpamPackage.Set.add nv packages, not_installed with Not_found -> packages, atom :: not_installed) (OpamPackage.Set.empty,[]) atoms in let to_install = if only_installed || not_installed = [] then [] else if auto_install || OpamConsole.confirm "%s %s not installed. Install %s?" (OpamStd.Format.pretty_list (List.rev_map OpamFormula.short_string_of_atom not_installed)) (match not_installed with [_] -> "is" | _ -> "are") (match not_installed with [_] -> "it" | _ -> "them") then not_installed else [] in let upgrade_atoms to_upgrade = (* packages corresponds to the currently installed versions. Not what we are interested in, recover the original atom constraints *) List.map (fun nv -> let name = nv.name in try name, List.assoc name atoms with Not_found -> name, None) (OpamPackage.Set.elements to_upgrade) in if all then let t, full_orphans, orphan_versions = orphans ~transitive:true t in let to_upgrade = t.installed -- full_orphans in names, OpamSolution.resolve t Upgrade ~orphans:(full_orphans ++ orphan_versions) ~requested:names ~reinstall:(Lazy.force t.reinstall) (OpamSolver.request ~install:to_install ~upgrade:(upgrade_atoms to_upgrade) ~criteria:`Upgrade ()) else let changes = requested_installed ++ OpamSwitchState.packages_of_atoms t to_install in let t, full_orphans, orphan_versions = orphans ~changes t in let to_remove = requested_installed %% full_orphans in let to_upgrade = requested_installed -- full_orphans in names, OpamSolution.resolve t Upgrade ~orphans:(full_orphans ++ orphan_versions) ~requested:names (OpamSolver.request ~install:to_install ~remove:(OpamSolution.atoms_of_packages to_remove) ~upgrade:(upgrade_atoms to_upgrade) ()) let upgrade_t ?strict_upgrade ?auto_install ?ask ?(check=false) ?(terse=false) ?only_installed ~all atoms t = log "UPGRADE %a" (slog @@ function [] -> "" | a -> OpamFormula.string_of_atoms a) atoms; match compute_upgrade_t ?strict_upgrade ?auto_install ?only_installed ~all atoms t with | requested, Conflicts cs -> log "conflict!"; if not (OpamPackage.Name.Set.is_empty requested) then (OpamConsole.error "Package conflict!"; OpamConsole.errmsg "%s" (OpamCudf.string_of_conflicts t.packages (OpamSwitchState.unavailable_reason t) cs); OpamStd.Sys.exit_because `No_solution); let reasons, cycles = OpamCudf.conflict_explanations t.packages (OpamSwitchState.unavailable_reason t) cs in if cycles <> [] then begin OpamConsole.error "Dependency errors in the upgrade actions. Please update, and \ report the following to the package maintainers if the error \ persists:"; OpamConsole.errmsg "%s\n%s\n" (OpamStd.Format.itemize (fun x -> x) cycles) "You may try upgrading packages individually to work around this." end else begin OpamConsole.warning "Upgrade is not possible because of conflicts or packages that \ are no longer available:"; OpamConsole.errmsg " %s" (OpamStd.Format.itemize (OpamCudf.string_of_conflict ~start_column:2) reasons); OpamConsole.errmsg "\nYou may run \"opam upgrade --fixup\" to let opam fix the \ current state.\n" end; OpamStd.Sys.exit_because `No_solution | requested, Success solution -> if check then OpamStd.Sys.exit_because (if OpamSolver.solution_is_empty solution then `False else `Success) else let t, result = OpamSolution.apply ?ask t ~requested solution in if result = Nothing_to_do then ( let to_check = if OpamPackage.Name.Set.is_empty requested then t.installed else OpamPackage.packages_of_names t.installed requested in let latest = OpamPackage.Name.Set.fold (fun name acc -> OpamPackage.Set.add (OpamPackage.max_version t.packages name) acc) (OpamPackage.names_of_packages to_check) OpamPackage.Set.empty in let notuptodate = latest -- to_check in if OpamPackage.Set.is_empty notuptodate then OpamConsole.msg "Already up-to-date.\n" else if terse then OpamConsole.msg "No package build needed.\n" else (let hdmsg = "Everything as up-to-date as possible" in let unav = notuptodate -- Lazy.force t.available_packages in let unopt = notuptodate %% Lazy.force t.available_packages in let base = OpamPackage.packages_of_names unopt (OpamPackage.names_of_packages t.compiler_packages) in let unopt = unopt -- base in let conflicts = let get_formula pkg = OpamStd.Option.map (fun opam -> OpamFilter.filter_formula ~default:false (OpamPackageVar.resolve_switch ~package:pkg t) (OpamFile.OPAM.conflicts opam)) (OpamSwitchState.opam_opt t pkg) in OpamPackage.Set.fold (fun unopt_pkg map -> let set = OpamSwitchState.conflicts_with t (OpamPackage.Set.singleton unopt_pkg) latest in OpamPackage.Set.fold (fun installed_pkg map -> match get_formula installed_pkg with | None -> map | Some conflicts_formula -> OpamFormula.fold_left (fun map (n,formula) -> if OpamPackage.name unopt_pkg = n && OpamFormula.check_version_formula formula (OpamPackage.version unopt_pkg) then OpamPackage.Map.update unopt_pkg (OpamStd.List.cons (installed_pkg, formula)) [] map else map ) map conflicts_formula ) set map ) unopt OpamPackage.Map.empty in (* First, folding on [latest] packages: for each one, check if a [unopt] package does not verify [latest] package dependency formula *) let incompatibilities = let get_formula pkg = OpamStd.Option.map (OpamPackageVar.all_depends t) (OpamSwitchState.opam_opt t pkg) in OpamPackage.Set.fold (fun latest_pkg map -> match get_formula latest_pkg with | None -> map | Some depends_formula -> OpamPackage.Set.fold (fun unopt_pkg map -> OpamFormula.fold_left (fun map (n, formula) -> if OpamPackage.name unopt_pkg = n && formula <> OpamFormula.Empty && not (OpamFormula.check_version_formula formula (OpamPackage.version unopt_pkg)) then OpamPackage.Map.update unopt_pkg (OpamStd.List.cons (latest_pkg, formula)) [] map else map ) map depends_formula ) unopt map ) latest OpamPackage.Map.empty in if (OpamConsole.verbose ()) && not (OpamPackage.Set.is_empty unav) then (OpamConsole.formatted_msg "%s.\n\ The following newer versions couldn't be installed:\n" hdmsg; OpamConsole.msg "%s" (OpamStd.Format.itemize (fun p -> Printf.sprintf "%s.%s: %s" (OpamConsole.colorise `bold (OpamPackage.name_to_string p)) (OpamPackage.version_to_string p) (OpamSwitchState.unavailable_reason t ~default:"unavailable for unknown reasons (this may \ be a bug in opam)" (OpamPackage.name p, Atom (`Eq, OpamPackage.version p)))) (OpamPackage.Set.elements unav))) else OpamConsole.formatted_msg "%s (run with --verbose to show unavailable upgrades).\n" hdmsg; if not (OpamPackage.Set.is_empty unopt) then (let bullet = OpamConsole.(colorise `red (utf8_symbol Symbols.asterisk_operator "--")) ^ " " in let string_dep pkg map reason = List.fold_right (fun (p, f) acc -> Printf.sprintf "%s\n%s%s is installed and %s %s" acc bullet (OpamPackage.to_string p) reason (OpamFormula.to_string (Atom (pkg.name, f))) ) (OpamStd.Option.default [] (OpamPackage.Map.find_opt pkg map)) "" in OpamConsole.formatted_msg "\nThe following packages are not being upgraded because the new \ versions conflict with other installed packages:\n"; OpamConsole.msg "%s" (OpamStd.Format.itemize (fun pkg -> Printf.sprintf "%s.%s%s%s" (OpamConsole.colorise `bold (OpamPackage.name_to_string pkg)) (OpamPackage.version_to_string pkg) (string_dep pkg incompatibilities "requires") (string_dep pkg conflicts "conflicts with") ) (OpamPackage.Set.elements unopt)) ); OpamConsole.formatted_msg "However, you may \"opam upgrade\" these packages explicitly, \ which will ask permission to downgrade or uninstall the \ conflicting packages.\n"; ) ); OpamSolution.check_solution t (Success result); t let upgrade t ?check ?only_installed ~all names = let atoms = OpamSolution.sanitize_atom_list t names in let t = update_dev_packages_t ?only_installed atoms t in upgrade_t ?check ~strict_upgrade:(not all) ?only_installed ~all atoms t let fixup t = log "FIXUP"; let t, full_orphans, orphan_versions = orphans ~transitive:true t in let all_orphans = full_orphans ++ orphan_versions in let resolve pkgs = pkgs, OpamSolution.resolve t Upgrade ~orphans:all_orphans ~requested:(OpamPackage.names_of_packages pkgs) (OpamSolver.request ~install:(OpamSolution.atoms_of_packages pkgs) ~criteria:`Fixup ()) in let is_success = function | _, Success _ -> true | _, Conflicts cs -> log "conflict: %a" (slog (OpamCudf.string_of_conflicts t.packages @@ OpamSwitchState.unavailable_reason t)) cs; false in let requested, solution = let s = log "fixup-1/ keep installed packages with orphaned versions and roots"; resolve (t.installed_roots %% t.installed -- full_orphans ++ orphan_versions) in if is_success s then s else let s = log "fixup-2/ keep just roots"; resolve (t.installed_roots %% t.installed -- full_orphans) in if is_success s then s else let s = log "fixup-3/ keep packages with orphaned versions"; resolve orphan_versions in if is_success s then s else let s = log "fixup-4/ last resort: no constraints. This should never fail"; resolve OpamPackage.Set.empty in s (* Could still fail with uninstallable base packages actually, but we can only fix so far *) in let t, result = match solution with | Conflicts cs -> (* ouch... *) OpamConsole.error "It appears that the switch invariant is no longer satisfiable. \ Either fix the package prerequisites or change the invariant \ with 'opam switch set-invariant'."; OpamConsole.errmsg "%s" (OpamCudf.string_of_conflicts t.packages (OpamSwitchState.unavailable_reason t) cs); t, Conflicts cs | Success solution -> let _, req_rm, _ = orphans ~transitive:false t in let t, res = OpamSolution.apply ~ask:true t ~requested:(OpamPackage.names_of_packages (requested ++ req_rm)) solution in t, Success res in OpamSolution.check_solution t result; t let update gt ~repos_only ~dev_only ?(all=false) names = log "UPDATE %a" (slog @@ String.concat ", ") names; let rt = OpamRepositoryState.load `Lock_none gt in let st, repos_only = match OpamStateConfig.get_switch_opt () with | None -> OpamSwitchState.load_virtual gt rt, true | Some sw -> OpamSwitchState.load `Lock_none gt rt sw, repos_only in let repo_names = let all_repos = OpamRepositoryName.Map.keys rt.repositories in if dev_only then [] else if names <> [] then List.filter (fun r -> List.mem (OpamRepositoryName.to_string r) names) all_repos else if all then all_repos else OpamSwitchState.repos_list st in let packages, ignore_packages = if repos_only then OpamPackage.Set.empty, OpamPackage.Set.empty else let packages = st.installed ++ st.pinned in let packages = if names = [] then packages else OpamPackage.Set.filter (fun nv -> let name = OpamPackage.Name.to_string nv.name in let pkg = OpamPackage.to_string nv in List.exists (fun s -> s = name || s = pkg) names && let pinned = OpamPinned.package_opt st nv.name in pinned = None || pinned = Some nv ) packages in let dev_packages, nondev_packages = OpamPackage.Set.partition (OpamSwitchState.is_dev_package st) packages in let dev_packages = dev_packages -- (st.compiler_packages -- st.pinned) in let nondev_packages = if names = [] || OpamPackage.Set.is_empty nondev_packages then OpamPackage.Set.empty else (OpamConsole.warning "The following are not development packages (no dynamic or version \ controlled upstream) and can't be updated individually: %s\n\ You may want to update your repositories with just %s or to \ upgrade your package%s with %s %s" (OpamStd.List.concat_map ", " ~last_sep:"and" OpamPackage.to_string (OpamPackage.Set.elements nondev_packages)) (OpamConsole.colorise `bold "opam update") (if OpamPackage.Set.is_singleton nondev_packages then "" else "s") (OpamConsole.colorise `bold "opam upgrade") (OpamConsole.colorise `bold (OpamStd.List.concat_map " " OpamPackage.name_to_string (OpamPackage.Set.elements nondev_packages))); nondev_packages) in let dirty_dev_packages, dev_packages = if names <> [] || OpamClientConfig.(!r.drop_working_dir) then OpamPackage.Set.empty, dev_packages else OpamPackage.Set.partition (fun nv -> let src_cache = OpamSwitchState.source_dir st nv in let cache_url = OpamUrl.of_string (OpamFilename.Dir.to_string src_cache) in match OpamSwitchState.primary_url st nv with | Some { OpamUrl.backend = #OpamUrl.version_control as vc; _ } -> (try OpamProcess.Job.run @@ OpamRepository.is_dirty { cache_url with OpamUrl.backend = vc } with OpamSystem.Process_error _ -> log "Skipping %s, not a git repo" (OpamPackage.to_string nv); false) | _ -> false) dev_packages in OpamPackage.Set.iter (fun nv -> OpamConsole.note "%s has previously been updated with --working-dir, \ not resetting unless explicitly selected" (OpamPackage.to_string nv)) dirty_dev_packages; dev_packages, nondev_packages in let remaining = let ps = packages ++ ignore_packages in List.filter (fun n -> not ( List.mem (OpamRepositoryName.of_string n) repo_names || (try OpamPackage.has_name ps (OpamPackage.Name.of_string n) with Failure _ -> false) || (try OpamPackage.Set.mem (OpamPackage.of_string n) ps with Failure _ -> false) )) names in if remaining <> [] then OpamConsole.error "Unknown repositories or installed packages: %s" (String.concat ", " remaining); (* Do the updates *) let rt_before = rt in let repo_update_failure, rt = if repo_names = [] then [], rt else OpamRepositoryState.with_write_lock rt @@ fun rt -> OpamConsole.header_msg "Updating package repositories"; OpamRepositoryCommand.update_with_auto_upgrade rt repo_names in let repo_changed = not (OpamRepositoryName.Map.equal (OpamPackage.Map.equal (OpamFile.OPAM.effectively_equal)) rt_before.repo_opams rt.repo_opams) in (* st is still based on the old rt, it's not a problem at this point, but don't return it *) let (dev_update_success, dev_changed), st = if OpamPackage.Set.is_empty packages then (true, false), st else OpamSwitchState.with_write_lock st @@ fun st -> let working_dir = if OpamClientConfig.(!r.working_dir) && names <> [] then Some (OpamPackage.packages_of_names packages (OpamPackage.Name.(Set.of_list (List.map of_string names)))) else None in OpamConsole.header_msg "Synchronising development packages"; let success, st, updates = OpamUpdate.dev_packages st ?working_dir packages in if OpamClientConfig.(!r.json_out <> None) then OpamJson.append "dev-packages-updates" (OpamPackage.Set.to_json updates); (success, not (OpamPackage.Set.is_empty updates)), st in OpamSwitchState.drop st; repo_update_failure = [] && dev_update_success && remaining = [] && OpamPackage.Set.is_empty ignore_packages, repo_changed || dev_changed, rt let init_checks ?(hard_fail_exn=true) init_config = (* Check for the external dependencies *) let check_external_dep name = OpamSystem.resolve_command name <> None in OpamConsole.msg "Checking for available remotes: "; let repo_types = ["rsync", "rsync and local"; "git", "git"; "hg", "mercurial"; "darcs", "darcs"] in let available_repos, unavailable_repos = List.partition (check_external_dep @* fst) repo_types in OpamConsole.msg "%s.%s\n" (match available_repos with | [] -> "none" | r -> String.concat ", " (List.map snd r)) (if unavailable_repos = [] then " Perfect!" else "\n" ^ OpamStd.Format.itemize (fun (cmd,msg) -> Printf.sprintf "you won't be able to use %s repositories unless you \ install the %s command on your system." msg (OpamConsole.colorise `bold cmd)) unavailable_repos); let soft_fail = if OpamCudfSolver.has_builtin_solver () then false else let external_solvers = ["aspcud"; "packup"; "mccs"] in if not (List.exists check_external_dep external_solvers) then (OpamConsole.error "No external solver found. You should get one of %s, or use a \ version of opam compiled with a built-in solver (see \ http://opam.ocaml.org/doc/External_solvers.html for \ details)" (OpamStd.Format.pretty_list ~last:"or" (List.map (OpamConsole.colorise `bold) external_solvers)); true) else false in let env v = let vs = OpamVariable.Full.variable v in OpamStd.Option.Op.(OpamStd.Option.of_Not_found (List.assoc vs) OpamSysPoll.variables >>= Lazy.force) in let filter_tools = OpamStd.List.filter_map (fun (cmd,str,oflt) -> match oflt with | None -> Some (cmd,str) | Some flt -> if (OpamFilter.eval_to_bool env flt) then Some (cmd,str) else None) in let check_tool logf tools = match List.filter (not @* (List.exists check_external_dep) @* fst) tools with | [] -> false | missing -> (logf (OpamStd.Format.itemize (fun (miss,msg) -> Printf.sprintf "%s%s" (OpamStd.List.concat_map " or " (OpamConsole.colorise `bold) miss) (match msg with | None -> "" | Some m -> ": "^m)) missing); true) in let advised_deps = filter_tools (OpamFile.InitConfig.recommended_tools init_config) in let _ = check_tool (fun s -> OpamConsole.warning "Recommended dependencies -- most packages rely on these:"; OpamConsole.errmsg "%s" s) advised_deps in let required_deps = filter_tools (OpamFile.InitConfig.required_tools init_config) in let hard_fail = let msg = if hard_fail_exn then OpamConsole.error else OpamConsole.warning in check_tool (fun s -> msg "Missing dependencies -- \ the following commands are required for opam to operate:"; OpamConsole.errmsg "%s" s) required_deps in if hard_fail && hard_fail_exn then OpamStd.Sys.exit_because `Configuration_error else not (soft_fail || hard_fail) let update_with_init_config ?(overwrite=false) config init_config = let module I = OpamFile.InitConfig in let module C = OpamFile.Config in let setifnew getter setter v conf = if overwrite then setter v conf else if getter conf = getter C.empty then setter v conf else conf in config |> (match I.jobs init_config with | Some j -> setifnew C.jobs C.with_jobs j | None -> fun c -> c) |> setifnew C.dl_tool C.with_dl_tool_opt (I.dl_tool init_config) |> setifnew C.dl_cache C.with_dl_cache (I.dl_cache init_config) |> setifnew C.dl_jobs C.with_dl_jobs (OpamStd.Option.default OpamStateConfig.(default.dl_jobs) (I.dl_jobs init_config)) |> setifnew C.criteria C.with_criteria (I.solver_criteria init_config) |> setifnew C.solver C.with_solver_opt (I.solver init_config) |> setifnew C.wrappers C.with_wrappers (I.wrappers init_config) |> setifnew C.global_variables C.with_global_variables (I.global_variables init_config) |> setifnew C.eval_variables C.with_eval_variables (I.eval_variables init_config) |> setifnew C.default_compiler C.with_default_compiler (I.default_compiler init_config) |> setifnew C.default_invariant C.with_default_invariant (I.default_invariant init_config) let reinit ?(init_config=OpamInitDefaults.init_config()) ~interactive ?dot_profile ?update_config ?env_hook ?completion ?inplace ?(check_sandbox=true) ?(bypass_checks=false) config shell = let root = OpamStateConfig.(!r.root_dir) in let config = update_with_init_config config init_config in let _all_ok = if bypass_checks then false else init_checks ~hard_fail_exn:false init_config in let custom_init_scripts = let env v = let vs = OpamVariable.Full.variable v in OpamStd.Option.Op.(OpamStd.Option.of_Not_found (List.assoc vs) OpamSysPoll.variables >>= Lazy.force) in OpamStd.List.filter_map (fun ((nam,scr),oflt) -> match oflt with | None -> Some (nam,scr) | Some flt -> if OpamFilter.eval_to_bool env flt then Some (nam,scr) else None) (OpamFile.InitConfig.init_scripts init_config) in OpamEnv.write_custom_init_scripts root custom_init_scripts; let config = if check_sandbox then OpamAuxCommands.check_and_revert_sandboxing root config else config in OpamFile.Config.write (OpamPath.config root) config; OpamEnv.setup root ~interactive ?dot_profile ?update_config ?env_hook ?completion ?inplace shell; let gt = OpamGlobalState.load `Lock_write in let rt = OpamRepositoryState.load `Lock_write gt in OpamConsole.header_msg "Updating repositories"; let _failed, rt = OpamRepositoryCommand.update_with_auto_upgrade rt (OpamRepositoryName.Map.keys rt.repos_definitions) in OpamRepositoryState.drop rt let init ~init_config ~interactive ?repo ?(bypass_checks=false) ?dot_profile ?update_config ?env_hook ?(completion=true) ?(check_sandbox=true) shell = log "INIT %a" (slog @@ OpamStd.Option.to_string OpamRepositoryBackend.to_string) repo; let root = OpamStateConfig.(!r.root_dir) in let config_f = OpamPath.config root in let root_empty = not (OpamFilename.exists_dir root) || OpamFilename.dir_is_empty root in let gt, rt, default_compiler = if OpamFile.exists config_f then ( OpamConsole.msg "Opam has already been initialized.\n"; let gt = OpamGlobalState.load `Lock_write in if OpamFile.Config.installed_switches gt.config = [] then OpamConsole.msg "... but you have no switches installed, use `opam switch \ create ' to get started."; gt, OpamRepositoryState.load `Lock_none gt, [] ) else ( if not root_empty then ( OpamConsole.warning "%s exists and is not empty" (OpamFilename.Dir.to_string root); if not (OpamConsole.confirm "Proceed?") then OpamStd.Sys.exit_because `Aborted); try (* Create the content of ~/.opam/config *) let repos = match repo with | Some r -> [r.repo_name, (r.repo_url, r.repo_trust)] | None -> OpamFile.InitConfig.repositories init_config in let config = update_with_init_config OpamFile.Config.(with_opam_root_version root_version empty) init_config |> OpamFile.Config.with_repositories (List.map fst repos) in let dontswitch = if bypass_checks then false else let all_ok = init_checks init_config in if not all_ok && not (OpamConsole.confirm "Continue initialisation anyway ?") then OpamStd.Sys.exit_because `Configuration_error else not all_ok in let custom_scripts = let env v = let vs = OpamVariable.Full.variable v in OpamStd.Option.Op.(OpamStd.Option.of_Not_found (List.assoc vs) OpamSysPoll.variables >>= Lazy.force) in let scripts = OpamFile.InitConfig.init_scripts init_config in OpamStd.List.filter_map (fun ((nam,scr),oflt) -> match oflt with | None -> Some (nam,scr) | Some flt -> if OpamFilter.eval_to_bool env flt then Some (nam,scr) else None) scripts in OpamEnv.write_custom_init_scripts root custom_scripts; let config = if check_sandbox then OpamAuxCommands.check_and_revert_sandboxing root config else config in OpamFile.Config.write config_f config; let repos_config = OpamRepositoryName.Map.of_list repos |> OpamRepositoryName.Map.map OpamStd.Option.some in OpamFile.Repos_config.write (OpamPath.repos_config root) repos_config; log "updating repository state"; let gt = OpamGlobalState.load `Lock_write in let rt = OpamRepositoryState.load `Lock_write gt in OpamConsole.header_msg "Fetching repository information"; let failed, rt = OpamRepositoryCommand.update_with_auto_upgrade rt (List.map fst repos) in if failed <> [] then (if root_empty then (try OpamFilename.rmdir root with _ -> ()); OpamConsole.error_and_exit `Sync_error "Initial download of repository failed."); let default_compiler = if dontswitch then [] else let chrono = OpamConsole.timer () in let alternatives = OpamFormula.to_dnf (OpamFile.InitConfig.default_compiler init_config) in let invariant = OpamFile.InitConfig.default_invariant init_config in let virt_st = OpamSwitchState.load_virtual ~avail_default:false gt rt in let univ = OpamSwitchState.universe virt_st ~requested:OpamPackage.Name.Set.empty Query in let univ = { univ with u_invariant = invariant } in let default_compiler = OpamStd.List.find_opt (OpamSolver.atom_coinstallability_check univ) alternatives |> OpamStd.Option.default [] in log "Selected default compiler %s in %0.3fs" (OpamFormula.string_of_atoms default_compiler) (chrono ()); default_compiler in gt, OpamRepositoryState.unlock ~cleanup:false rt, default_compiler with e -> OpamStd.Exn.finalise e @@ fun () -> if not (OpamConsole.debug ()) && root_empty then begin OpamSystem.release_all_locks (); OpamFilename.rmdir root end) in OpamEnv.setup root ~interactive ?dot_profile ?update_config ?env_hook ~completion shell; gt, rt, default_compiler (* Checks a request for [atoms] for conflicts with the orphan packages *) let check_conflicts t atoms = let changes = OpamSwitchState.packages_of_atoms t atoms in let t, full_orphans, orphan_versions = orphans ~changes t in let available = Lazy.force t.available_packages in let available_changes = changes %% available in (* packages which still have local data are OK for install/reinstall if still "available" *) let full_orphans_reinstallable, full_orphans = OpamPackage.Set.partition (fun nv -> match OpamPackage.Map.find_opt nv t.opams with | None -> false | Some opam -> OpamFilter.eval_to_bool ~default:false (OpamPackageVar.resolve_switch ~package:nv t) (OpamFile.OPAM.available opam)) full_orphans in let orphan_versions_reinstallable, orphan_versions = OpamPackage.Set.partition (fun nv -> not (OpamPackage.has_name available_changes nv.name) && match OpamPackage.Map.find_opt nv t.opams with | None -> false | Some opam -> OpamFilter.eval_to_bool ~default:false (OpamPackageVar.resolve_switch ~package:nv t) (OpamFile.OPAM.available opam)) orphan_versions in let orphans = full_orphans ++ orphan_versions in let conflict_atoms = let non_orphans = lazy (t.packages -- full_orphans -- orphan_versions) in List.filter (fun (name,_ as a) -> not (OpamPackage.has_name t.pinned name) && OpamPackage.Set.exists (OpamFormula.check a) orphans && (*optim*) not (OpamPackage.Set.exists (OpamFormula.check a) (* real check *) (Lazy.force non_orphans))) atoms in if conflict_atoms <> [] then (* Atoms that were unavailable to begin with should be already filtered out at this point (by [sanitize_atom_list]) *) OpamConsole.error_and_exit `Not_found "Sorry, these packages are no longer available from the repositories: \ %s" (OpamStd.Format.pretty_list (List.map OpamFormula.string_of_atom conflict_atoms)) else {t with available_packages = lazy (available ++ full_orphans_reinstallable ++ orphan_versions_reinstallable)}, full_orphans, orphan_versions let check_installed ~build ~post t atoms = let available = (Lazy.force t.available_packages) in let uninstalled = OpamPackage.Set.Op.(available -- t.installed) in let pkgs = OpamPackage.to_map (OpamFormula.packages_of_atoms available atoms) in let test = OpamStateConfig.(!r.build_test) in let doc = OpamStateConfig.(!r.build_doc) in let env p = OpamFilter.deps_var_env ~build ~post ~test ~doc ~dev:(OpamSwitchState.is_dev_package t p) in OpamPackage.Name.Map.fold (fun name versions map -> let compliant, missing_opt = OpamPackage.Version.Set.fold (fun version (found, missing) -> if found then (found, missing) else let pkg = OpamPackage.create name version in let cnf_formula = OpamSwitchState.opam t pkg |> OpamFile.OPAM.depends |> OpamFilter.filter_formula (env pkg) |> OpamFormula.to_cnf in let missing_conj = List.filter (List.for_all (fun ((n,_vc) as atom) -> OpamPackage.Set.for_all (fun p -> not (OpamFormula.check atom p)) (OpamPackage.packages_of_name t.installed n))) cnf_formula in if missing_conj = [] then true, None else false, Some (pkg,missing_conj)) versions (false,None) in if compliant then map else match missing_opt with | None -> assert false (* version set can't be empty *) | Some (pkg, missing_conj) -> OpamPackage.Map.add pkg (OpamPackage.names_of_packages (List.fold_left (fun names disj -> OpamPackage.Set.union names (OpamFormula.packages_of_atoms uninstalled disj)) OpamPackage.Set.empty missing_conj)) map ) pkgs OpamPackage.Map.empty let assume_built_restrictions ?available_packages t atoms = let missing = check_installed ~build:false ~post:false t atoms in let atoms = if OpamPackage.Map.is_empty missing then atoms else (OpamConsole.warning "You specified '--assume-built' but the following dependencies \ aren't installed, skipping\n%s\ Launch 'opam install %s --deps-only' (and recompile) to \ install them.\n" (OpamStd.Format.itemize (fun (nv, names) -> Printf.sprintf "%s: %s" (OpamPackage.name_to_string nv) (OpamStd.List.concat_map " " OpamPackage.Name.to_string (OpamPackage.Name.Set.elements names))) (OpamPackage.Map.bindings missing)) (OpamStd.List.concat_map " " OpamPackage.name_to_string (OpamPackage.Map.keys missing)); List.filter (fun (n,_) -> not (OpamPackage.Map.exists (fun nv _ -> OpamPackage.name nv = n) missing)) atoms) in let pinned = (* Not pinned atoms already removed. *) OpamPackage.Set.filter (fun p -> List.exists (fun a -> OpamFormula.check a p) atoms) t.pinned in let installed_dependencies = OpamSolver.dependencies ~build:false ~post:false ~depopts:false ~installed:true ~unavailable:false (OpamSwitchState.universe t ~requested:(OpamPackage.names_of_packages pinned) Query) pinned in let available_packages = match available_packages with | Some a -> a | None -> Lazy.force t.available_packages in let uninstalled_dependencies = (OpamPackage.Map.values missing |> List.fold_left OpamPackage.Name.Set.union OpamPackage.Name.Set.empty |> OpamPackage.packages_of_names available_packages) -- installed_dependencies in let available_packages = lazy ( (available_packages -- uninstalled_dependencies) ++ t.installed ++ pinned ) in let fixed_atoms = List.map (fun nv -> (OpamPackage.name nv , Some (`Eq, OpamPackage.version nv))) (OpamPackage.Set.elements pinned @ OpamPackage.Set.elements installed_dependencies) in { t with available_packages }, fixed_atoms let filter_unpinned_locally t atoms f = OpamStd.List.filter_map (fun at -> let n,_ = at in if OpamSwitchState.is_pinned t n && OpamStd.Option.Op.(OpamPinned.package_opt t n >>= OpamSwitchState.primary_url t >>= OpamUrl.local_dir) <> None then Some (f at) else (log "Package %a is not pinned locally and assume built \ option is set, skipping" (slog OpamPackage.Name.to_string) n; None)) atoms let install_t t ?ask ?(ignore_conflicts=false) ?(depext_only=false) ?(download_only=false) atoms add_to_roots ~deps_only ~assume_built = log "INSTALL %a" (slog OpamFormula.string_of_atoms) atoms; let names = OpamPackage.Name.Set.of_list (List.rev_map fst atoms) in let t, full_orphans, orphan_versions = check_conflicts t atoms in let atoms = let compl = function | (_, Some _) as at -> at | (name, None) as at -> match OpamPinned.package_opt t name with | Some nv -> OpamSolution.eq_atom_of_package nv | None -> at in if assume_built then filter_unpinned_locally t atoms compl else List.map compl atoms in let pkg_skip, pkg_new = get_installed_atoms t atoms in let pkg_reinstall = if assume_built then OpamPackage.Set.of_list pkg_skip else Lazy.force t.reinstall %% OpamPackage.Set.of_list pkg_skip in (* Add the packages to the list of package roots and display a warning for already installed package roots. *) let current_roots = t.installed_roots in let t = if deps_only then t else List.fold_left (fun t nv -> if OpamPackage.Set.mem nv t.installed then match add_to_roots with | None -> if not (OpamPackage.Set.mem nv pkg_reinstall) then OpamConsole.note "Package %s is already installed (current version is %s)." (OpamPackage.Name.to_string nv.name) (OpamPackage.Version.to_string nv.version); t | Some true -> if OpamPackage.Set.mem nv t.installed_roots then OpamConsole.note "Package %s is already installed as a root." (OpamPackage.Name.to_string nv.name); { t with installed_roots = OpamPackage.Set.add nv t.installed_roots } | Some false -> if OpamPackage.Set.mem nv t.installed_roots then begin if OpamPackage.Set.mem nv t.compiler_packages then OpamConsole.note "Package %s is part of the switch invariant and won't be uninstalled \ unless the invariant is updated." (OpamPackage.name_to_string nv); { t with installed_roots = OpamPackage.Set.remove nv t.installed_roots } end else (OpamConsole.note "Package %s is already marked as 'installed automatically'." (OpamPackage.Name.to_string nv.name); t) else t ) t pkg_skip in if t.installed_roots <> current_roots then ( let diff = t.installed_roots -- current_roots in if not (OpamPackage.Set.is_empty diff) then let diff = OpamPackage.Set.elements diff in let diff = List.rev (List.rev_map OpamPackage.to_string diff) in OpamConsole.msg "Adding %s to the list of installed roots.\n" (OpamStd.Format.pretty_list diff) else ( let diff = current_roots -- t.installed_roots in let diff = OpamPackage.Set.elements diff in let diff = List.rev (List.rev_map OpamPackage.to_string diff) in OpamConsole.msg "Removing %s from the list of installed roots.\n" (OpamStd.Format.pretty_list diff) ); OpamSwitchAction.write_selections t ); let available_packages = Lazy.force t.available_packages in let available_packages = if deps_only then (* Assume the named packages are available *) List.fold_left (fun avail (name, _ as atom) -> if OpamPackage.Set.exists (OpamFormula.check atom) avail then avail else match OpamPinned.package_opt t name with | Some nv when OpamFormula.check atom nv -> OpamPackage.Set.add nv avail | _ -> avail ++ OpamPackage.Set.filter (OpamFormula.check atom) t.packages) available_packages atoms else (OpamSolution.check_availability t available_packages atoms; available_packages) in let opams = if deps_only && ignore_conflicts then (let pkgs = OpamFormula.packages_of_atoms available_packages atoms in log "removing conflicts from %s" (OpamPackage.Set.to_string pkgs); OpamPackage.Set.fold (fun pkg opams -> let opam = OpamFile.OPAM.with_conflicts Empty (OpamSwitchState.opam t pkg) in OpamPackage.Map.add pkg opam opams) pkgs t.opams) else t.opams in let t = {t with available_packages = lazy available_packages; opams} in if pkg_new = [] && OpamPackage.Set.is_empty pkg_reinstall then t else let t, atoms = if assume_built then assume_built_restrictions ~available_packages t atoms else t, atoms in let request = OpamSolver.request ~install:atoms () in let solution = let reinstall = if assume_built then Some pkg_reinstall else None in OpamSolution.resolve t Install ~orphans:(full_orphans ++ orphan_versions) ~requested:names ?reinstall request in let t, solution = match solution with | Conflicts cs -> log "conflict!"; OpamConsole.error "Package conflict!"; let (conflicts, _cycles) as explanations = OpamCudf.conflict_explanations_raw t.packages cs in let has_missing_depexts = let check = function | `Missing (_, _, fdeps) -> OpamFormula.fold_right (fun a x -> match OpamSwitchState.unavailable_reason_raw t x with | `MissingDepexts _ -> true | _ -> a) false fdeps | _ -> false in List.exists check conflicts in let extra_message = if has_missing_depexts then OpamStd.Option.map_default (fun s -> s ^ ".\n\n") "" (OpamSysInteract.repo_enablers ()) else "" in OpamConsole.errmsg "%s%s" (OpamCudf.string_of_explanations (OpamSwitchState.unavailable_reason t) explanations) extra_message; t, if depext_only then None else Some (Conflicts cs) | Success full_solution -> let solution = if deps_only then OpamSolver.filter_solution (fun nv -> not (OpamPackage.Name.Set.mem nv.name names)) full_solution else full_solution in if depext_only then (OpamSolution.install_depexts ~force_depext:true ~confirm:false t (OpamSolver.all_packages solution)), None else let add_roots = if deps_only && add_to_roots <> Some false then let requested_deps = OpamPackage.Set.fold (fun nv acc -> OpamFormula.ors [ OpamPackageVar.all_depends t (OpamSwitchState.opam t nv) ~depopts:false ~build:true ~post:false; acc ]) (OpamPackage.packages_of_names (OpamSolver.all_packages full_solution) names) OpamFormula.Empty in Some (OpamPackage.names_of_packages (OpamFormula.packages (OpamSolver.all_packages solution) requested_deps)) else OpamStd.Option.map (function | true -> names | false -> OpamPackage.Name.Set.empty) add_to_roots in let t, res = OpamSolution.apply ?ask t ~requested:names ?add_roots ~download_only ~assume_built solution in t, Some (Success res) in OpamStd.Option.iter (OpamSolution.check_solution t) solution; t let install t ?autoupdate ?add_to_roots ?(deps_only=false) ?(ignore_conflicts=false) ?(assume_built=false) ?(download_only=false) ?(depext_only=false) names = let atoms = OpamSolution.sanitize_atom_list ~permissive:true t names in let autoupdate_atoms = match autoupdate with | None -> atoms | Some a -> OpamSolution.sanitize_atom_list ~permissive:true t a in let t = update_dev_packages_t autoupdate_atoms t in install_t t atoms add_to_roots ~ignore_conflicts ~depext_only ~deps_only ~download_only ~assume_built let remove_t ?ask ~autoremove ~force atoms t = log "REMOVE autoremove:%b %a" autoremove (slog OpamFormula.string_of_atoms) atoms; let t, full_orphans, orphan_versions = if atoms = [] then t, OpamPackage.Set.empty, OpamPackage.Set.empty else let changes = OpamSwitchState.packages_of_atoms t atoms in orphans ~changes t in let nothing_to_do = ref true in let packages, not_installed = get_installed_atoms t atoms in if not_installed <> [] then ( if force then let force_remove atom = let candidates = OpamPackage.Set.filter (OpamFormula.check atom) t.packages in try let nv = OpamPackage.max_version candidates (fst atom) in OpamConsole.note "Forcing removal of (uninstalled) %s" (OpamPackage.to_string nv); OpamProcess.Job.run (OpamAction.remove_package t nv); OpamAction.cleanup_package_artefacts t nv; nothing_to_do := false with Not_found -> OpamConsole.error "No package %s found for (forced) removal.\n" (OpamFormula.short_string_of_atom atom) in List.iter force_remove not_installed else OpamConsole.note "%s %s not installed.\n" (OpamStd.Format.pretty_list (List.map OpamFormula.short_string_of_atom not_installed)) (match not_installed with [_] -> "is" | _ -> "are") ); if autoremove || packages <> [] then ( let packages = OpamPackage.Set.of_list packages in let universe = OpamSwitchState.universe t ~requested:(OpamPackage.names_of_packages packages) Remove in let to_remove = OpamSolver.reverse_dependencies ~build:true ~post:true ~depopts:false ~installed:true universe packages in let to_keep = (if autoremove then t.installed_roots %% t.installed else t.installed) ++ universe.u_base -- to_remove in let to_keep = OpamSolver.dependencies ~build:true ~post:true ~depopts:true ~installed:true universe to_keep in (* to_keep includes the depopts, because we don't want to autoremove them. But that may re-include packages that we wanted removed, so we need to remove them again *) let to_keep = to_keep -- to_remove in let requested = OpamPackage.names_of_packages packages in let to_remove = if autoremove then let to_remove1 = t.installed -- to_keep in if atoms = [] then to_remove1 else (* restrict to the dependency cone of removed pkgs *) to_remove1 %% (OpamSolver.dependencies ~build:true ~post:true ~depopts:true ~installed:true universe to_remove) else to_remove in let t, solution = OpamSolution.resolve_and_apply ?ask t Remove ~force_remove:force ~requested ~orphans:(full_orphans ++ orphan_versions) (OpamSolver.request ~install:(OpamSolution.eq_atoms_of_packages to_keep) ~remove:(OpamSolution.atoms_of_packages to_remove) ()) in OpamSolution.check_solution t solution; t ) else if !nothing_to_do then ( OpamConsole.msg "Nothing to do.\n"; t ) else t let remove t ~autoremove ~force names = let atoms = OpamSolution.sanitize_atom_list t names in remove_t ~autoremove ~force atoms t let reinstall_t t ?ask ?(force=false) ~assume_built atoms = log "reinstall %a" (slog OpamFormula.string_of_atoms) atoms; let atoms = if assume_built then filter_unpinned_locally t atoms (fun x -> x) else atoms in let reinstall, not_installed = get_installed_atoms t atoms in let to_install = if not_installed <> [] then if force || assume_built || OpamConsole.confirm "%s %s not installed. Install %s?" (OpamStd.Format.pretty_list (List.rev_map OpamFormula.short_string_of_atom not_installed)) (match not_installed with [_] -> "is" | _ -> "are") (match not_installed with [_] -> "it" | _ -> "them") then not_installed else OpamStd.Sys.exit_because `Aborted else [] in let reinstall = OpamPackage.Set.of_list reinstall in let atoms = to_install @ OpamSolution.eq_atoms_of_packages reinstall in let t, full_orphans, orphan_versions = check_conflicts t atoms in let requested = OpamPackage.Name.Set.of_list (List.rev_map fst atoms) in let t, atoms = if assume_built then assume_built_restrictions t atoms else t, atoms in let request = OpamSolver.request ~install:atoms ~criteria:`Fixup () in let t, solution = OpamSolution.resolve_and_apply ?ask t Reinstall ~orphans:(full_orphans ++ orphan_versions) ~reinstall:(OpamPackage.packages_of_names t.installed requested) ~requested ~assume_built request in OpamSolution.check_solution t solution; t let reinstall t ?(assume_built=false) names = let atoms = OpamSolution.sanitize_atom_list t names in let t = update_dev_packages_t atoms t in reinstall_t t ~assume_built atoms module PIN = struct open OpamPinCommand let post_pin_action st was_pinned names = let names = OpamPackage.Set.Op.(st.pinned -- was_pinned) |> OpamPackage.names_of_packages |> (fun s -> List.fold_left (fun s p -> OpamPackage.Name.Set.add p s) s names) |> OpamPackage.Name.Set.elements in try upgrade_t ~strict_upgrade:false ~auto_install:true ~ask:true ~terse:true ~all:false (List.map (fun name -> name, None) names) st with e -> OpamConsole.note "Pinning command successful, but your installed packages \ may be out of sync."; raise e let get_upstream t name = try match OpamStd.Option.Op.( OpamSwitchState.get_package t name |> OpamSwitchState.opam_opt t >>= OpamFile.OPAM.dev_repo ) with | None -> OpamConsole.error_and_exit `Not_found "\"dev-repo\" field missing in %s metadata, you'll need to specify \ the pinning location" (OpamPackage.Name.to_string name) | Some url -> url with Not_found -> OpamConsole.error_and_exit `Not_found "No package named %S found" (OpamPackage.Name.to_string name) let pin st name ?(edit=false) ?version ?(action=true) ?subpath ?locked target = try let pinned = st.pinned in let st = match target with | `Source url -> source_pin st name ?version ~edit ?subpath ?locked (Some url) | `Version v -> let st = version_pin st name v in if edit then OpamPinCommand.edit st name else st | `Source_version (srcv, version) -> let url = let nv = (OpamPackage.create name srcv) in match OpamPackage.Map.find_opt nv st.repos_package_index with | Some opam -> (match OpamStd.Option.Op.(OpamFile.OPAM.url opam >>| OpamFile.URL.url) with | Some u -> u | None -> OpamConsole.error_and_exit `Not_found "Package %s has no url defined in its opam file description" (OpamPackage.to_string nv)) | None -> OpamConsole.error_and_exit `Not_found "Package %s has no known version %s in the repositories" (OpamPackage.Name.to_string name) (OpamPackage.Version.to_string version) in source_pin st name ~version ~edit ?locked (Some url) | `Dev_upstream -> source_pin st name ?version ~edit ?locked (Some (get_upstream st name)) | `None -> source_pin st name ?version ~edit ?locked None in if action then (OpamConsole.msg "\n"; post_pin_action st pinned [name]) else st with | OpamPinCommand.Aborted -> OpamStd.Sys.exit_because `Aborted | OpamPinCommand.Nothing_to_do -> st let url_pins st ?edit ?(action=true) ?locked ?(pre=fun _ -> ()) pins = let names = List.map (fun (n,_,_,_,_) -> n) pins in (match names with | _::_::_ -> if not (OpamConsole.confirm "This will pin the following packages: %s. Continue?" (OpamStd.List.concat_map ", " OpamPackage.Name.to_string names)) then OpamStd.Sys.exit_because `Aborted | _ -> ()); let pins = let urls_ok = OpamPinCommand.fetch_all_pins st (List.map (fun (name, _, _, url, subpath) -> name, url, subpath) pins) in List.filter (fun (_,_,_, url, subpath) -> List.mem (url, subpath) urls_ok) pins in let pinned = st.pinned in let st = List.fold_left (fun st (name, version, opam, url, subpath as pin) -> pre pin; try OpamPinCommand.source_pin st name ?version ?opam ?edit ?subpath ?locked (Some url) with | OpamPinCommand.Aborted -> OpamStd.Sys.exit_because `Aborted | OpamPinCommand.Nothing_to_do -> st) st pins in if action then (OpamConsole.msg "\n"; post_pin_action st pinned names) else st let edit st ?(action=true) ?version ?locked name = let pinned = st.pinned in let st = if OpamPackage.has_name st.pinned name then edit st ?version name else let pin_nv = match version with | Some v -> let nv = OpamPackage.create name v in if OpamPackage.Set.mem nv st.packages then Some nv else None | None -> OpamStd.Option.of_Not_found (OpamSwitchState.get_package st) name in match pin_nv with | Some nv -> if OpamConsole.confirm "Package %s is not pinned. Edit as a new pinning to version %s?" (OpamPackage.Name.to_string name) (OpamPackage.version_to_string nv) then let target = OpamStd.Option.Op.(OpamSwitchState.url st nv >>| OpamFile.URL.url) in let opam = OpamPackage.Map.find_opt nv st.repos_package_index in try source_pin st name ~edit:true ?version ?opam ?locked target with OpamPinCommand.Aborted -> OpamStd.Sys.exit_because `Aborted | OpamPinCommand.Nothing_to_do -> st else OpamStd.Sys.exit_because `Aborted | None -> OpamConsole.error_and_exit `Not_found "Package is not pinned, and no existing version was supplied." in if action then post_pin_action st pinned [name] else st let unpin st ?(action=true) names = let pinned_before = st.pinned in let st = unpin st names in let installed_unpinned = (pinned_before -- st.pinned) %% st.installed in if action && not (OpamPackage.Set.is_empty installed_unpinned) then let atoms = OpamPackage.Set.fold (fun nv acc -> (nv.name, None) :: acc) installed_unpinned [] in upgrade_t ~strict_upgrade:false ~auto_install:true ~ask:true ~all:false ~terse:true atoms st else st let list = list end opam-2.1.5/src/client/opamPinCommand.mli0000644000175000017500000000774514427463453017206 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2018 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Functions handling the "opam pin" subcommand *) open OpamTypes open OpamStateTypes (** Pins a package to the given version, and writes to disk. Returns the updated state. The main difference with [source_pin] is that a definition overlay is not created. Therefore, the package must exist already. *) val version_pin: rw switch_state -> name -> version -> rw switch_state exception Aborted exception Nothing_to_do (** Sets the package as pinned to the given target. A package definition is looked for in the package source and current metadata (in this order), unless specified using [~opam]. If [edit], or if no package definition is found, this opens an editor (with a template if no definition is available). If [force], don't abort even if the source can't be fetched from [target] May raise [Aborted] or [Nothing_to_do]. *) val source_pin: rw switch_state -> name -> ?version:version -> ?edit:bool -> ?opam:OpamFile.OPAM.t -> ?quiet:bool -> ?force:bool -> ?ignore_extra_pins:bool -> ?subpath: string -> ?locked:bool -> url option -> rw switch_state (** Interactively handles the [pin-depends] in an opam file *) val handle_pin_depends: rw switch_state -> package -> OpamFile.OPAM.t -> rw switch_state (** Fetch in parallel jobs a list of pins [name, url, subpath], and return the successful ones. Ask for confirmation to continue if a fetching fails. *) val fetch_all_pins: 'a switch_state -> ?working_dir:bool -> (name * url * string option) list -> (url * string option) list (** Let the user edit a pinned package's opam file. If given, the version is put into the template in advance. Writes and returns the updated switch state. *) val edit: rw switch_state -> ?version:version -> name -> rw switch_state (** Unpin packages *) val unpin: rw switch_state -> name list -> rw switch_state (** Pure function that reverts a single package pinning *) val unpin_one: 'a switch_state -> package -> 'a switch_state (** List the pinned packages to the user. *) val list: 'a switch_state -> short:bool -> unit (** Scan pinning separator, used for printing and parsing by [scan] and [parse_pins]. *) val scan_sep: char (** Scan for available packages to pin, and display it on stdout. If [normalise] is true, displays it's normalised format `name.version[scan_sep]url[scan_sep]subpath`. *) val scan: normalise:bool -> recurse:bool -> ?subpath: string -> url -> unit (** Detect if a string is a normalised format of [scan]. *) val looks_like_normalised: string list -> bool (** Parse the normalised form of [scan], and returns pinning informations. *) val parse_pins: string list -> (name * version option * url * string option) list (** Lints the given opam file, prints warnings or errors accordingly (unless [quiet]), upgrades it to current format, adds references to files below the 'files/' subdir (unless the file is directly below the specified, local [url]), and returns it *) val read_opam_file_for_pinning: ?quiet:bool -> name -> OpamFile.OPAM.t OpamFile.t -> url -> OpamFile.OPAM.t option (** The default version for pinning a package: depends on the state, what is installed and available, and defaults to [~dev]. *) val default_version: 'a switch_state -> name -> version opam-2.1.5/src/client/opamClient.mli0000644000175000017500000001604314427463453016366 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** High-level execution of user-facing functions like install and upgrade, and wrappers around the pinning commands *) open OpamTypes open OpamStateTypes (** Initialize the client to a consistent state. Returns the initial state and, in case a switch is to be created, its initial set of packages *) val init: init_config:OpamFile.InitConfig.t -> interactive:bool -> ?repo:repository -> ?bypass_checks:bool -> ?dot_profile:filename -> ?update_config:bool -> ?env_hook:bool -> ?completion:bool -> ?check_sandbox:bool -> shell -> rw global_state * unlocked repos_state * atom list (* (\** Gets the initial config (opamrc) to be used *\) * val get_init_config: * no_default_config_file:bool -> * add_config_file:OpamUrl.t -> * OpamFile.InitConfig.t *) (** Re-runs the extra tools checks, updates the configuration from [init_config] (defaults to [OpamInitDefaults.init_config]) for the settings that are unset, and updates all repositories *) val reinit: ?init_config:OpamFile.InitConfig.t -> interactive:bool -> ?dot_profile:filename -> ?update_config:bool -> ?env_hook:bool -> ?completion:bool -> ?inplace:bool -> ?check_sandbox:bool -> ?bypass_checks:bool -> OpamFile.Config.t -> shell -> unit (** Install the given list of packages. [add_to_roots], if given, specifies that given packages should be added or removed from the roots. [autoupdate] defaults to the list of atoms, and can be used to restrict the atoms which are updated if pinned. *) val install: rw switch_state -> ?autoupdate:atom list -> ?add_to_roots:bool -> ?deps_only:bool -> ?ignore_conflicts:bool -> ?assume_built:bool -> ?download_only:bool -> ?depext_only:bool -> atom list -> rw switch_state (** Low-level version of [reinstall], bypassing the package name sanitization and dev package update, and offering more control *) val install_t: rw switch_state -> ?ask:bool -> ?ignore_conflicts:bool -> ?depext_only:bool -> ?download_only:bool -> atom list -> bool option -> deps_only:bool -> assume_built:bool -> rw switch_state (** Check that the given list of packages [atoms] have their dependencies satisfied, without calling the solver. Returns missing dependencies. *) val check_installed: build:bool -> post:bool -> rw switch_state -> atom list -> OpamPackage.Name.Set.t OpamPackage.Map.t (** Reinstall the given set of packages. *) val reinstall: rw switch_state -> ?assume_built:bool -> atom list -> rw switch_state (** Low-level version of [reinstall], bypassing the package name sanitization and dev package update, and offering more control *) val reinstall_t: rw switch_state -> ?ask:bool -> ?force:bool -> assume_built:bool -> atom list -> rw switch_state (** Update the local mirrors for the repositories and/or development packages. Returns [(success, changes, rt)], where [success] is [true] only if all updates were successful, [changes] is true if any upstream had updates, and [rt] is the updated repository state. *) val update: 'a global_state -> repos_only:bool -> dev_only:bool -> ?all:bool -> string list -> bool * bool * unlocked repos_state (** Upgrade the switch, that is, move packages to their more recent available versions. The specified atoms are kept installed (or newly installed after a confirmation). The upgrade concerns them only unless [all] is specified. *) val upgrade: rw switch_state -> ?check:bool -> ?only_installed:bool -> all:bool -> atom list -> rw switch_state (** Low-level version of [upgrade], bypassing the package name sanitization and dev package update, and offering more control. [terse] avoids the verbose message when we are at a local maximum, but there are possible upgrades *) val upgrade_t: ?strict_upgrade:bool -> ?auto_install:bool -> ?ask:bool -> ?check:bool -> ?terse:bool -> ?only_installed:bool -> all:bool -> atom list -> rw switch_state -> rw switch_state (** Recovers from an inconsistent universe *) val fixup: rw switch_state -> rw switch_state (** Remove the given list of packages. *) val remove: rw switch_state -> autoremove:bool -> force:bool -> atom list -> rw switch_state module PIN: sig (** Set a package pinning. If [action], prompt for install/reinstall as appropriate after pinning. *) val pin: rw switch_state -> OpamPackage.Name.t -> ?edit:bool -> ?version:version -> ?action:bool -> ?subpath:string -> ?locked:bool -> [< `Source of url | `Version of version | `Dev_upstream | `Source_version of version * version (* the first version is the source one, the second the package one *) | `None ] -> rw switch_state val edit: rw switch_state -> ?action:bool -> ?version:version -> ?locked:bool -> OpamPackage.Name.t -> rw switch_state val url_pins: rw switch_state -> ?edit:bool -> ?action:bool -> ?locked:bool -> ?pre:((name * version option * OpamFile.OPAM.t option * url * string option) -> unit) -> (name * version option * OpamFile.OPAM.t option * url * string option) list -> rw switch_state val unpin: rw switch_state -> ?action:bool -> OpamPackage.Name.t list -> rw switch_state (** List the current pinned packages. *) val list: 'a switch_state -> short:bool -> unit (** Runs an install/upgrade on the listed packages if necessary. [post_pin_action st was_pinned names] takes the set of packages pinned beforehand, and a list of newly pinned packages *) val post_pin_action: rw switch_state -> package_set -> name list -> rw switch_state end (** {2 Auxiliary functions} These functions are exposed for advanced uses by external libraries *) (** Orphan packages are installed but no longer available packages; we add special treatment so that opam doesn't force their removal for consistency reasons on any action. Returns the "fixed" state, fully orphan packages (no available version of the package remaining), and orphan package versions. Find more technical explanations in the source. *) val orphans: ?changes:package_set -> ?transitive:bool -> 'a switch_state -> 'a switch_state * package_set * package_set (** An extended version of [orphans] that checks for conflicts between a given request and the orphan packages *) val check_conflicts: 'a switch_state -> atom list -> 'a switch_state * package_set * package_set opam-2.1.5/src/client/opamBase64Compat.ml.50000644000175000017500000000013214427463453017322 0ustar stephstephmodule Base64 = struct let decode_exn = B64.decode let encode_string = B64.encode end opam-2.1.5/src/client/opamCommands.ml0000644000175000017500000050700314427463453016541 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open Cmdliner open OpamArg open OpamTypes open OpamStateTypes open OpamTypesBase open OpamStd.Op let self_upgrade_exe opamroot = OpamFilename.Op.(opamroot // "opam", opamroot // "opam.version") let self_upgrade_bootstrapping_value = "bootstrapping" let switch_to_updated_self debug opamroot = let updated_self, updated_self_version = self_upgrade_exe opamroot in let updated_self_str = OpamFilename.to_string updated_self in let updated_self_version_str = OpamFilename.to_string updated_self_version in if updated_self_str <> Sys.executable_name && OpamFilename.exists updated_self && OpamFilename.is_exec updated_self && OpamFilename.exists updated_self_version then let no_version = OpamVersion.of_string "" in let update_version = try let s = OpamSystem.read updated_self_version_str in let s = let len = String.length s in if len > 0 && s.[len-1] = '\n' then String.sub s 0 (len-1) else s in OpamVersion.of_string s with e -> OpamStd.Exn.fatal e; no_version in if update_version = no_version then OpamConsole.error "%s exists but cannot be read, disabling self-upgrade." updated_self_version_str else if OpamVersion.compare update_version OpamVersion.current <= 0 then OpamConsole.warning "Obsolete opam self-upgrade package v.%s found, \ not using it (current system version is %s)." (OpamVersion.to_string update_version) (OpamVersion.to_string OpamVersion.current) else ( if OpamVersion.is_dev_version () then OpamConsole.warning "Using opam self-upgrade to %s while the system \ opam is a development version (%s)" (OpamVersion.to_string update_version) (OpamVersion.to_string (OpamVersion.full ())); (if debug || (OpamConsole.debug ()) then OpamConsole.errmsg "!! %s found, switching to it !!\n" updated_self_str; let env = Array.append [|"OPAMNOSELFUPGRADE="^ self_upgrade_bootstrapping_value|] (Unix.environment ()) in try OpamStd.Sys.exec_at_exit (); Unix.execve updated_self_str Sys.argv env with e -> OpamStd.Exn.fatal e; OpamConsole.error "Couldn't run the upgraded opam %s found at %s. \ Continuing with %s from the system." (OpamVersion.to_string update_version) updated_self_str (OpamVersion.to_string OpamVersion.current))) let global_options cli = let no_self_upgrade = mk_flag ~cli cli_original ~section:global_option_section ["no-self-upgrade"] (Printf.sprintf "Opam will replace itself with a newer binary found \ at $(b,OPAMROOT%sopam) if present. This disables this behaviour." OpamArg.dir_sep) in let self_upgrade no_self_upgrade options = let self_upgrade_status = if OpamClientConfig.E.noselfupgrade () = Some self_upgrade_bootstrapping_value then `Running else if no_self_upgrade then `Disable else if OpamStd.Option.Op.((OpamClientConfig.E.noselfupgrade ()) >>= OpamStd.Config.bool_of_string) = Some true then `Disable else `None in if self_upgrade_status = `None then switch_to_updated_self OpamStd.Option.Op.(options.debug_level ++ OpamCoreConfig.E.debug () +! 0 |> abs > 0) (OpamStateConfig.opamroot ?root_dir:options.opt_root ()); let root_is_ok = OpamStd.Option.default false (OpamClientConfig.E.rootisok ()) in if not (options.safe_mode || root_is_ok) && Unix.getuid () = 0 then OpamConsole.warning "Running as root is not recommended"; {options with cli = fst cli}, self_upgrade_status in Term.(const self_upgrade $ no_self_upgrade $ global_options cli) let apply_global_options cli (options,self_upgrade) = apply_global_options cli options; OpamConsole.log "CLI" "Parsing CLI version %s" (OpamCLIVersion.to_string options.cli); try let argv0 = OpamFilename.of_string Sys.executable_name in if self_upgrade <> `Running && OpamFilename.starts_with OpamStateConfig.(!r.root_dir) argv0 && not !OpamCoreConfig.r.OpamCoreConfig.safe_mode then OpamConsole.warning "You should not be running opam from within %s. \ Copying %s to your PATH first is advised." (OpamFilename.Dir.to_string OpamStateConfig.(!r.root_dir)) (OpamFilename.to_string argv0) with e -> OpamStd.Exn.fatal e let self_upgrade_status global_options = snd global_options let get_init_config ~no_sandboxing ~no_default_config_file ~add_config_file = let builtin_config = OpamInitDefaults.init_config ~sandboxing:(not no_sandboxing) () in let config_files = (if no_default_config_file then [] else List.filter OpamFile.exists (OpamPath.init_config_files ())) @ List.map (fun url -> match OpamUrl.local_file url with | Some f -> OpamFile.make f | None -> let f = OpamFilename.of_string (OpamSystem.temp_file "conf") in OpamProcess.Job.run (OpamDownload.download_as ~overwrite:false url f); let hash = OpamHash.compute ~kind:`SHA256 (OpamFilename.to_string f) in if OpamConsole.confirm "Using configuration file from %s. \ Please verify the following SHA256:\n %s\n\ Is this correct?" (OpamUrl.to_string url) (OpamHash.contents hash) then OpamFile.make f else OpamStd.Sys.exit_because `Aborted ) add_config_file in try let others = match config_files with | [] -> "" | [file] -> OpamFile.to_string file ^ " and then from " | _ -> (OpamStd.List.concat_map ~right:", and finally from " ", then " OpamFile.to_string (List.rev config_files)) in if config_files = [] then OpamConsole.msg "No configuration file found, using built-in defaults.\n" else OpamConsole.msg "Configuring from %sbuilt-in defaults.\n" others; List.fold_left (fun acc f -> OpamFile.InitConfig.add acc (OpamFile.InitConfig.read f)) builtin_config config_files with e -> OpamConsole.error "Error in configuration file, fix it, use '--no-opamrc', or check \ your '--config FILE' arguments:"; OpamConsole.errmsg "%s\n" (Printexc.to_string e); OpamStd.Sys.exit_because `Configuration_error (* INIT *) let init_doc = "Initialize opam state, or set init options." let init cli = let doc = init_doc in let man = [ `S Manpage.s_description; `P "Initialise the opam state, or update opam init options"; `P (Printf.sprintf "The $(b,init) command initialises a local \"opam root\" (by default, \ $(i,~%s.opam%s)) that holds opam's data and packages. This is a \ necessary step for normal operation of opam. The initial software \ repositories are fetched, and an initial 'switch' can also be \ installed, according to the configuration and options. These can be \ afterwards configured using $(b,opam switch) and $(b,opam \ repository)." OpamArg.dir_sep OpamArg.dir_sep); `P (Printf.sprintf "The initial repository and defaults can be set through a \ configuration file found at $(i,~%s.opamrc) or $(i,/etc/opamrc)." OpamArg.dir_sep); `P "Additionally, this command allows one to customise some aspects of opam's \ shell integration, when run initially (avoiding the interactive \ dialog), but also at any later time."; `S Manpage.s_arguments; `S Manpage.s_options; `S "CONFIGURATION FILE"; `P (Printf.sprintf "Any field from the built-in initial configuration can be overridden \ through $(i,~%s.opamrc), $(i,/etc/opamrc), or a file supplied with \ $(i,--config). The default configuration for this version of opam \ can be obtained using $(b,--show-default-opamrc)." OpamArg.dir_sep); ] @ OpamArg.man_build_option_section in let compiler = mk_opt ~cli cli_original ["c";"compiler"] "PACKAGE" "Set the compiler to install (when creating an initial switch)" Arg.(some string) None in let no_compiler = mk_flag ~cli cli_original ["bare"] "Initialise the opam state, but don't setup any compiler switch yet." in let repo_name = let doc = Arg.info [] ~docv:"NAME" ~doc: "Name of the initial repository, when creating a new opam root." in Arg.(value & pos ~rev:true 1 repository_name OpamRepositoryName.default & doc) in let repo_url = let doc = Arg.info [] ~docv:"ADDRESS" ~doc: "Address of the initial package repository, when creating a new opam \ root." in Arg.(value & pos ~rev:true 0 (some string) None & doc) in let interactive = mk_vflag ~cli None [ cli_original, (Some false), ["a";"auto-setup"], "Automatically do a full setup, including adding a line to your \ shell init files."; cli_original, (Some true), ["i";"interactive"], "Run the setup interactively (this is the default for an initial \ run, or when no more specific options are specified)"; ] in let update_config = mk_vflag ~cli None [ cli_original, (Some true), ["shell-setup"], "Automatically setup the user shell configuration for opam, e.g. \ adding a line to the `~/.profile' file."; cli_original, (Some false), ["n";"no-setup"], "Do not update the user shell configuration to setup opam. Also \ implies $(b,--disable-shell-hook), unless $(b,--interactive) or \ specified otherwise"; ] in let setup_completion = mk_vflag ~cli None [ cli_original, (Some true), ["enable-completion"], "Setup shell completion in opam init scripts, for supported \ shells."; cli_original, (Some false), ["disable-completion"], "Disable shell completion in opam init scripts."; ] in let env_hook = mk_vflag ~cli None [ cli_original, (Some true), ["enable-shell-hook"], "Setup opam init scripts to register a shell hook that will \ automatically keep the shell environment up-to-date at every \ prompt."; cli_original, (Some false), ["disable-shell-hook"], "Disable registration of a shell hook in opam init scripts."; ] in let config_file = mk_opt_all ~cli cli_original ["config"] "FILE" "Use the given init config file. If repeated, latest has the highest \ priority ($(b,i.e.) each field gets its value from where it was defined \ last). Specifying a URL pointing to a config file instead is \ allowed." OpamArg.url in let no_config_file = mk_flag ~cli cli_original ["no-opamrc"] (Printf.sprintf "Don't read `/etc/opamrc' or `~%s.opamrc': use the default settings and \ the files specified through $(b,--config) only" OpamArg.dir_sep) in let reinit = mk_flag ~cli cli_original ["reinit"] "Re-run the initial checks and setup, according to opamrc, even if this \ is not a new opam root" in let show_default_opamrc = mk_flag ~cli cli_original ["show-default-opamrc"] "Print the built-in default configuration to stdout and exit" in let bypass_checks = mk_flag ~cli cli_original ["bypass-checks"] "Skip checks on required or recommended tools, and assume everything is \ fine" in let no_sandboxing = mk_flag ~cli cli_original ["disable-sandboxing"] "Use a default configuration with sandboxing disabled (note that this \ may be overridden by `opamrc' if $(b,--no-opamrc) is not specified or \ $(b,--config) is used). Use this at your own risk, without sandboxing \ it is possible for a broken package script to delete all your files." in let init global_options build_options repo_kind repo_name repo_url interactive update_config completion env_hook no_sandboxing shell dot_profile_o compiler no_compiler config_file no_config_file reinit show_opamrc bypass_checks () = apply_global_options cli global_options; apply_build_options cli build_options; (* If show option is set, dump opamrc and exit *) if show_opamrc then (OpamFile.InitConfig.write_to_channel stdout @@ OpamInitDefaults.init_config ~sandboxing:(not no_sandboxing) (); OpamStd.Sys.exit_because `Success); (* Else continue init *) if compiler <> None && no_compiler then OpamConsole.error_and_exit `Bad_arguments "Options --bare and --compiler are incompatible"; let root = OpamStateConfig.(!r.root_dir) in let config_f = OpamPath.config root in let already_init = OpamFile.exists config_f in (* handling of `-ni` option *) let inplace = interactive = Some true && update_config = Some false && env_hook = None && completion = None in let interactive, update_config, completion, env_hook = match interactive with | Some false -> OpamStd.Option.Op.( false, update_config ++ Some true, completion ++ Some true, env_hook ++ Some true ) | None -> (not already_init || update_config = None && completion = None && env_hook = None), update_config, completion, OpamStd.Option.Op.(env_hook ++ update_config) | Some true -> if update_config = None && completion = None && env_hook = None then true, None, None, None else let reconfirm = function | None | Some false -> None | Some true -> Some true in true, (if update_config = Some true then update_config else Some false), reconfirm completion, reconfirm env_hook in let shell = match shell with | Some s -> s | None -> OpamStd.Sys.guess_shell_compat () in let dot_profile = match dot_profile_o with | Some n -> n | None -> OpamFilename.of_string (OpamStd.Sys.guess_dot_profile shell) in if already_init then if reinit then let init_config = get_init_config ~no_sandboxing ~no_default_config_file:no_config_file ~add_config_file:config_file in let reinit conf = OpamClient.reinit ~init_config ~interactive ~dot_profile ?update_config ?env_hook ?completion ~inplace ~bypass_checks ~check_sandbox:(not no_sandboxing) conf shell in let config = match OpamStateConfig.load ~lock_kind:`Lock_write root with | Some c -> c | exception (OpamPp.Bad_version _ as e) -> OpamFormatUpgrade.hard_upgrade_from_2_1_intermediates ~reinit root; raise e | None -> OpamFile.Config.empty in reinit config else (if not interactive && update_config <> Some true && completion <> Some true && env_hook <> Some true then OpamConsole.msg "Opam was already initialised. If you want to set it up again, \ use `--interactive', `--reinit', or choose a different \ `--root'.\n"; OpamEnv.setup root ~interactive ~dot_profile ?update_config ?env_hook ?completion ~inplace shell) else let init_config = get_init_config ~no_sandboxing ~no_default_config_file:no_config_file ~add_config_file:config_file in let repo = OpamStd.Option.map (fun url -> let repo_url = OpamUrl.parse ?backend:repo_kind ~from_file:false url in { repo_name; repo_url; repo_trust = None }) repo_url in let gt, rt, default_compiler = OpamClient.init ~init_config ~interactive ?repo ~bypass_checks ~dot_profile ?update_config ?env_hook ?completion ~check_sandbox:(not no_sandboxing) shell in OpamStd.Exn.finally (fun () -> OpamRepositoryState.drop rt) @@ fun () -> if no_compiler then () else let invariant, default_compiler, name = match compiler with | Some comp when String.length comp > 0 -> OpamSwitchCommand.guess_compiler_invariant rt [comp], [], comp | _ -> OpamFile.Config.default_invariant gt.config, default_compiler, "default" in OpamConsole.header_msg "Creating initial switch '%s' (invariant %s%s)" name (match invariant with | OpamFormula.Empty -> "empty" | c -> OpamFileTools.dep_formula_to_string c) (match default_compiler with | [] -> "" | comp -> " - initially with "^ (OpamFormula.string_of_atoms comp)); let (), st = try OpamSwitchCommand.create gt ~rt ~invariant ~update_config:true (OpamSwitch.of_string name) @@ (fun st -> (), OpamSwitchCommand.install_compiler st ~ask:false ~additional_installs:default_compiler) with e -> OpamStd.Exn.finalise e @@ fun () -> OpamConsole.note "Opam has been initialised, but the initial switch creation \ failed.\n\ Use 'opam switch create ' to get started." in OpamSwitchState.drop st in mk_command ~cli cli_original "init" ~doc ~man Term.(const init $global_options cli $build_options cli $repo_kind_flag cli cli_original $repo_name $repo_url $interactive $update_config $setup_completion $env_hook $no_sandboxing $shell_opt cli cli_original $dot_profile_flag cli cli_original $compiler $no_compiler $config_file $no_config_file $reinit $show_default_opamrc $bypass_checks) (* LIST *) let list_doc = "Display the list of available packages." let list ?(force_search=false) cli = let doc = list_doc in let selection_docs = OpamArg.package_selection_section in let display_docs = OpamArg.package_listing_section in let man = [ `S Manpage.s_description; `P "List selections of opam packages."; `P "Without argument, the command displays the list of currently installed \ packages. With pattern arguments, lists all available packages \ matching one of the patterns."; `P "Unless the $(b,--short) switch is used, the output format displays one \ package per line, and each line contains the name of the package, the \ installed version or `--' if the package is not installed, and a short \ description. In color mode, manually installed packages (as opposed to \ automatically installed ones because of dependencies) are underlined."; `P ("See section $(b,"^selection_docs^") for all the ways to select the \ packages to be displayed, and section $(b,"^display_docs^") to \ customise the output format."); `P "For a more detailed description of packages, see $(b,opam show). For \ extended search capabilities within the packages' metadata, see \ $(b,opam search)."; `S Manpage.s_arguments; `S selection_docs; `S display_docs; ] in let pattern_list = arg_list "PATTERNS" "Package patterns with globs. Unless $(b,--search) is specified, they \ match againsta $(b,NAME) or $(b,NAME.VERSION)" Arg.string in let state_selector = mk_vflag_all ~cli ~section:selection_docs [ cli_original, OpamListCommand.Any, ["A";"all"], "Include all, even uninstalled or unavailable packages"; cli_original, OpamListCommand.Installed, ["i";"installed"], "List installed packages only. This is the default when no \ further arguments are supplied"; cli_original, OpamListCommand.Root, ["roots";"installed-roots"], "List only packages that were explicitly installed, excluding \ the ones installed as dependencies"; cli_original, OpamListCommand.Available, ["a";"available"], "List only packages that are available on the current system"; cli_original, OpamListCommand.Installable, ["installable"], "List only packages that can be installed on the current switch \ (this calls the solver and may be more costly; a package \ depending on an unavailable package may be available, but is \ never installable)"; cli_original, OpamListCommand.Compiler, ["base"], "List only the immutable base of the current switch (i.e. \ compiler packages)"; cli_original, OpamListCommand.Pinned, ["pinned"], "List only the pinned packages"; ] in let section = selection_docs in let search = if force_search then Term.const true else mk_flag ~cli cli_original ["search"] ~section "Match $(i,PATTERNS) against the full descriptions of packages, and \ require all of them to match, instead of requiring at least one to \ match against package names (unless $(b,--or) is also specified)." in let repos = mk_opt ~cli cli_original ["repos"] "REPOS" ~section "Include only packages that took their origin from one of the given \ repositories (unless $(i,no-switch) is also specified, this excludes \ pinned packages)." Arg.(some & list & repository_name) None in let owns_file = mk_opt ~cli cli_original ["owns-file"] "FILE" ~section "Finds installed packages responsible for installing the given file" Arg.(some OpamArg.filename) None in let no_switch = mk_flag ~cli cli_original ["no-switch"] ~section:selection_docs "List what is available from the repositories, without consideration for \ the current (or any other) switch (installed or pinned packages, etc.)" in let disjunction = mk_flag ~cli cli_original ["or"] ~section:selection_docs "Instead of selecting packages that match $(i,all) the criteria, select \ packages that match $(i,any) of them" in let depexts = mk_flag ~cli cli_original ["e";"external";"depexts"] ~section:display_docs "Instead of displaying the packages, display their external dependencies \ that are associated with the current system. This excludes other \ display options. Rather than using this directly, you should probably \ head for the `depext' plugin, that will use your system package \ management system to handle the installation of the dependencies. Run \ `opam depext'." in let vars = mk_opt ~cli cli_original ["vars"] "[VAR=STR,...]" ~section:display_docs "Define the given variable bindings. Typically useful with \ $(b,--external) to override the values for $(i,arch), $(i,os), \ $(i,os-distribution), $(i,os-version), $(i,os-family)." OpamArg.variable_bindings [] in let silent = mk_flag_replaced ~cli [ cli_between ~default:true cli2_0 cli2_1 ~replaced:"--check", ["silent"]; cli_from cli2_1, ["check"] ] "Don't write anything in the output, exit with return code 0 if the list \ is not empty, 1 otherwise." in let no_depexts = mk_flag ~cli cli_original ["no-depexts"] "Disable external dependencies handling for the query. This can be used \ to include packages that are marked as unavailable because of an unavailable \ system dependency." in let list global_options selection state_selector no_switch depexts vars repos owns_file disjunction search silent no_depexts format packages () = apply_global_options cli global_options; let no_switch = no_switch || OpamStateConfig.get_switch_opt () = None in let format = let force_all_versions = not search && state_selector = [] && match packages with | [single] -> let nameglob = match OpamStd.String.cut_at single '.' with | None -> single | Some (n, _v) -> n in (try ignore (OpamPackage.Name.of_string nameglob); true with Failure _ -> false) | _ -> false in format ~force_all_versions in let join = if disjunction then OpamFormula.ors else OpamFormula.ands in let state_selector = if state_selector = [] then if no_switch || search || owns_file <> None then Empty else if packages = [] && selection = [] then Atom OpamListCommand.Installed else Or (Atom OpamListCommand.Installed, Atom OpamListCommand.Available) else join (List.map (fun x -> Atom x) state_selector) in let pattern_selector = if search then join (List.map (fun p -> Atom (OpamListCommand.(Pattern (default_pattern_selector, p)))) packages) else OpamListCommand.pattern_selector packages in let filter = OpamFormula.ands [ join (pattern_selector :: (if no_switch then Empty else match repos with None -> Empty | Some repos -> Atom (OpamListCommand.From_repository repos)) :: OpamStd.Option.Op. ((owns_file >>| fun f -> Atom (OpamListCommand.Owns_file f)) +! Empty) :: List.map (fun x -> Atom x) selection); state_selector; ] in OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamRepositoryState.with_ `Lock_none gt @@ fun rt -> if no_depexts then OpamStateConfig.update ~no_depexts:true (); let st = if no_switch then OpamSwitchState.load_virtual ?repos_list:repos gt rt else OpamSwitchState.load `Lock_none gt rt (OpamStateConfig.get_switch ()) in let st = let open OpamFile.Switch_config in let conf = st.switch_config in { st with switch_config = { conf with variables = conf.variables @ List.map (fun (var, v) -> var, S v) vars } } in if not depexts && not format.OpamListCommand.short && filter <> OpamFormula.Empty && not silent then OpamConsole.msg "# Packages matching: %s\n" (OpamListCommand.string_of_formula filter); let all = OpamPackage.Set.union st.packages st.installed in let results = OpamListCommand.filter ~base:all st filter in if not no_depexts && not silent then (let drop_by_depexts = List.fold_left (fun missing str -> let is_missing pkgs = if OpamStd.String.contains_char str '.' then let nv = OpamPackage.of_string str in if OpamPackage.Set.mem nv results then None else OpamPackage.Set.find_opt (OpamPackage.equal nv) pkgs else let n = OpamPackage.Name.of_string str in if OpamPackage.has_name results n then None else let exist = OpamPackage.packages_of_name pkgs n in if OpamPackage.Set.is_empty exist then None else Some (OpamPackage.Set.max_elt exist) in match OpamStd.Option.Op.( is_missing OpamPackage.Set.Op.(st.packages ++ st.pinned) >>= OpamSwitchState.depexts_unavailable st) with | Some nf -> OpamStd.String.Map.add str nf missing | None -> missing | exception Failure _ -> missing (* invalid package *) ) OpamStd.String.Map.empty packages in if not (OpamStd.String.Map.is_empty drop_by_depexts) then OpamConsole.note "Some packages are unavailable because of their external dependencies. \ Use `--no-depexts' to show them anyway.\n%s" (OpamStd.Format.itemize (fun (n, spkgs) -> Printf.sprintf "%s: %s" n (OpamStd.Format.pretty_list (List.map OpamSysPkg.to_string (OpamSysPkg.Set.elements spkgs)))) (OpamStd.String.Map.bindings drop_by_depexts))); if not depexts then (if not silent then OpamListCommand.display st format results else if OpamPackage.Set.is_empty results then OpamStd.Sys.exit_because `False) else let results_depexts = OpamListCommand.get_depexts st results in if not silent then OpamListCommand.print_depexts results_depexts else if OpamSysPkg.Set.is_empty results_depexts then OpamStd.Sys.exit_because `False in mk_command ~cli cli_original "list" ~doc ~man Term.(const list $global_options cli $package_selection cli $state_selector $no_switch $depexts $vars $repos $owns_file $disjunction $search $silent $no_depexts $package_listing cli $pattern_list) (* SHOW *) let show_doc = "Display information about specific packages." let show cli = let doc = show_doc in let man = [ `S Manpage.s_description; `P "This command displays the information block for the selected \ package(s)."; `P "The information block consists of the name of the package, \ the installed version if this package is installed in the currently \ selected compiler, the list of available (installable) versions, and a \ complete description."; `P "$(b,opam list) can be used to display the list of \ available packages as well as a short description for each."; `P "Paths to package definition files or to directories containing package \ definitions can also be specified, in which case the corresponding \ metadata will be shown." ] in let fields = mk_opt ~cli cli_original ["f";"field"] "FIELDS" (Printf.sprintf "Only display the values of these fields. Fields can be selected \ among %s. Multiple fields can be separated with commas, in which case \ field titles will be printed; the raw value of any opam-file \ field can be queried by combinig with $(b,--raw)" (OpamStd.List.concat_map ", " (Printf.sprintf "$(i,%s)" @* snd) OpamListCommand.field_names)) Arg.(list string) [] in let show_empty = mk_flag ~cli cli_original ["empty-fields"] "Show fields that are empty. This is implied when $(b,--field) is \ given." in let raw = mk_flag ~cli cli_original ["raw"] "Print the raw opam file for this package" in let where = mk_flag ~cli cli_original ["where"] "Print the location of the opam file used for this package" in let list_files = mk_flag ~cli cli_original ["list-files"] "List the files installed by the package. Equivalent to \ $(b,--field=installed-files), and only available for installed \ packages" in let file = mk_opt ~cli (cli_between cli2_0 cli2_1 ~replaced:"--just-file") ["file"] "FILE" "DEPRECATED: use an explicit path argument as package instead. \ Get package information from the given FILE instead of from \ known packages. This implies $(b,--raw) unless $(b,--fields) is \ used. Only raw opam-file fields can be queried." existing_filename_or_dash None in let normalise = mk_flag ~cli cli_original ["normalise"] "Print the values of opam fields normalised (no newlines, no implicit \ brackets)" in let no_lint = mk_flag ~cli cli_original ["no-lint"] "Don't output linting warnings or errors when reading from files" in let just_file = mk_flag ~cli (cli_from cli2_1) ["just-file"] "Load and display information from the given files (allowed \ $(i,PACKAGES) are file or directory paths), without consideration for \ the repositories or state of the package. This implies $(b,--raw) unless \ $(b,--fields) is used. Only raw opam-file fields can be queried. If no \ PACKAGES argument is given, read opam file from stdin." in let all_versions = mk_flag ~cli (cli_from cli2_1) ["all-versions"] "Display information of all packages matching $(i,PACKAGES), not \ restrained to a single package matching $(i,PACKAGES) constraints." in let sort = mk_flag ~cli (cli_from cli2_1) ["sort"] "Sort opam fields" in let opam_files_in_dir d = match OpamPinned.files_in_source d with | [] -> [] | l -> List.map (fun (_,f,_) -> f) l in let show global_options fields show_empty raw where list_files file normalise no_lint just_file all_versions sort atom_locs () = let print_just_file opamf opam = if not no_lint then OpamFile.OPAM.print_errors opam; let opam = if not sort then opam else OpamFileTools.sort_opam opam in if where then OpamConsole.msg "%s\n" (match opamf with | Some opamf -> OpamFilename.(Dir.to_string (dirname (OpamFile.filename opamf))) | None -> ".") else let opam_content_list = OpamFile.OPAM.to_list opam in let get_field f = try OpamListCommand.mini_field_printer ~prettify:true ~normalise (List.assoc f opam_content_list) with Not_found -> "" in match fields with | [] -> OpamFile.OPAM.write_to_channel stdout opam | [f] -> OpamConsole.msg "%s\n" (get_field f) | flds -> let tbl = List.map (fun fld -> [ OpamConsole.colorise `blue (fld ^ ":"); get_field fld ]) flds in OpamStd.Format.align_table tbl |> OpamConsole.print_table stdout ~sep:" " in apply_global_options cli global_options; match file with | Some file -> let opamf = OpamFile.make file in print_just_file (Some opamf) (OpamFile.OPAM.safe_read opamf); `Ok () | None -> (match atom_locs, just_file with | [], false -> `Error (true, "required argument PACKAGES is missing") | [], true -> (try let opam = OpamFile.OPAM.read_from_channel stdin in print_just_file None opam; `Ok () with | Parsing.Parse_error | OpamLexer.Error _ | OpamPp.Bad_version _ | OpamPp.Bad_format _ as exn -> OpamConsole.error_and_exit `File_error "Stdin parsing failed:\n%s" (Printexc.to_string exn)) | atom_locs, false -> let fields, show_empty = if list_files then fields @ [OpamListCommand.(string_of_field Installed_files)], show_empty else fields, show_empty || fields <> [] in OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamRepositoryState.with_ `Lock_none gt @@ fun rt -> let st = OpamListCommand.get_switch_state gt rt in let st, atoms = OpamAuxCommands.simulate_autopin ~quiet:no_lint ~for_view:true st atom_locs in if atoms = [] then OpamConsole.error_and_exit `Not_found "No package found" else OpamListCommand.info st ~fields ~raw ~where ~normalise ~show_empty ~all_versions ~sort atoms; `Ok () | atom_locs, true -> if List.exists (function `Atom _ -> true | _ -> false) atom_locs then `Error (true, "packages can't be specified with --just-file") else let opamfs = List.fold_left (fun acc al -> match al with | `Filename f -> (OpamFile.make f) :: acc | `Dirname d -> opam_files_in_dir d @ acc | _ -> acc) [] atom_locs in if opamfs = [] then let dirnames = OpamStd.List.filter_map (function | `Dirname d -> Some (OpamFilename.Dir.to_string d) | _ -> None) atom_locs in OpamConsole.error_and_exit `Not_found "No opam files found at %s" (OpamStd.List.concat_map ", " ~last_sep:" and " (fun x -> x) dirnames ) else let errors, opams = List.fold_left (fun (errors,opams) opamf -> try errors, (Some opamf, (OpamFile.OPAM.read opamf))::opams with | Parsing.Parse_error | OpamLexer.Error _ | OpamPp.Bad_version _ | OpamPp.Bad_format _ as exn -> (opamf, exn)::errors, opams) ([],[]) opamfs in List.iter (fun (f,o) -> print_just_file f o) opams; (if errors <> [] then let sgl = match errors with [_] -> true | _ -> false in let tostr (opamf, error) = (OpamFilename.to_string (OpamFile.filename opamf)) ^ ":\n" ^ Printexc.to_string error in OpamConsole.error "Parsing error on%s:%s" (if sgl then "" else "some opam files") (match errors with | [f] -> tostr f | fs -> OpamStd.Format.itemize tostr fs)); if opams = [] then OpamStd.Sys.exit_because `File_error else `Ok () ) in mk_command_ret ~cli cli_original "show" ~doc ~man Term.(const show $global_options cli $fields $show_empty $raw $where $list_files $file $normalise $no_lint $just_file $all_versions $sort $atom_or_local_list) (* Shared between [option] and [var] *) module Var_Option_Common = struct let global cli = mk_flag ~cli (cli_from cli2_1) ["global"] "Act on global configuration" let var_option global global_options cmd var = let switch_set = (fst global_options).opt_switch <> None in if global && switch_set then `Error (true, "--global and --switch sw option can't be used together") else let scope = if global then `Global else if switch_set then `Switch else match var with | None -> `All | Some f -> match cmd with | `var -> `All_var | `option -> OpamConfigCommand.get_scope f in let apply = match var with | None -> `empty | Some var -> try `value_eq (OpamConfigCommand.parse_update var) with Invalid_argument _ -> `value_wo_eq var in match scope with | `None field -> (* must be an option command *) OpamConsole.error_and_exit `Bad_arguments "No option named '%s' found. Use 'opam option [--global]' to list them" field | `All -> OpamGlobalState.with_ `Lock_none @@ fun gt -> (match cmd with | `var -> OpamConfigCommand.vars_list gt | `option -> OpamConfigCommand.options_list gt); `Ok () | `All_var -> (match apply with | `value_wo_eq v -> OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamConfigCommand.var_show gt v; `Ok () | `empty -> assert false (* can't happen *) | `value_eq _ -> `Error (true, "variable setting needs a scope, \ use '--global' or '--switch '")) | (`Global | `Switch) as scope -> match cmd, apply with | _ , `empty -> (match scope with | `Switch -> OpamGlobalState.with_ `Lock_none @@ fun gt -> (match cmd with | `var -> OpamConfigCommand.vars_list_switch gt | `option -> OpamConfigCommand.options_list_switch gt); `Ok () | `Global -> OpamGlobalState.with_ `Lock_none @@ fun gt -> (match cmd with | `var -> OpamConfigCommand.vars_list_global gt | `option -> OpamConfigCommand.options_list_global gt); `Ok ()) | _, `value_wo_eq v -> (match scope with | `Switch -> OpamGlobalState.with_ `Lock_none @@ fun gt -> (match cmd with | `var -> OpamConfigCommand.var_show_switch gt v | `option -> OpamConfigCommand.option_show_switch gt v); `Ok () | `Global -> OpamGlobalState.with_ `Lock_none @@ fun gt -> (match cmd with | `var -> OpamConfigCommand.var_show_global gt v | `option -> OpamConfigCommand.option_show_global gt v); `Ok ()) | `var, `value_eq (_,#OpamConfigCommand.append_op) -> `Error (true, "var: append operation are not permitted") | _, `value_eq (v,u) -> match scope with | `Switch -> OpamGlobalState.with_ `Lock_none @@ fun gt -> let _st = match cmd with | `var -> OpamConfigCommand.set_var_switch gt v (OpamConfigCommand.whole_of_update_op u) | `option -> OpamConfigCommand.set_opt_switch gt v u in `Ok () | `Global -> OpamGlobalState.with_ `Lock_write @@ fun gt -> let _st = match cmd with | `var -> OpamConfigCommand.set_var_global gt v (OpamConfigCommand.whole_of_update_op u) | `option -> OpamConfigCommand.set_opt_global gt v u in `Ok () end (* VAR *) let var_doc = "Display and update the value associated with a given variable" let var cli = let doc = var_doc in let man = [ `S Manpage.s_description; `P "Without argument, lists the opam variables currently defined. With a \ $(i,VAR) argument, prints the value associated with $(i,VAR). \ Otherwise, sets or updates $(i,VAR)'s value. \ If no scope is given, it acts on switch variables by default. \ This command does not perform any variable expansion."; ] in let open Var_Option_Common in let varvalue = let docv = "VAR[=[VALUE]]" in let doc = "If only $(i,VAR) is given, displays its associated value. \ If $(i,VALUE) is absent, $(i,VAR)'s value is removed. Otherwise, its \ value is overwritten." in Arg.(value & pos 0 (some string) None & info ~docv ~doc []) in let package = mk_opt ~cli cli_original ["package"] "PACKAGE" "List all variables defined for the given package" Arg.(some package_name) None in let print_var global_options package varvalue global () = apply_global_options cli global_options; match varvalue, package with | _, None -> var_option global global_options `var varvalue | None, Some pkg -> OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_none gt @@ fun st -> (try `Ok (OpamConfigCommand.list st [pkg]) with Failure msg -> `Error (false, msg)) | _, _ -> `Error (true, "--package can't be specified with a var argument, use \ 'pkg:var' instead.") in mk_command_ret ~cli cli_original "var" ~doc ~man Term.(const print_var $global_options cli $package $varvalue $global cli) (* OPTION *) let option_doc = "Global and switch configuration options settings" let option cli = let doc = option_doc in let man = [ `S Manpage.s_description; `P "Without argument, list all configurable fields. If a field name \ $(i,FIELD) is given, display its content. Otherwise, sets or updates \ the given field in the global/switch configuration file. \ For global configuration, $(i,FIELD) is reset to its default initial \ value, as after a fresh init (use `opam init show-default-opamrc` to \ display it)." ] in let open Var_Option_Common in let fieldvalue = let docv = "FIELD[(=|+=|-=)[VALUE]]" in let doc = "If only $(i,FIELD) is given, displays its associated value. If \ $(i,VALUE) is absent, $(i,FIELD)'s value is reverted. Otherwise, its \ value is updated: overwrite (=), append (+=), or remove of an element \ (-=)." in Arg.(value & pos 0 (some string) None & info ~docv ~doc []) in let option global_options fieldvalue global () = apply_global_options cli global_options; var_option global global_options `option fieldvalue in mk_command_ret ~cli (cli_from cli2_1) "option" ~doc ~man Term.(const option $global_options cli $fieldvalue $global cli) module Common_config_flags = struct let sexp cli = mk_flag ~cli cli_original ["sexp"] "Print environment as an s-expression rather than in shell format" let inplace_path cli = mk_flag ~cli cli_original ["inplace-path"] "When updating the $(i,PATH) variable, replace any pre-existing opam \ path in-place rather than putting the new path in front. This means \ programs installed in opam that were shadowed will remain so after \ $(b,opam env)" let set_opamroot cli = mk_flag ~cli cli_original ["set-root"] "With the $(b,env) and $(b,exec) subcommands, also sets the \ $(i,OPAMROOT) variable, making sure further calls to opam will use the \ same root." let set_opamswitch cli = mk_flag ~cli cli_original ["set-switch"] "With the $(b,env) and $(b,exec) subcommands, also sets the \ $(i,OPAMSWITCH) variable, making sure further calls to opam will use \ the same switch as this one." end (* CONFIG *) let config_doc = "Display configuration options for packages." let config cli = let shell = OpamStd.Sys.guess_shell_compat () in let doc = config_doc in let commands = [ cli_original, "env", `env, [], Printf.sprintf "Returns the bindings for the environment variables set in the \ current switch, e.g. PATH, in a format intended to be evaluated by \ a shell. With $(i,-v), add comments documenting the reason or \ package of origin for each binding. This is most usefully used as \ $(b,%s) to have further shell commands be evaluated in the proper \ opam context. Can also be accessed through $(b,opam env)." OpamEnv.(shell_eval_invocation shell "opam config env" |> Manpage.escape); cli_original, "revert-env", `revert_env, [], Printf.sprintf "Reverts environment changes made by opam, e.g. $(b,%s) undoes what \ $(b,%s) did, as much as possible." OpamEnv.(shell_eval_invocation shell "opam config revert-env" |> Manpage.escape) OpamEnv.(shell_eval_invocation shell "opam config env" |> Manpage.escape); cli_original, "list", `list, ["[PACKAGE]..."], "Without argument, prints a documented list of all available variables. \ With $(i,PACKAGE), lists all the variables available for these packages. \ Use $(i,-) to include global configuration variables for this switch."; cli_original, "expand", `expand, ["STRING"], "Expand variable interpolations in the given string"; cli_original, "subst", `subst, ["FILE..."], "Substitute variables in the given files. The strings $(i,%{var}%) are \ replaced by the value of variable $(i,var) (see $(b,var))."; cli_original, "report", `report, [], "Prints a summary of your setup, useful for bug-reports."; cli_original, "cudf-universe", `cudf, ["[FILE]"], "Outputs the current available package universe in CUDF format."; cli_original, "pef-universe", `pef, ["[FILE]"], "Outputs the current package universe in PEF format."; (* Deprecated options *) cli_between ~default:true cli2_0 cli2_1 ~replaced:"opam exec", "exec", `exec, ["[--] COMMAND"; "[ARG]..."], "Execute $(i,COMMAND) with the correct environment variables. This command \ can be used to cross-compile between switches using $(b,opam config exec \ --switch=SWITCH -- COMMAND ARG1 ... ARGn). Opam expansion takes place in \ command and args. If no switch is present on the command line or in the \ $(i,OPAMSWITCH) environment variable, $(i,OPAMSWITCH) is not set in \ $(i,COMMAND)'s environment. Can also be accessed through $(b,opam exec)."; cli_between ~default:true cli2_0 cli2_1 ~replaced:"opam var", "set", `set, ["VAR";"VALUE"], "Set switch variable"; cli_between ~default:true cli2_0 cli2_1 ~replaced:"opam var", "unset", `unset, ["VAR"], "Unset switch variable"; cli_between ~default:true cli2_0 cli2_1 ~replaced:"opam var", "set-global", `set_global, ["VAR";"VALUE"], "Set global variable"; cli_between ~default:true cli2_0 cli2_1 ~replaced:"opam var", "unset-global", `unset_global, ["VAR"], "Unset global variable"; cli_between ~default:true cli2_0 cli2_1 ~replaced:"opam var", "var", `var, ["VAR"], "Return the value associated with variable $(i,VAR), looking in switch \ first, global if not found. Package variables can be accessed with the \ syntax $(i,pkg:var). Can also be accessed through $(b,opam var VAR)"; ] in let man = [ `S Manpage.s_description; `P "This command uses opam state to output information on how to use \ installed libraries, update the $(b,PATH), and substitute \ variables used in opam packages."; `P "Apart from $(b,opam config env), most of these commands are used \ by opam internally, and are of limited interest for the casual \ user."; ] @ mk_subdoc ~cli commands @ [`S Manpage.s_options] in let command, params = mk_subcommands ~cli commands in let open Common_config_flags in let config global_options command shell sexp inplace_path set_opamroot set_opamswitch params () = apply_global_options cli global_options; let shell = match shell with | Some s -> s | None -> OpamStd.Sys.guess_shell_compat () in match command, params with | Some `env, [] -> OpamGlobalState.with_ `Lock_none @@ fun gt -> (match OpamStateConfig.get_switch_opt () with | None -> `Ok () | Some sw -> `Ok (OpamConfigCommand.env gt sw ~set_opamroot ~set_opamswitch ~csh:(shell=SH_csh) ~sexp ~fish:(shell=SH_fish) ~inplace_path)) | Some `revert_env, [] -> OpamGlobalState.with_ `Lock_none @@ fun gt -> (match OpamStateConfig.get_switch_opt () with | None -> `Ok () | Some sw -> `Ok (OpamConfigCommand.ensure_env gt sw; OpamConfigCommand.print_eval_env ~csh:(shell=SH_csh) ~sexp ~fish:(shell=SH_fish) (OpamEnv.add [] []))) | Some `list, [] -> OpamGlobalState.with_ `Lock_none @@ fun gt -> `Ok (OpamConfigCommand.vars_list gt) | Some `list, params -> OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_none gt @@ fun st -> (try `Ok (OpamConfigCommand.list st (List.map OpamPackage.Name.of_string params)) with Failure msg -> `Error (false, msg)) | Some `expand, [str] -> OpamGlobalState.with_ `Lock_none @@ fun gt -> `Ok (OpamConfigCommand.expand gt str) | Some `var, [var] -> OpamGlobalState.with_ `Lock_none @@ fun gt -> (try `Ok (OpamConfigCommand.var_show gt var) with Failure msg -> `Error (false, msg)) | Some `subst, (_::_ as files) -> OpamGlobalState.with_ `Lock_none @@ fun gt -> `Ok (OpamConfigCommand.subst gt (List.map OpamFilename.Base.of_string files)) | Some `pef, params -> OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_none gt @@ fun st -> (match params with | [] | ["-"] -> OpamSwitchState.dump_pef_state st stdout; `Ok () | [file] -> let oc = open_out file in OpamSwitchState.dump_pef_state st oc; close_out oc; `Ok () | _ -> bad_subcommand ~cli commands ("config", command, params)) | Some `cudf, params -> OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_none gt @@ fun opam_state -> let opam_univ = OpamSwitchState.universe opam_state ~requested:(OpamPackage.names_of_packages opam_state.packages) Query in let dump oc = OpamSolver.dump_universe opam_univ oc in (match params with | [] -> `Ok (dump stdout) | [file] -> let oc = open_out file in dump oc; close_out oc; `Ok () | _ -> bad_subcommand ~cli commands ("config", command, params)) | Some `report, [] -> ( let print label fmt = OpamConsole.msg ("# %-20s "^^fmt^^"\n") label in OpamConsole.msg "# opam config report\n"; print "opam-version" "%s " (OpamVersion.to_string (OpamVersion.full ())); print "self-upgrade" "%s" (if self_upgrade_status global_options = `Running then OpamFilename.prettify (fst (self_upgrade_exe (OpamStateConfig.(!r.root_dir)))) else "no"); print "system" "arch=%s os=%s os-distribution=%s os-version=%s" OpamStd.Option.Op.(OpamSysPoll.arch () +! "unknown") OpamStd.Option.Op.(OpamSysPoll.os () +! "unknown") OpamStd.Option.Op.(OpamSysPoll.os_distribution () +! "unknown") OpamStd.Option.Op.(OpamSysPoll.os_version () +! "unknown"); try OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_none gt @@ fun state -> let module Solver = (val OpamSolverConfig.(Lazy.force !r.solver)) in print "solver" "%s" (OpamCudfSolver.get_name (module Solver)); print "install-criteria" "%s" (OpamSolverConfig.criteria `Default); print "upgrade-criteria" "%s" (OpamSolverConfig.criteria `Upgrade); let nprint label n = if n <> 0 then [Printf.sprintf "%d (%s)" n label] else [] in print "jobs" "%d" (Lazy.force OpamStateConfig.(!r.jobs)); print "repositories" "%s" (let repos = state.switch_repos.repositories in let default, nhttp, nlocal, nvcs = OpamRepositoryName.Map.fold (fun _ repo (dft, nhttp, nlocal, nvcs) -> let dft = if OpamUrl.root repo.repo_url = OpamUrl.root OpamInitDefaults.repository_url then OpamRepositoryName.Map.find repo.repo_name state.switch_repos.repos_definitions |> OpamFile.Repo.stamp else dft in match repo.repo_url.OpamUrl.backend with | `http -> dft, nhttp+1, nlocal, nvcs | `rsync -> dft, nhttp, nlocal+1, nvcs | _ -> dft, nhttp, nlocal, nvcs+1) repos (None,0,0,0) in String.concat ", " (nprint "http" nhttp @ nprint "local" nlocal @ nprint "version-controlled" nvcs) ^ match default with | Some v -> Printf.sprintf " (default repo at %s)" v | None -> "" ); print "pinned" "%s" (if OpamPackage.Set.is_empty state.pinned then "0" else let pinnings = OpamPackage.Set.fold (fun nv acc -> let opam = OpamSwitchState.opam state nv in let kind = if Some opam = OpamPackage.Map.find_opt nv state.repos_package_index then "version" else OpamStd.Option.to_string ~none:"local" (fun u -> OpamUrl.string_of_backend u.OpamUrl.backend) (OpamFile.OPAM.get_url opam) in OpamStd.String.Map.update kind succ 0 acc) state.pinned OpamStd.String.Map.empty in String.concat ", " (List.flatten (List.map (fun (k,v) -> nprint k v) (OpamStd.String.Map.bindings pinnings))) ); print "current-switch" "%s" (OpamSwitch.to_string state.switch); let process nv = try let conf = OpamSwitchState.package_config state nv.name in let bindings = let f (name, value) = (OpamVariable.Full.create nv.name name, OpamVariable.string_of_variable_contents value) in List.map f (OpamFile.Dot_config.bindings conf) in let print (name, value) = let name = OpamVariable.Full.to_string name in print name "%s" value in List.iter print bindings with Not_found -> () in state.installed |> OpamPackage.Set.filter (fun p -> match OpamSwitchState.opam_opt state p with | Some o -> OpamFile.OPAM.has_flag Pkgflag_Compiler o | None -> false) |> OpamSolver.dependencies ~depopts:true ~post:true ~build:true ~installed:true (OpamSwitchState.universe ~test:true ~doc:true ~requested:OpamPackage.Name.Set.empty state Query) |> OpamPackage.Set.iter process; if List.mem "." (OpamStd.Sys.split_path_variable (Sys.getenv "PATH")) then OpamConsole.warning "PATH contains '.' : this is a likely cause of trouble."; `Ok () with e -> print "read-state" "%s" (Printexc.to_string e); `Ok ()) (* deprecated *) | Some `exec, (_::_ as c) -> OpamGlobalState.with_ `Lock_none @@ fun gt -> `Ok (OpamConfigCommand.exec gt ~set_opamroot ~set_opamswitch ~inplace_path c) | Some (`set | `unset as cmd), var::value -> let args = match cmd,value with | `unset, [] -> Some None | `set, v::_ -> Some (Some v) | _, _ -> None in (match args with | None -> bad_subcommand ~cli commands ("config", command, params) | Some opt_value -> OpamGlobalState.with_ `Lock_none @@ fun gt -> let value = OpamStd.Option.map_default (fun v -> `Overwrite v) `Revert opt_value in let _ = OpamConfigCommand.set_var_switch gt var value in `Ok ()) | Some (`set_global | `unset_global as cmd), var::value -> let args = match cmd,value with |`unset_global, [] -> Some None | `set_global, v::_ -> Some (Some v) | _, _ -> None in (match args with | None -> bad_subcommand ~cli commands ("config", command, params) | Some opt_value -> OpamGlobalState.with_ `Lock_write @@ fun gt -> let value = OpamStd.Option.map_default (fun v -> `Overwrite v) `Revert opt_value in let _gt = OpamConfigCommand.set_var_global gt var value in `Ok ()) | command, params -> bad_subcommand ~cli commands ("config", command, params) in mk_command_ret ~cli cli_original "config" ~doc ~man Term.(const config $global_options cli $command $shell_opt cli cli_original $sexp cli $inplace_path cli $set_opamroot cli $set_opamswitch cli $params) (* EXEC *) let exec_doc = "Executes a command in the proper opam environment" let exec cli = let doc = exec_doc in let man = [ `S Manpage.s_description; `P "Execute $(i,COMMAND) with the correct environment variables. This \ command can be used to cross-compile between switches using $(b,opam \ config exec --switch=SWITCH -- COMMAND ARG1 ... ARGn). Opam expansion \ takes place in command and args. If no switch is present on the \ command line or in the $(i,OPAMSWITCH) environment variable, \ $(i,OPAMSWITCH) is not set in $(i,COMMAND)'s environment."; `P "This is a shortcut, and equivalent to $(b,opam config exec)."; ] in let cmd = Arg.(non_empty & pos_all string [] & info ~docv:"COMMAND [ARG]..." []) in let exec global_options inplace_path set_opamroot set_opamswitch cmd () = apply_global_options cli global_options; OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamConfigCommand.exec gt ~set_opamroot ~set_opamswitch ~inplace_path cmd in let open Common_config_flags in mk_command ~cli cli_original "exec" ~doc ~man Term.(const exec $global_options cli $inplace_path cli $set_opamroot cli $set_opamswitch cli $cmd) (* ENV *) let env_doc = "Prints appropriate shell variable assignments to stdout" let env cli = let shell = OpamStd.Sys.guess_shell_compat () in let doc = env_doc in let man = [ `S Manpage.s_description; `P (Printf.sprintf "Returns the bindings for the environment variables set in the current \ switch, e.g. PATH, in a format intended to be evaluated by a shell. \ With $(i,-v), add comments documenting the reason or package of origin \ for each binding. This is most usefully used as $(b,%s) \ to have further shell commands be evaluated in the proper opam \ context." OpamEnv.( shell_eval_invocation shell (opam_env_invocation ()) |> Manpage.escape)); `P "This is a shortcut, and equivalent to $(b,opam config env)."; ] in let revert = mk_flag ~cli cli_original ["revert"] "Output the environment with updates done by opam reverted instead." in let check = mk_flag ~cli (cli_from cli2_1) ["check"] "Exits with 0 if the environment is already up-to-date, 1 otherwise, \ after printing the list of not up-to-date variables." in let env global_options shell sexp inplace_path set_opamroot set_opamswitch revert check () = apply_global_options cli global_options; if check then (OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_none gt @@ fun st -> if not (OpamEnv.is_up_to_date ~skip:false st) then OpamStd.Sys.exit_because `False) else let shell = match shell with | Some s -> s | None -> OpamStd.Sys.guess_shell_compat () in match revert with | false -> OpamGlobalState.with_ `Lock_none @@ fun gt -> (match OpamStateConfig.get_switch_opt () with | None -> () | Some sw -> OpamConfigCommand.env gt sw ~set_opamroot ~set_opamswitch ~csh:(shell=SH_csh) ~sexp ~fish:(shell=SH_fish) ~inplace_path); | true -> OpamConfigCommand.print_eval_env ~csh:(shell=SH_csh) ~sexp ~fish:(shell=SH_fish) (OpamEnv.add [] []) in let open Common_config_flags in mk_command ~cli cli_original "env" ~doc ~man Term.(const env $global_options cli $shell_opt cli cli_original $sexp cli $inplace_path cli $set_opamroot cli $set_opamswitch cli $revert $check) (* INSTALL *) let install_doc = "Install a list of packages." let install cli = let doc = install_doc in let man = [ `S Manpage.s_description; `P "This command installs one or more packages inside the currently \ selected switch (see $(b,opam switch)). Once installed, you can remove \ packages with $(b,opam remove), upgrade them with $(b,opam upgrade), \ and list them with $(b,opam list). See $(b,opam pin) as well to manage \ package versions, reroute existing packages or add packages that are \ not defined in the repositories."; `P "All required dependencies of the selected packages will be installed \ first. Any already installed packages having dependencies, or optional \ dependencies to the changed packages will be recompiled. The proposed \ solution may also imply removing incompatible or conflicting \ packages."; `P "If paths are provided as argument instead of packages, they are \ assumed to point to either project source directories containing one \ or more package definitions ($(i,opam) files), or directly to \ $(i,opam) files. Then the corresponding packages will be pinned to \ their local directory and installed (unless $(b,--deps-only) was \ specified)."; `S Manpage.s_arguments; `S Manpage.s_options; ] @ OpamArg.man_build_option_section in let add_to_roots = mk_vflag ~cli None [ cli_original, (Some true), ["set-root"], "Mark given packages as installed roots. This is the default \ for newly manually-installed packages."; cli_original, (Some false), ["unset-root"], "Mark given packages as \"installed automatically\"."; ] in let deps_only = mk_flag ~cli cli_original ["deps-only"] "Install all its dependencies, but don't actually install the package." in let ignore_conflicts = mk_flag ~cli (cli_from cli2_1) ["ignore-conflicts"] "Used with $(b,--deps-only), ignores conflicts of given package" in let download_only = mk_flag ~cli (cli_from cli2_1) ["download-only"] "Fetch the sources of the packages, but don't build or install anything." in let restore = mk_flag ~cli cli_original ["restore"] "Attempt to restore packages that were marked for installation but have \ been removed due to errors" in let destdir = mk_opt ~cli cli_original ["destdir"] "DIR" "Copy the files installed by the given package within the current opam \ switch below the prefix $(i,DIR), respecting their hierarchy, after \ installation. Caution, calling this can overwrite, but never remove \ files, even if they were installed by a previous use of $(b,--destdir), \ e.g. on a previous version of the same package. See $(b,opam remove \ --destdir) to revert." Arg.(some dirname) None in let check = mk_flag ~cli (cli_from cli2_1) ["check"] "Exit with 0 if all the dependencies of $(i,PACKAGES) are already \ installed. If not, output the names of the missing dependencies to \ stdout, and exits with 1." in let depext_only = mk_flag ~cli (cli_from cli2_1) ["depext-only"] "Resolves the package installation normally, but only installs \ the required system dependencies, without affecting the opam switch \ state or installing opam packages." in let install global_options build_options add_to_roots deps_only ignore_conflicts restore destdir assume_built check recurse subpath depext_only download_only atoms_or_locals () = apply_global_options cli global_options; apply_build_options cli build_options; if atoms_or_locals = [] && not restore then `Error (true, "required argument PACKAGES is missing") else if depext_only && (OpamClientConfig.(!r.assume_depexts) || OpamStateConfig.(!r.no_depexts)) then `Error (true, Printf.sprintf "--depext-only and --%s can't be used together" (if OpamClientConfig.(!r.assume_depexts) then "assume-depexts" else "no-depexts")) else OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_write gt @@ fun st -> let pure_atoms = OpamStd.List.filter_map (function `Atom a -> Some a | _ -> None) atoms_or_locals in let atoms_or_locals = if restore then let to_restore = OpamPackage.Set.diff st.installed_roots st.installed in if OpamPackage.Set.is_empty to_restore then OpamConsole.msg "No packages to restore found\n" else OpamConsole.msg "Packages to be restored: %s\n" (OpamPackage.Name.Set.to_string (OpamPackage.names_of_packages to_restore)); atoms_or_locals @ List.map (fun p -> `Atom (OpamSolution.atom_of_package p)) (OpamPackage.Set.elements to_restore) else atoms_or_locals in if atoms_or_locals = [] then `Ok () else let st, atoms = OpamAuxCommands.autopin st ~recurse ?subpath ~quiet:check ~simulate:(deps_only||check||depext_only) atoms_or_locals in if atoms = [] then (OpamConsole.msg "Nothing to do\n"; OpamStd.Sys.exit_because `Success); if check then (let missing = OpamPackage.Map.fold (fun _ -> OpamPackage.Name.Set.union) (OpamClient.check_installed ~build:true ~post:true st atoms) (OpamPackage.Name.Set.empty) in if OpamPackage.Name.Set.is_empty missing then (OpamConsole.errmsg "All dependencies installed\n"; OpamStd.Sys.exit_because `Success) else (OpamConsole.errmsg "Missing dependencies:\n"; OpamConsole.msg "%s\n" (OpamStd.List.concat_map " " OpamPackage.Name.to_string (OpamPackage.Name.Set.elements missing)); OpamStd.Sys.exit_because `False)); let st = OpamClient.install st atoms ~autoupdate:pure_atoms ?add_to_roots ~deps_only ~ignore_conflicts ~assume_built ~depext_only ~download_only in match destdir with | None -> `Ok () | Some dest -> let packages = OpamFormula.packages_of_atoms st.installed atoms in OpamAuxCommands.copy_files_to_destdir st dest packages; `Ok () in mk_command_ret ~cli cli_original "install" ~doc ~man Term.(const install $global_options cli $build_options cli $add_to_roots $deps_only $ignore_conflicts $restore $destdir $assume_built cli $check $recurse cli $subpath cli $depext_only $download_only $atom_or_local_list) (* REMOVE *) let remove_doc = "Remove a list of packages." let remove cli = let doc = remove_doc in let man = [ `S Manpage.s_description; `P "This command uninstalls one or more packages currently \ installed in the currently selected compiler switch. To remove packages \ installed in another compiler, you need to switch compilers using \ $(b,opam switch) or use the $(b,--switch) flag. This command is the \ inverse of $(b,opam-install)."; `P "If a directory name is specified as package, packages pinned to that \ directory are both unpinned and removed."; `S Manpage.s_arguments; `S Manpage.s_options; ] @ OpamArg.man_build_option_section in let autoremove = mk_flag ~cli cli_original ["a";"auto-remove"] "Remove all the packages which have not been explicitly installed and \ which are not necessary anymore. It is possible to prevent the removal \ of an already-installed package by running $(b,opam install \ --set-root). This flag can also be set using the $(b,\\$OPAMAUTOREMOVE) \ configuration variable." in let force = mk_flag ~cli cli_original ["force"] "Execute the remove commands of given packages directly, even if they are \ not considered installed by opam." in let destdir = mk_opt ~cli cli_original ["destdir"] "DIR" "Instead of uninstalling the packages, reverts the action of $(b,opam \ install --destdir): remove files corresponding to what the listed \ packages installed to the current switch from the given $(i,DIR). Note \ that the package needs to still be installed to the same version that \ was used for $(b,install --destdir) for this to work reliably. The \ packages are not removed from the current opam switch when this is \ specified." Arg.(some dirname) None in let remove global_options build_options autoremove force destdir recurse subpath atom_locs () = apply_global_options cli global_options; apply_build_options cli build_options; OpamGlobalState.with_ `Lock_none @@ fun gt -> match destdir with | Some d -> OpamSwitchState.with_ `Lock_none gt @@ fun st -> let atoms = OpamAuxCommands.resolve_locals_pinned st atom_locs in let packages = OpamFormula.packages_of_atoms st.installed atoms in let uninst = List.filter (fun (name, _) -> not (OpamPackage.has_name packages name)) atoms in if uninst <> [] then OpamConsole.warning "Can't remove the following packages from the given destdir, they \ need to be installed in opam: %s" (OpamStd.List.concat_map " " OpamFormula.short_string_of_atom uninst); OpamAuxCommands.remove_files_from_destdir st d packages | None -> OpamSwitchState.with_ `Lock_write gt @@ fun st -> let pure_atoms, pin_atoms = List.partition (function `Atom _ -> true | _ -> false) atom_locs in let pin_atoms = OpamAuxCommands.resolve_locals_pinned st ~recurse ?subpath pin_atoms in let st = if OpamStateConfig.(!r.dryrun) || OpamClientConfig.(!r.show) then st else OpamPinCommand.unpin st (List.map fst pin_atoms) in let atoms = List.map (function `Atom a -> a | _ -> assert false) pure_atoms @ pin_atoms in let autoremove = autoremove || OpamClientConfig.(!r.autoremove) in OpamSwitchState.drop (OpamClient.remove st ~autoremove ~force atoms) in mk_command ~cli cli_original "remove" ~doc ~man Term.(const remove $global_options cli $build_options cli $autoremove $force $destdir $recurse cli $subpath cli $atom_or_dir_list) (* REINSTALL *) let reinstall cli = let doc = "Reinstall a list of packages." in let man = [ `S Manpage.s_description; `P "This command removes the given packages and the ones that depend on \ them, and reinstalls the same versions. Without arguments, assume \ $(b,--pending) and reinstall any package with upstream changes."; `P "If a directory is specified as argument, anything that is pinned to \ that directory is selected for reinstall."; `S Manpage.s_arguments; `S Manpage.s_options; ] @ OpamArg.man_build_option_section in let cmd = mk_vflag ~cli `Default [ cli_original, `Pending, ["pending"], "Perform pending reinstallations, i.e. reinstallations of \ packages that have changed since installed"; cli_original, `List_pending, ["list-pending"], "List packages that have been changed since installed and are \ marked for reinstallation"; cli_original, `Forget_pending, ["forget-pending"], "Forget about pending reinstallations of listed packages. This \ implies making opam assume that your packages were installed \ with a newer version of their metadata, so only use this if \ you know what you are doing, and the actual changes you are \ overriding." ] in let reinstall global_options build_options assume_built recurse subpath atoms_locs cmd () = apply_global_options cli global_options; apply_build_options cli build_options; let open OpamPackage.Set.Op in OpamGlobalState.with_ `Lock_none @@ fun gt -> match cmd, atoms_locs with | `Default, (_::_ as atom_locs) -> OpamSwitchState.with_ `Lock_write gt @@ fun st -> OpamSwitchState.drop @@ OpamClient.reinstall st ~assume_built (OpamAuxCommands.resolve_locals_pinned st ~recurse ?subpath atom_locs); `Ok () | `Pending, [] | `Default, [] -> OpamSwitchState.with_ `Lock_write gt @@ fun st -> let atoms = OpamSolution.eq_atoms_of_packages (Lazy.force st.reinstall) in OpamSwitchState.drop @@ OpamClient.reinstall st atoms; `Ok () | `List_pending, [] -> OpamSwitchState.with_ `Lock_none gt @@ fun st -> OpamListCommand.display st { OpamListCommand.default_package_listing_format with OpamListCommand. columns = [OpamListCommand.Package]; short = true; header = false; order = `Dependency; } (Lazy.force st.reinstall); `Ok () | `Forget_pending, atom_locs -> OpamSwitchState.with_ `Lock_write gt @@ fun st -> let atoms = OpamAuxCommands.resolve_locals_pinned ~recurse ?subpath st atom_locs in let reinstall = Lazy.force st.reinstall in let to_forget = match atoms with | [] -> reinstall | atoms -> OpamFormula.packages_of_atoms reinstall atoms in OpamPackage.Set.iter (fun nv -> try let installed = OpamPackage.Map.find nv st.installed_opams in let upstream = OpamPackage.Map.find nv st.opams in if not (OpamFile.OPAM.effectively_equal installed upstream) && OpamConsole.confirm "Metadata of %s were updated. Force-update, without performing \ the reinstallation?" (OpamPackage.to_string nv) then OpamSwitchAction.install_metadata st nv with Not_found -> ()) to_forget; let reinstall = reinstall -- to_forget in OpamSwitchState.drop @@ OpamSwitchAction.update_switch_state ~reinstall st; `Ok () | _, _::_ -> `Error (true, "Package arguments not allowed with this option") in mk_command_ret ~cli cli_original "reinstall" ~doc ~man Term.(const reinstall $global_options cli $build_options cli $assume_built cli $recurse cli $subpath cli $atom_or_dir_list $cmd) (* UPDATE *) let update_doc = "Update the list of available packages." let update cli = let doc = update_doc in let man = [ `S Manpage.s_description; `P "Update the package definitions. This fetches the newest version of the \ repositories configured through $(b, opam repository), and the sources \ of installed development packages and packages pinned in the current \ switch. To use the updated sources and definitions, use \ $(b,opam upgrade)."; ] in let repos_only = mk_flag ~cli cli_original ["R"; "repositories"] "Update repositories (skipping development packages unless \ $(b,--development) is also specified)." in let dev_only = mk_flag ~cli cli_original ["development"] "Update development packages (skipping repositories unless \ $(b,--repositories) is also specified)." in let depexts_only = mk_flag ~cli (cli_from cli2_1) ["depexts"] "Request the system package manager to update its databases (skipping \ all opam packages, unless $(b,--development) or $(b,--repositories) is \ also specified). This generally requires $(b,sudo) rights." in let upgrade = mk_flag ~cli cli_original ["u";"upgrade"] "Automatically run $(b,opam upgrade) after the update." in let name_list = arg_list "NAMES" "List of repository or development package names to update." Arg.string in let all = mk_flag ~cli cli_original ["a"; "all"] "Update all configured repositories, not only what is set in the current \ switch" in let check = mk_flag ~cli cli_original ["check"] "Do the update, then return with code 0 if there were any upstream \ changes, 1 if there were none. Repositories or development packages \ that failed to update are considered without changes. With \ $(b,--upgrade), applies to the upgrade step: that is $(b,opam update \ --upgrade --check) behaves like $(b,opam update && opam upgrade --check), \ returning 0 if there are available upgrades, rather than upstream updates." in let update global_options jobs names repos_only dev_only depexts_only all check upgrade () = apply_global_options cli global_options; OpamStateConfig.update ?jobs:OpamStd.Option.Op.(jobs >>| fun j -> lazy j) (); OpamClientConfig.update (); if depexts_only then OpamSysInteract.update (); if depexts_only && not (repos_only || dev_only) then () else OpamGlobalState.with_ `Lock_write @@ fun gt -> let success, changed, rt = OpamClient.update gt ~repos_only:(repos_only && not dev_only) ~dev_only:(dev_only && not repos_only) ~all names in OpamStd.Exn.finally (fun () -> OpamRepositoryState.drop rt) @@ fun () -> if upgrade then OpamSwitchState.with_ `Lock_write gt ~rt @@ fun st -> OpamConsole.msg "\n"; OpamSwitchState.drop @@ OpamClient.upgrade st ~check ~all:true [] else if check then OpamStd.Sys.exit_because (if changed then `Success else `False) else if changed then OpamConsole.msg "Now run 'opam upgrade' to apply any package updates.\n"; if not success then OpamStd.Sys.exit_because `Sync_error in mk_command ~cli cli_original "update" ~doc ~man Term.(const update $global_options cli $jobs_flag cli cli_original $name_list $repos_only $dev_only $depexts_only $all $check $upgrade) (* UPGRADE *) let upgrade_doc = "Upgrade the installed package to latest version." let upgrade cli = let doc = upgrade_doc in let man = [ `S Manpage.s_description; `P "This command upgrades the installed packages to their latest available \ versions. More precisely, this command calls the dependency solver to \ find a consistent state where $(i,most) of the installed packages are \ upgraded to their latest versions."; `P "If a directory is specified as argument, anything that is pinned to \ that directory is selected for upgrade."; `S Manpage.s_arguments; `S Manpage.s_options; ] @ OpamArg.man_build_option_section in let fixup = mk_flag ~cli cli_original ["fixup"] "Recover from a broken state (eg. missing dependencies, two conflicting \ packages installed together...)." in let check = mk_flag ~cli cli_original ["check"] "Don't run the upgrade: just check if anything could be upgraded. \ Returns 0 if that is the case, 1 if there is nothing that can be \ upgraded." in let all = mk_flag ~cli cli_original ["a";"all"] "Run an upgrade of all installed packages. This is the default if \ $(i,PACKAGES) was not specified, and can be useful with $(i,PACKAGES) \ to upgrade while ensuring that some packages get or remain installed." in let installed = mk_flag ~cli (cli_from cli2_1) ["installed"] "When a directory is provided as argument, do not install pinned package \ that are not yet installed." in let upgrade global_options build_options fixup check only_installed all recurse subpath atom_locs () = apply_global_options cli global_options; apply_build_options cli build_options; let all = all || atom_locs = [] in OpamGlobalState.with_ `Lock_none @@ fun gt -> if fixup then if atom_locs <> [] || check then `Error (true, Printf.sprintf "--fixup doesn't allow extra arguments") else OpamSwitchState.with_ `Lock_write gt @@ fun st -> OpamSwitchState.drop @@ OpamClient.fixup st; `Ok () else OpamSwitchState.with_ `Lock_write gt @@ fun st -> let atoms = OpamAuxCommands.resolve_locals_pinned st ~recurse ?subpath atom_locs in OpamSwitchState.drop @@ OpamClient.upgrade st ~check ~only_installed ~all atoms; `Ok () in mk_command_ret ~cli cli_original "upgrade" ~doc ~man Term.(const upgrade $global_options cli $build_options cli $fixup $check $installed $all $recurse cli $subpath cli $atom_or_dir_list) (* REPOSITORY *) let repository_doc = "Manage opam repositories." let repository cli = let doc = repository_doc in let scope_section = "SCOPE SPECIFICATION OPTIONS" in let commands = [ cli_original, "add", `add, ["NAME"; "[ADDRESS]"; "[QUORUM]"; "[FINGERPRINTS]"], "Adds under $(i,NAME) the repository at address $(i,ADDRESS) to the list \ of configured repositories, if not already registered, and sets this \ repository for use in the current switch (or the specified scope). \ $(i,ADDRESS) is required if the repository name is not already \ registered, and is otherwise an error if different from the registered \ address. The quorum is a positive integer that determines the validation \ threshold for signed repositories, with fingerprints the trust anchors \ for said validation."; cli_original, " ", `add, [], (* using an unbreakable space here will indent the text paragraph at the level of the previous labelled paragraph, which is what we want for our note. *) "$(b,Note:) By default, the repository is only added to the current \ switch. To add a repository to other switches, you need to use the \ $(b,--all) or $(b,--set-default) options (see below). If you want to \ enable a repository only to install its switches, you may be \ looking for $(b,opam switch create --repositories=REPOS)."; cli_original, "remove", `remove, ["NAME..."], "Unselects the given repositories so that they will not be used to get \ package definitions anymore. With $(b,--all), makes opam forget about \ these repositories completely."; cli_original, "set-repos", `set_repos, ["NAME..."], "Explicitly selects the list of repositories to look up package \ definitions from, in the specified priority order (overriding previous \ selection and ranks), according to the specified scope."; cli_original, "set-url", `set_url, ["NAME"; "ADDRESS"; "[QUORUM]"; "[FINGERPRINTS]"], "Updates the URL and trust anchors associated with a given repository \ name. Note that if you don't specify $(i,[QUORUM]) and \ $(i,[FINGERPRINTS]), any previous settings will be erased."; cli_original, "list", `list, [], "Lists the currently selected repositories in priority order from rank 1. \ With $(b,--all), lists all configured repositories and the switches \ where they are active."; cli_original, "priority", `priority, ["NAME"; "RANK"], "Synonym to $(b,add NAME --rank RANK)"; ] in let man = [ `S Manpage.s_description; `P "This command is used to manage package repositories. Repositories can \ be registered through subcommands $(b,add), $(b,remove) and \ $(b,set-url), and are updated from their URLs using $(b,opam update). \ Their names are global for all switches, and each switch has its own \ selection of repositories where it gets package definitions from."; `P ("Main commands $(b,add), $(b,remove) and $(b,set-repos) act only on \ the current switch, unless differently specified using options \ explained in $(b,"^scope_section^")."); `P "Without a subcommand, or with the subcommand $(b,list), lists selected \ repositories, or all configured repositories with $(b,--all)."; ] @ mk_subdoc ~cli ~defaults:["","list"] commands @ [ `S scope_section; `P "These flags allow one to choose which selections are changed by $(b,add), \ $(b,remove), $(b,set-repos). If no flag in this section is specified \ the updated selections default to the current switch. Multiple scopes \ can be selected, e.g. $(b,--this-switch --set-default)."; `S Manpage.s_options; ] in let command, params = mk_subcommands ~cli commands in let scope = let scope_info ?docv flags doc = Arg.info ~docs:scope_section ~doc ?docv flags in let flags = mk_vflag_all ~cli ~section:scope_section [ cli_original, `No_selection, ["dont-select"], "Don't update any selections"; cli_original, `Current_switch, ["this-switch"], "Act on the selections for the current switch (this is the default)"; cli_original, `Default, ["set-default"], "Act on the default repository selection that is used for newly \ created switches"; cli_original, `All, ["all-switches";"a"], "Act on the selections of all configured switches"; ] in let switches = Arg.opt Arg.(list string) [] (scope_info ["on-switches"] ~docv:"SWITCHES" "Act on the selections of the given list of switches") in let switches = Term.(const (List.map (fun s -> `Switch (OpamSwitch.of_string s))) $ Arg.value switches) in Term.(const (fun l1 l2 -> match l1@l2 with [] -> [`Current_switch] | l -> l) $ flags $ switches) in let rank = mk_opt ~cli cli_original ["rank"] "RANK" "Set the rank of the repository in the list of configured repositories. \ Package definitions are looked in the repositories in increasing rank \ order, therefore 1 is the highest priority. Negative ints can be used to \ select from the lowest priority, -1 being last. $(b,set-repos) can \ otherwise be used to explicitly set the repository list at once." Arg.(int) 1 in let repository global_options command kind short scope rank params () = apply_global_options cli global_options; let global = List.mem `Default scope in let command, params, rank = match command, params, rank with | Some `priority, [name; rank], 1 -> (try Some `add, [name], int_of_string rank with Failure _ -> OpamConsole.error_and_exit `Bad_arguments "Invalid rank specification %S" rank) | Some `priority, [], rank -> Some `add, [], rank | command, params, rank -> command, params, rank in let update_repos new_repo repos = let rank = if rank < 0 then List.length repos + rank + 1 else rank - 1 in OpamStd.List.insert_at rank new_repo (List.filter (( <> ) new_repo ) repos) in let check_for_repos rt names err = match List.filter (fun n -> not (OpamRepositoryName.Map.mem n rt.repositories)) names with [] -> () | l -> err (OpamStd.List.concat_map " " OpamRepositoryName.to_string l) in OpamGlobalState.with_ `Lock_none @@ fun gt -> let all_switches = OpamFile.Config.installed_switches gt.config in let switches = let all = OpamSwitch.Set.of_list all_switches in List.fold_left (fun acc -> function | `Default | `No_selection -> acc | `All -> all_switches | `Switch sw -> if not (OpamSwitch.Set.mem sw all) && not (OpamSwitch.is_external sw) then OpamConsole.error_and_exit `Not_found "No switch %s found" (OpamSwitch.to_string sw) else if List.mem sw acc then acc else acc @ [sw] | `Current_switch -> match OpamStateConfig.get_switch_opt () with | None -> OpamConsole.warning "No switch is currently set, perhaps you meant \ '--set-default'?"; acc | Some sw -> if List.mem sw acc then acc else acc @ [sw]) [] scope in match command, params with | Some `add, name :: url :: security -> let name = OpamRepositoryName.of_string name in let backend = match kind with | Some _ -> kind | None -> OpamUrl.guess_version_control url in let url = OpamUrl.parse ?backend ~from_file:false url in let trust_anchors = match security with | [] -> None | quorum::fingerprints -> try let quorum = int_of_string quorum in if quorum < 0 then failwith "neg" else Some { quorum; fingerprints } with Failure _ -> failwith ("Invalid quorum: "^quorum) in OpamRepositoryState.with_ `Lock_write gt (fun rt -> let rt = OpamRepositoryCommand.add rt name url trust_anchors in let failed, rt = OpamRepositoryCommand.update_with_auto_upgrade rt [name] in if failed <> [] then (OpamRepositoryState.drop @@ OpamRepositoryCommand.remove rt name; OpamConsole.error_and_exit `Sync_error "Initial repository fetch failed")); OpamGlobalState.drop @@ OpamRepositoryCommand.update_selection gt ~global ~switches (update_repos name); if scope = [`Current_switch] then OpamConsole.note "Repository %s has been added to the selections of switch %s \ only.\n\ Run `opam repository add %s --all-switches|--set-default' to use it \ in all existing switches, or in newly created switches, \ respectively.\n" (OpamRepositoryName.to_string name) (OpamSwitch.to_string (OpamStateConfig.get_switch ())) (OpamRepositoryName.to_string name); `Ok () | Some `remove, names -> let names = List.map OpamRepositoryName.of_string names in let rm = List.filter (fun n -> not (List.mem n names)) in let full_wipe = List.mem `All scope in let global = global || full_wipe in let gt = OpamRepositoryCommand.update_selection gt ~global ~switches:switches rm in if full_wipe then OpamRepositoryState.with_ `Lock_write gt @@ fun rt -> check_for_repos rt names (OpamConsole.warning "No configured repositories by these names found: %s"); OpamRepositoryState.drop @@ List.fold_left OpamRepositoryCommand.remove rt names else if scope = [`Current_switch] then OpamConsole.msg "Repositories removed from the selections of switch %s. \ Use '--all' to forget about them altogether.\n" (OpamSwitch.to_string (OpamStateConfig.get_switch ())); `Ok () | Some `add, [name] -> let name = OpamRepositoryName.of_string name in OpamRepositoryState.with_ `Lock_none gt (fun rt -> check_for_repos rt [name] (OpamConsole.error_and_exit `Not_found "No configured repository '%s' found, you must specify an URL")); OpamGlobalState.drop @@ OpamRepositoryCommand.update_selection gt ~global ~switches (update_repos name); `Ok () | Some `set_url, (name :: url :: security) -> let name = OpamRepositoryName.of_string name in let backend = match kind with | Some _ -> kind | None -> OpamUrl.guess_version_control url in let url = OpamUrl.parse ?backend ~from_file:false url in let trust_anchors = match security with | [] -> None | quorum::fingerprints -> try let quorum = int_of_string quorum in if quorum < 0 then failwith "neg" else Some { quorum; fingerprints } with Failure _ -> failwith ("Invalid quorum: "^quorum) in OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamRepositoryState.with_ `Lock_write gt @@ fun rt -> let rt = OpamRepositoryCommand.set_url rt name url trust_anchors in let _failed, _rt = OpamRepositoryCommand.update_with_auto_upgrade rt [name] in `Ok () | Some `set_repos, names -> let names = List.map OpamRepositoryName.of_string names in OpamGlobalState.with_ `Lock_none @@ fun gt -> let repos = OpamStateConfig.Repos.safe_read ~lock_kind:`Lock_read gt in let not_found = List.filter (fun r -> not (OpamRepositoryName.Map.mem r repos)) names in if not_found = [] then (OpamGlobalState.drop @@ OpamRepositoryCommand.update_selection gt ~global ~switches (fun _ -> names); `Ok ()) else OpamConsole.error_and_exit `Bad_arguments "No configured repositories by these names found: %s" (OpamStd.List.concat_map " " OpamRepositoryName.to_string not_found) | (None | Some `list), [] -> OpamRepositoryState.with_ `Lock_none gt @@ fun rt -> if List.mem `All scope then OpamRepositoryCommand.list_all rt ~short; let global = List.mem `Default scope in let switches = if scope = [] || List.exists (function `Current_switch | `Switch _ -> true | _ -> false) scope then switches else [] in if not short && scope = [`Current_switch] then OpamConsole.note "These are the repositories in use by the current switch. Use \ '--all' to see all configured repositories."; OpamRepositoryCommand.list rt ~global ~switches ~short; `Ok () | command, params -> bad_subcommand ~cli commands ("repository", command, params) in mk_command_ret ~cli cli_original "repository" ~doc ~man Term.(const repository $global_options cli $command $repo_kind_flag cli cli_original $print_short_flag cli cli_original $scope $rank $params) (* SWITCH *) (* From a list of strings (either "repo_name" or "repo_name=URL"), configure the repos with URLs if possible, and return the updated repos_state and selection of repositories *) let with_repos_rt gt repos f = OpamRepositoryState.with_ `Lock_none gt @@ fun rt -> let repos, rt = match repos with | None -> None, rt | Some repos -> let repos = List.map (fun s -> match OpamStd.String.cut_at s '=' with | None -> OpamRepositoryName.of_string s, None | Some (name, url) -> OpamRepositoryName.of_string name, Some url) repos in let new_defs = OpamStd.List.filter_map (function | (_, None) -> None | (n, Some url) -> let repo = OpamStd.Option.Op.( OpamUrl.parse_opt ~handle_suffix:false ~from_file:false url >>| fun u -> n, u) in if repo = None then OpamConsole.warning "Skipping %s, malformed url" url; repo) repos in if List.for_all (fun (name,url) -> match OpamRepositoryName.Map.find_opt name rt.repositories with | Some r -> r.repo_url = url | None -> false) new_defs then Some (List.map fst repos), rt else OpamRepositoryState.with_write_lock rt @@ fun rt -> let rt = List.fold_left (fun rt (name, url) -> OpamConsole.msg "Creating repository %s...\n" (OpamRepositoryName.to_string name); OpamRepositoryCommand.add rt name url None) rt new_defs in let failed, rt = OpamRepositoryCommand.update_with_auto_upgrade rt (List.map fst new_defs) in if failed <> [] then (OpamRepositoryState.drop @@ List.fold_left OpamRepositoryCommand.remove rt failed; OpamConsole.error_and_exit `Sync_error "Initial fetch of these repositories failed: %s" (OpamStd.List.concat_map ", " OpamRepositoryName.to_string failed)) else Some (List.map fst repos), rt in f (repos, rt) let switch_doc = "Manage multiple installation prefixes." let switch cli = let shell = OpamStd.Sys.guess_shell_compat () in let doc = switch_doc in let commands = [ cli_original, "create", `install, ["SWITCH"; "[COMPILER]"], "Create a new switch, and install the given compiler there. $(i,SWITCH) \ can be a plain name, or a directory, absolute or relative, in which case \ a local switch is created below the given directory. $(i,COMPILER), if \ omitted, defaults to $(i,SWITCH) if it is a plain name, unless \ $(b,--packages), $(b,--formula) or $(b,--empty) is specified. When \ creating a local switch, and none of these options are present, the \ compiler is chosen according to the configuration default (see \ opam-init(1)). If the chosen directory contains package definitions, a \ compatible compiler is searched within the default selection, and the \ packages will automatically get installed."; cli_original, "set", `set, ["SWITCH"], "Set the currently active switch, among the installed switches."; cli_original, "remove", `remove, ["SWITCH"], "Remove the given switch from disk."; cli_original, "export", `export, ["FILE"], "Save the current switch state to a file. If $(b,--full) is specified, it \ includes the metadata of all installed packages, and if $(b,--freeze) is \ specified, it freezes all vcs to their current commit."; cli_original, "import", `import, ["FILE"], "Import a saved switch state. If $(b,--switch) is specified and doesn't \ point to an existing switch, the switch will be created for the import."; cli_original, "reinstall", `reinstall, ["[SWITCH]"], "Reinstall the given compiler switch and all its packages."; cli_original, "list", `list, [], "Lists installed switches."; cli_original, "list-available", `list_available, ["[PATTERN]"], "Lists all the possible packages that are advised for installation when \ creating a new switch, i.e. packages with the $(i,compiler) flag set. If \ no pattern is supplied, all versions are shown."; cli_original, "show", `current, [], "Prints the name of the current switch."; cli_from cli2_1, "invariant", `show_invariant, [], "Prints the active switch invariant."; cli_from cli2_1, "set-invariant", `set_invariant, ["PACKAGES"], "Updates the switch invariant, that is, the formula that the switch must \ keep verifying throughout all operations. The previous setting is \ overriden. See also options $(b,--force) and $(b,--no-action). Without \ arguments, an invariant is chosen automatically."; cli_original, "set-description", `set_description, ["STRING"], "Sets the description for the selected switch."; cli_original, "link", `link, ["SWITCH";"[DIR]"], "Sets a local alias for a given switch, so that the switch gets \ automatically selected whenever in that directory or a descendant."; cli_between cli2_0 cli2_1 ~replaced:"create", "install", `install, ["SWITCH"], "Install a new switch"; cli_between cli2_0 cli2_1 ~replaced:"set-invariant", "set-base", `set_invariant, ["PACKAGES"], "Define a set of switch base packages."; ] in let man = [ `S Manpage.s_description; `P "This command is used to manage \"switches\", which are independent \ installation prefixes with their own compiler and sets of installed \ and pinned packages. This is typically useful to have different \ versions of the compiler available at once."; `P "Use $(b,opam switch create) to create a new switch, and $(b,opam \ switch set) to set the currently active switch. Without argument, \ lists installed switches, with one switch argument, defaults to \ $(b,set)."; `P (Printf.sprintf "Switch handles $(i,SWITCH) can be either a plain name, for switches \ that will be held inside $(i,~%s.opam), or a directory name, which in \ that case is the directory where the switch prefix will be installed, as \ %s. Opam will automatically select a switch by that name found in the \ current directory or its parents, unless $(i,OPAMSWITCH) is set or \ $(b,--switch) is specified. When creating a directory switch, if \ package definitions are found locally, the user is automatically \ prompted to install them after the switch is created unless \ $(b,--no-install) is specified." OpamArg.dir_sep OpamSwitch.external_dirname); `P (Printf.sprintf "$(b,opam switch set) sets the default switch globally, but it is also \ possible to select a switch in a given shell session, using the \ environment. For that, use $(i,%s)." OpamEnv.( shell_eval_invocation shell (opam_env_invocation ~switch:"SWITCH" ~set_opamswitch:true ()) |> Manpage.escape)); ] @ mk_subdoc ~cli ~defaults:["","list";"SWITCH","set"] commands @ [ `S Manpage.s_examples; `Pre " opam switch create 4.08.0"; `P "Create a new switch called \"4.08.0\" and select it, with a compiler \ automatically selected at version 4.08.0 (note that this can fail in \ case there is more than one compiler matching that version)."; `Pre " opam switch create ./ --deps-only"; `P "Prepare a local switch for building the packages defined in $(i,./). \ This scans the current directory for package definitions, chooses a \ compatible compiler, creates a local switch and installs the local \ package dependencies."; `Pre " opam switch create trunk --repos \ default,beta=git+https://github.com/ocaml/ocaml-beta-repository.git \ ocaml-variants.4.10.0+trunk"; `P "Create a new switch called \"trunk\", with \ $(b,ocaml-variants.4.10.0+trunk) as compiler, with a new $(i,beta) \ repository bound to the given URL selected besides the default one." ] @ [`S Manpage.s_options] @ OpamArg.man_build_option_section in let command, params = mk_subcommands_with_default ~cli commands in let no_switch = mk_flag ~cli cli_original ["no-switch"] "Don't automatically select newly installed switches." in let packages = mk_opt ~cli cli_original ["packages"] "PACKAGES" "When installing a switch, explicitly define the set of packages to \ enforce as the switch invariant." Arg.(some (list atom)) None in let formula = mk_opt ~cli (cli_from cli2_1) ["formula"] "FORMULA" "Allows specifying a complete \"dependency formula\", possibly including \ disjunction cases, as the switch invariant." Arg.(some OpamArg.dep_formula) None in let empty = mk_flag ~cli cli_original ["empty"] "Allow creating an empty switch, with no invariant." in let repos = mk_opt ~cli cli_original ["repositories"] "REPOS" "When creating a new switch, use the given selection of repositories \ instead of the default. $(i,REPOS) should be a comma-separated list of \ either already registered repository names (configured through e.g. \ $(i,opam repository add --dont-select)), or $(b,NAME)=$(b,URL) \ bindings, in which case $(b,NAME) should not be registered already to a \ different URL, and the new repository will be registered. See $(i,opam \ repository) for more details. This option also affects \ $(i,list-available)." Arg.(some (list string)) None in let descr = mk_opt ~cli cli_original ["description"] "STRING" "Attach the given description to a switch when creating it. Use the \ $(i,set-description) subcommand to modify the description of an \ existing switch." Arg.(some string) None in let full = mk_flag ~cli cli_original ["full"] "When exporting, include the metadata of all installed packages, \ allowing to re-import even if they don't exist in the repositories (the \ default is to include only the metadata of pinned packages)." in let freeze = mk_flag ~cli (cli_from cli2_1) ["freeze"] "When exporting, locks all VCS urls to their current commit, failing if \ it can not be retrieved. This ensures that an import will restore the \ exact state. Implies $(b,--full)." in let no_install = mk_flag ~cli cli_original ["no-install"] "When creating a local switch, don't look for any local package \ definitions to install." in let deps_only = mk_flag ~cli cli_original ["deps-only"] "When creating a local switch in a project directory (i.e. a directory \ containing opam package definitions), install the dependencies of the \ project but not the project itself." in let force = mk_flag ~cli (cli_from cli2_1) ["force"] "Only for $(i,set-invariant): force setting the invariant, bypassing \ consistency checks." in let no_action = mk_flag ~cli (cli_from cli2_1) ["n"; "no-action"] "Only for $(i,set-invariant): set the invariant, but don't enforce it \ right away: wait for the next $(i,install), $(i,upgrade) or similar \ command." in (* Deprecated options *) let d_alias_of = mk_opt ~cli (cli_between cli2_0 cli2_1) ["A";"alias-of"] "COMP" "Deprecated" Arg.(some string) None in let d_no_autoinstall = mk_flag ~cli (cli_between cli2_0 cli2_1) ["no-autoinstall"] "Deprecated" in let switch global_options build_options command print_short no_switch packages formula empty descr full freeze no_install deps_only repos force no_action d_alias_of d_no_autoinstall params () = if d_alias_of <> None then OpamConsole.warning "Option %s is deprecated, ignoring it. \ Use instead 'opam switch '" (OpamConsole.colorise `bold "--alias-of"); if d_no_autoinstall then OpamConsole.warning "Option %s is deprecated, ignoring it." (OpamConsole.colorise `bold "--no-autoinstall"); apply_global_options cli global_options; apply_build_options cli build_options; let invariant_arg ?repos rt args = match args, packages, formula, empty with | [], None, None, false -> None | _::_ as packages, None, None, false -> Some (OpamSwitchCommand.guess_compiler_invariant ?repos rt packages) | [], Some atoms, None, false -> let atoms = List.map (fun p -> Atom p) atoms in Some (OpamFormula.of_atom_formula (OpamFormula.ands atoms)) | [], None, (Some f), false -> Some f | [], None, None, true -> Some OpamFormula.Empty | _::_ as packages, Some atoms, None, false -> if fst cli = cli2_0 then let atoms = List.map (fun p -> Atom p) atoms in let pkgs_formula = OpamFormula.of_atom_formula (OpamFormula.ands atoms) in let args_formula = OpamSwitchCommand.guess_compiler_invariant ?repos rt packages in Some (OpamFormula.And (args_formula, pkgs_formula)) else OpamConsole.error_and_exit `Bad_arguments "Individual package and option '--packages' can not be specified at \ the same time. Use just '--packages' instead, e.g.\n\ opam switch create flambda \ --packages=ocaml.4.12.0,ocaml-option-flambda\n\ or '--formula'\n\ opam switch create flambda \ --formula='[\"ocaml\" {=\"4.12.0\"} \"ocaml-option-flambda\"]'" | _ -> OpamConsole.error_and_exit `Bad_arguments "Individual packages, options --packages, --formula and --empty may \ not be specified at the same time" in match command, params with | None , [] | Some `list, [] -> OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchCommand.list gt ~print_short; `Ok () | Some `list_available, pattlist -> OpamGlobalState.with_ `Lock_none @@ fun gt -> with_repos_rt gt repos @@ fun (repos, rt) -> let compilers = OpamSwitchCommand.get_compiler_packages ?repos rt in let st = OpamSwitchState.load_virtual ?repos_list:repos gt rt in OpamConsole.msg "# Listing available compilers from repositories: %s\n" (OpamStd.List.concat_map ", " OpamRepositoryName.to_string (OpamStd.Option.default (OpamGlobalState.repos_list gt) repos)); let filters = List.map (fun patt -> OpamListCommand.Pattern ({ OpamListCommand.default_pattern_selector with OpamListCommand.fields = ["name"; "version"] }, patt)) pattlist in let compilers = OpamListCommand.filter ~base:compilers st (OpamFormula.ands (List.map (fun f -> OpamFormula.Atom f) filters)) in let format = if print_short then OpamListCommand.([ Package ]) else OpamListCommand.([ Name; Version; Synopsis; ]) in let order nv1 nv2 = if nv1.version = nv2.version then OpamPackage.Name.compare nv1.name nv2.name else OpamPackage.Version.compare nv1.version nv2.version in OpamListCommand.display st {OpamListCommand.default_package_listing_format with OpamListCommand. short = print_short; header = not print_short; columns = format; all_versions = true; order = `Custom order; } compilers; `Ok () | Some `install, switch_arg::params -> OpamGlobalState.with_ `Lock_write @@ fun gt -> with_repos_rt gt repos @@ fun (repos, rt) -> let switch = OpamSwitch.of_string switch_arg in let use_local = not no_install && not empty && OpamSwitch.is_external switch in let is_implicit = params = [] && packages = None && formula = None && not empty in let pkg_params = if is_implicit && not (OpamSwitch.is_external switch) then [switch_arg] else params in (match invariant_arg ?repos rt pkg_params with | exception Failure e -> `Error (false, e) | invariant_opt -> let invariant = OpamStd.Option.default (OpamFile.Config.default_invariant rt.repos_global.config) invariant_opt in let (), st = OpamSwitchCommand.create gt ~rt ?synopsis:descr ?repos ~update_config:(not no_switch) ~invariant switch @@ fun st -> let st, additional_installs = if use_local then let st, atoms = OpamAuxCommands.autopin st ~simulate:deps_only ~quiet:true [`Dirname (OpamFilename.Dir.of_string switch_arg)] in let st = if is_implicit then let local_compilers = OpamStd.List.filter_map (fun (name, _) -> (* The opam file for the local package might not be the current pinning (e.g. with deps-only), but it's guaranteed to be the only available version by autopin. *) match OpamSwitchState.opam st (OpamPackage.package_of_name (Lazy.force st.available_packages) name) with | opam -> if OpamFile.OPAM.has_flag Pkgflag_Compiler opam then Some (Atom (name, None)) else None | exception Not_found -> None) atoms in if local_compilers <> [] then OpamSwitchCommand.set_invariant_raw st OpamFormula.(of_atom_formula (ands local_compilers)) else st else st in st, atoms else st, [] in (), OpamSwitchCommand.install_compiler st ~additional_installs ~deps_only ~ask:(additional_installs <> []) in OpamSwitchState.drop st; `Ok ()) | Some `export, [filename] -> OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamRepositoryState.with_ `Lock_none gt @@ fun rt -> OpamSwitchCommand.export rt ~full:(full || freeze) ~freeze (if filename = "-" then None else Some (OpamFile.make (OpamFilename.of_string filename))); `Ok () | Some `import, [filename] -> OpamGlobalState.with_ `Lock_none @@ fun gt -> let switch = OpamStateConfig.get_switch () in let is_new_switch = not (OpamGlobalState.switch_exists gt switch) in let import_source = if filename = "-" then None else Some (OpamFile.make (OpamFilename.of_string filename)) in if is_new_switch then with_repos_rt gt repos @@ fun (repos, rt) -> let synopsis = "Import from " ^ Filename.basename filename in let (), gt = OpamGlobalState.with_write_lock gt @@ fun gt -> let gt, st = OpamSwitchCommand.create gt ~rt ~synopsis ?repos ~invariant:OpamFormula.Empty ~update_config:(not no_switch) switch @@ fun st -> let st = OpamSwitchCommand.import st import_source in let invariant = OpamSwitchState.infer_switch_invariant st in let st = OpamSwitchCommand.set_invariant_raw st invariant in st.switch_global, st in OpamSwitchState.drop st; (), gt in OpamGlobalState.drop gt else begin if repos <> None then OpamConsole.warning "Switch exists, '--repositories' argument ignored"; OpamSwitchState.with_ `Lock_write gt ~switch @@ fun st -> OpamSwitchState.drop @@ OpamSwitchCommand.import st import_source end; `Ok () | Some `remove, switches -> OpamGlobalState.with_ `Lock_write @@ fun gt -> let _gt = List.fold_left (fun gt switch -> let opam_dir = OpamFilename.Op.( OpamFilename.Dir.of_string switch / OpamSwitch.external_dirname ) in if OpamFilename.is_symlink_dir opam_dir then (OpamFilename.rmdir opam_dir; gt) else OpamSwitchCommand.remove gt (OpamSwitch.of_string switch)) gt switches in `Ok () | Some `reinstall, switch -> let switch = match switch with | [sw] -> OpamSwitch.of_string sw | [] -> OpamStateConfig.get_switch () | _ -> OpamConsole.error_and_exit `Bad_arguments "Only one switch argument is supported" in OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_write gt ~switch @@ fun st -> OpamSwitchState.drop @@ OpamSwitchCommand.reinstall st; `Ok () | Some `current, [] -> OpamSwitchCommand.show (); `Ok () | Some `set, [switch] | Some `default switch, [] -> OpamGlobalState.with_ `Lock_write @@ fun gt -> let switch_name = OpamSwitch.of_string switch in OpamSwitchCommand.switch `Lock_none gt switch_name; `Ok () | Some `show_invariant, [] -> OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_none gt @@ fun st -> OpamConsole.msg "%s\n" (OpamFileTools.dep_formula_to_string st.switch_invariant); `Ok () | Some `set_invariant, params -> OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamRepositoryState.with_ `Lock_none gt @@ fun rt -> OpamSwitchState.with_ `Lock_write gt @@ fun st -> let repos = OpamSwitchState.repos_list st in (match invariant_arg ~repos rt params with | exception Failure e -> `Error (false, e) | invariant_opt -> let invariant = match invariant_opt with | Some i -> i | None -> OpamSwitchState.infer_switch_invariant st in let st = OpamSwitchCommand.set_invariant ~force st invariant in OpamConsole.msg "The switch invariant was set to %s\n" (OpamFormula.to_string invariant); let st = if no_action || OpamFormula.satisfies_depends st.installed invariant then st else OpamClient.install_t st ~ask:true [] None ~deps_only:false ~assume_built:false in OpamSwitchState.drop st; `Ok ()) | Some `link, args -> (try let switch, dir = match args with | switch::dir::[] -> OpamSwitch.of_string switch, OpamFilename.Dir.of_string dir | switch::[] -> OpamSwitch.of_string switch, OpamFilename.cwd () | [] -> failwith "Missing SWITCH argument" | _::_::_::_ -> failwith "Extra argument" in let open OpamFilename.Op in let linkname = dir / OpamSwitch.external_dirname in OpamGlobalState.with_ `Lock_none @@ fun gt -> if not (OpamGlobalState.switch_exists gt switch) then OpamConsole.error_and_exit `Not_found "The switch %s was not found" (OpamSwitch.to_string switch); if OpamFilename.is_symlink_dir linkname then OpamFilename.rmdir linkname; if OpamFilename.exists_dir linkname then OpamConsole.error_and_exit `Bad_arguments "There already is a local switch in %s. Remove it and try again." (OpamFilename.Dir.to_string dir); if OpamFilename.exists (dir // OpamSwitch.external_dirname) then OpamConsole.error_and_exit `Bad_arguments "There is a '%s' file in the way. Remove it and try again." (OpamFilename.Dir.to_string linkname); OpamFilename.link_dir ~link:linkname ~target:(OpamPath.Switch.root gt.root switch); OpamConsole.msg "Directory %s set to use switch %s.\n\ Just remove %s to unlink.\n" (OpamConsole.colorise `cyan (OpamFilename.Dir.to_string dir)) (OpamConsole.colorise `bold (OpamSwitch.to_string switch)) (OpamConsole.colorise `cyan (OpamFilename.Dir.to_string linkname)); `Ok () with Failure e -> `Error (true, e)) | Some `set_description, text -> let synopsis = String.concat " " text in OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_write gt @@ fun st -> let config = { st.switch_config with OpamFile.Switch_config.synopsis } in OpamSwitchAction.install_switch_config gt.root st.switch config; `Ok () | command, params -> bad_subcommand ~cli commands ("switch", command, params) in mk_command_ret ~cli cli_original "switch" ~doc ~man Term.(const switch $global_options cli $build_options cli $command $print_short_flag cli cli_original $no_switch $packages $formula $empty $descr $full $freeze $no_install $deps_only $repos $force $no_action $d_alias_of $d_no_autoinstall $params) (* PIN *) let pin_doc = "Pin a given package to a specific version or source." let pin ?(unpin_only=false) cli = let doc = pin_doc in let commands = [ cli_original, "list", `list, [], "Lists pinned packages."; cli_from cli2_1, "scan", `scan, ["DIR"], "Lists available packages to pin in directory."; cli_original, "add", `add, ["PACKAGE"; "TARGET"], "Pins package $(i,PACKAGE) to $(i,TARGET), which may be a version, a path, \ or a URL.\n\ $(i,PACKAGE) can be omitted if $(i,TARGET) contains one or more \ package descriptions. $(i,TARGET) can be replaced by \ $(b,--dev-repo) if a package by that name is already known. If \ $(i,TARGET) is $(b,-), the package is pinned as a virtual package, \ without any source. opam will infer the kind of pinning from the format \ (and contents, if local) of $(i,TARGET), Use $(b,--kind) or an explicit \ URL to disable that behaviour.\n\ Pins to version control systems may target a specific branch or commit \ using $(b,#branch) e.g. $(b,git://host/me/pkg#testing).\n\ If $(i,PACKAGE) is not a known package name, a new package by that name \ will be locally created.\n\ For source pinnings, the package version may be specified by using the \ format $(i,NAME).$(i,VERSION) for $(i,PACKAGE), in the source opam file, \ or with $(b,edit)."; cli_original, "remove", `remove, ["NAMES...|TARGET"], "Unpins packages $(i,NAMES), restoring their definition from the \ repository, if any. With a $(i,TARGET), unpins everything that is \ currently pinned to that target."; cli_original, "edit", `edit, ["NAME"], "Opens an editor giving you the opportunity to change the package \ definition that opam will locally use for package $(i,NAME), including \ its version and source URL. Using the format $(i,NAME.VERSION) will \ update the version in the opam file in advance of editing, without \ changing the actual target. The chosen editor is determined from \ environment variables $(b,OPAM_EDITOR), $(b,VISUAL) or $(b,EDITOR), in \ order."; ] in let man = [ `S Manpage.s_description; `P "This command allows local customisation of the packages in a given \ switch. A pinning can either just enforce a given version, or provide \ a local, editable version of the definition of the package. It is also \ possible to create a new package just by pinning a non-existing \ package name."; `P "Any customisation is available through the $(i,edit) subcommand, but \ the command-line gives facility for altering the source URL of the \ package, since it is the most common use: $(i,opam pin add PKG URL) \ modifies package $(i,PKG) to fetch its source from $(i,URL). If a \ package definition is found in the package's source tree, it will be \ used locally."; `P "If (or $(i,-)) is specified, the package is pinned without a source \ archive. The package name can be omitted if the target is a directory \ containing one or more valid package definitions (this allows one to do \ e.g. $(i,opam pin add .) from a source directory."; `P "If $(i,PACKAGE) has the form $(i,name.version), the pinned package \ will be considered as version $(i,version) by opam. Beware that this \ doesn't relate with the version of the source actually used for the \ package. See also the $(b,--with-version) option."; `P "The default subcommand is $(i,list) if there are no further arguments, \ and $(i,add) otherwise if unambiguous."; ] @ mk_subdoc ~cli ~defaults:["","list"] commands @ [ `S Manpage.s_options; ] @ OpamArg.man_build_option_section in let command, params = if unpin_only then Term.const (Some `remove), Arg.(value & pos_all string [] & Arg.info []) else mk_subcommands_with_default ~cli commands in let edit = mk_flag ~cli cli_original ["e";"edit"] "With $(i,opam pin add), edit the opam file as with `opam pin edit' \ after pinning." in let kind = let main_kinds = [ "version", `version; "path" , `rsync; "http" , `http; "git" , `git; "darcs" , `darcs; "hg" , `hg; "none" , `none; "auto" , `auto; ] in let help = Printf.sprintf "Sets the kind of pinning. Must be one of %s. \ If unset or $(i,auto), is inferred from the format of the target, \ defaulting to the appropriate version control if one is detected in \ the given directory, or to $(i,path) otherwise. $(i,OPAMPINKINDAUTO) \ can be set to \"0\" to disable automatic detection of version control.\ Use $(i,none) to pin without a target (for virtual packages)." (Arg.doc_alts_enum main_kinds) in let doc = Arg.info ~docv:"KIND" ~doc:help ["k";"kind"] in let kinds = main_kinds @ [ "local" , `rsync; "rsync" , `rsync; ] in Arg.(value & opt (some & enum kinds) None & doc) in let no_act = mk_flag ~cli cli_original ["n";"no-action"] "Just record the new pinning status, and don't prompt for \ (re)installation or removal of affected packages." in let dev_repo = mk_flag ~cli cli_original ["dev-repo"] "Pin to the upstream package source for the latest development version" in let normalise = mk_flag ~cli (cli_from cli2_1) ["normalise"] (Printf.sprintf "Print list of available package to pin in format \ `name.version%curl`, that is comprehensible by `opam pin \ add`. Available only with the scan subcommand. An example of use is \ `opam pin scan . --normalise | grep foo | xargs opam pin add`" OpamPinCommand.scan_sep) in let with_version = mk_opt ~cli (cli_from cli2_1) ["with-version"] "VERSION" "Set the pinning version to $(i,VERSION) for named $(i,PACKAGES) or \ packages retrieved from $(i,TARGET). It has priority over any other \ version specification (opam file version field, $(b,name.vers) \ argument)). When pinning to a version, the package source from that \ version is used, but declared as being $(i,VERSION) to opam.\n\ Using $(b,--with-version) is equivalent to using $(b,--edit) and \ adjusting the version in the package definition file." Arg.(some package_version) None in let guess_names kind ~recurse ?subpath url k = let found, cleanup = match OpamUrl.local_dir url with | Some d -> let same_kind url = match kind, url.OpamUrl.backend with | (None | Some `auto), _ | Some `rsync, `rsync | Some `http, `http -> true | Some (#OpamUrl.version_control as vc1), (#OpamUrl.version_control as vc2) -> vc1 = vc2 | Some (`none | `version), _ -> assert false | _ -> false in let pkgs = OpamAuxCommands.opams_of_dir_w_target ~recurse ?subpath ~same_kind url d |> List.map (fun (n,o,u,b) -> (n, OpamFile.OPAM.read_opt o, b, u)) in pkgs, None | None -> let pin_cache_dir = OpamRepositoryPath.pin_cache url in let cleanup = fun () -> OpamFilename.rmdir @@ OpamRepositoryPath.pin_cache_dir () in let basename = match OpamStd.String.split (OpamUrl.basename url) '.' with | [] -> OpamConsole.error_and_exit `Bad_arguments "Can not retrieve a path from '%s'" (OpamUrl.to_string url) | b::_ -> b in try let open OpamProcess.Job.Op in OpamProcess.Job.run @@ OpamRepository.pull_tree ~cache_dir:(OpamRepositoryPath.download_cache OpamStateConfig.(!r.root_dir)) basename pin_cache_dir [] [url] @@| function | Not_available (_,u) -> OpamConsole.error_and_exit `Sync_error "Could not retrieve %s" u | Result _ | Up_to_date _ -> let pkgs = OpamAuxCommands.opams_of_dir ~recurse ?subpath pin_cache_dir |> List.map (fun (n,o,b) -> (n, OpamFile.OPAM.read_opt o, b, url)) in pkgs, Some cleanup with e -> OpamStd.Exn.finalise e cleanup in let finalise = OpamStd.Option.default (fun () -> ()) cleanup in OpamStd.Exn.finally finalise @@ fun () -> k found in let pin_target kind target = let looks_like_version_re = Re.(compile @@ seq [ bos; opt @@ char 'v'; digit; rep @@ diff any (set "/\\"); eos]) in let parse ?backend ?handle_suffix target = match OpamUrl.parse_opt ?backend ?handle_suffix ~from_file:false target with | Some url -> `Source url | None -> OpamConsole.error_and_exit `Bad_arguments "No package pinned, invalid url" in let auto () = if target = "-" then `None else if Re.execp looks_like_version_re target then `Version (OpamPackage.Version.of_string target) else let backend = OpamUrl.guess_version_control target in parse ?backend ~handle_suffix:true target in let target = match kind with | Some `version -> `Version (OpamPackage.Version.of_string target) | Some (#OpamUrl.backend as k) -> parse ~backend:k target | Some `none -> `None | Some `auto -> auto () | None when OpamClientConfig.(!r.pin_kind_auto) -> auto () | None -> parse ~handle_suffix:false target in match target with | `Source url -> `Source (OpamAuxCommands.url_with_local_branch url) | _ -> target in let pin global_options build_options kind edit no_act dev_repo print_short recurse subpath normalise with_version command params () = apply_global_options cli global_options; apply_build_options cli build_options; let locked = OpamStateConfig.(!r.locked) <> None in let action = not no_act in let get_command = function | Some `list, [] | None, [] -> `list | Some `scan, [url] -> `scan url | Some `remove, (_::_ as arg) -> `remove arg | Some `edit, [nv] -> `edit nv | Some `add, pins when OpamPinCommand.looks_like_normalised pins -> `add_normalised pins | Some `default p, pins when OpamPinCommand.looks_like_normalised (p::pins) -> `add_normalised (p::pins) | Some `add, [nv] | Some `default nv, [] when dev_repo -> `add_dev nv | Some `add, [arg] | Some `default arg, [] -> `add_url arg | Some `add, [n; target] | Some `default n, [target] -> `add_wtarget (n,target) | _ -> `incorrect in match get_command (command, params) with | `list -> OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_none gt @@ fun st -> OpamClient.PIN.list st ~short:print_short; `Ok () | `scan url -> let backend, handle_suffix = match kind with | Some (#OpamUrl.backend as k) -> Some k, None | Some `auto -> OpamUrl.guess_version_control url, Some true | None when OpamClientConfig.(!r.pin_kind_auto) -> OpamUrl.guess_version_control url, Some true | _ -> None, None in OpamUrl.parse ?backend ?handle_suffix url |> OpamAuxCommands.url_with_local_branch |> OpamPinCommand.scan ~normalise ~recurse ?subpath; `Ok () | `remove arg -> OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_write gt @@ fun st -> let err, to_unpin = let open OpamStd.Option.Op in List.fold_left (fun (err, acc) arg -> let as_url = OpamUrl.parse_opt ~handle_suffix:false ~from_file:false arg >>| fun url -> OpamPackage.Set.filter (fun nv -> match OpamSwitchState.url st nv with | Some u -> let spu = OpamFile.URL.subpath u in let u = OpamFile.URL.url u in let path_equality () = let open OpamUrl in match subpath, recurse with | Some sp, false -> u.path = url.path && spu = Some sp | Some sp, true -> (match spu with | Some spp -> OpamUrl.Op.(OpamStd.String.starts_with ~prefix:(url / sp).path (u / spp).path) | None -> false) | None, true -> u.path = url.path | None, false -> spu = None && u.path = url.path in OpamUrl.(u.transport = url.transport) && path_equality () | None -> false) st.pinned |> OpamPackage.names_of_packages |> OpamPackage.Name.Set.elements in match as_url with | Some ((_::_) as url) -> err, url @ acc | _-> match (fst package_name) arg with | `Ok name -> err, name::acc | `Error _ -> OpamConsole.error "No package pinned to this target found, or invalid package \ name/url: %s" arg; true, acc) (false,[]) arg in if err then OpamStd.Sys.exit_because `Bad_arguments else (OpamSwitchState.drop @@ OpamClient.PIN.unpin st ~action to_unpin; `Ok ()) | `edit nv -> (match (fst package) nv with | `Ok (name, version) -> OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_write gt @@ fun st -> let version = OpamStd.Option.Op.(with_version ++ version) in OpamSwitchState.drop @@ OpamClient.PIN.edit st ~locked ~action ?version name; `Ok () | `Error e -> `Error (false, e)) | `add_normalised pins -> let pins = OpamPinCommand.parse_pins pins in OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_write gt @@ fun st -> OpamSwitchState.drop @@ OpamClient.PIN.url_pins st ~locked ~edit ~action (List.map (fun (n,v,u,sb) -> n, OpamStd.Option.Op.(with_version ++ v), None, u, sb) pins); `Ok () | `add_dev nv -> (match (fst package) nv with | `Ok (name,version) -> OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_write gt @@ fun st -> let name = OpamSolution.fuzzy_name st name in let version = OpamStd.Option.Op.(with_version ++ version) in OpamSwitchState.drop @@ OpamClient.PIN.pin st name ~locked ~edit ?version ~action `Dev_upstream; `Ok () | `Error e -> if command = Some `add then `Error (false, e) else bad_subcommand ~cli commands ("pin", command, params)) | `add_url arg -> (match pin_target kind arg with | `None | `Version _ -> let msg = Printf.sprintf "Ambiguous argument %S, if it is the pinning target, \ you must specify a package name first" arg in `Error (true, msg) | `Source url -> guess_names kind ~recurse ?subpath url @@ fun names -> OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_write gt @@ fun st -> OpamSwitchState.drop @@ OpamClient.PIN.url_pins st ~locked ~edit ~action (List.map (fun (n,o,u,sb) -> n,with_version,o,sb,u) names); `Ok ()) | `add_wtarget (n, target) -> (match (fst package) n with | `Ok (name,version) -> let pin = match pin_target kind target, with_version with | `Version v, Some v' -> `Source_version (v, v') | p, _ -> p in let version = OpamStd.Option.Op.(with_version ++ version) in OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_write gt @@ fun st -> OpamSwitchState.drop @@ OpamClient.PIN.pin st name ~locked ?version ~edit ~action ?subpath pin; `Ok () | `Error e -> `Error (false, e)) | `incorrect -> bad_subcommand ~cli commands ("pin", command, params) in mk_command_ret ~cli cli_original "pin" ~doc ~man Term.(const pin $global_options cli $build_options cli $kind $edit $no_act $dev_repo $print_short_flag cli cli_original $recurse cli $subpath cli $normalise $with_version $command $params) (* SOURCE *) let source_doc = "Get the source of an opam package." let source cli = let doc = source_doc in let man = [ `S Manpage.s_description; `P "Downloads the source for a given package to a local directory \ for development, bug fixing or documentation purposes." ] in let atom = Arg.(required & pos 0 (some atom) None & info ~docv:"PACKAGE" [] ~doc:"A package name with an optional version constraint") in let dev_repo = mk_flag ~cli cli_original ["dev-repo"] "Get the latest version-controlled source rather than the \ release archive" in let pin = mk_flag ~cli cli_original ["pin"] "Pin the package to the downloaded source (see `opam pin')." in let dir = mk_opt ~cli cli_original ["dir"] "DIR" "The directory where to put the source." Arg.(some dirname) None in let source global_options atom dev_repo pin dir () = apply_global_options cli global_options; OpamGlobalState.with_ `Lock_none @@ fun gt -> (* Fixme: this needs a write lock, because it uses the routines that download to opam's shared switch cache. (it's needed anyway when --pin is used) *) OpamSwitchState.with_ `Lock_write gt @@ fun t -> let nv = try OpamPackage.Set.max_elt (OpamPackage.Set.filter (OpamFormula.check atom) t.packages) with Not_found -> OpamConsole.error_and_exit `Not_found "No package matching %s found." (OpamFormula.short_string_of_atom atom) in let dir = match dir with | Some d -> d | None -> let dirname = if dev_repo then OpamPackage.name_to_string nv else OpamPackage.to_string nv in OpamFilename.Op.(OpamFilename.cwd () / dirname) in let open OpamFilename in if exists_dir dir then OpamConsole.error_and_exit `Bad_arguments "Directory %s already exists. Please remove it or use a different one \ (see option `--dir')" (Dir.to_string dir); let opam = OpamSwitchState.opam t nv in let subpath = OpamStd.Option.map_default OpamFile.URL.subpath None (OpamFile.OPAM.url opam) in if dev_repo then ( match OpamFile.OPAM.dev_repo opam with | None -> OpamConsole.error_and_exit `Not_found "Version-controlled repo for %s unknown \ (\"dev-repo\" field missing from metadata)" (OpamPackage.to_string nv) | Some url -> mkdir dir; match OpamProcess.Job.run (OpamRepository.pull_tree ~cache_dir:(OpamRepositoryPath.download_cache OpamStateConfig.(!r.root_dir)) ?subpath (OpamPackage.to_string nv) dir [] [url]) with | Not_available (_,u) -> OpamConsole.error_and_exit `Sync_error "%s is not available" u | Result _ | Up_to_date _ -> OpamConsole.formatted_msg "Successfully fetched %s development repo to .%s%s%s\n" (OpamPackage.name_to_string nv) Filename.dir_sep (OpamPackage.name_to_string nv) Filename.dir_sep ) else ( let job = let open OpamProcess.Job.Op in OpamUpdate.download_package_source t nv dir @@+ function | Some (Not_available (_,s)), _ | _, (_, Not_available (_, s)) :: _ -> OpamConsole.error_and_exit `Sync_error "Download failed: %s" s | None, _ | Some (Result _ | Up_to_date _), _ -> OpamAction.prepare_package_source t nv dir @@| function | None -> OpamConsole.formatted_msg "Successfully extracted to %s\n" (Dir.to_string dir) | Some e -> OpamConsole.warning "Some errors extracting to %s: %s\n" (Dir.to_string dir) (Printexc.to_string e) in OpamProcess.Job.run job; if OpamPinned.find_opam_file_in_source nv.name (OpamStd.Option.map_default (fun sp -> Op.(dir / sp)) dir subpath) = None then let f = if OpamFilename.exists_dir Op.(dir / "opam") then OpamFile.make Op.(dir / "opam" // "opam") else OpamFile.make Op.(dir // "opam") in OpamFile.OPAM.write f (OpamFile.OPAM.with_substs [] @@ OpamFile.OPAM.with_patches [] @@ opam) ); if pin then let backend = if dev_repo then match OpamFile.OPAM.dev_repo opam with | Some {OpamUrl.backend = #OpamUrl.version_control as kind; _} -> kind | _ -> `rsync else `rsync in let target = `Source (OpamUrl.parse ~backend ~from_file:false ("file://"^OpamFilename.Dir.to_string dir)) in OpamSwitchState.drop (OpamClient.PIN.pin t nv.name ~version:nv.version target) in mk_command ~cli cli_original "source" ~doc ~man Term.(const source $global_options cli $atom $dev_repo $pin $dir) (* LINT *) let lint_doc = "Checks and validate package description ('opam') files." let lint cli = let doc = lint_doc in let man = [ `S Manpage.s_description; `P "Given an $(i,opam) file, performs several quality checks on it and \ outputs recommendations, warnings or errors on stderr."; `S Manpage.s_arguments; `S Manpage.s_options; `S "LINT CODES" ] @ List.map (fun (c,t,s) -> `P (Printf.sprintf "%s$(b,%d): %s" (match t with | `Warning -> "W" | `Error -> "$(i,E)") c s)) (OpamFileTools.all_lint_warnings ()) in let files = Arg.(value & pos_all (existing_filename_dirname_or_dash) [] & info ~docv:Manpage.s_files [] ~doc:"Name of the opam files to check, or directory containing \ them. Current directory if unspecified") in let normalise = mk_flag ~cli cli_original ["normalise"] "Output a normalised version of the opam file to stdout" in let short = mk_flag ~cli cli_original ["short";"s"] "Only print the warning/error numbers, space-separated, if any" in let warnings = mk_opt ~cli cli_original ["warnings";"W"] "WARNS" "Select the warnings to show or hide. $(i,WARNS) should be a \ concatenation of $(b,+N), $(b,-N), $(b,+N..M), $(b,-N..M) to \ respectively enable or disable warning or error number $(b,N) or \ all warnings with numbers between $(b,N) and $(b,M) inclusive.\n\ All warnings are enabled by default, unless $(i,WARNS) starts with \ $(b,+), which disables all but the selected ones." warn_selector [] in let package = mk_opt ~cli cli_original ["package"] "PKG" "Lint the current definition of the given package instead of specifying \ an opam file directly." Arg.(some package) None in let check_upstream = mk_flag ~cli cli_original ["check-upstream"] "Check upstream, archive availability and checksum(s)" in let lint global_options files package normalise short warnings_sel check_upstream recurse subpath () = apply_global_options cli global_options; let opam_files_in_dir d = match OpamPinned.files_in_source ~recurse ?subpath d with | [] -> OpamConsole.warning "No opam files found in %s" (OpamFilename.Dir.to_string d); [] | l -> List.map (fun (_name,f,_) -> Some f) l in let files = match files, package with | [], None -> (* Lookup in cwd if nothing was specified *) opam_files_in_dir (OpamFilename.cwd ()) | files, None -> List.map (function | None -> [None] (* this means '-' was specified for stdin *) | Some (OpamFilename.D d) -> opam_files_in_dir d | Some (OpamFilename.F f) -> [Some (OpamFile.make f)]) files |> List.flatten | [], Some pkg -> (OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_none gt @@ fun st -> try let nv = match pkg with | name, Some v -> OpamPackage.create name v | name, None -> OpamSwitchState.get_package st name in let opam = OpamSwitchState.opam st nv in match OpamPinned.orig_opam_file st (OpamPackage.name nv) opam with | None -> raise Not_found | some -> [some] with Not_found -> OpamConsole.error_and_exit `Not_found "No opam file found for %s%s" (OpamPackage.Name.to_string (fst pkg)) (match snd pkg with None -> "" | Some v -> "."^OpamPackage.Version.to_string v)) | _::_, Some _ -> OpamConsole.error_and_exit `Bad_arguments "--package and a file argument are incompatible" in let msg = if normalise then OpamConsole.errmsg else OpamConsole.msg in let json = match OpamClientConfig.(!r.json_out) with | None -> None | Some _ -> Some [] in let err,json = List.fold_left (fun (err,json) opam_f -> try let warnings,opam = match opam_f with | Some f -> OpamFileTools.lint_file ~check_upstream ~handle_dirname:true f | None -> OpamFileTools.lint_channel ~check_upstream ~handle_dirname:false (OpamFile.make (OpamFilename.of_string "-")) stdin in let enabled = let default = match warnings_sel with | (_,true) :: _ -> false | _ -> true in let map = List.fold_left (fun acc (wn, enable) -> OpamStd.IntMap.add wn enable acc) OpamStd.IntMap.empty warnings_sel in fun w -> try OpamStd.IntMap.find w map with Not_found -> default in let warnings = List.filter (fun (n, _, _) -> enabled n) warnings in let failed = List.exists (function _,`Error,_ -> true | _ -> false) warnings in if short then (if warnings <> [] then msg "%s\n" (OpamStd.List.concat_map " " (fun (n,_,_) -> string_of_int n) warnings)) else if warnings = [] then (if not normalise then msg "%s%s\n" (OpamStd.Option.to_string (fun f -> OpamFile.to_string f ^ ": ") opam_f) (OpamConsole.colorise `green "Passed.")) else msg "%s%s\n%s\n" (OpamStd.Option.to_string (fun f -> OpamFile.to_string f ^ ": ") opam_f) (if failed then OpamConsole.colorise `red "Errors." else OpamConsole.colorise `yellow "Warnings.") (OpamFileTools.warns_to_string warnings); if normalise then OpamStd.Option.iter (OpamFile.OPAM.write_to_channel stdout) opam; let json = OpamStd.Option.map (OpamStd.List.cons (OpamFileTools.warns_to_json ?filename:(OpamStd.Option.map OpamFile.to_string opam_f) warnings)) json in (err || failed), json with | Parsing.Parse_error | OpamLexer.Error _ | OpamPp.Bad_version _ | OpamPp.Bad_format _ -> msg "File format error\n"; (true, json)) (false, json) files in OpamStd.Option.iter (fun json -> OpamJson.append "lint" (`A json)) json; if err then OpamStd.Sys.exit_because `False in mk_command ~cli cli_original "lint" ~doc ~man Term.(const lint $global_options cli $files $package $normalise $short $warnings $check_upstream $recurse cli $subpath cli) (* CLEAN *) let clean_doc = "Cleans up opam caches" let clean cli = let doc = clean_doc in let man = [ `S Manpage.s_description; `P "Cleans up opam caches, reclaiming some disk space. If no options are \ specified, the default is $(b,--logs --download-cache \ --switch-cleanup)." ] in let dry_run = mk_flag ~cli cli_original ["dry-run"] "Print the removal commands, but don't execute them" in let download_cache = mk_flag ~cli cli_original ["c"; "download-cache"] (Printf.sprintf "Clear the cache of downloaded files (\\$OPAMROOT%sdownload-cache), as \ well as the obsolete \\$OPAMROOT%sarchives, if that exists." OpamArg.dir_sep OpamArg.dir_sep) in let repos = mk_flag ~cli cli_original ["unused-repositories"] "Clear any configured repository that is not used by any switch nor the \ default." in let repo_cache = mk_flag ~cli cli_original ["r"; "repo-cache"] "Clear the repository cache. It will be rebuilt by the next opam command \ that needs it." in let logs = mk_flag ~cli cli_original ["logs"] "Clear the logs directory." in let switch = mk_flag ~cli cli_original ["s";"switch-cleanup"] "Run the switch-specific cleanup: clears backups, build dirs, \ uncompressed package sources of non-dev packages, local metadata of \ previously pinned packages, etc." in let all_switches = mk_flag ~cli cli_original ["a"; "all-switches"] "Run the switch cleanup commands in all switches. Implies $(b,--switch-cleanup)" in let clean global_options dry_run download_cache repos repo_cache logs switch all_switches () = apply_global_options cli global_options; let logs, download_cache, switch = if logs || download_cache || repos || repo_cache || switch || all_switches then logs, download_cache, switch else true, true, true in OpamGlobalState.with_ `Lock_write @@ fun gt -> let root = gt.root in let cleandir d = if dry_run then OpamConsole.msg "rm -rf \"%s\"/*\n" (OpamFilename.Dir.to_string d) else try OpamFilename.cleandir d with OpamSystem.Internal_error msg -> OpamConsole.warning "Error ignored: %s" msg in let rmdir d = if dry_run then OpamConsole.msg "rm -rf \"%s\"\n" (OpamFilename.Dir.to_string d) else try OpamFilename.rmdir d with OpamSystem.Internal_error msg -> OpamConsole.warning "Error ignored: %s" msg in let rm f = if dry_run then OpamConsole.msg "rm -f \"%s\"\n" (OpamFilename.to_string f) else OpamFilename.remove f in let switches = if all_switches then OpamGlobalState.switches gt else if switch then match OpamStateConfig.get_switch_opt () with | Some s -> [s] | None -> [] else [] in if switches <> [] then (OpamRepositoryState.with_ `Lock_none gt @@ fun rt -> List.iter (fun sw -> OpamSwitchState.with_ `Lock_write gt ~rt ~switch:sw @@ fun st -> OpamConsole.msg "Cleaning up switch %s\n" (OpamSwitch.to_string sw); cleandir (OpamPath.Switch.backup_dir root sw); cleandir (OpamPath.Switch.build_dir root sw); cleandir (OpamPath.Switch.remove_dir root sw); cleandir (OpamPath.Switch.extra_files_dir root sw); let pinning_overlay_dirs = List.map (fun nv -> OpamPath.Switch.Overlay.package root sw nv.name) (OpamPackage.Set.elements st.pinned) in List.iter (fun d -> if not (List.mem d pinning_overlay_dirs) then rmdir d) (OpamFilename.dirs (OpamPath.Switch.Overlay.dir root sw)); let keep_sources_dir = OpamPackage.Set.elements (OpamPackage.Set.union st.pinned (OpamPackage.Set.filter (OpamSwitchState.is_dev_package st) st.installed)) |> List.map (OpamSwitchState.source_dir st) in OpamFilename.dirs (OpamPath.Switch.sources_dir root sw) |> List.iter (fun d -> if not (List.mem d keep_sources_dir) then rmdir d)) switches); if repos then (OpamFilename.with_flock `Lock_write (OpamPath.repos_lock gt.root) @@ fun _lock -> let repos_config = OpamStateConfig.Repos.safe_read ~lock_kind:`Lock_write gt in let all_repos = OpamRepositoryName.Map.keys repos_config |> OpamRepositoryName.Set.of_list in let default_repos = OpamGlobalState.repos_list gt |> OpamRepositoryName.Set.of_list in let unused_repos = List.fold_left (fun repos sw -> let switch_config = OpamStateConfig.Switch.safe_load ~lock_kind:`Lock_read gt sw in let used_repos = OpamStd.Option.default [] switch_config.OpamFile.Switch_config.repos |> OpamRepositoryName.Set.of_list in OpamRepositoryName.Set.diff repos used_repos) (OpamRepositoryName.Set.diff all_repos default_repos) (OpamGlobalState.switches gt) in OpamRepositoryName.Set.iter (fun r -> OpamConsole.msg "Removing repository %s\n" (OpamRepositoryName.to_string r); rmdir (OpamRepositoryPath.root root r); rm (OpamRepositoryPath.tar root r)) unused_repos; let repos_config = OpamRepositoryName.Map.filter (fun r _ -> not (OpamRepositoryName.Set.mem r unused_repos)) repos_config in OpamConsole.msg "Updating %s\n" (OpamFile.to_string (OpamPath.repos_config root)); if not dry_run then OpamFile.Repos_config.write (OpamPath.repos_config root) repos_config); if repo_cache then (OpamConsole.msg "Clearing repository cache\n"; if not dry_run then OpamRepositoryState.Cache.remove ()); if download_cache then (OpamConsole.msg "Clearing cache of downloaded files\n"; List.iter (fun dir -> match OpamFilename.(Base.to_string (basename_dir dir)) with | "git" -> (try OpamFilename.exec dir ~name:"git gc" [["git"; "gc"]] with e -> OpamStd.Exn.fatal e) | _ -> cleandir dir ) (OpamFilename.dirs (OpamRepositoryPath.download_cache root))); if logs then (OpamConsole.msg "Clearing logs\n"; cleandir (OpamPath.log root)) in mk_command ~cli cli_original "clean" ~doc ~man Term.(const clean $global_options cli $dry_run $download_cache $repos $repo_cache $logs $switch $all_switches) (* LOCK *) let lock_doc = "Create locked opam files to share build environments across hosts." let lock cli = let doc = lock_doc in let man = [ `S Manpage.s_description; `P "Generates a lock file of a package: checks the current \ state of their installed dependencies, and outputs modified versions of \ the opam file with a $(i,.locked) suffix, where all the (transitive) \ dependencies and pinnings have been bound strictly to the currently \ installed version."; `P "By using these locked opam files, it is then possible to recover the \ precise build environment that was setup when they were generated."; `P "If paths (filename or directory) are given, those opam files are locked. \ If package is given, installed one is locked, otherwise its latest \ version. If a locally pinned package is given, its current local opam \ file is locked, even if not versioned or uncommitted changes"; `P "Fails if all mandatory dependencies are not installed in the switch."; `S "LOCK FILE CHANGED FIELDS"; `P "- $(i,depends) are fixed to their specific versions, with all filters \ removed (except for the exceptions below"; `P "- $(i,depopts) that are installed in the current switch are turned into \ depends, with their version set. Others are set in the $(i,conflict) field"; `P "- `{dev}`, `{with-test}, and `{with-doc}` filters are kept if all \ packages of a specific filters are installed in the switch. Versions are \ fixed and the same filter is on all dependencies that are added from \ them"; `P "- $(i,pin-depends) are kept and new ones are added if in the \ dependencies some packages are pinned "; `P "- pins are resolved: if a package is locally pinned, opam tries to get \ its remote url and branch, and sets this as the target URL"; `S Manpage.s_arguments; `S Manpage.s_options; ] in let only_direct_flag = mk_flag ~cli cli_original ["d"; "direct-only"] "Only lock direct dependencies, rather than the whole dependency tree." in let lock_suffix = OpamArg.lock_suffix cli in let lock global_options only_direct lock_suffix atom_locs () = apply_global_options cli global_options; OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_none gt @@ fun st -> let st, packages = OpamLockCommand.select_packages atom_locs st in if OpamPackage.Set.is_empty packages then OpamConsole.msg "No lock file generated\n" else let pkg_done = OpamPackage.Set.fold (fun nv msgs -> let opam = OpamSwitchState.opam st nv in let locked = OpamLockCommand.lock_opam ~only_direct st opam in let locked_fname = OpamFilename.add_extension (OpamFilename.of_string (OpamPackage.name_to_string nv)) ("opam." ^ lock_suffix) in if not (OpamCoreConfig.(!r).OpamCoreConfig.safe_mode || OpamStateConfig.(!r.dryrun)) then OpamFile.OPAM.write_with_preserved_format (OpamFile.make locked_fname) locked; (nv, locked_fname)::msgs) packages [] in OpamConsole.msg "Generated %slock files for:\n%s" (if OpamCoreConfig.(!r).safe_mode || OpamStateConfig.(!r.dryrun) then "(not saved) " else "") (OpamStd.Format.itemize (fun (nv, file) -> Printf.sprintf "%s: %s" (OpamPackage.to_string nv) (OpamFilename.to_string file)) pkg_done) in mk_command ~cli (cli_from cli2_1) "lock" ~doc ~man Term.(const lock $global_options cli $only_direct_flag $lock_suffix $atom_or_local_list) (* HELP *) let help = let doc = "Display help about opam and opam commands." in let man = [ `S Manpage.s_description; `P "Prints help about opam commands."; `P "Use `$(mname) help topics' to get the full list of help topics."; ] in let topic = let doc = Arg.info [] ~docv:"TOPIC" ~doc:"The topic to get help on." in Arg.(value & pos 0 (some string) None & doc ) in let help man_format cmds topic = match topic with | None -> `Help (`Pager, None) | Some topic -> let topics = "topics" :: cmds in let conv, _ = Cmdliner.Arg.enum (List.rev_map (fun s -> (s, s)) topics) in match conv topic with | `Error e -> `Error (false, e) | `Ok t when t = "topics" -> List.iter (OpamConsole.msg "%s\n") cmds; `Ok () | `Ok t -> `Help (man_format, Some t) in Term.(ret (const help $Term.man_format $Term.choice_names $topic)), Term.info "help" ~doc ~man let default cli = let doc = "source-based package management" in let man = [ `S Manpage.s_description; `P "Opam is a package manager. It uses the powerful mancoosi tools to \ handle dependencies, including support for version constraints, \ optional dependencies, and conflict management. The default \ configuration binds it to the official package repository for OCaml."; `P "It has support for different remote repositories such as HTTP, rsync, \ git, darcs and mercurial. Everything is installed within a local opam \ directory, that can include multiple installation prefixes with \ different sets of intalled packages."; `P "Use either $(b,opam --help) or $(b,opam help ) \ for more information on a specific command."; `S Manpage.s_commands; `S "COMMAND ALIASES"; ] @ help_sections cli in let usage global_options = apply_global_options cli global_options; OpamConsole.formatted_msg "usage: opam [--version]\n\ \ [--help]\n\ \ []\n\ \n\ The most commonly used opam commands are:\n\ \ init %s\n\ \ list %s\n\ \ show %s\n\ \ install %s\n\ \ remove %s\n\ \ update %s\n\ \ upgrade %s\n\ \ config %s\n\ \ repository %s\n\ \ switch %s\n\ \ pin %s\n\ \ admin %s\n\ \n\ See 'opam help ' for more information on a specific command.\n" init_doc list_doc show_doc install_doc remove_doc update_doc upgrade_doc config_doc repository_doc switch_doc pin_doc OpamAdminCommand.admin_command_doc in Term.(const usage $global_options cli), Term.info "opam" ~version:(OpamVersion.to_string OpamVersion.current) ~sdocs:global_option_section ~doc ~man let admin = (* cmdliner never sees the admin subcommand, so this "can't happen" *) let doc = "Internal opam error - main admin command invoked" in Term.(ret (const (`Error (true, doc)))), Term.info "admin" ~doc:OpamAdminCommand.admin_command_doc (* Note: for cli versionning check, all commands must be constructed with [OpamArg.mk_command] or [OpamArg.mk_command_ret]. *) let commands cli = let show = show cli in let remove = remove cli in let repository = repository cli in (* This list must always include *all* commands, regardless of cli *) [ init cli; list cli; make_command_alias ~cli (list ~force_search:true cli) ~options:" --search" "search"; show; make_command_alias ~cli show "info"; install cli; remove; make_command_alias ~cli remove "uninstall"; reinstall cli; update cli; upgrade cli; var cli; option cli; config cli; exec cli; env cli; repository; make_command_alias ~cli repository "remote"; switch cli; pin cli; make_command_alias ~cli (pin ~unpin_only:true cli) ~options:" remove" "unpin"; source cli; lint cli; clean cli; lock cli; admin; help; ] let current_commands = commands OpamCLIVersion.Sourced.current let is_builtin_command prefix = List.exists (fun (_,info) -> OpamStd.String.starts_with ~prefix (Term.name info)) current_commands let is_admin_subcommand prefix = prefix = "admin" || let matches = List.filter (fun (_,info) -> OpamStd.String.starts_with ~prefix (Term.name info)) current_commands in match matches with | [(_,info)] when Term.name info = "admin" -> true | _ -> false let get_cmdliner_parser cli = (default cli, commands cli) opam-2.1.5/src/client/opamConfigCommand.mli0000644000175000017500000001477114427463453017662 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Functions handling the `opam config` subcommand and configuration actions *) open OpamTypes open OpamStateTypes (** {2 `opam config` subcommand and their associated commands } *) (** Display the current environment. Booleans csh, sexp and fish set an alternative output (unspecified if more than one is true, sh-style by default). [inplace_path] changes how the PATH variable is updated when there is already an opam entry: either at the same rank, or pushed in front. *) val env: 'a global_state -> switch -> ?set_opamroot:bool -> ?set_opamswitch:bool -> csh:bool -> sexp:bool -> fish:bool -> inplace_path:bool -> unit (** Ensures that the environment file exists in the given switch, regenerating it, if necessary. *) val ensure_env: 'a global_state -> switch -> unit (** Like [env] but allows one to specify the precise env to print rather than compute it from a switch state *) val print_eval_env: csh:bool -> sexp:bool -> fish:bool -> env -> unit (** Display the content of all available packages variables *) val list: 'a switch_state -> name list -> unit (** Substitute files *) val subst: 'a global_state -> basename list -> unit (** Prints expansion of variables in string *) val expand: 'a global_state -> string -> unit (** Execute a command in a subshell, after variable expansion *) val exec: [< unlocked ] global_state -> set_opamroot:bool -> set_opamswitch:bool -> inplace_path:bool -> string list -> unit (** {2 Variables and options display and setting } *) (** Functions handling `opam var` and `opam option` command *) (** Given an `opam option` field or field-value argument, detect the scope, switch, global or nonexistent field (cf. [OpamCommands.Var_Option_Common.var_option]) *) val get_scope: string -> [> `Switch | `Global | `None of string ] (** {3 Setting variables and options } *) (** Update operation type *) type whole_op = [ `Overwrite of string | `Revert ] type append_op = [ `Add of string | `Remove of string ] type update_op = [ append_op | whole_op ] (** Parse an update operation. String is of the form [var[(+=|-=|=)[value]]]. If 'value' is absent, it is a revert operation. Raise [Invalid_argument] if the string is malformed *) val parse_update: string -> string * update_op (** As [parse_update] but parse only overwrites and reverts. String is of the form [var=[value]]`. Raise [Invalid_argument] if the string is malformed *) val parse_whole: string -> string * whole_op val whole_of_update_op: update_op -> whole_op (** [set_opt_global gt field value] updates global config field with update value in /config file. Modifiable fields are a subset of all defined fields in [OpamFile.Config.t]. On revert, field is reverted to its initial value as defined in [OpamInitDefaults.init_config], to default value otherwise ([OpamFile.Config.empty]). May raise [OpamStd.Sys.Exit 2]. *) val set_opt_global: rw global_state -> string -> update_op -> rw global_state (** As [set_opt_global], [set_opt_switch] updates switch config file in //.opam-switch/switch-config. If switch state is given, uses its config and returns it with then new config. Otherwise, loads the raw switch state and returns [None]. Raises [OpamStd.Sys.Exit 50] ([`Configuration_error]) if no switch is set *) val set_opt_switch: 'a global_state -> ?st:rw switch_state -> string -> update_op -> rw switch_state option (** [set_var_global] and [set_var_switch] update respectively `global-variables` field in global config and `variables` field in switch config, by appending the new variables to current set. If switch state is given, uses its config and returns it with then new config. Otherwise, loads the raw switch state and returns [None]. Raises [OpamStd.Sys.Exit 2] ([`Bad_argument]) if field is not modifiable *) val set_var_global: rw global_state -> string -> whole_op -> rw global_state (** Raises [OpamStd.Sys.Exit 50] ([`Configuration_error]) if no switch is set *) val set_var_switch: 'a global_state -> ?st:rw switch_state -> string -> whole_op -> rw switch_state option (** {3 Display list of variables and options } *) (** List switch and/or global fields/sections and their value. If switch state is given, uses its config, otherwise loads the raw switch state. *) val options_list: ?st:unlocked switch_state -> 'a global_state -> unit val options_list_global: 'a global_state -> unit (** Raises [OpamStd.Sys.Exit 50] ([`Configuration_error]) if no switch is set *) val options_list_switch: ?st:unlocked switch_state -> 'a global_state -> unit (** List switch and/or global variables and their value. If switch state is given, uses its config, otherwise loads the raw switch state. *) val vars_list: ?st:'a switch_state -> 'b global_state -> unit val vars_list_global: 'a global_state -> unit (** Raises [OpamStd.Sys.Exit 50] ([`Configuration_error]) if no switch is set *) val vars_list_switch: ?st:'a switch_state -> 'b global_state -> unit (** {3 Display a variable and option } *) (** Display [field] name and content in the global / switch configuration. If switch state is given, uses its config, otherwise loads the raw switch state. *) val option_show_global: 'a global_state -> string -> unit (** Raises [OpamStd.Sys.Exit 50] ([`Configuration_error]) if no switch is set *) val option_show_switch: 'a global_state -> ?st:unlocked switch_state -> string -> unit (** Display [var] name and content in the global / switch configuration. Look first in the raw switch_state, if not found, uses the given switch state or loads one. *) val var_show_global: 'a global_state -> string -> unit val var_show_switch: 'a global_state -> ?st:'b switch_state -> string -> unit val var_show: 'a global_state -> string -> unit opam-2.1.5/src/client/opamCommands.mli0000644000175000017500000000225114427463453016705 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Opam CLI main entry point *) (** {2 Commands} *) (** [is_builtin_command arg] is [true] if [arg] is a prefix of any built-in command *) val is_builtin_command: string -> bool (** [is_admin_subcommand arg] is [true] if [arg] is a unique prefix of the admin sub-command. *) val is_admin_subcommand: string -> bool val get_cmdliner_parser: OpamCLIVersion.Sourced.t -> OpamArg.command * OpamArg.command list opam-2.1.5/src/client/opamInitDefaults.ml0000644000175000017500000001333514427463453017373 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2016-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes let repository_url = { OpamUrl. transport = "https"; path = "opam.ocaml.org"; hash = None; backend = `http; } let default_compiler = OpamFormula.ors [ OpamFormula.Atom (OpamPackage.Name.of_string "ocaml-system", OpamFormula.Empty); OpamFormula.Atom (OpamPackage.Name.of_string "ocaml-base-compiler", OpamFormula.Empty); ] let default_invariant = OpamFormula.Atom (OpamPackage.Name.of_string "ocaml", OpamFormula.Atom (`Geq, OpamPackage.Version.of_string "4.05.0")) let eval_variables = [ OpamVariable.of_string "sys-ocaml-version", ["ocamlc"; "-vnum"], "OCaml version present on your system independently of opam, if any"; OpamVariable.of_string "sys-ocaml-arch", ["sh"; "-c"; "ocamlc -config 2>/dev/null | tr -d '\\r' | grep '^architecture: ' | sed -e 's/.*: //' -e 's/i386/i686/' -e 's/amd64/x86_64/'"], "Target architecture of the OCaml compiler present on your system"; OpamVariable.of_string "sys-ocaml-cc", ["sh"; "-c"; "ocamlc -config 2>/dev/null | tr -d '\\r' | grep '^ccomp_type: ' | sed -e 's/.*: //'"], "Host C Compiler type of the OCaml compiler present on your system"; OpamVariable.of_string "sys-ocaml-libc", ["sh"; "-c"; "ocamlc -config 2>/dev/null | tr -d '\\r' | grep '^os_type: ' | sed -e 's/.*: //' -e 's/Win32/msvc/' -e '/^msvc$/!s/.*/libc/'"], "Host C Runtime Library type of the OCaml compiler present on your system"; ] let os_filter os = FOp (FIdent ([], OpamVariable.of_string "os", None), `Eq, FString os) let linux_filter = os_filter "linux" let macos_filter = os_filter "macos" let openbsd_filter = os_filter "openbsd" let freebsd_filter = os_filter "freebsd" let not_open_free_bsd_filter = FNot (FOr (openbsd_filter, freebsd_filter)) let win32_filter = os_filter "win32" let sandbox_filter = FOr (linux_filter, macos_filter) let gpatch_filter = FOr (openbsd_filter, freebsd_filter) let patch_filter = FNot gpatch_filter let gtar_filter = openbsd_filter let tar_filter = FNot gtar_filter let getconf_filter = FNot (FOr (win32_filter, freebsd_filter)) let sandbox_wrappers = let cmd t = [ CString "%{hooks}%/sandbox.sh", None; CString t, None; ] in [ `build [cmd "build", Some sandbox_filter]; `install [cmd "install", Some sandbox_filter]; `remove [cmd "remove", Some sandbox_filter]; ] let wrappers ~sandboxing () = let w = OpamFile.Wrappers.empty in if sandboxing then List.fold_left OpamFile.Wrappers.(fun w -> function | `build wrap_build -> { w with wrap_build } | `install wrap_install -> { w with wrap_install } | `remove wrap_remove -> { w with wrap_remove } ) OpamFile.Wrappers.empty sandbox_wrappers else w let bwrap_cmd = "bwrap" let bwrap_filter = linux_filter let bwrap_string () = Printf.sprintf "Sandboxing tool %s was not found. You should install 'bubblewrap'. \ See https://opam.ocaml.org/doc/FAQ.html#Why-does-opam-require-bwrap." bwrap_cmd let req_dl_tools () = let msg = Some "A download tool is required, check env variables OPAMCURL or OPAMFETCH" in let default = [ ["curl"; "wget"], msg, Some not_open_free_bsd_filter; ["fetch"], msg, Some freebsd_filter; ["ftp"], msg, Some openbsd_filter ] in let open OpamStd.Option.Op in let cmd = (OpamRepositoryConfig.E.fetch () >>= fun s -> match OpamStd.String.split s ' ' with | c::_ -> Some c | _ -> None) >>+ fun () -> OpamRepositoryConfig.E.curl () in match cmd with | Some cmd -> [[cmd], Some "Custom download tool, check OPAMCURL or OPAMFETCH", None] | None -> default let dl_tool () = let open OpamStd.Option.Op in (OpamRepositoryConfig.E.fetch () >>+ fun () -> OpamRepositoryConfig.E.curl ()) >>| fun cmd -> [(CString cmd), None] let recommended_tools () = let make = OpamStateConfig.(Lazy.force !r.makecmd) in [ [make], None, None; ["cc"], None, None; ] let required_tools ~sandboxing () = req_dl_tools () @ [ ["diff"], None, None; ["patch"], None, Some patch_filter; ["gpatch"], None, Some gpatch_filter; ["tar"], None, Some tar_filter; ["gtar"], None, Some gtar_filter; ["unzip"], None, None; ["getconf"], None, Some getconf_filter; ] @ if sandboxing then [ [bwrap_cmd], Some (bwrap_string()), Some bwrap_filter; ["sandbox-exec"], None, Some macos_filter; ] else [] let init_scripts () = [ ("sandbox.sh", OpamScript.bwrap), Some bwrap_filter; ("sandbox.sh", OpamScript.sandbox_exec), Some macos_filter; ] module I = OpamFile.InitConfig let (@|) g f = OpamStd.Op.(g @* f) () let init_config ?(sandboxing=true) () = I.empty |> I.with_repositories [OpamRepositoryName.of_string "default", (repository_url, None)] |> I.with_default_compiler default_compiler |> I.with_default_invariant default_invariant |> I.with_eval_variables eval_variables |> I.with_wrappers @| wrappers ~sandboxing |> I.with_recommended_tools @| recommended_tools |> I.with_required_tools @| required_tools ~sandboxing |> I.with_init_scripts @| init_scripts |> I.with_dl_tool @| dl_tool opam-2.1.5/src/client/opamAdminCheck.ml0000644000175000017500000004125614427463453016771 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2017-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamPackage.Set.Op [@@@ocaml.warning "-33"] open OpamDoseCompat let env ~with_test ~with_doc ~dev nv v = match OpamVariable.Full.scope v, OpamVariable.(to_string (Full.variable v)) with | (OpamVariable.Full.Global | OpamVariable.Full.Self), "name" -> Some (S (OpamPackage.Name.to_string nv.name)) | (OpamVariable.Full.Global | OpamVariable.Full.Self), "version" -> Some (S (OpamPackage.Version.to_string nv.version)) | OpamVariable.Full.Global, "opam-version" -> Some (S OpamVersion.(to_string current)) | OpamVariable.Full.Global, "with-test" -> Some (B with_test) | OpamVariable.Full.Global, "dev" -> Some (B dev) | OpamVariable.Full.Global, "with-doc" -> Some (B with_doc) | _ -> None let get_universe ~with_test ~with_doc ~dev opams = let env = env ~with_test ~with_doc ~dev in let packages = OpamPackage.keys opams in { u_packages = packages; u_action = Query; u_installed = OpamPackage.Set.empty; u_available = packages; u_depends = OpamPackage.Map.mapi (fun nv o -> OpamFile.OPAM.depends o |> OpamFilter.partial_filter_formula (env nv)) opams; u_depopts = OpamPackage.Map.mapi (fun nv o -> OpamFile.OPAM.depopts o |> OpamFilter.partial_filter_formula (env nv)) opams; u_conflicts = OpamPackage.Map.mapi (fun nv o -> OpamFile.OPAM.conflicts o |> OpamFilter.filter_formula ~default:false (env nv)) opams; u_installed_roots = OpamPackage.Set.empty; u_pinned = OpamPackage.Set.empty; u_base = OpamPackage.Set.empty; u_invariant = OpamFormula.Empty; u_attrs = []; u_reinstall = OpamPackage.Set.empty; } let installability_check univ = let packages = univ.u_packages in let graph = OpamCudf.Graph.of_universe @@ OpamSolver.load_cudf_universe ~depopts:false ~build:true ~post:true univ packages () in let filter_roots g packages = let has_pkg p = OpamPackage.Set.mem (OpamCudf.cudf2opam p) packages in OpamCudf.Graph.fold_vertex (fun p acc -> if has_pkg p && not (List.exists has_pkg (OpamCudf.Graph.succ g p)) then OpamPackage.Set.add (OpamCudf.cudf2opam p) acc else acc) g OpamPackage.Set.empty in let installable = OpamSolver.installable univ in let uninstallable = packages -- installable in let unav_roots = filter_roots graph uninstallable in unav_roots, uninstallable let formula_of_pkglist packages = function | [] -> OpamFormula.Empty | [p] -> let nv = OpamCudf.cudf2opam p in Atom (nv.name, Atom (`Eq, nv.version)) | p::ps -> let name = (OpamCudf.cudf2opam p).name in let nvs = List.map OpamCudf.cudf2opam (p::ps) in Atom (name, OpamFormula.formula_of_version_set (OpamPackage.versions_of_name packages name) (OpamPackage.versions_of_packages (OpamPackage.Set.of_list nvs))) let cycle_check univ = let cudf_univ = OpamSolver.load_cudf_universe ~depopts:true ~build:true ~post:false univ univ.u_packages () in let graph = OpamCudf.Graph.of_universe cudf_univ |> OpamCudf.Graph.mirror in (* conflicts break cycles *) let conflicts = Dose_algo.Defaultgraphs.PackageGraph.conflict_graph cudf_univ in let module CGraph = Dose_algo.Defaultgraphs.PackageGraph.UG in CGraph.iter_edges (fun nv1 nv2 -> OpamCudf.Graph.remove_edge graph nv1 nv2; OpamCudf.Graph.remove_edge graph nv2 nv1) conflicts; let scc = let module Comp = Graph.Components.Make(OpamCudf.Graph) in Comp.scc_list graph |> List.filter (function [] | [_] -> false | _ -> true) in let node_map, cy = List.fold_left (fun (node_map, acc) pkgs -> let univ = Cudf.load_universe pkgs in let g = OpamCudf.Graph.of_universe univ in let conflicts = Dose_algo.Defaultgraphs.PackageGraph.conflict_graph univ in (* Simplify the graph by merging all equivalent versions of each package *) (* (note: this is not completely accurate, as dependencies might be conjunctions or disjunctions, information which is lost in the dependency graph) *) (* let count = OpamCudf.Graph.nb_vertex g in *) let node_map = Cudf.fold_packages_by_name (fun node_map _ pkgs -> let id p = let f pl = List.sort compare @@ List.map (Cudf.uid_by_package univ) pl in f (OpamCudf.Graph.pred g p), f (OpamCudf.Graph.succ g p), f (CGraph.succ conflicts p) in let ids = List.fold_left (fun acc p -> OpamCudf.Map.add p (id p) acc) OpamCudf.Map.empty pkgs in let rec gather node_map = function | [] -> node_map | p::pkgs -> let pid = OpamCudf.Map.find p ids in let ps, pkgs = List.partition (fun p1 -> OpamCudf.Map.find p1 ids = pid) pkgs in List.iter (OpamCudf.Graph.remove_vertex g) ps; let node_map = OpamCudf.Map.add p (p::ps) node_map in gather node_map pkgs in gather node_map pkgs) node_map univ in (* OpamConsole.msg * "Number of vertices: before merge %d, after merge %d\n" * count (OpamCudf.Graph.nb_vertex g); *) let it = ref 0 in let rec extract_cycles acc seen rpath v g = incr it; let rec find_pref acc v = function | [] -> None | v1::r -> if Cudf.(=%) v v1 then Some (v1::acc) else if CGraph.mem_edge conflicts v v1 then None else find_pref (v1::acc) v r in match find_pref [] v rpath with | Some cy -> cy :: acc, seen | None -> if OpamCudf.Set.mem v seen then acc, seen else let seen = OpamCudf.Set.add v seen in let rpath = v::rpath in (* split into sub-graphs for each successor *) List.fold_left (fun (acc, seen) s -> extract_cycles acc seen rpath s g) (acc, seen) (OpamCudf.Graph.succ g v) in let p0 = List.find (OpamCudf.Graph.mem_vertex g) pkgs in (* OpamConsole.msg "Iterations: %d\n" !it; *) let r, _seen = extract_cycles acc OpamCudf.Set.empty [] p0 g in node_map, r ) (OpamCudf.Map.empty, []) scc in (* OpamConsole.msg "all cycles: %d\n" (List.length cy); *) let rec has_conflict = function | [] | [_] -> false | p::r -> List.exists (CGraph.mem_edge conflicts p) r || has_conflict r in let cy = List.rev cy |> List.filter (fun c -> not (has_conflict c)) in let cycle_packages = List.fold_left (List.fold_left (fun acc p -> List.fold_left (fun acc p -> OpamPackage.Set.add (OpamCudf.cudf2opam p) acc) acc (OpamCudf.Map.find p node_map))) OpamPackage.Set.empty cy in let cycle_formulas = cy |> List.map @@ List.map @@ fun p -> formula_of_pkglist univ.u_packages (OpamCudf.Map.find p node_map) in cycle_packages, cycle_formulas let print_cycles cy = let arrow = OpamConsole.colorise `yellow @@ if OpamConsole.utf8 () then " \xe2\x86\x92 " (* U+2192 *) else " -> " in OpamStd.Format.itemize ~bullet:(OpamConsole.colorise `bold " * ") (OpamStd.List.concat_map arrow OpamFormula.to_string) cy (* Obsolete packages check *) module PkgSet = OpamPackage.Set module PkgMap = OpamPackage.Map module PkgSetSet = OpamStd.Set.Make(PkgSet) (* module PkgSetMap = OpamStd.Map.Make(PkgSet) *) let pkg_deps univ package = let deps = try OpamFilter.filter_deps ~build:true ~post:true ~default:true (OpamPackage.Map.find package univ.u_depends) with Not_found -> Empty in let sets_formula = OpamFormula.map (fun (name, vconstr) -> OpamPackage.Version.Set.filter (OpamFormula.check_version_formula vconstr) (OpamPackage.versions_of_name univ.u_packages name) |> OpamPackage.Name.Map.singleton name |> OpamPackage.of_map |> fun s -> Atom (PkgSetSet.singleton s)) deps in let product ss1 ss2 = PkgSetSet.fold (fun s1 -> PkgSetSet.union (PkgSetSet.map (PkgSet.union s1) ss2)) ss1 PkgSetSet.empty in let depsets = (* PkgSetSet-encoded CNF *) match OpamFormula.map_up_formula (function | Atom s -> Atom s | And (Atom s1, Atom s2) -> Atom (PkgSetSet.union s1 s2) | Or (Atom s1, Atom s2) -> Atom (product s1 s2) | And _ | Or _ -> assert false | Block x -> x | Empty -> Atom (PkgSetSet.empty)) sets_formula with | And _ | Or _ | Block _ | Empty -> assert false | Atom depsets -> depsets in let inferred_conflicts = (* Versions that may be present in some disjunctions but will always be rejected. We filter them out to get more accurate reverse deps *) PkgSetSet.fold (fun dset acc -> try let n = (PkgSet.choose dset).name in if PkgSet.for_all (fun p -> p.name = n) dset then acc ++ (OpamPackage.packages_of_name univ.u_packages n -- dset) else acc with Not_found -> acc) depsets PkgSet.empty in PkgSetSet.map (fun s -> s -- inferred_conflicts) depsets let more_restrictive_deps_than deps1 deps2 = PkgSetSet.for_all (fun disj2 -> PkgSetSet.exists (fun disj1 -> PkgSet.subset disj1 disj2) deps1) deps2 (* Aggregates all versionned packages with an exclusive version relationship (when b.vb1 can only be installed with a.va1, and the only version of b that can be installed with a.va1 is vb1). An aggregate should not contain more than one version per package name. *) let aggregate packages deps revdeps = if OpamClientConfig.E.noaggregate () = Some true then PkgSet.fold (fun nv -> PkgSetSet.add (PkgSet.singleton nv)) packages PkgSetSet.empty else let friends p (deps, revdeps) = (* dependencies which have a 1-1 version relationship *) try PkgMap.find p deps |> OpamPackage.to_map |> OpamPackage.Name.Map.filter (fun _ vs -> OpamPackage.Version.Set.is_singleton vs) |> OpamPackage.of_map |> PkgSet.filter (fun d -> OpamPackage.packages_of_name (PkgMap.find d revdeps) p.name = PkgSet.singleton p) with Not_found -> PkgSet.empty in let rec all_friends acc p = let acc = PkgSet.add p acc in PkgSet.fold (fun p acc -> all_friends acc p) (friends p (deps, revdeps) ++ friends p (revdeps, deps) -- acc) acc in let rec aux acc packages = if PkgSet.is_empty packages then acc else let p = PkgSet.choose packages in let fr = all_friends PkgSet.empty p in aux (PkgSetSet.add fr acc) (packages -- fr) in aux PkgSetSet.empty packages (* we work on aggregates of packages (expected to be a.g. different names with the same version), encode their dependencies as CNF mapped to sets, i.e. sets of sets from each of which one package must be present. Then, we detect aggregates with an inferior version, and equivalent or less restrictive dependencies: their members are obsolete *) let get_obsolete univ opams = let deps_map = (* pkg -> setset-encoded CNF *) PkgSet.fold (fun p -> PkgMap.add p (pkg_deps univ p)) univ.u_packages PkgMap.empty in let simple_deps = (* pkg -> set *) PkgMap.map (fun deps -> PkgSetSet.fold PkgSet.union deps PkgSet.empty) deps_map in let revdeps_map = (* pkg -> set *) PkgMap.fold (fun pkg -> PkgSet.fold (fun d -> PkgMap.update d (PkgSet.add pkg) PkgSet.empty)) simple_deps PkgMap.empty in let aggregates = aggregate univ.u_packages simple_deps revdeps_map in let aggregate_deps pkgs = PkgSet.fold (fun pkg -> PkgSetSet.union (PkgMap.find pkg deps_map)) pkgs PkgSetSet.empty |> PkgSetSet.map (fun ps -> ps -- pkgs) in let aggregate_revdeps pkgs = PkgSet.fold (fun pkg acc -> try PkgSet.union (PkgMap.find pkg revdeps_map) acc with Not_found -> acc) pkgs PkgSet.empty -- pkgs in let aggregate_nextv pkgs = let ps = OpamPackage.packages_of_names univ.u_packages (OpamPackage.names_of_packages pkgs) in PkgSet.map (fun p -> match PkgSet.split p ps with | (_, true, s1) -> let next = PkgSet.min_elt s1 in if next.name = p.name then next else raise Not_found | _ -> raise Not_found) pkgs in PkgSetSet.fold (fun pkgs acc -> let is_obsolete = not @@ PkgSet.exists (fun p -> OpamFile.OPAM.has_flag Pkgflag_Compiler (OpamPackage.Map.find p opams)) pkgs && try let next = aggregate_nextv pkgs in more_restrictive_deps_than (aggregate_deps pkgs) (aggregate_deps next) && let next_rd = aggregate_revdeps next in not (OpamPackage.Set.is_empty next_rd) && PkgSet.subset (aggregate_revdeps pkgs) next_rd with Not_found -> false in if is_obsolete then acc ++ pkgs else acc) aggregates PkgSet.empty let check ~quiet ~installability ~cycles ~obsolete ~ignore_test repo_root = let pkg_prefixes = OpamRepository.packages_with_prefixes repo_root in let opams = OpamPackage.Map.fold (fun nv prefix acc -> let opam_file = OpamRepositoryPath.opam repo_root prefix nv in match OpamFile.OPAM.read_opt opam_file with | Some o -> OpamPackage.Map.add nv o acc | None -> OpamConsole.warning "Error while reading %s" (OpamFile.to_string opam_file); acc) pkg_prefixes OpamPackage.Map.empty in let univ = get_universe ~with_test:(not ignore_test) ~with_doc:(not ignore_test) ~dev:false opams in (* Installability check *) let unav_roots, uninstallable = if not installability then PkgSet.empty, PkgSet.empty else ( if not quiet then OpamConsole.msg "Checking installability of every package. This may \ take a few minutes...\n"; installability_check univ ) in if not quiet then if not (PkgSet.is_empty uninstallable) then OpamConsole.error "These packages are not installable (%d):\n%s%s" (PkgSet.cardinal unav_roots) (OpamStd.List.concat_map " " OpamPackage.to_string (PkgSet.elements unav_roots)) (let unav_others = uninstallable -- unav_roots in if PkgSet.is_empty unav_others then "" else "\n(the following depend on them and are also unavailable:\n"^ (OpamStd.List.concat_map " " OpamPackage.to_string (PkgSet.elements unav_others))^")"); (* Cyclic dependency checks *) let cycle_packages, cycle_formulas = if not cycles then PkgSet.empty, [] else cycle_check univ in if not quiet && cycle_formulas <> [] then (OpamConsole.error "Dependency cycles detected:"; OpamConsole.errmsg "%s" @@ print_cycles cycle_formulas); (* Obsolescence checks *) let obsolete_packages = if not obsolete then PkgSet.empty else get_obsolete univ opams in if not quiet && not( PkgSet.is_empty obsolete_packages) then (OpamConsole.error "Obsolete packages detected:"; OpamConsole.errmsg "%s" (OpamStd.Format.itemize (fun (n, vs) -> Printf.sprintf "%s %s" (OpamConsole.colorise `bold (OpamPackage.Name.to_string n)) (OpamStd.List.concat_map ", " (fun v -> OpamConsole.colorise `magenta (OpamPackage.Version.to_string v)) (OpamPackage.Version.Set.elements vs))) (OpamPackage.Name.Map.bindings (OpamPackage.to_map obsolete_packages)))); univ.u_packages, unav_roots, uninstallable, cycle_packages, obsolete_packages opam-2.1.5/src/client/opamCLIVersion.mli0000644000175000017500000000355014427463453017124 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2020 David Allsopp Ltd. *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** CLI Versions *) include OpamStd.ABSTRACT (** The current version of the CLI (major and minor of OpamVersion.current *) val current : t (* Default CLI version, currently 2.0. This value is checked in CI. *) val default : t (** Tests whether a valid CLI version is supported by the client library *) val is_supported : t -> bool (** ['a option] version of {!to_string} *) val of_string_opt : string -> t option val of_string : string -> t (** Comparison [>]] with [(major, minor)] *) val ( >= ) : t -> int * int -> bool (** Comparison [<] with [(major, minor)] *) val ( < ) : t -> int * int -> bool val compare : t -> t -> int (** Returns previous supported version. @raise Not_found if there isn't one. *) val previous: t -> t (* CLI version extended with provenance *) module Sourced : sig type nonrec t = t * OpamStateTypes.provenance (** The current version of the CLI (major and minor of OpamVersion.current *) val current : t (** Parse the given environment variable result as MAJOR.MINOR *) val env: string option -> t option end module Op : sig val (@<) : Sourced.t -> t -> bool val (@=) : Sourced.t -> t -> bool val (@>=) : Sourced.t -> t -> bool end opam-2.1.5/src/client/opamAdminCommand.ml0000644000175000017500000013017714427463453017333 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamProcess.Job.Op open OpamStateTypes open Cmdliner type command = unit Cmdliner.Term.t * Cmdliner.Term.info let checked_repo_root () = let repo_root = OpamFilename.cwd () in if not (OpamFilename.exists_dir (OpamRepositoryPath.packages_dir repo_root)) then OpamConsole.error_and_exit `Bad_arguments "No repository found in current directory.\n\ Please make sure there is a \"packages%s\" directory" OpamArg.dir_sep; repo_root let global_options cli = let apply_cli options = { options with OpamArg.cli = options.OpamArg.cli} in Term.(const apply_cli $ OpamArg.global_options cli) let admin_command_doc = "Tools for repository administrators" let admin_command_man = [ `S Manpage.s_description; `P (Printf.sprintf "This command can perform various actions on repositories in the opam \ format. It is expected to be run from the root of a repository, i.e. a \ directory containing a 'repo' file and a subdirectory 'packages%s' \ holding package definition within subdirectories. A 'compilers%s' \ subdirectory (opam repository format version < 2) will also be used by \ the $(b,upgrade-format) subcommand." OpamArg.dir_sep OpamArg.dir_sep) ] let index_command_doc = "Generate an inclusive index file for serving over HTTP." let index_command cli = let command = "index" in let doc = index_command_doc in let man = [ `S Manpage.s_description; `P "An opam repository can be served over HTTP or HTTPS using any web \ server. To that purpose, an inclusive index needs to be generated \ first: this command generates the files the opam client will expect \ when fetching from an HTTP remote, and should be run after any changes \ are done to the contents of the repository." ] in let urls_txt_arg cli = OpamArg.mk_vflag ~cli `minimal_urls_txt [ OpamArg.cli_original, `no_urls_txt, ["no-urls-txt"], "Don't generate a 'urls.txt' file. That index file is no longer \ needed from opam 2.0 on, but is still used by older versions."; OpamArg.cli_original, `full_urls_txt, ["full-urls-txt"], "Generate an inclusive 'urls.txt', for a repository that will be \ used by opam versions earlier than 2.0."; OpamArg.cli_original, `minimal_urls_txt, ["minimal-urls-txt"], "Generate a minimal 'urls.txt' file, that only includes the 'repo' \ file. This allows opam versions earlier than 2.0 to read that file, \ and be properly redirected to a repository dedicated to their \ version, assuming a suitable 'redirect:' field is defined, instead \ of failing. This is the default."; ] in let cmd global_options urls_txt () = OpamArg.apply_global_options cli global_options; let repo_root = checked_repo_root () in let repo_file = OpamRepositoryPath.repo repo_root in let repo_def = match OpamFile.Repo.read_opt repo_file with | None -> OpamConsole.warning "No \"repo\" file found. Creating a minimal one."; OpamFile.Repo.create () | Some r -> r in let repo_stamp = let date () = let t = Unix.gmtime (Unix.time ()) in Printf.sprintf "%04d-%02d-%02d %02d:%02d" (t.Unix.tm_year + 1900) (t.Unix.tm_mon +1) t.Unix.tm_mday t.Unix.tm_hour t.Unix.tm_min in match OpamUrl.guess_version_control (OpamFilename.Dir.to_string repo_root) with | None -> date () | Some vcs -> let module VCS = (val OpamRepository.find_backend_by_kind vcs) in match OpamProcess.Job.run (VCS.revision repo_root) with | None -> date () | Some hash -> OpamPackage.Version.to_string hash in let repo_def = OpamFile.Repo.with_stamp repo_stamp repo_def in OpamFile.Repo.write repo_file repo_def; if urls_txt <> `no_urls_txt then (OpamConsole.msg "Generating urls.txt...\n"; OpamFilename.of_string "repo" :: (if urls_txt = `full_urls_txt then OpamFilename.rec_files OpamFilename.Op.(repo_root / "compilers") @ OpamFilename.rec_files (OpamRepositoryPath.packages_dir repo_root) else []) |> List.fold_left (fun set f -> if not (OpamFilename.exists f) then set else let attr = OpamFilename.to_attribute repo_root f in OpamFilename.Attribute.Set.add attr set ) OpamFilename.Attribute.Set.empty |> OpamFile.File_attributes.write (OpamFile.make (OpamFilename.of_string "urls.txt"))); OpamConsole.msg "Generating index.tar.gz...\n"; OpamHTTP.make_index_tar_gz repo_root; OpamConsole.msg "Done.\n"; in OpamArg.mk_command ~cli OpamArg.cli_original command ~doc ~man Term.(const cmd $ global_options cli $ urls_txt_arg cli) let cache_urls repo_root repo_def = let global_dl_cache = OpamStd.Option.Op.(OpamStateConfig.(load ~lock_kind:`Lock_read !r.root_dir) +! OpamFile.Config.empty) |> OpamFile.Config.dl_cache in let repo_dl_cache = OpamStd.List.filter_map (fun rel -> if OpamStd.String.contains ~sub:"://" rel then OpamUrl.parse_opt ~handle_suffix:false rel else Some OpamUrl.Op.(OpamUrl.of_string (OpamFilename.Dir.to_string repo_root) / rel)) (OpamFile.Repo.dl_cache repo_def) in repo_dl_cache @ global_dl_cache (* Downloads all urls of the given package to the given cache_dir *) let package_files_to_cache repo_root cache_dir cache_urls ?link (nv, prefix) = match OpamFileTools.read_opam (OpamRepositoryPath.packages repo_root prefix nv) with | None -> Done (OpamPackage.Map.empty) | Some opam -> let add_to_cache ?name urlf errors = let label = OpamPackage.to_string nv ^ OpamStd.Option.to_string ((^) "/") name in match OpamFile.URL.checksum urlf with | [] -> OpamConsole.warning "[%s] no checksum, not caching" (OpamConsole.colorise `green label); Done errors | (first_checksum :: _) as checksums -> OpamRepository.pull_file_to_cache label ~cache_urls ~cache_dir checksums (OpamFile.URL.url urlf :: OpamFile.URL.mirrors urlf) @@| fun r -> match OpamRepository.report_fetch_result nv r with | Not_available (_,m) -> OpamPackage.Map.update nv (fun l -> m::l) [] errors | Up_to_date () | Result () -> OpamStd.Option.iter (fun link_dir -> let target = OpamRepository.cache_file cache_dir first_checksum in let name = OpamStd.Option.default (OpamUrl.basename (OpamFile.URL.url urlf)) name in let link = OpamFilename.Op.(link_dir / OpamPackage.to_string nv // name) in OpamFilename.link ~relative:true ~target ~link) link; errors in let urls = (match OpamFile.OPAM.url opam with | None -> [] | Some urlf -> [add_to_cache urlf]) @ (List.map (fun (name,urlf) -> add_to_cache ~name:(OpamFilename.Base.to_string name) urlf) (OpamFile.OPAM.extra_sources opam)) in OpamProcess.Job.seq urls OpamPackage.Map.empty let cache_command_doc = "Fills a local cache of package archives" let cache_command cli = let command = "cache" in let doc = cache_command_doc in let man = [ `S Manpage.s_description; `P "Downloads the archives for all packages to fill a local cache, that \ can be used when serving the repository." ] in let cache_dir_arg = Arg.(value & pos 0 OpamArg.dirname (OpamFilename.Dir.of_string "./cache") & info [] ~docv:"DIR" ~doc: "Name of the cache directory to use.") in let no_repo_update_arg = OpamArg.mk_flag ~cli OpamArg.cli_original ["no-repo-update";"n"] "Don't check, create or update the 'repo' file to point to the \ generated cache ('archive-mirrors:' field)." in let link_arg = OpamArg.mk_opt ~cli OpamArg.cli_original ["link"] "DIR" (Printf.sprintf "Create reverse symbolic links to the archives within $(i,DIR), in \ the form $(b,DIR%sPKG.VERSION%sFILENAME)." OpamArg.dir_sep OpamArg.dir_sep) Arg.(some OpamArg.dirname) None in let jobs_arg = OpamArg.mk_opt ~cli OpamArg.cli_original ["jobs"; "j"] "JOBS" "Number of parallel downloads" OpamArg.positive_integer 8 in let cmd global_options cache_dir no_repo_update link jobs () = OpamArg.apply_global_options cli global_options; let repo_root = checked_repo_root () in let repo_file = OpamRepositoryPath.repo repo_root in let repo_def = OpamFile.Repo.safe_read repo_file in let pkg_prefixes = OpamRepository.packages_with_prefixes repo_root in let cache_urls = cache_urls repo_root repo_def in let errors = OpamParallel.reduce ~jobs ~nil:OpamPackage.Map.empty ~merge:(OpamPackage.Map.union (fun a _ -> a)) ~command:(package_files_to_cache repo_root cache_dir cache_urls ?link) (List.sort (fun (nv1,_) (nv2,_) -> (* Some pseudo-randomisation to avoid downloading all files from the same host simultaneously *) match compare (Hashtbl.hash nv1) (Hashtbl.hash nv2) with | 0 -> compare nv1 nv2 | n -> n) (OpamPackage.Map.bindings pkg_prefixes)) in let cache_dir_url = OpamFilename.remove_prefix_dir repo_root cache_dir in if not no_repo_update then if not (List.mem cache_dir_url (OpamFile.Repo.dl_cache repo_def)) then (OpamConsole.msg "Adding %s to %s...\n" cache_dir_url (OpamFile.to_string repo_file); OpamFile.Repo.write repo_file (OpamFile.Repo.with_dl_cache (cache_dir_url :: OpamFile.Repo.dl_cache repo_def) repo_def)); if not (OpamPackage.Map.is_empty errors) then ( OpamConsole.error "Got some errors while processing: %s" (OpamStd.List.concat_map ", " OpamPackage.to_string (OpamPackage.Map.keys errors)); OpamConsole.errmsg "%s" (OpamStd.Format.itemize (fun (nv,el) -> Printf.sprintf "[%s] %s" (OpamPackage.to_string nv) (String.concat "\n" el)) (OpamPackage.Map.bindings errors)) ); OpamConsole.msg "Done.\n"; in OpamArg.mk_command ~cli OpamArg.cli_original command ~doc ~man Term.(const cmd $ global_options cli $ cache_dir_arg $ no_repo_update_arg $ link_arg $ jobs_arg) let add_hashes_command_doc = "Add archive hashes to an opam repository." let add_hashes_command cli = let command = "add-hashes" in let doc = add_hashes_command_doc in let cache_dir = OpamFilename.Dir.of_string "~/.cache/opam-hash-cache" in let man = [ `S Manpage.s_description; `P (Printf.sprintf "This command scans through package definitions, and add hashes as \ requested (fetching the archives if required). A cache is generated \ in %s for subsequent runs." (OpamArg.escape_path (OpamFilename.Dir.to_string cache_dir))); ] in let hash_kinds = [`MD5; `SHA256; `SHA512] in let hash_types_arg = OpamArg.nonempty_arg_list "HASH_ALGO" "The hash, or hashes to be added" (Arg.enum (List.map (fun k -> OpamHash.string_of_kind k, k) hash_kinds)) in let packages = OpamArg.mk_opt ~cli OpamArg.(cli_from cli2_1) ["p";"packages"] "PACKAGES" "Only add hashes for the given packages" Arg.(list OpamArg.package) [] in let replace_arg = OpamArg.mk_flag ~cli OpamArg.cli_original ["replace"] "Replace the existing hashes rather than adding to them" in let hash_tables = let t = Hashtbl.create (List.length hash_kinds) in List.iter (fun k1 -> List.iter (fun k2 -> if k1 <> k2 then ( let cache_file : string list list OpamFile.t = OpamFile.make @@ OpamFilename.Op.( cache_dir // (OpamHash.string_of_kind k1 ^ "_to_" ^ OpamHash.string_of_kind k2)) in let t_mapping = Hashtbl.create 187 in (OpamStd.Option.default [] (OpamFile.Lines.read_opt cache_file) |> List.iter @@ function | [src; dst] -> Hashtbl.add t_mapping (OpamHash.of_string src) (OpamHash.of_string dst) | _ -> failwith ("Bad cache at "^OpamFile.to_string cache_file)); Hashtbl.add t (k1,k2) (cache_file, t_mapping); )) hash_kinds ) hash_kinds; t in let save_hashes () = Hashtbl.iter (fun _ (file, tbl) -> Hashtbl.fold (fun src dst l -> [OpamHash.to_string src; OpamHash.to_string dst]::l) tbl [] |> fun lines -> try OpamFile.Lines.write file lines with e -> OpamStd.Exn.fatal e; OpamConsole.log "ADMIN" "Could not write hash cache to %s, skipping (%s)" (OpamFile.to_string file) (Printexc.to_string e)) hash_tables in let additions_count = ref 0 in let get_hash cache_urls kind known_hashes url = let found = List.fold_left (fun result hash -> match result with | None -> let known_kind = OpamHash.kind hash in let _, tbl = Hashtbl.find hash_tables (known_kind, kind) in (try Some (Hashtbl.find tbl hash) with Not_found -> None) | some -> some) None known_hashes in match found with | Some h -> Some h | None -> let h = OpamProcess.Job.run @@ OpamFilename.with_tmp_dir_job @@ fun dir -> let f = OpamFilename.Op.(dir // OpamUrl.basename url) in OpamProcess.Job.ignore_errors ~default:None (fun () -> OpamRepository.pull_file (OpamUrl.to_string url) ~cache_dir:(OpamRepositoryPath.download_cache OpamStateConfig.(!r.root_dir)) ~cache_urls f known_hashes [url] @@| function | Result () | Up_to_date () -> OpamHash.compute ~kind (OpamFilename.to_string f) |> OpamStd.Option.some | Not_available _ -> None) in (match h with | Some h -> List.iter (fun h0 -> Hashtbl.replace (snd (Hashtbl.find hash_tables (OpamHash.kind h0, kind))) h0 h ) known_hashes; incr additions_count; if !additions_count mod 20 = 0 then save_hashes () | None -> ()); h in let cmd global_options hash_types replace packages () = OpamArg.apply_global_options cli global_options; let repo_root = checked_repo_root () in let cache_urls = cache_urls repo_root (OpamFile.Repo.safe_read (OpamRepositoryPath.repo repo_root)) in let pkg_prefixes = let pkgs_map = OpamRepository.packages_with_prefixes repo_root in if packages = [] then pkgs_map else (let pkgs_map, missing_pkgs = List.fold_left (fun ((map: string option OpamPackage.Map.t),error) (n,vo)-> match vo with | Some v -> let nv = OpamPackage.create n v in (match OpamPackage.Map.find_opt nv pkgs_map with | Some pre ->( OpamPackage.Map.add nv pre map), error | None -> map, (n,vo)::error) | None -> let n_map = OpamPackage.packages_of_name_map pkgs_map n in if OpamPackage.Map.is_empty n_map then map, (n,vo)::error else (OpamPackage.Map.union (fun _nv _nv' -> assert false) n_map map), error ) (OpamPackage.Map.empty, []) packages in if missing_pkgs <> [] then OpamConsole.warning "Not found package%s %s. Ignoring them." (if List.length missing_pkgs = 1 then "" else "s") (OpamStd.List.concat_map ~left:"" ~right:"" ~last_sep:" and " ", " (fun (n,vo) -> OpamConsole.colorise `underline (match vo with | Some v -> OpamPackage.to_string (OpamPackage.create n v) | None -> OpamPackage.Name.to_string n)) missing_pkgs); pkgs_map) in let has_error = OpamPackage.Map.fold (fun nv prefix has_error -> let opam_file = OpamRepositoryPath.opam repo_root prefix nv in let opam = OpamFile.OPAM.read opam_file in let has_error = if OpamFile.exists (OpamRepositoryPath.url repo_root prefix nv) then (OpamConsole.warning "Not updating external URL file at %s" (OpamFile.to_string (OpamRepositoryPath.url repo_root prefix nv)); true) else has_error in let process_url has_error urlf = let hashes = OpamFile.URL.checksum urlf in let hashes = if replace then List.filter (fun h -> List.mem (OpamHash.kind h) hash_types) hashes else hashes in let has_error, hashes = List.fold_left (fun (has_error, hashes) kind -> if List.exists (fun h -> OpamHash.kind h = kind) hashes then has_error, hashes else match get_hash cache_urls kind hashes (OpamFile.URL.url urlf) with | Some h -> has_error, hashes @ [h] | None -> OpamConsole.error "Could not get hash for %s: %s" (OpamPackage.to_string nv) (OpamUrl.to_string (OpamFile.URL.url urlf)); true, hashes) (has_error, hashes) hash_types in has_error, OpamFile.URL.with_checksum hashes urlf in let has_error, url_opt = match OpamFile.OPAM.url opam with | None -> has_error, None | Some urlf -> let has_error, urlf = process_url has_error urlf in has_error, Some urlf in let has_error, extra_sources = List.fold_right (fun (basename, urlf) (has_error, acc) -> let has_error, urlf = process_url has_error urlf in has_error, (basename, urlf) :: acc) (OpamFile.OPAM.extra_sources opam) (has_error, []) in let opam1 = OpamFile.OPAM.with_url_opt url_opt opam in let opam1 = OpamFile.OPAM.with_extra_sources extra_sources opam1 in if opam1 <> opam then OpamFile.OPAM.write_with_preserved_format opam_file opam1; has_error ) pkg_prefixes false in save_hashes (); if has_error then OpamStd.Sys.exit_because `Sync_error else OpamStd.Sys.exit_because `Success in OpamArg.mk_command ~cli OpamArg.cli_original command ~doc ~man Term.(const cmd $ global_options cli $ hash_types_arg $ replace_arg $ packages) let upgrade_command_doc = "Upgrades repository from earlier opam versions." let upgrade_command cli = let command = "upgrade" in let doc = upgrade_command_doc in let man = [ `S Manpage.s_description; `P (Printf.sprintf "This command reads repositories from earlier opam versions, and \ converts them to repositories suitable for the current opam version. \ Packages might be created or renamed, and any compilers defined in the \ old format ('compilers%s' directory) will be turned into packages, \ using a pre-defined hierarchy that assumes OCaml compilers." OpamArg.dir_sep) ] in let clear_cache_arg = OpamArg.mk_flag ~cli OpamArg.cli_original ["clear-cache"] (Printf.sprintf "Instead of running the upgrade, clear the cache of archive hashes (held \ in ~%s.cache), that is used to avoid re-downloading files to obtain \ their hashes at every run." OpamArg.dir_sep) in let create_mirror_arg = OpamArg.mk_opt ~cli OpamArg.cli_original ["m"; "mirror"] "URL" "Don't overwrite the current repository, but put an upgraded mirror in \ place in a subdirectory, with proper redirections. Needs the URL the \ repository will be served from to put in the redirects (older versions \ of opam don't understand relative redirects)." Arg.(some OpamArg.url) None in let cmd global_options clear_cache create_mirror () = OpamArg.apply_global_options cli global_options; if clear_cache then OpamAdminRepoUpgrade.clear_cache () else match create_mirror with | None -> OpamAdminRepoUpgrade.do_upgrade (OpamFilename.cwd ()); if OpamFilename.exists (OpamFilename.of_string "index.tar.gz") || OpamFilename.exists (OpamFilename.of_string "urls.txt") then OpamConsole.note "Indexes need updating: you should now run:\n\ \n\ \ opam admin index" | Some m -> OpamAdminRepoUpgrade.do_upgrade_mirror (OpamFilename.cwd ()) m in OpamArg.mk_command ~cli OpamArg.cli_original command ~doc ~man Term.(const cmd $ global_options cli $ clear_cache_arg $ create_mirror_arg) let lint_command_doc = "Runs 'opam lint' and reports on a whole repository" let lint_command cli = let command = "lint" in let doc = lint_command_doc in let man = [ `S Manpage.s_description; `P "This command gathers linting results on all files in a repository. The \ warnings and errors to show or hide can be selected" ] in let short_arg = OpamArg.mk_flag ~cli OpamArg.cli_original ["s";"short"] "Print only packages and warning/error numbers, without explanations" in let list_arg = OpamArg.mk_flag ~cli OpamArg.cli_original ["list";"l"] "Only list package names, without warning details" in let include_arg = OpamArg.arg_list "INT" "Show only these warnings" OpamArg.positive_integer in let exclude_arg = OpamArg.mk_opt_all ~cli OpamArg.cli_original ["exclude";"x"] "INT" "Exclude the given warnings or errors" OpamArg.positive_integer in let ignore_arg = OpamArg.mk_opt_all ~cli OpamArg.cli_original ["ignore-packages";"i"] "INT" "Ignore any packages having one of these warnings or errors" OpamArg.positive_integer in let warn_error_arg = OpamArg.mk_flag ~cli OpamArg.cli_original ["warn-error";"W"] "Return failure on any warnings, not only on errors" in let cmd global_options short list incl excl ign warn_error () = OpamArg.apply_global_options cli global_options; let repo_root = OpamFilename.cwd () in if not (OpamFilename.exists_dir OpamFilename.Op.(repo_root / "packages")) then OpamConsole.error_and_exit `Bad_arguments "No repository found in current directory.\n\ Please make sure there is a \"packages\" directory"; let pkg_prefixes = OpamRepository.packages_with_prefixes repo_root in let ret = OpamPackage.Map.fold (fun nv prefix ret -> let opam_file = OpamRepositoryPath.opam repo_root prefix nv in let w, _ = OpamFileTools.lint_file ~handle_dirname:true opam_file in if List.exists (fun (n,_,_) -> List.mem n ign) w then ret else let w = List.filter (fun (n,_,_) -> (incl = [] || List.mem n incl) && not (List.mem n excl)) w in if w <> [] then if list then OpamConsole.msg "%s\n" (OpamPackage.to_string nv) else if short then OpamConsole.msg "%s %s\n" (OpamPackage.to_string nv) (OpamStd.List.concat_map " " (fun (n,k,_) -> OpamConsole.colorise (match k with `Warning -> `yellow | `Error -> `red) (string_of_int n)) w) else begin OpamConsole.carriage_delete (); OpamConsole.msg "In %s:\n%s\n" (OpamPackage.to_string nv) (OpamFileTools.warns_to_string w) end; ret && not (warn_error && w <> [] || List.exists (fun (_,k,_) -> k = `Error) w)) pkg_prefixes true in OpamStd.Sys.exit_because (if ret then `Success else `False) in OpamArg.mk_command ~cli OpamArg.cli_original command ~doc ~man Term.(const cmd $ global_options cli $ short_arg $ list_arg $ include_arg $ exclude_arg $ ignore_arg $ warn_error_arg) let check_command_doc = "Runs some consistency checks on a repository" let check_command cli = let command = "check" in let doc = check_command_doc in let man = [ `S Manpage.s_description; `P "This command runs consistency checks on a repository, and prints a \ report to stdout. Checks include packages that are not installable \ (due e.g. to a missing dependency) and dependency cycles. The \ 'available' field is ignored for these checks, that is, all packages \ are supposed to be available. By default, all checks are run." ] in let ignore_test_arg = OpamArg.mk_flag ~cli OpamArg.cli_original ["ignore-test-doc";"i"] "By default, $(b,{with-test}) and $(b,{with-doc}) dependencies are \ included. This ignores them, and makes the test more tolerant." in let print_short_arg = OpamArg.mk_flag ~cli OpamArg.cli_original ["s";"short"] "Only output a list of uninstallable packages" in let installability_arg = OpamArg.mk_flag ~cli OpamArg.cli_original ["installability"] "Do the installability check (and disable the others by default)" in let cycles_arg = OpamArg.mk_flag ~cli OpamArg.cli_original ["cycles"] "Do the cycles check (and disable the others by default)" in let obsolete_arg = OpamArg.mk_flag ~cli OpamArg.cli_original ["obsolete"] "Analyse for obsolete packages" in let cmd global_options ignore_test print_short installability cycles obsolete () = OpamArg.apply_global_options cli global_options; let repo_root = checked_repo_root () in let installability, cycles, obsolete = if installability || cycles || obsolete then installability, cycles, obsolete else true, true, false in let pkgs, unav_roots, uninstallable, cycle_packages, obsolete = OpamAdminCheck.check ~quiet:print_short ~installability ~cycles ~obsolete ~ignore_test repo_root in let all_ok = OpamPackage.Set.is_empty uninstallable && OpamPackage.Set.is_empty cycle_packages && OpamPackage.Set.is_empty obsolete in let open OpamPackage.Set.Op in (if print_short then OpamConsole.msg "%s\n" (OpamStd.List.concat_map "\n" OpamPackage.to_string (OpamPackage.Set.elements (uninstallable ++ cycle_packages ++ obsolete))) else if all_ok then OpamConsole.msg "No issues detected on this repository's %d packages\n" (OpamPackage.Set.cardinal pkgs) else let pr set msg = if OpamPackage.Set.is_empty set then "" else Printf.sprintf "- %d %s\n" (OpamPackage.Set.cardinal set) msg in OpamConsole.msg "Summary: out of %d packages (%d distinct names)\n\ %s%s%s%s\n" (OpamPackage.Set.cardinal pkgs) (OpamPackage.Name.Set.cardinal (OpamPackage.names_of_packages pkgs)) (pr unav_roots "uninstallable roots") (pr (uninstallable -- unav_roots) "uninstallable dependent packages") (pr (cycle_packages -- uninstallable) "packages part of dependency cycles") (pr obsolete "obsolete packages")); OpamStd.Sys.exit_because (if all_ok then `Success else `False) in OpamArg.mk_command ~cli OpamArg.cli_original command ~doc ~man Term.(const cmd $ global_options cli $ ignore_test_arg $ print_short_arg $ installability_arg $ cycles_arg $ obsolete_arg) let pattern_list_arg = OpamArg.arg_list "PATTERNS" "Package patterns with globs. matching against $(b,NAME) or \ $(b,NAME.VERSION)" Arg.string let env_arg cli = OpamArg.mk_opt ~cli OpamArg.cli_original ["environment"] "VAR=VALUE[;VAR=VALUE]" (Printf.sprintf "Use the given opam environment, in the form of a list of \ comma-separated 'var=value' bindings, when resolving variables. This \ is used e.g. when computing available packages: if undefined, \ availability of packages will be assumed as soon as it can not be \ resolved purely from globally defined variables. Note that, unless \ overridden, variables like 'root' or 'opam-version' may be taken \ from the current opam installation. What is defined in \ $(i,~%s.opam%sconfig) is always ignored." OpamArg.dir_sep OpamArg.dir_sep) Arg.(list string) [] let state_selection_arg cli = OpamArg.mk_vflag ~cli ~section:OpamArg.package_selection_section OpamListCommand.Available [ OpamArg.cli_original, OpamListCommand.Any, ["A";"all"], "Include all, even uninstalled or unavailable packages"; OpamArg.cli_original, OpamListCommand.Available, ["a";"available"], "List only packages that are available according to the defined \ $(b,environment). Without $(b,--environment), this will include \ any packages for which availability is not resolvable at this \ point."; OpamArg.cli_original, OpamListCommand.Installable, ["installable"], "List only packages that are installable according to the defined \ $(b,environment) (this calls the solver and may be more costly; \ a package depending on an unavailable one may be available, but \ is never installable)"; ] let get_virtual_switch_state repo_root env = let env = List.map (fun s -> match OpamStd.String.cut_at s '=' with | Some (var,value) -> OpamVariable.of_string var, S value | None -> OpamVariable.of_string s, B true) env in let repo = { repo_name = OpamRepositoryName.of_string "local"; repo_url = OpamUrl.empty; repo_trust = None; } in let repo_file = OpamRepositoryPath.repo repo_root in let repo_def = OpamFile.Repo.safe_read repo_file in let opams = OpamRepositoryState.load_opams_from_dir repo.repo_name repo_root in let gt = { global_lock = OpamSystem.lock_none; root = OpamStateConfig.(!r.root_dir); config = OpamStd.Option.Op.(OpamStateConfig.( load ~lock_kind:`Lock_read !r.root_dir) +! OpamFile.Config.empty); global_variables = OpamVariable.Map.empty; } in let singl x = OpamRepositoryName.Map.singleton repo.repo_name x in let repos_tmp = let t = Hashtbl.create 1 in Hashtbl.add t repo.repo_name (lazy repo_root); t in let rt = { repos_global = gt; repos_lock = OpamSystem.lock_none; repositories = singl repo; repos_definitions = singl repo_def; repo_opams = singl opams; repos_tmp; } in let gt = {gt with global_variables = OpamVariable.Map.of_list @@ List.map (fun (var, value) -> var, (lazy (Some value), "Manually defined")) env } in OpamSwitchState.load_virtual ~repos_list:[repo.repo_name] ~avail_default:(env = []) gt rt let or_arg cli = OpamArg.mk_flag ~cli OpamArg.cli_original ~section:OpamArg.package_selection_section ["or"] "Instead of selecting packages that match $(i,all) the \ criteria, select packages that match $(i,any) of them" let list_command_doc = "Lists packages from a repository" let list_command cli = let command = "list" in let doc = list_command_doc in let man = [ `S Manpage.s_description; `P "This command is similar to 'opam list', but allows listing packages \ directly from a repository instead of what is available in a given \ opam installation."; `S Manpage.s_arguments; `S Manpage.s_options; `S OpamArg.package_selection_section; `S OpamArg.package_listing_section; ] in let cmd global_options package_selection disjunction state_selection package_listing env packages () = OpamArg.apply_global_options cli global_options; let format = let force_all_versions = match packages with | [single] -> let nameglob = match OpamStd.String.cut_at single '.' with | None -> single | Some (n, _v) -> n in (try ignore (OpamPackage.Name.of_string nameglob); true with Failure _ -> false) | _ -> false in package_listing ~force_all_versions in let pattern_selector = OpamListCommand.pattern_selector packages in let join = if disjunction then OpamFormula.ors else OpamFormula.ands in let filter = OpamFormula.ands [ Atom state_selection; join (pattern_selector :: List.map (fun x -> Atom x) package_selection); ] in let st = get_virtual_switch_state (OpamFilename.cwd ()) env in if not format.OpamListCommand.short && filter <> OpamFormula.Empty then OpamConsole.msg "# Packages matching: %s\n" (OpamListCommand.string_of_formula filter); let results = OpamListCommand.filter ~base:st.packages st filter in OpamListCommand.display st format results in OpamArg.mk_command ~cli OpamArg.cli_original command ~doc ~man Term.(const cmd $ global_options cli $ OpamArg.package_selection cli $ or_arg cli $ state_selection_arg cli $ OpamArg.package_listing cli $ env_arg cli $ pattern_list_arg) let filter_command_doc = "Filters a repository to only keep selected packages" let filter_command cli = let command = "filter" in let doc = filter_command_doc in let man = [ `S Manpage.s_description; `P "This command removes all package definitions that don't match the \ search criteria (specified similarly to 'opam admin list') from a \ repository."; `S Manpage.s_arguments; `S Manpage.s_options; `S OpamArg.package_selection_section; ] in let remove_arg = OpamArg.mk_flag ~cli OpamArg.cli_original ["remove"] "Invert the behaviour and remove the matching packages, keeping the ones \ that don't match." in let dryrun_arg = OpamArg.mk_flag ~cli OpamArg.cli_original ["dry-run"] "List the removal commands, without actually performing them" in let cmd global_options package_selection disjunction state_selection env remove dryrun packages () = OpamArg.apply_global_options cli global_options; let repo_root = OpamFilename.cwd () in let pattern_selector = OpamListCommand.pattern_selector packages in let join = if disjunction then OpamFormula.ors else OpamFormula.ands in let filter = OpamFormula.ands [ Atom state_selection; join (pattern_selector :: List.map (fun x -> Atom x) package_selection) ] in let st = get_virtual_switch_state repo_root env in let packages = OpamListCommand.filter ~base:st.packages st filter in if OpamPackage.Set.is_empty packages then if remove then (OpamConsole.warning "No packages match the selection criteria"; OpamStd.Sys.exit_because `Success) else OpamConsole.error_and_exit `Not_found "No packages match the selection criteria"; let num_total = OpamPackage.Set.cardinal st.packages in let num_selected = OpamPackage.Set.cardinal packages in if remove then OpamConsole.formatted_msg "The following %d packages will be REMOVED from the repository (%d \ packages will be kept):\n%s\n" num_selected (num_total - num_selected) (OpamStd.List.concat_map " " OpamPackage.to_string (OpamPackage.Set.elements packages)) else OpamConsole.formatted_msg "The following %d packages will be kept in the repository (%d packages \ will be REMOVED):\n%s\n" num_selected (num_total - num_selected) (OpamStd.List.concat_map " " OpamPackage.to_string (OpamPackage.Set.elements packages)); let packages = if remove then packages else OpamPackage.Set.Op.(st.packages -- packages) in if not (dryrun || OpamConsole.confirm "Confirm?") then OpamStd.Sys.exit_because `Aborted else let pkg_prefixes = OpamRepository.packages_with_prefixes repo_root in OpamPackage.Map.iter (fun nv prefix -> if OpamPackage.Set.mem nv packages then let d = OpamRepositoryPath.packages repo_root prefix nv in if dryrun then OpamConsole.msg "rm -rf %s\n" (OpamFilename.Dir.to_string d) else (OpamFilename.cleandir d; OpamFilename.rmdir_cleanup d)) pkg_prefixes in OpamArg.mk_command ~cli OpamArg.cli_original command ~doc ~man Term.(const cmd $ global_options cli $ OpamArg.package_selection cli $ or_arg cli $ state_selection_arg cli $ env_arg cli $ remove_arg $ dryrun_arg $ pattern_list_arg) let add_constraint_command_doc = "Adds version constraints on all dependencies towards a given package" let add_constraint_command cli = let command = "add-constraint" in let doc = add_constraint_command_doc in let man = [ `S Manpage.s_description; `P "This command searches to all dependencies towards a given package, and \ adds a version constraint to them. It is particularly useful to add \ upper bounds to existing dependencies when a new, incompatible major \ version of a library is added to a repository. The new version \ constraint is merged with the existing one, and simplified if \ possible (e.g. $(b,>=3 & >5) becomes $(b,>5))."; `S Manpage.s_arguments; `S Manpage.s_options; ] in let atom_arg = Arg.(required & pos 0 (some OpamArg.atom) None & info [] ~docv:"PACKAGE" ~doc: "A package name with a version constraint, e.g. $(b,name>=version). \ If no version constraint is specified, the command will just \ simplify existing version constraints on dependencies to the named \ package.") in let force_arg = OpamArg.mk_flag ~cli OpamArg.cli_original ["force"] "Force updating of constraints even if the resulting constraint is \ unsatisfiable (e.g. when adding $(b,>3) to the constraint \ $(b,<2)). The default in this case is to print a warning and keep \ the existing constraint unchanged." in let cmd global_options force atom () = OpamArg.apply_global_options cli global_options; let repo_root = checked_repo_root () in let pkg_prefixes = OpamRepository.packages_with_prefixes repo_root in let name, cstr_opt = atom in let cstr = match cstr_opt with | Some (relop, v) -> OpamFormula.Atom (Constraint (relop, FString (OpamPackage.Version.to_string v))) | None -> OpamFormula.Empty in let add_cstr op cstr nv n c = let f = op [ cstr; c] in match OpamFilter.simplify_extended_version_formula f with | Some f -> f | None -> (* conflicting constraint *) if force then f else (OpamConsole.warning "In package %s, updated constraint %s cannot be satisfied, not \ updating (use `--force' to update anyway)" (OpamPackage.to_string nv) (OpamConsole.colorise `bold (OpamFilter.string_of_filtered_formula (Atom (n, f)))); c) in OpamPackage.Map.iter (fun nv prefix -> let opam_file = OpamRepositoryPath.opam repo_root prefix nv in let opam = OpamFile.OPAM.read opam_file in let deps0 = OpamFile.OPAM.depends opam in let deps = OpamFormula.map (function | (n,c as atom) -> if n = name then Atom (n, (add_cstr OpamFormula.ands cstr nv n c)) else Atom atom) deps0 in let depopts0 = OpamFile.OPAM.depopts opam in let conflicts0 = OpamFile.OPAM.conflicts opam in let contains name = OpamFormula.fold_left (fun contains (n,_) -> contains || n = name) false in let conflicts = if contains name depopts0 then match cstr_opt with | Some (relop, v) -> let icstr = OpamFormula.Atom (Constraint (OpamFormula.neg_relop relop, FString (OpamPackage.Version.to_string v))) in if contains name conflicts0 then OpamFormula.map (function | (n,c as atom) -> if n = name then Atom (n, (add_cstr OpamFormula.ors icstr nv n c)) else Atom atom) conflicts0 else OpamFormula.ors [ conflicts0; Atom (name, icstr) ] | None -> conflicts0 else conflicts0 in if deps <> deps0 || conflicts <> conflicts0 then OpamFile.OPAM.write_with_preserved_format opam_file (OpamFile.OPAM.with_depends deps opam |> OpamFile.OPAM.with_conflicts conflicts)) pkg_prefixes in OpamArg.mk_command ~cli OpamArg.cli_original command ~doc ~man Term.(pure cmd $ global_options cli $ force_arg $ atom_arg) (* HELP *) let help = let doc = "Display help about opam admin and opam admin subcommands." in let man = [ `S Manpage.s_description; `P "Prints help about opam admin commands."; `P "Use `$(mname) help topics' to get the full list of help topics."; ] in let topic = let doc = Arg.info [] ~docv:"TOPIC" ~doc:"The topic to get help on." in Arg.(value & pos 0 (some string) None & doc ) in let help man_format cmds topic = match topic with | None -> `Help (`Pager, None) | Some topic -> let topics = "topics" :: cmds in let conv, _ = Cmdliner.Arg.enum (List.rev_map (fun s -> (s, s)) topics) in match conv topic with | `Error e -> `Error (false, e) | `Ok t when t = "topics" -> List.iter (OpamConsole.msg "%s\n") cmds; `Ok () | `Ok t -> `Help (man_format, Some t) in Term.(ret (const help $Term.man_format $Term.choice_names $topic)), Term.info "help" ~doc ~man let admin_subcommands cli = let index_command = index_command cli in [ index_command; OpamArg.make_command_alias ~cli index_command "make"; cache_command cli; upgrade_command cli; lint_command cli; check_command cli; list_command cli; filter_command cli; add_constraint_command cli; add_hashes_command cli; help; ] let default_subcommand cli = let man = admin_command_man @ [ `S Manpage.s_commands; `S "COMMAND ALIASES"; ] @ OpamArg.help_sections cli in let usage global_options = OpamArg.apply_global_options cli global_options; OpamConsole.formatted_msg "usage: opam admin [--version]\n\ \ [--help]\n\ \ []\n\ \n\ The most commonly used opam admin commands are:\n\ \ index %s\n\ \ cache %s\n\ \ upgrade-format %s\n\ \n\ See 'opam admin --help' for more information on a specific \ command.\n" index_command_doc cache_command_doc upgrade_command_doc in Term.(const usage $ global_options cli), Term.info "opam admin" ~version:(OpamVersion.to_string OpamVersion.current) ~sdocs:OpamArg.global_option_section ~doc:admin_command_doc ~man let get_cmdliner_parser cli = default_subcommand cli, admin_subcommands cli opam-2.1.5/src/client/opamAdminRepoUpgrade.ml0000644000175000017500000004636614427463453020200 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2016-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamProcess.Job.Op open OpamStd.Option.Op module O = OpamFile.OPAM let upgradeto_version_string = "2.0" let upgradeto_version = OpamVersion.of_string upgradeto_version_string let ocaml_wrapper_pkgname = OpamPackage.Name.of_string "ocaml" let ocaml_official_pkgname = OpamPackage.Name.of_string "ocaml-base-compiler" let ocaml_variants_pkgname = OpamPackage.Name.of_string "ocaml-variants" let ocaml_system_pkgname = OpamPackage.Name.of_string "ocaml-system" let ocaml_conflict_class = OpamPackage.Name.of_string "ocaml-core-compiler" let ocaml_package_names = [ocaml_wrapper_pkgname; ocaml_official_pkgname; ocaml_variants_pkgname; ocaml_system_pkgname] (* OCaml script that generates the .config file for a given ocaml compiler *) let wrapper_conf_script = "let () =\n\ \ let ocaml_version =\n\ \ let v = Sys.ocaml_version in\n\ \ try String.sub v 0 (String.index v '+') with Not_found -> v\n\ \ in\n\ \ if ocaml_version <> \"%{_:version}%\" then\n\ \ (Printf.eprintf\n\ \ \"OCaml version mismatch: %%s, expected %{_:version}%\"\n\ \ ocaml_version;\n\ \ exit 1)\n\ \ else\n\ \ let oc = open_out \"%{_:name}%.config\" in\n\ \ let exe = \".exe\" in\n\ \ let (ocaml, suffix) =\n\ \ let s = Sys.executable_name in\n\ \ if Filename.check_suffix s exe then\n\ \ (Filename.chop_suffix s exe, exe)\n\ \ else\n\ \ (s, \"\")\n\ \ in\n\ \ let ocamlc = ocaml^\"c\"^suffix in\n\ \ let libdir =\n\ \ let ic = Unix.open_process_in (ocamlc^\" -where\") in\n\ \ set_binary_mode_in ic false;\n\ \ let r = input_line ic in\n\ \ if Unix.close_process_in ic <> Unix.WEXITED 0 then \n\ \ failwith \"Bad return from 'ocamlc -where'\";\n\ \ r\n\ \ in\n\ \ let stubsdir =\n\ \ let ic = open_in (Filename.concat libdir \"ld.conf\") in\n\ \ let rec r acc = try r (input_line ic::acc) with End_of_file -> acc in\n\ \ let lines = List.rev (r []) in\n\ \ close_in ic;\n\ \ String.concat \":\" lines\n\ \ in\n\ \ let p fmt = Printf.fprintf oc (fmt ^^ \"\\n\") in\n\ \ p \"opam-version: \\\"" ^ upgradeto_version_string ^ "\\\"\";\n\ \ p \"variables {\";\n\ \ p \" native: %%b\"\n\ \ (Sys.file_exists (ocaml^\"opt\"^suffix));\n\ \ p \" native-tools: %%b\"\n\ \ (Sys.file_exists (ocamlc^\".opt\"^suffix));\n\ \ p \" native-dynlink: %%b\"\n\ \ (Sys.file_exists (Filename.concat libdir \"dynlink.cmxa\"));\n\ \ p \" stubsdir: %%S\"\n\ \ stubsdir;\n\ \ p \" preinstalled: %{ocaml-system:installed}%\";\n\ \ p \" compiler: \\\"%{ocaml-system:installed?system:}%\ %{ocaml-base-compiler:version}%\ %{ocaml-variants:version}%\\\"\";\n\ \ p \"}\";\n\ \ close_out oc\n\ " let system_conf_script = "let () =\n\ \ let exe = \".exe\" in\n\ \ let ocamlc =\n\ \ let (base, suffix) =\n\ \ let s = Sys.executable_name in\n\ \ if Filename.check_suffix s exe then\n\ \ (Filename.chop_suffix s exe, exe)\n\ \ else\n\ \ (s, \"\") in\n\ \ base ^ \"c\" ^ suffix in\n\ \ if Sys.ocaml_version <> \"%{_:version}%\" then\n\ \ (Printf.eprintf\n\ \ \"ERROR: The compiler found at %%s has version %%s,\\n\\\n\ \ and this package requires %{_:version}%.\\n\\\n\ \ You should use e.g. 'opam switch create %{_:name}%.%%s' \\\n\ \ instead.\"\n\ \ ocamlc Sys.ocaml_version Sys.ocaml_version;\n\ \ exit 1)\n\ \ else\n\ \ let ocamlc_digest = Digest.to_hex (Digest.file ocamlc) in\n\ \ let libdir =\n\ \ if Sys.command (ocamlc^\" -where > %{_:name}%.config\") = 0 then\n\ \ let ic = open_in \"%{_:name}%.config\" in\n\ \ let r = input_line ic in\n\ \ close_in ic;\n\ \ Sys.remove \"%{_:name}%.config\";\n\ \ r\n\ \ else\n\ \ failwith \"Bad return from 'ocamlc -where'\"\n\ \ in\n\ \ let graphics = Filename.concat libdir \"graphics.cmi\" in\n\ \ let graphics_digest =\n\ \ if Sys.file_exists graphics then\n\ \ Digest.to_hex (Digest.file graphics)\n\ \ else\n\ \ String.make 32 '0'\n\ \ in\n\ \ let oc = open_out \"%{_:name}%.config\" in\n\ \ Printf.fprintf oc \"opam-version: \\\"" ^ upgradeto_version_string ^ "\\\"\\n\\\n\ \ file-depends: [ [ %%S %%S ] [ %%S %%S ] ]\\n\\\n\ \ variables { path: %%S }\\n\"\n\ \ ocamlc ocamlc_digest graphics graphics_digest (Filename.dirname ocamlc);\n\ \ close_out oc\n\ " let conf_script_name = "gen_ocaml_config.ml" let all_base_packages = OpamPackage.Name.Set.of_list (List.map OpamPackage.Name.of_string [ "base-bigarray"; "base-threads"; "base-unix"; ]) let cache_file : string list list OpamFile.t = OpamFile.make @@ OpamFilename.of_string "~/.cache/opam-compilers-to-packages/url-hashes" let do_upgrade repo_root = let write_opam ?(add_files=[]) opam = let nv = O.package opam in let pfx = Some (OpamPackage.name_to_string nv) in let files_dir = OpamRepositoryPath.files repo_root pfx nv in O.write (OpamRepositoryPath.opam repo_root pfx nv) opam; List.iter (fun (base,contents) -> OpamFilename.(write Op.(files_dir // base) contents)) add_files in let compilers = let compilers_dir = OpamFilename.Op.(repo_root / "compilers") in if OpamFilename.exists_dir compilers_dir then ( List.fold_left (fun map f -> if OpamFilename.check_suffix f ".comp" then let c = OpamFilename.(Base.to_string (basename (chop_extension f))) in OpamStd.String.Map.add c f map else map) OpamStd.String.Map.empty (OpamFilename.rec_files compilers_dir) ) else OpamStd.String.Map.empty in let get_url_md5, save_cache = let url_md5 = Hashtbl.create 187 in let () = OpamFile.Lines.read_opt cache_file +! [] |> List.iter @@ function | [url; md5] -> OpamStd.Option.iter (fun url -> Hashtbl.add url_md5 url (OpamHash.of_string md5)) (OpamUrl.parse_opt ~handle_suffix:false url) | _ -> failwith "Bad cache, run 'opam admin upgrade --clear-cache'" in (fun url -> try Done (Some (Hashtbl.find url_md5 url)) with Not_found -> OpamFilename.with_tmp_dir_job @@ fun dir -> OpamProcess.Job.ignore_errors ~default:None (fun () -> (* Download to package.patch, rather than allowing the name to be guessed since, on Windows, some of the characters which are valid in URLs are not valid in filenames *) let f = let base = OpamFilename.Base.of_string "package.patch" in OpamFilename.create dir base in OpamDownload.download_as ~overwrite:false url f @@| fun () -> let hash = OpamHash.compute (OpamFilename.to_string f) in Hashtbl.add url_md5 url hash; Some hash)), (fun () -> Hashtbl.fold (fun url hash l -> [OpamUrl.to_string url; OpamHash.to_string hash]::l) url_md5 [] |> fun lines -> try OpamFile.Lines.write cache_file lines with e -> OpamStd.Exn.fatal e; OpamConsole.log "REPO_UPGRADE" "Could not write archive hash cache to %s, skipping (%s)" (OpamFile.to_string cache_file) (Printexc.to_string e)) in let ocaml_versions = OpamStd.String.Map.fold (fun c comp_file ocaml_versions -> let comp = OpamFile.Comp.read (OpamFile.make comp_file) in let descr_file = OpamFilename.(opt_file (add_extension (chop_extension comp_file) "descr")) in let descr = descr_file >>| fun f -> OpamFile.Descr.read (OpamFile.make f) in let nv, ocaml_version, variant = match OpamStd.String.cut_at c '+' with | None -> OpamPackage.create ocaml_official_pkgname (OpamPackage.Version.of_string c), c, None | Some (version,variant) -> OpamPackage.create ocaml_variants_pkgname (OpamPackage.Version.of_string (version^"+"^variant)), version, Some variant in (* (Some exotic compiler variants have e.g. 'lwt' as base package, which won't work in our current setup. They'll need to be rewritten, but break the following detection of all base packages, which isn't idempotent anyway...) List.iter (fun (name, _) -> all_base_packages := OpamPackage.Name.Set.add name !all_base_packages) (OpamFormula.atoms (OpamFile.Comp.packages comp)); *) let opam = OpamFormatUpgrade.comp_file ~package:nv ?descr comp in let opam = O.with_conflict_class [ocaml_conflict_class] opam in let opam = match OpamFile.OPAM.url opam with | Some urlf when OpamFile.URL.checksum urlf = [] -> let url = OpamFile.URL.url urlf in (match url.OpamUrl.backend with | #OpamUrl.version_control -> Some opam | `rsync when OpamUrl.local_dir url <> None -> Some opam | _ -> (match OpamProcess.Job.run (get_url_md5 url) with | None -> None | Some hash -> Some (OpamFile.OPAM.with_url (OpamFile.URL.with_checksum [hash] urlf) opam))) | _ -> Some opam in match opam with | None -> OpamConsole.error "Could not get the archive of %s, skipping" (OpamPackage.to_string nv); ocaml_versions | Some opam -> let patches = OpamFile.Comp.patches comp in if patches <> [] then OpamConsole.msg "Fetching patches of %s to check their hashes...\n" (OpamPackage.to_string nv); let extra_sources = (* Download them just to get their MD5 *) OpamParallel.map ~jobs:3 ~command:(fun url -> get_url_md5 url @@| function | Some md5 -> Some (url, md5, None) | None -> OpamConsole.error "Could not get patch file for %s from %s, skipping" (OpamPackage.to_string nv) (OpamUrl.to_string url); None) (OpamFile.Comp.patches comp) in if List.mem None extra_sources then ocaml_versions else let opam = opam |> OpamFile.OPAM.with_extra_sources (List.map (fun (url, hash, _) -> OpamFilename.Base.of_string (OpamUrl.basename url), OpamFile.URL.create ~checksum:[hash] url) (OpamStd.List.filter_some extra_sources)) in write_opam opam; if variant = None then begin (* "official" compiler release: generate a system compiler package *) let sys_nv = OpamPackage.create ocaml_system_pkgname nv.version in let rev_dep_flag = Filter (FIdent ([], OpamVariable.of_string "post", None)) in let system_opam = O.create sys_nv |> O.with_substs [OpamFilename.Base.of_string conf_script_name] |> O.with_build [ List.map (fun s -> CString s, None) [ "ocaml"; conf_script_name ], None ] |> O.with_conflict_class [ocaml_conflict_class] |> O.with_depends (OpamFormula.ands ( List.map (fun name -> Atom (OpamPackage.Name.of_string name, Atom (rev_dep_flag))) ["ocaml"; "base-unix"; "base-threads"; "base-bigarray"] )) |> O.with_maintainer [ "platform@lists.ocaml.org" ] |> O.with_flags [Pkgflag_Compiler] |> O.with_descr (OpamFile.Descr.create "The OCaml compiler (system version, from outside of opam)") |> O.with_available (FOp (FIdent ([],OpamVariable.of_string "sys-ocaml-version",None), `Eq, FString (OpamPackage.Version.to_string nv.version))) (* add depext towards an 'ocaml' package? *) in write_opam ~add_files:[conf_script_name^".in", system_conf_script] system_opam end; (* cleanup *) OpamFilename.remove comp_file; OpamStd.Option.iter OpamFilename.remove descr_file; OpamFilename.rmdir_cleanup (OpamFilename.dirname comp_file); OpamConsole.status_line "Compiler %s successfully converted to package %s" c (OpamPackage.to_string nv); OpamStd.String.Set.add ocaml_version ocaml_versions ) compilers OpamStd.String.Set.empty in OpamConsole.clear_status (); save_cache (); (* Generate "ocaml" package wrappers depending on one of the implementations at the appropriate version *) let gen_ocaml_wrapper str_version = let version = OpamPackage.Version.of_string str_version in let wrapper_nv = OpamPackage.create ocaml_wrapper_pkgname version in let upper_bound_v = try let g = Re.(exec @@ compile @@ seq [rep1 digit; eos]) str_version in let sn = Re.Group.get g 0 in String.sub str_version 0 (fst (Re.Group.offset g 0)) ^ (string_of_int (1 + int_of_string sn)) ^ "~" with Not_found -> str_version ^ "a" in let wrapper_opam = O.create wrapper_nv |> O.with_substs [OpamFilename.Base.of_string conf_script_name] |> O.with_build [ List.map (fun s -> CString s, None) [ "ocaml"; "unix.cma"; conf_script_name ], None ] |> O.with_maintainer [ "platform@lists.ocaml.org" ] |> O.with_build_env ["CAML_LD_LIBRARY_PATH", Eq, "", None] |> O.with_env [ "CAML_LD_LIBRARY_PATH", Eq, "%{_:stubsdir}%", None; "CAML_LD_LIBRARY_PATH", PlusEq, "%{lib}%/stublibs", None; "OCAML_TOPLEVEL_PATH", Eq, "%{toplevel}%", None; ] |> (* leave the Compiler flag to the implementations (since the user needs to select one) O.with_flags [Pkgflag_Compiler] |> *) O.with_descr (OpamFile.Descr.create "The OCaml compiler (virtual package)\n\ This package requires a matching implementation of OCaml,\n\ and polls it to initialise specific variables like \ `ocaml:native-dynlink`") |> O.with_depends (OpamFormula.ors [ Atom ( ocaml_official_pkgname, Atom (Constraint (`Eq, FString str_version)) ); Atom ( ocaml_variants_pkgname, OpamFormula.ands [ Atom (Constraint (`Geq, FString str_version)); Atom (Constraint (`Lt, FString upper_bound_v)); ] ); Atom ( ocaml_system_pkgname, Atom (Constraint (`Eq, FString str_version)) ) ]) in write_opam ~add_files:[conf_script_name^".in", wrapper_conf_script] wrapper_opam in OpamStd.String.Set.iter gen_ocaml_wrapper ocaml_versions; let packages = OpamRepository.packages_with_prefixes repo_root in OpamConsole.log "REPO_UPGRADE" "Will not update base packages: %s\n" (OpamPackage.Name.Set.to_string all_base_packages); OpamPackage.Map.iter (fun package prefix -> let opam_file = OpamRepositoryPath.opam repo_root prefix package in let opam0 = OpamFile.OPAM.read opam_file in OpamFile.OPAM.print_errors ~file:opam_file opam0; let nv = OpamFile.OPAM.package opam0 in if not (List.mem nv.name ocaml_package_names) && not (OpamPackage.Name.Set.mem nv.name all_base_packages) then let opam = OpamFileTools.add_aux_files ~files_subdir_hashes:true opam0 in let opam = OpamFormatUpgrade.opam_file_from_1_2_to_2_0 ~filename:opam_file opam in if opam <> opam0 then (OpamFile.OPAM.write_with_preserved_format opam_file opam; List.iter OpamFilename.remove [ OpamFile.filename (OpamRepositoryPath.descr repo_root prefix package); OpamFile.filename (OpamRepositoryPath.url repo_root prefix package); ]; OpamConsole.status_line "Updated %s" (OpamFile.to_string opam_file)) ) packages; OpamConsole.clear_status (); let repo_file = OpamRepositoryPath.repo repo_root in OpamFile.Repo.write repo_file (OpamFile.Repo.with_opam_version upgradeto_version (OpamFile.Repo.safe_read repo_file)) let clear_cache () = OpamFilename.remove (OpamFile.filename cache_file) let do_upgrade_mirror repo_root base_url = OpamFilename.with_tmp_dir @@ fun tmp_mirror_dir -> let open OpamFilename.Op in let copy_dir d = let src = repo_root / d in if OpamFilename.exists_dir src then OpamFilename.copy_dir ~src ~dst:(tmp_mirror_dir / d) in let copy_file f = let src = repo_root // f in if OpamFilename.exists src then OpamFilename.copy ~src ~dst:(tmp_mirror_dir // f) in copy_dir "packages"; copy_dir "compilers"; copy_file "repo"; do_upgrade tmp_mirror_dir; let repo_file = OpamFile.make (OpamFilename.of_string "repo") in let repo0 = OpamFile.Repo.safe_read repo_file in let opam_version_fid = FIdent ([], OpamVariable.of_string "opam-version", None) in let redir = OpamUrl.to_string OpamUrl.Op.(base_url / upgradeto_version_string), Some (FOp (opam_version_fid, `Geq, FString (upgradeto_version_string ^ "~"))) in let repo0 = if OpamFile.Repo.opam_version repo0 = None then OpamFile.Repo.with_opam_version (OpamVersion.of_string "1.2") repo0 else repo0 in let repo0 = OpamFile.Repo.with_redirect (List.filter (fun r -> r <> redir) (OpamFile.Repo.redirect repo0)) repo0 in let repo_12 = OpamFile.Repo.with_redirect (redir :: OpamFile.Repo.redirect repo0) repo0 in let repo_20 = let redir = (OpamUrl.to_string base_url, Some (FOp (opam_version_fid, `Lt, FString (upgradeto_version_string ^ "~")))) in repo0 |> OpamFile.Repo.with_opam_version OpamFile.Repo.format_version |> OpamFile.Repo.with_redirect (redir :: OpamFile.Repo.redirect repo0) in OpamFile.Repo.write repo_file repo_12; OpamFile.Repo.write (OpamFile.make OpamFilename.Op.(tmp_mirror_dir // "repo")) repo_20; let dir20 = OpamFilename.Dir.of_string upgradeto_version_string in OpamFilename.rmdir dir20; OpamFilename.move_dir ~src:tmp_mirror_dir ~dst:dir20; OpamConsole.note "Indexes need updating: you should now run\n\ \n%s\ \ cd %s && opam admin index" (if repo_12 <> repo0 && OpamFilename.exists (OpamFilename.of_string "urls.txt") then " opam admin index --full-urls-txt\n" else "") (OpamFilename.remove_prefix_dir repo_root dir20) opam-2.1.5/src/client/opamAdminRepoUpgrade.mli0000644000175000017500000000154414427463453020336 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2017 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) val clear_cache: unit -> unit val upgradeto_version: OpamVersion.t val do_upgrade: OpamTypes.dirname -> unit val do_upgrade_mirror: OpamTypes.dirname -> OpamUrl.t -> unit opam-2.1.5/src/client/opamListCommand.ml0000644000175000017500000006717714427463453017227 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCompat open OpamParserTypes.FullPos open OpamTypes open OpamStateTypes open OpamStd.Op open OpamPackage.Set.Op let log fmt = OpamConsole.log "LIST" fmt let slog = OpamConsole.slog type dependency_toggles = { recursive: bool; depopts: bool; build: bool; post: bool; test: bool; doc: bool; dev: bool; } let default_dependency_toggles = { recursive = false; depopts = false; build = true; post = false; test = false; doc = false; dev = false; } type pattern_selector = { case_sensitive: bool; exact: bool; glob: bool; fields: string list; ext_fields: bool; } let default_pattern_selector = { case_sensitive = false; exact = false; glob = true; fields = ["name"; "synopsis"; "descr"; "tags"]; ext_fields = false; } type selector = | Any | Installed | Root | Compiler | Available | Installable | Pinned | Depends_on of dependency_toggles * atom list | Required_by of dependency_toggles * atom list | Conflicts_with of package list | Coinstallable_with of dependency_toggles * package list | Solution of dependency_toggles * atom list | Pattern of pattern_selector * string | Atoms of atom list | Flag of package_flag | Tag of string | From_repository of repository_name list | Owns_file of filename let string_of_selector = let (%) s col = OpamConsole.colorise col s in function | Any -> "any" % `cyan | Installed -> "installed" % `cyan | Root -> "root" % `cyan | Compiler -> "base" % `cyan | Available -> "available" % `cyan | Installable -> "installable" % `cyan | Pinned -> "pinned" % `cyan | Depends_on (tog,atoms) -> Printf.sprintf "%s(%s)" ((if tog.recursive then "rec-depends-on" else "depends-on") % `blue) (OpamStd.List.concat_map " " OpamFormula.short_string_of_atom atoms % `bold) | Required_by (tog,atoms) -> Printf.sprintf "%s(%s)" ((if tog.recursive then "rec-required-by" else "required-by") % `blue) (OpamStd.List.concat_map " " OpamFormula.short_string_of_atom atoms % `bold) | Conflicts_with packages -> Printf.sprintf "%s(%s)" ("conflicts" % `blue) ((OpamStd.List.concat_map " " OpamPackage.to_string packages) % `bold) | Coinstallable_with (_,packages) -> Printf.sprintf "%s(%s)" ("coinstallable" % `blue) ((OpamStd.List.concat_map " " OpamPackage.to_string packages) % `bold) | Solution (_tog,atoms) -> Printf.sprintf "%s(%s)" ("solution" % `blue) (OpamStd.List.concat_map " " OpamFormula.short_string_of_atom atoms % `bold) | Pattern (sel,str) -> let str = if sel.exact then str else Printf.sprintf "*%s*" str in let fctname = if sel.glob then "match" else "exact-match" in let fctname = match sel.fields with | [] -> Printf.sprintf "none-%s" fctname | [fld] -> Printf.sprintf "%s-%s" fld fctname | _ -> fctname in Printf.sprintf "%s(%s)" (fctname % `green) (str % `bold) | Atoms atoms -> OpamStd.List.concat_map ~left:"(" ~right:")" " | " (fun a -> OpamFormula.short_string_of_atom a % `bold) atoms | Flag fl -> Printf.sprintf "%s(%s)" ("has-flag" % `green) (OpamTypesBase.string_of_pkg_flag fl % `bold) | Tag t -> Printf.sprintf "%s(%s)" ("has-tag" % `green) (t % `bold) | From_repository r -> Printf.sprintf "%s(%s)" ("from-repository" % `magenta) (OpamStd.List.concat_map " " OpamRepositoryName.to_string r % `bold) | Owns_file f -> Printf.sprintf "%s(%s)" ("owns-file" % `magenta) (OpamFilename.prettify f % `bold) let string_of_formula = OpamFormula.string_of_formula string_of_selector let get_opam st nv = match OpamSwitchState.opam_opt st nv with | Some o -> OpamFile.OPAM.(with_name nv.OpamPackage.name (with_version nv.OpamPackage.version o)) | None -> OpamFile.OPAM.create nv let packages_of_atoms st atoms = atoms |> OpamSolution.sanitize_atom_list ~permissive:true st |> OpamFormula.packages_of_atoms (st.packages ++ st.installed) let package_dependencies st tog nv = get_opam st nv |> OpamPackageVar.all_depends ~build:tog.build ~post:tog.post ~test:tog.test ~doc:tog.doc ~dev:tog.dev ~depopts:tog.depopts st let atom_dependencies st tog atoms = atoms |> OpamFormula.packages_of_atoms (st.packages ++ st.installed) |> fun pkgs -> OpamPackage.Set.fold (fun nv acc -> OpamFormula.ors [acc; package_dependencies st tog nv]) pkgs OpamFormula.Empty let get_universe st ?requested tog = let requested = match requested with | Some r -> r | None -> OpamPackage.names_of_packages st.packages in OpamSwitchState.universe st ~test:tog.test ~doc:tog.doc ~force_dev_deps:tog.dev ~requested Query let rec value_strings value = let module SS = OpamStd.String.Set in match value with | Bool _ | Int _ -> SS.empty | Ident s -> SS.singleton s | String s -> SS.singleton s | Relop (_, v1, v2) | Logop (_, v1, v2) | Env_binding (v1, _, v2) -> SS.union (value_strings v1.pelem) (value_strings v2.pelem) | Prefix_relop (_, v) | Pfxop (_, v) -> value_strings v.pelem | List l | Group l -> List.fold_left (fun acc v -> SS.union acc (value_strings v.pelem)) SS.empty l.pelem | Option (v, vl) -> List.fold_left (fun acc v -> SS.union acc (value_strings v.pelem)) (value_strings v.pelem) vl.pelem let pattern_selector patterns = let name_patt = { default_pattern_selector with exact = true; fields = ["name"] } in let version_patt = { default_pattern_selector with exact = true; fields = ["version"] } in OpamFormula.ors (List.map (fun patt -> match OpamStd.String.cut_at patt '.' with | None -> Atom (Pattern (name_patt, patt)) | Some (name, version) -> OpamFormula.ands [Atom (Pattern (name_patt, name)); Atom (Pattern (version_patt, version))]) patterns) let apply_selector ~base st = function | Any -> base | Installed -> st.installed | Root -> st.installed_roots | Compiler -> st.compiler_packages | Available -> Lazy.force st.available_packages | Installable -> OpamSolver.installable_subset (OpamSwitchState.universe st ~requested:OpamPackage.Name.Set.empty Query) base | Pinned -> OpamPinned.packages st | (Required_by ({recursive=true; _} as tog, atoms) | Depends_on ({recursive=true; _} as tog, atoms)) as direction -> let deps_fun = match direction with | Required_by _ -> OpamSolver.dependencies | Depends_on _ -> OpamSolver.reverse_dependencies | _ -> assert false in deps_fun ~depopts:tog.depopts ~build:tog.build ~post:tog.post ~installed:false ~unavailable:true (get_universe st tog) (packages_of_atoms st atoms) | Required_by (tog, atoms) -> atom_dependencies st tog atoms |> OpamFormula.packages base | Depends_on (tog, atoms) -> let packages = packages_of_atoms st atoms in OpamPackage.Set.filter (fun nv -> OpamPackage.Set.exists (OpamFormula.verifies (package_dependencies st tog nv)) packages) base | Conflicts_with packages -> OpamSwitchState.conflicts_with st (OpamPackage.Set.of_list packages) base | Coinstallable_with (tog, packages) -> let universe = get_universe st tog in let set = OpamPackage.Set.of_list packages in OpamSolver.coinstallable_subset universe set base | Solution (tog, atoms) -> let universe = let requested = OpamFormula.packages_of_atoms st.packages atoms |> OpamPackage.names_of_packages in get_universe st tog ~requested in let universe = { universe with u_installed = OpamPackage.Set.empty; u_installed_roots = OpamPackage.Set.empty } in (match OpamSolver.resolve universe ~orphans:OpamPackage.Set.empty (OpamSolver.request ~install:atoms ()) with | Success s -> OpamSolver.new_packages s | Conflicts cs -> OpamConsole.error_and_exit `No_solution "No solution%s for %s: %s" (if tog.depopts then " including optional dependencies" else "") (OpamFormula.string_of_atoms atoms) (OpamCudf.string_of_conflicts st.packages (OpamSwitchState.unavailable_reason st) cs)) | Pattern (psel, pat) -> let re = if psel.glob then Re.Glob.glob ~expand_braces:true pat else Re.str pat in let re = if psel.case_sensitive then Re.case re else Re.no_case re in let re = if psel.exact then Re.seq [Re.bos; re; Re.eos] else re in let re = Re.compile re in let content_strings nv = let opam = get_opam st nv in if psel.fields = [] then List.map (fun (_,v) -> value_strings v.pelem) (OpamFile.OPAM.to_list opam) else try List.map (fun f -> match OpamFile.OPAM.print_field_as_syntax f opam with | None -> OpamStd.String.Set.empty | Some v -> value_strings v.pelem) psel.fields with Not_found -> OpamConsole.error_and_exit `Bad_arguments "Unrecognised field in selection %s" (String.concat ", " psel.fields) in OpamPackage.Set.filter (fun nv -> List.exists (OpamStd.String.Set.exists (Re.execp re)) (content_strings nv)) base | Atoms atoms -> OpamFormula.packages_of_atoms base atoms | Flag f -> OpamPackage.Set.filter (fun nv -> get_opam st nv |> OpamFile.OPAM.has_flag f) base | Tag t -> OpamPackage.Set.filter (fun nv -> get_opam st nv |> List.mem t @* OpamFile.OPAM.tags) base | From_repository repos -> let rt = st.switch_repos in let rec aux = function | [] -> OpamPackage.Set.empty | r :: rl -> let packages = OpamPackage.keys (OpamRepositoryName.Map.find r rt.repo_opams) in if List.mem r repos then OpamPackage.Set.union packages (aux rl) else OpamPackage.Set.diff (aux rl) packages in aux (OpamSwitchState.repos_list st) | Owns_file file -> (try let root = st.switch_global.root in let switch = List.find (fun sw -> OpamFilename.remove_prefix (OpamPath.Switch.root root sw) file <> OpamFilename.to_string file) (OpamFile.Config.installed_switches st.switch_global.config) in let rel_name = OpamFilename.remove_prefix (OpamPath.Switch.root root switch) file in let matching_change_files = List.filter (fun change_f -> OpamFilename.check_suffix change_f ".changes" && let changes = OpamFile.Changes.safe_read (OpamFile.make change_f) in OpamStd.String.Map.exists (fun f -> function | OpamDirTrack.Removed -> false | _ -> rel_name = f) changes) (OpamFilename.files (OpamPath.Switch.install_dir root switch)) in let selections = if switch = st.switch then OpamSwitchState.selections st else OpamSwitchState.load_selections st.switch_global switch in List.fold_left (fun acc f -> let name = OpamPackage.Name.of_string @@ OpamFilename.(Base.to_string (basename (chop_extension f))) in try OpamPackage.Set.add (OpamPackage.package_of_name selections.sel_installed name) acc with Not_found -> acc) OpamPackage.Set.empty matching_change_files with Not_found -> log "%a doesn't belong to a known opam switch" (slog OpamFilename.to_string) file; OpamPackage.Set.empty) let rec filter ~base st = function | Empty -> base | Atom select -> base %% apply_selector ~base st select | Block b -> filter ~base st b | And (a, b) -> let base = filter ~base st a in filter ~base st b | Or (a, b) -> filter ~base st a ++ filter ~base st b type output_format = | Name | Version | Package | Synopsis | Synopsis_or_target | Description | Field of string | Raw_field of string | Installed_version | Pinning_target | Source_hash | Raw | All_installed_versions | Available_versions | All_versions | Repository | Installed_files | VC_ref | Depexts let default_list_format = [Name; Installed_version; Synopsis_or_target] let disp_header = function | Name -> "Name" | Version -> "Version" | Package -> "Package" | Synopsis | Synopsis_or_target -> "Synopsis" | Description -> "Description" | Field s | Raw_field s -> String.capitalize_ascii s | Installed_version -> "Installed" | Pinning_target -> "Pin" | Source_hash -> "Source hash" | Raw -> "Metadata" | All_installed_versions -> "Installed versions" | Available_versions -> "Available versions" | All_versions -> "Versions" | Repository -> "Repository" | Installed_files -> "Installed files" | VC_ref -> "VC ref" | Depexts -> "Depexts" let field_names = [ Name, "name"; Version, "version"; Package, "package"; Synopsis, "synopsis"; Synopsis_or_target, "synopsis-or-target"; Description, "description"; Field "", ""; Raw_field ":", ":"; Installed_version, "installed-version"; Pinning_target, "pin"; Source_hash, "source-hash"; Raw, "opam-file"; All_installed_versions, "all-installed-versions"; Available_versions, "available-versions"; All_versions, "all-versions"; Repository, "repository"; Installed_files, "installed-files"; VC_ref, "vc-ref"; Depexts, "depexts"; ] let raw_field_names = List.filter (function Field _, _ -> false | _ -> true) field_names let string_of_field ?(raw=false) = function | Field s -> if raw then s ^":" else s | Raw_field s -> s ^":" | f -> List.assoc f field_names let field_of_string ~raw = let names_fields = List.map (fun (a,b) -> b, a) field_names in let opam_fields = List.map fst OpamFile.OPAM.fields in if raw then fun s -> Raw_field s else fun s -> if OpamStd.String.ends_with ~suffix:":" s then Raw_field (OpamStd.String.remove_suffix ~suffix:":" s) else try List.assoc s names_fields with Not_found -> match OpamStd.List.find_opt (fun x -> s = x) opam_fields with | Some f -> Field f | None -> OpamConsole.error_and_exit `Bad_arguments "No printer for %S" s let version_color st nv = let installed = (* (in any switch) *) OpamGlobalState.installed_versions st.switch_global nv.name in let is_available nv = (* Ignore unavailability due to pinning *) try OpamFilter.eval_to_bool ~default:false (OpamPackageVar.resolve_switch_raw ~package:nv st.switch_global st.switch st.switch_config) (OpamFile.OPAM.available (get_opam st nv)) with Not_found -> false in if OpamPackage.Set.mem nv st.installed then [`bold;`magenta] else (if OpamPackage.Map.mem nv installed then [`bold] else []) @ (if is_available nv then [] else [`crossed;`red]) let mini_field_printer ?(prettify=false) ?(normalise=false) = let module OpamPrinter = OpamPrinter.FullPos in if normalise then OpamPrinter.Normalise.value else fun v -> match v.pelem with | String s when prettify -> s | List l when prettify && List.for_all (function {pelem=String _;_} -> true | _ -> false) l.pelem -> OpamStd.List.concat_map ", " (function {pelem=String s;_} -> s | _ -> assert false) l.pelem | List l -> OpamPrinter.value_list l | _ -> OpamPrinter.Normalise.value v let detail_printer ?prettify ?normalise ?(sort=false) st nv = let open OpamStd.Option.Op in let (%) s cols = OpamConsole.colorise' cols s in let root_sty = if OpamPackage.Set.mem nv st.installed_roots then [`underline] else [] in let get_opam = if not sort then get_opam else fun st nv -> OpamFileTools.sort_opam (get_opam st nv) in function | Name -> OpamPackage.Name.to_string nv.name % (`bold :: root_sty) | Version -> OpamPackage.Version.to_string nv.version % version_color st nv | Package -> (OpamPackage.name_to_string nv % (`bold :: root_sty)) ^ ("." ^ OpamPackage.version_to_string nv) % root_sty | Synopsis -> (get_opam st nv |> OpamFile.OPAM.descr >>| OpamFile.Descr.synopsis) +! "" | Synopsis_or_target -> (match OpamPinned.package_opt st nv.name with | Some nv -> let opam = get_opam st nv in if Some opam = OpamPackage.Map.find_opt nv st.repos_package_index then Printf.sprintf "pinned to version %s" (OpamPackage.Version.to_string nv.version % [`blue]) else Printf.sprintf "pinned to version %s at %s" (OpamPackage.Version.to_string nv.version % [`blue]) (OpamStd.Option.to_string ~none:"(local metadata only)" (fun u -> OpamUrl.to_string u % [`underline]) (OpamFile.OPAM.get_url opam)) | None -> (get_opam st nv |> OpamFile.OPAM.descr >>| OpamFile.Descr.synopsis) +! "") | Description -> (get_opam st nv |> OpamFile.OPAM.descr >>| OpamFile.Descr.body) +! "" | Raw_field f | Field f -> (try List.assoc f (OpamFile.OPAM.to_list (get_opam st nv)) |> mini_field_printer ?prettify ?normalise with Not_found -> "") | Installed_version -> (try OpamPackage.package_of_name st.installed nv.name |> fun inst_nv -> OpamPackage.version_to_string inst_nv |> fun s -> if OpamPackage.Set.mem inst_nv st.pinned then s % [`blue] else if OpamPackage.has_name st.pinned nv.name then s % [`bold;`red] else if nv <> inst_nv && not (OpamPackage.Set.mem inst_nv st.compiler_packages) then s % [`bold;`yellow] else s % [`magenta] with Not_found -> "--" % [`cyan]) | Pinning_target -> if OpamPackage.Set.mem nv st.pinned then let opam = get_opam st nv in OpamStd.Option.to_string ~none:"--" OpamUrl.to_string (OpamFile.OPAM.get_url opam) else "" | Source_hash -> let hash_opt = let open OpamStd.Option.Op in OpamSwitchState.url st nv >>| OpamFile.URL.url >>= fun url -> OpamSwitchState.source_dir st nv |> OpamFilename.opt_dir >>= fun srcdir -> OpamProcess.Job.run (OpamRepository.revision srcdir url) >>| OpamPackage.Version.to_string in OpamStd.Option.default "" hash_opt | Raw -> OpamFile.OPAM.write_to_string (get_opam st nv) | All_installed_versions -> OpamGlobalState.installed_versions st.switch_global nv.name |> OpamPackage.Map.mapi (fun nv switches -> Printf.sprintf "%s [%s]" (OpamPackage.version_to_string nv % version_color st nv) (String.concat " " (List.map OpamSwitch.to_string switches))) |> OpamPackage.Map.values |> String.concat " " | Available_versions -> let available = OpamPackage.packages_of_name (Lazy.force st.available_packages) nv.name in OpamStd.List.concat_map " " (fun nv -> OpamPackage.Version.to_string nv.version % version_color st nv) (OpamPackage.Set.elements available) | All_versions -> let pkgs = OpamPackage.packages_of_name st.packages nv.name in OpamStd.List.concat_map " " (fun nv -> OpamPackage.Version.to_string nv.version % version_color st nv) (OpamPackage.Set.elements pkgs) | Repository -> OpamRepositoryState.find_package_opt st.switch_repos (OpamSwitchState.repos_list st) nv |> OpamStd.Option.to_string (fun (r, _) -> OpamRepositoryName.to_string r) | Installed_files -> let changes_f = OpamPath.Switch.changes st.switch_global.root st.switch nv.name in (match OpamFile.Changes.read_opt changes_f with | None -> "" | Some c -> OpamStd.Format.itemize ~bullet:"" (fun (file, status) -> OpamFilename.to_string file ^ match status with | `Unchanged -> "" | `Removed -> " (absent)" % [`red] | `Changed -> " (modified since)" % [`yellow]) (OpamDirTrack.check (OpamPath.Switch.root st.switch_global.root st.switch) c)) | VC_ref -> OpamStd.Option.Op.( (OpamSwitchState.url st nv >>| OpamFile.URL.url >>= fun url -> url.OpamUrl.hash) +! "" ) | Depexts -> OpamStd.List.concat_map " " OpamSysPkg.to_string (OpamSysPkg.Set.elements (OpamSwitchState.depexts st nv)) type package_listing_format = { short: bool; header: bool; columns: output_format list; all_versions: bool; wrap: [`Wrap of string | `Truncate | `None] option; separator: string; value_printer: [`Normal | `Pretty | `Normalised]; order: [`Standard | `Dependency | `Custom of package -> package -> int]; } let default_package_listing_format = { short = false; header = true; columns = default_list_format; all_versions = false; wrap = None; separator = " "; value_printer = `Normal; order = `Standard; } let display st format packages = let packages = if format.all_versions then packages else OpamPackage.Name.Set.fold (fun name -> let pkgs = OpamPackage.packages_of_name packages name in let nv = let get = OpamPackage.Set.max_elt in try get (pkgs %% st.installed) with Not_found -> try get (pkgs %% st.pinned) with Not_found -> try get (pkgs %% Lazy.force st.available_packages) with Not_found -> get pkgs in OpamPackage.Set.add nv) (OpamPackage.names_of_packages packages) OpamPackage.Set.empty in let packages = if format.order = `Dependency then let universe = OpamSwitchState.universe st ~requested:(OpamPackage.names_of_packages packages) Query in OpamSolver.dependency_sort ~depopts:true ~build:true ~post:false universe packages else match format.order with | `Custom o -> List.sort o (OpamPackage.Set.elements packages) | _ -> OpamPackage.Set.elements packages in let add_head l = if format.header then (List.map (fun f -> "# "^disp_header f) format.columns) :: l else l in let prettify = format.value_printer = `Pretty in let normalise = format.value_printer = `Normalised in if packages = [] then (if format.header then OpamConsole.errmsg "%s\n" (OpamConsole.colorise `red "# No matches found")) else List.rev_map (fun nv -> List.map (detail_printer ~prettify ~normalise st nv) format.columns) packages |> List.rev |> add_head |> OpamStd.Format.align_table |> OpamConsole.print_table ?cut:format.wrap stdout ~sep:format.separator let get_switch_state gt rt = match OpamStateConfig.get_switch_opt () with | None -> OpamSwitchState.load_virtual gt rt | Some sw -> OpamSwitchState.load `Lock_none gt rt sw let get_depexts st packages = OpamPackage.Name.Set.fold (fun name acc -> let nv = OpamSwitchState.get_package st name in let nv = if OpamPackage.Set.mem nv packages then nv else OpamPackage.Set.max_elt (OpamPackage.packages_of_name packages name) in OpamSysPkg.Set.union acc (OpamSwitchState.depexts st nv)) (OpamPackage.names_of_packages packages) OpamSysPkg.Set.empty let print_depexts = OpamSysPkg.Set.iter (fun d -> OpamConsole.msg "%s\n" (OpamSysPkg.to_string d)) let info st ~fields ~raw ~where ?normalise ?(show_empty=false) ?(all_versions=false) ?(sort=false) atoms = let packages = OpamFormula.packages_of_atoms ~disj:all_versions (st.packages ++ st.installed) atoms in let atoms, missing_atoms = List.partition (fun (n,_) -> OpamPackage.has_name packages n) atoms in if missing_atoms <> [] then (OpamConsole.error "No package matching %s found" (OpamStd.List.concat_map " or " OpamFormula.short_string_of_atom missing_atoms); if OpamPackage.Set.is_empty packages then OpamStd.Sys.exit_because `Not_found); let fields = List.map (field_of_string ~raw) fields in let all_versions_fields = [ Name; All_installed_versions; All_versions; ] in let one_version_fields = [ Version; Repository; Pinning_target; Source_hash; Field "url.src"; Field "url.checksum"; Field "homepage"; Field "doc"; Field "bug-reports"; Field "dev-repo"; Field "authors"; Field "maintainer"; Field "license"; Field "tags"; Field "flags"; Field "depends"; Field "depopts"; Field "conflicts"; Field "conflict-class"; Synopsis; Description; ] in let output_table fields nv = let tbl = List.fold_left (fun acc item -> let contents = detail_printer ?normalise ~sort st nv item in if show_empty || contents <> "" then [ OpamConsole.colorise `blue (string_of_field ~raw item); contents ] :: acc else acc) [] (List.rev fields) in let cut = match normalise with | Some true -> Some `None | _ -> None in OpamStd.Format.align_table tbl |> OpamConsole.print_table ?cut stdout ~sep:" "; in let header pkg = if fields = [] && not raw && not where then (OpamConsole.header_msg "%s: information on all versions" (OpamPackage.Name.to_string pkg.name); output_table all_versions_fields pkg) in let output_package pkg = let opam = get_opam st pkg in let opam = if not sort then opam else OpamFileTools.sort_opam opam in OpamFile.OPAM.print_errors opam; if where then OpamConsole.msg "%s\n" (match OpamFile.OPAM.metadata_dir opam with | Some (None, dir) -> Filename.concat dir "opam" | Some (Some repo, rdir) -> let repo_dir = OpamRepositoryPath.root st.switch_global.root repo in let tar = OpamRepositoryPath.tar st.switch_global.root repo in if OpamFilename.exists tar && not (OpamFilename.exists_dir repo_dir) then Printf.sprintf "<%s>%s%s" (OpamFilename.to_string tar) Filename.dir_sep rdir else OpamFilename.Dir.to_string OpamFilename.Op.(repo_dir / rdir) | None -> "") else if raw && fields = [] then OpamFile.OPAM.write_to_channel stdout opam else match fields with | [] -> OpamConsole.header_msg "Version-specific details"; output_table one_version_fields pkg | [f] -> OpamConsole.msg "%s\n" (detail_printer ?normalise ~sort st pkg f) | fields -> output_table fields pkg in List.iter (fun (name,_) -> (* Like OpamSwitchState.get_package, but restricted to [packages] *) let nvs = OpamPackage.packages_of_name packages name in if OpamPackage.Set.is_singleton nvs || all_versions then (header (OpamPackage.Set.max_elt nvs); OpamPackage.Set.iter output_package nvs) else (let choose = try OpamPackage.Set.choose (nvs %% st.pinned) with Not_found -> try OpamPackage.Set.choose (nvs %% st.installed) with Not_found -> try OpamPackage.Set.max_elt (nvs %% Lazy.force st.available_packages) with Not_found -> OpamPackage.Set.max_elt nvs in header choose; output_package choose) ) atoms opam-2.1.5/src/client/opamAction.ml0000644000175000017500000011305114427463453016211 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) let log ?level fmt = OpamConsole.log ?level "ACTION" fmt let slog = OpamConsole.slog open OpamTypes open OpamFilename.Op open OpamStateTypes open OpamProcess.Job.Op module PackageActionGraph = OpamSolver.ActionGraph (* Preprocess install: returns a list of files to install, and their respective install functions *) let preprocess_dot_install_t st nv build_dir = if not (OpamFilename.exists_dir build_dir) then [], None else let root = st.switch_global.root in let switch_prefix = OpamPath.Switch.root root st.switch in let file_wo_prefix f = OpamFilename.remove_prefix switch_prefix f in let name = nv.name in let install_f = OpamPath.Builddir.install build_dir nv in let install = OpamFile.Dot_install.safe_read install_f in (* .install *) let install_loc = OpamPath.Switch.install root st.switch name in if install <> OpamFile.Dot_install.empty then OpamFile.Dot_install.write install_loc install; (* .config *) let (files_and_installs, config) = let config_f = OpamPath.Builddir.config build_dir nv in let config = OpamFile.Dot_config.read_opt config_f in (match config with | Some config -> let file = OpamPath.Switch.config root st.switch name |> OpamFile.filename |> file_wo_prefix in let inst _ = let dot_config = OpamPath.Switch.config root st.switch name in OpamFile.Dot_config.write dot_config config; None in ([(file, inst)], Some config) | None -> ([], None)) in let check ~src ~dst base = let src_file = OpamFilename.create src base.c in if base.optional && not (OpamFilename.exists src_file) then log "Not installing %a is not present and optional." (slog OpamFilename.to_string) src_file; let exists = OpamFilename.exists src_file in let warn = if not base.optional && not exists then Some (dst, base.c) else None in exists, warn in (* Install a list of files *) let install_files (exec, dst_fn, files_fn) = let dst_dir = dst_fn root st.switch name in let files = files_fn install in let dir_and_install = if OpamFilename.exists_dir dst_dir || files = [] then [] else let dir = OpamFilename.remove_prefix_dir switch_prefix dst_dir in let inst _ = log "creating %a" (slog OpamFilename.Dir.to_string) dst_dir; OpamFilename.mkdir dst_dir; None in [dir, inst] in dir_and_install @ List.rev @@ List.rev_map (fun (base, dst) -> let (base, append) = if exec && not (OpamFilename.exists (OpamFilename.create build_dir base.c)) then let base' = {base with c = OpamFilename.Base.add_extension base.c "exe"} in if OpamFilename.exists (OpamFilename.create build_dir base'.c) then (OpamConsole.warning ".install file is missing .exe extension for %s" (OpamFilename.Base.to_string base.c); (base', true)) else (base, false) else (base, false) in let src_file = OpamFilename.create build_dir base.c in let dst_file = match dst with | None -> OpamFilename.create dst_dir (OpamFilename.basename src_file) | Some d -> if append && not (OpamFilename.Base.check_suffix d ".exe") then OpamFilename.create dst_dir (OpamFilename.Base.add_extension d "exe") else OpamFilename.create dst_dir d in let file = file_wo_prefix dst_file in let inst warning = if append then warning (OpamFilename.to_string src_file) `Add_exe; let check, warn = check ~src:build_dir ~dst:dst_dir base in if check then OpamFilename.install ~warning ~exec ~src:src_file ~dst:dst_file (); warn in file, inst) files in let module P = OpamPath.Switch in let module I = OpamFile.Dot_install in let instdir_gen fpath r s _ = fpath r s st.switch_config in let instdir_pkg fpath r s n = fpath r s st.switch_config n in let to_install = [ (* bin *) true, (instdir_gen P.bin), I.bin; (* sbin *) true, (instdir_gen P.sbin), I.sbin; (* lib *) false, (instdir_pkg P.lib), I.lib; true, (instdir_pkg P.lib), I.libexec; false, (instdir_gen P.lib_dir), I.lib_root; true, (instdir_gen P.lib_dir), I.libexec_root; (* toplevel *) false, (instdir_gen P.toplevel), I.toplevel; true, (instdir_gen P.stublibs), I.stublibs; (* Man pages *) false, (instdir_gen P.man_dir), I.man; (* Shared files *) false, (instdir_pkg P.share), I.share; false, (instdir_gen P.share_dir), I.share_root; (* Etc files *) false, (instdir_pkg P.etc), I.etc; (* Documentation files *) false, (instdir_pkg P.doc), I.doc; ] in let files_and_installs = List.fold_left (fun acc toi -> List.rev_append (install_files toi) acc) files_and_installs to_install in (* misc *) let misc_files = List.map (fun (src, dst) -> let file = file_wo_prefix dst in let inst warning = let src_file = OpamFilename.create (OpamFilename.cwd ()) src.c in if OpamFilename.exists dst && OpamConsole.confirm "Overwriting %s?" (OpamFilename.to_string dst) then OpamFilename.install ~warning ~src:src_file ~dst () else begin OpamConsole.msg "Installing %s to %s.\n" (OpamFilename.Base.to_string src.c) (OpamFilename.to_string dst); if OpamConsole.confirm "Continue?" then OpamFilename.install ~warning ~src:src_file ~dst () end; None in (file, inst)) (I.misc install) in List.rev_append files_and_installs misc_files, config (* Returns function to install package files from [.install] *) let preprocess_dot_install st nv build_dir = let files_and_installs, config = preprocess_dot_install_t st nv build_dir in let root = st.switch_global.root in let files, installs = List.split files_and_installs in let really_process_dot_install () = if OpamStateConfig.(!r.dryrun) then OpamConsole.msg "Installing %s.\n" (OpamPackage.to_string nv) else if OpamFilename.exists_dir build_dir then let (warning, had_windows_warnings) = if OpamFormatConfig.(!r.strict) then let had_warnings = ref false in let install_warning dst warning = let () = match warning with | `Add_exe | `Install_script | `Cygwin | `Cygwin_libraries -> had_warnings := true | _ -> () in OpamSystem.default_install_warning dst warning in (install_warning, (fun () -> !had_warnings)) else (OpamSystem.default_install_warning, (fun () -> false)) in OpamFilename.in_dir build_dir @@ fun () -> log "Installing %s.\n" (OpamPackage.to_string nv); let warnings = OpamStd.List.filter_map (fun install -> install warning) installs in if warnings <> [] then (let install_f = OpamPath.Switch.install root st.switch nv.name in let print (dir, base) = Printf.sprintf " - %s to %s\n" (OpamFilename.to_string (OpamFilename.create build_dir base)) (OpamFilename.Dir.to_string dir) in OpamConsole.error "Installation of %s failed" (OpamPackage.to_string nv); let msg = Printf.sprintf "Some files in %s couldn't be installed:\n%s" (OpamFile.to_string install_f) (String.concat "" (List.map print warnings)) in failwith msg); if had_windows_warnings () then failwith "Strict mode is enabled - previous warnings considered fatal" in files, really_process_dot_install, config let download_package st nv = log "download_package: %a" (slog OpamPackage.to_string) nv; if OpamStateConfig.(!r.dryrun) || OpamClientConfig.(!r.fake) then Done None else let dir = OpamSwitchState.source_dir st nv in if OpamPackage.Set.mem nv st.pinned && OpamFilename.exists_dir dir && OpamStd.Option.Op.( OpamPinned.find_opam_file_in_source nv.name dir >>| OpamFile.OPAM.safe_read >>= OpamFile.OPAM.version_opt) = Some nv.version then Done None else let print_action msg = OpamConsole.msg "%s retrieved %s.%s (%s)\n" (if not (OpamConsole.utf8 ()) then "->" else OpamActionGraph. (action_color (`Fetch ()) (action_strings (`Fetch ())))) (OpamConsole.colorise `bold (OpamPackage.name_to_string nv)) (OpamPackage.version_to_string nv) msg; in OpamUpdate.cleanup_source st (OpamPackage.Map.find_opt nv st.installed_opams) (OpamSwitchState.opam st nv); OpamProcess.Job.catch (fun e -> let na = match e with | OpamDownload.Download_fail (s,l) -> (s,l) | e -> (None, Printexc.to_string e) in Done (Some na)) @@ fun () -> OpamUpdate.download_package_source st nv dir @@| function | Some (Not_available (s, l)), _ -> let msg = match s with None -> l | Some s -> s in OpamConsole.error "Failed to get sources of %s: %s" (OpamPackage.to_string nv) msg; Some (s, l) | _, ((name, Not_available (s, l)) :: _) -> let msg = match s with None -> l | Some s -> s in OpamConsole.error "Failed to get extra source \"%s\" of %s: %s" name (OpamPackage.to_string nv) msg; Some (s, l) | Some (Result msg), _ -> print_action msg; None | Some (Up_to_date msg), _ -> print_action msg; None | None, [] -> None | None, (e :: es as extras) -> if List.for_all (function _, Up_to_date _ -> true | _ -> false) extras then print_action "cached" else begin match e, es with | (_, Result msg), [] -> print_action msg | _, _ -> print_action (Printf.sprintf "%d extra sources" (List.length extras)) end; None (* Prepare the package build: * apply the patches * substitute the files *) let prepare_package_build env opam nv dir = let patches = OpamFile.OPAM.patches opam in let print_apply basename = log "%s: applying %s.\n" (OpamPackage.name_to_string nv) (OpamFilename.Base.to_string basename); if OpamConsole.verbose () then OpamConsole.msg "[%s: patch] applying %s\n" (OpamConsole.colorise `green (OpamPackage.name_to_string nv)) (OpamFilename.Base.to_string basename) in let print_subst basename = let file = OpamFilename.Base.to_string basename in let file_in = file ^ ".in" in log "%s: expanding opam variables in %s, generating %s.\n" (OpamPackage.name_to_string nv) file_in file; if OpamConsole.verbose () then OpamConsole.msg "[%s: subst] expanding opam variables in %s, generating %s\n" (OpamConsole.colorise `green (OpamPackage.name_to_string nv)) file_in file in let apply_patches ?(dryrun=false) () = let patch base = if dryrun then Done None else OpamFilename.patch (dir // OpamFilename.Base.to_string base) dir in let rec aux = function | [] -> Done [] | (patchname,filter)::rest -> if OpamFilter.opt_eval_to_bool env filter then (print_apply patchname; patch patchname @@+ function | None -> aux rest | Some err -> aux rest @@| fun e -> (patchname, err) :: e) else aux rest in aux patches in let subst_patches, subst_others = List.partition (fun f -> List.mem_assoc f patches) (OpamFile.OPAM.substs opam) in if OpamStateConfig.(!r.dryrun) || OpamClientConfig.(!r.fake) then (List.iter print_subst (OpamFile.OPAM.substs opam); apply_patches ~dryrun:true ()) @@| fun _ -> None else let subst_errs = OpamFilename.in_dir dir @@ fun () -> List.fold_left (fun errs f -> try print_subst f; OpamFilter.expand_interpolations_in_file env f; errs with e -> (f, e)::errs) [] subst_patches in (* Apply the patches *) let text = OpamProcess.make_command_text (OpamPackage.Name.to_string nv.name) "patch" in OpamProcess.Job.with_text text (apply_patches ()) @@+ fun patching_errors -> (* Substitute the configuration files. We should be in the right directory to get the correct absolute path for the substitution files (see [OpamFilter.expand_interpolations_in_file] and [OpamFilename.of_basename]. *) let subst_errs = OpamFilename.in_dir dir @@ fun () -> List.fold_left (fun errs f -> try print_subst f; OpamFilter.expand_interpolations_in_file env f; errs with e -> (f, e)::errs) subst_errs subst_others in if patching_errors <> [] || subst_errs <> [] then let msg = (if patching_errors <> [] then Printf.sprintf "These patches didn't apply at %s:\n%s" (OpamFilename.Dir.to_string dir) (OpamStd.Format.itemize (fun (f,err) -> Printf.sprintf "%s: %s" (OpamFilename.Base.to_string f) (Printexc.to_string err)) patching_errors) else "") ^ (if subst_errs <> [] then Printf.sprintf "String expansion failed for these files:\n%s" (OpamStd.Format.itemize (fun (b,err) -> Printf.sprintf "%s.in: %s" (OpamFilename.Base.to_string b) (Printexc.to_string err)) subst_errs) else "") in Done (Some (Failure msg)) else Done None let prepare_package_source st nv dir = log "prepare_package_source: %a at %a" (slog OpamPackage.to_string) nv (slog OpamFilename.Dir.to_string) dir; if OpamStateConfig.(!r.dryrun) then Done None else let opam = OpamSwitchState.opam st nv in let get_extra_sources_job = (* !X The extra sources have normally been prefetched during the dl phase; this is, assuming their metadata contains a hash though. *) let dl_file_job (basename, urlf) = OpamProcess.Job.catch (fun e -> Done (Some e)) @@ fun () -> OpamRepository.pull_file ~cache_dir:(OpamRepositoryPath.download_cache st.switch_global.root) ~silent_hits:true (OpamPackage.to_string nv ^ "/" ^ OpamFilename.Base.to_string basename) (OpamFilename.create dir basename) (OpamFile.URL.checksum urlf) (OpamFile.URL.url urlf :: OpamFile.URL.mirrors urlf) @@| function | Result () | Up_to_date () -> None | Not_available (_,msg) -> Some (Failure msg) in List.fold_left (fun job dl -> job @@+ function | None -> dl_file_job dl | some_err -> Done some_err) (Done None) (OpamFile.OPAM.extra_sources opam) in let check_extra_files = let extra_files = let extra_files = OpamFile.OPAM.get_extra_files ~repos_roots:(OpamRepositoryState.get_root st.switch_repos) opam in if extra_files <> [] then extra_files else match OpamFile.OPAM.extra_files opam with | None -> [] | Some xs -> (* lookup in switch-local hashmap overlay *) let extra_files_dir = OpamPath.Switch.extra_files_dir st.switch_global.root st.switch in OpamStd.List.filter_map (fun (base, hash) -> let src = OpamFilename.create extra_files_dir (OpamFilename.Base.of_string (OpamHash.contents hash)) in if OpamFilename.exists src then Some (src, base, hash) else None) xs in let bad_hash = OpamStd.List.filter_map (fun (src, base, hash) -> if OpamHash.check_file (OpamFilename.to_string src) hash then (OpamFilename.copy ~src ~dst:(OpamFilename.create dir base); None) else Some src) extra_files in if bad_hash = [] then None else Some (Failure (Printf.sprintf "Bad hash for %s" (OpamStd.Format.itemize OpamFilename.to_string bad_hash))); in OpamFilename.mkdir dir; get_extra_sources_job @@+ function Some _ as err -> Done err | None -> check_extra_files |> function Some _ as err -> Done err | None -> let opam = OpamSwitchState.opam st nv in prepare_package_build (OpamPackageVar.resolve ~opam st) opam nv dir let compilation_env t opam = let open OpamParserTypes in let build_env = List.map (OpamEnv.env_expansion ~opam t) (OpamFile.OPAM.build_env opam) in let scrub = OpamClientConfig.(!r.scrubbed_environment_variables) in OpamEnv.get_full ~scrub ~set_opamroot:true ~set_opamswitch:true ~force_path:true t ~updates:([ "CDPATH", Eq, "", Some "shell env sanitization"; "MAKEFLAGS", Eq, "", Some "make env sanitization"; "MAKELEVEL", Eq, "", Some "make env sanitization"; "OPAM_PACKAGE_NAME", Eq, OpamPackage.Name.to_string (OpamFile.OPAM.name opam), Some "build environment definition"; "OPAM_PACKAGE_VERSION", Eq, OpamPackage.Version.to_string (OpamFile.OPAM.version opam), Some "build environment definition"; "OPAMCLI", Eq, "2.0", Some "opam CLI version"; ] @ build_env) let installed_opam_opt st nv = OpamStd.Option.Op.( OpamPackage.Map.find_opt nv st.installed_opams >>+ fun () -> OpamSwitchState.opam_opt st nv ) let removal_needs_download st nv = match installed_opam_opt st nv with | None -> if not (OpamFile.exists (OpamPath.Switch.changes st.switch_global.root st.switch nv.name)) then OpamConsole.warning "No opam or changes file found to remove package %s. Stale files may \ remain." (OpamPackage.to_string nv); false | Some opam -> not (OpamFile.OPAM.has_flag Pkgflag_LightUninstall opam || OpamFilter.commands (OpamPackageVar.resolve ~opam st) (OpamFile.OPAM.remove opam) = []) let get_wrappers t = OpamFile.Wrappers.add ~outer:(OpamFile.Config.wrappers t.switch_global.config) ~inner:(OpamFile.Switch_config.wrappers t.switch_config) let get_wrapper t opam wrappers ?local getter = let local_env = let hook_env = OpamEnv.hook_env t.switch_global.root in match local with | Some e -> OpamVariable.Map.union (fun _ v -> v) e hook_env | None -> hook_env in OpamFilter.commands (OpamPackageVar.resolve ~local:local_env ~opam t) (getter wrappers) |> OpamStd.List.filter_map (function | [] -> None | cmd::args -> Some (cmd, args)) let cmd_wrapper t opam wrappers getter cmd args = match get_wrapper t opam wrappers getter @ [cmd, args] with | (cmd, args) :: r -> cmd, args @ List.concat (List.map (fun (c, a) -> c::a) r) | [] -> assert false let opam_local_env_of_status ret = OpamVariable.Map.singleton (OpamVariable.of_string "error-code") (Some (S (match ret with | None -> "0" | Some r -> string_of_int r.OpamProcess.r_code))) let make_command st opam ?dir ?text_command (cmd, args) = let nv = OpamFile.OPAM.package opam in let name = OpamPackage.name_to_string nv in let env = OpamTypesBase.env_array (compilation_env st opam) in let dir = OpamStd.Option.map OpamFilename.Dir.to_string dir in let text = let cmd, args = OpamStd.Option.default (cmd, args) text_command in OpamProcess.make_command_text name ~args cmd in let context = let open OpamStd.Option.Op in String.concat " | " [ OpamVersion.(to_string current); (OpamSysPoll.os () +! "unknown") ^"/"^ (OpamSysPoll.arch () +! "unknown"); (OpamStd.List.concat_map " " OpamPackage.to_string OpamPackage.Set.(elements @@ inter st.compiler_packages st.installed_roots)); if OpamPackage.Set.mem nv st.pinned then match OpamFile.OPAM.url opam with | None -> "pinned" | Some url -> let u = OpamFile.URL.url url in let src = OpamPath.Switch.pinned_package st.switch_global.root st.switch nv.name in let rev = OpamProcess.Job.run (OpamRepository.revision src u) in Printf.sprintf "pinned(%s%s%s)" (OpamUrl.to_string u) (OpamStd.Option.to_string (fun s -> "("^s^")") (OpamFile.URL.subpath url)) (OpamStd.Option.to_string (fun r -> "#"^OpamPackage.Version.to_string r) rev) else match OpamRepositoryState.find_package_opt st.switch_repos (OpamSwitchState.repos_list st) nv with | None -> "no repo" | Some (r, _) -> let rt = st.switch_repos in let repo = OpamRepositoryName.Map.find r rt.repositories in let stamp = OpamFile.Repo.stamp (OpamRepositoryName.Map.find r rt.repos_definitions) in OpamUrl.to_string repo.repo_url ^ OpamStd.Option.to_string (fun s -> "#"^s) stamp ] in OpamSystem.make_command ~env ~name ?dir ~text ~resolve_path:OpamStateConfig.(not !r.dryrun) ~metadata:["context", context] ~verbose:(OpamConsole.verbose ()) cmd args let remove_commands t nv = match installed_opam_opt t nv with | None -> log "No opam file was found for removing %a\n" (slog OpamPackage.to_string) nv; [] | Some opam -> OpamFilter.commands (OpamPackageVar.resolve ~opam t) (OpamFile.OPAM.remove opam) |> OpamStd.List.filter_map (function [] -> None | cmd::args -> Some (cmd,args)) (* Testing wether a package removal will be a NOOP. *) let noop_remove_package t nv = let name = nv.name in let has_remove_commands = remove_commands t nv <> [] in let has_tracked_files = let changes_file = OpamPath.Switch.changes t.switch_global.root t.switch name in match OpamFile.Changes.read_opt changes_file with | Some map -> not (OpamStd.String.Map.is_empty map) | None -> let install_file = OpamPath.Switch.install t.switch_global.root t.switch name in OpamFile.exists install_file in not (has_remove_commands || has_tracked_files) (* Remove a given package *) let remove_package_aux t ?(silent=false) ?changes ?force ?build_dir nv = log "Removing %a" (slog OpamPackage.to_string) nv; let name = nv.name in let root = t.switch_global.root in (* There are three uninstall stages: 1. execute the package's remove script 2. remove remaining files listed in the .install file 3. remove remaining files added in the changes file (or changes parameter) The 3. step alone could be sufficient, but: - changes only revert additions, not any file changes, so 1. is needed - the remove script might take extra actions (stop daemon...) - existing installs don't have .changes files yet - 1st and 2nd steps may help recover partial/failed states *) let dot_install = OpamPath.Switch.install root t.switch name in let changes_file = OpamPath.Switch.changes root t.switch name in let opam = match installed_opam_opt t nv with | Some o -> o | None -> OpamFile.OPAM.create nv in (* Remove the installed plugin, if it matches *) if OpamFile.OPAM.has_flag Pkgflag_Plugin opam then ( let link = OpamPath.plugin_bin root name in let bin = OpamFilename.create (OpamPath.Switch.bin root t.switch t.switch_config) (OpamFilename.basename link) in if OpamFilename.exists link && OpamFilename.readlink link = bin then OpamFilename.remove link ); (* handle .install file *) let uninstall_files () = let install = OpamFile.Dot_install.safe_read dot_install in let remove_files dst_fn files = let files = files install in let dst_dir = dst_fn root t.switch t.switch_config in List.iter (fun (base, dst) -> let dst_file = match dst with | None -> dst_dir // Filename.basename (OpamFilename.Base.to_string base.c) | Some b -> OpamFilename.create dst_dir b in OpamFilename.remove dst_file ) files in let remove_files_and_dir dst_fn files = let dir = dst_fn root t.switch t.switch_config name in remove_files (fun _ _ _ -> dir) files; if OpamFilename.rec_files dir = [] then OpamFilename.rmdir dir in log "Removing files from .install"; remove_files OpamPath.Switch.sbin OpamFile.Dot_install.sbin; remove_files OpamPath.Switch.bin OpamFile.Dot_install.bin; remove_files_and_dir OpamPath.Switch.lib OpamFile.Dot_install.libexec; remove_files_and_dir OpamPath.Switch.lib OpamFile.Dot_install.lib; remove_files OpamPath.Switch.stublibs OpamFile.Dot_install.stublibs; remove_files_and_dir OpamPath.Switch.share OpamFile.Dot_install.share; remove_files OpamPath.Switch.share_dir OpamFile.Dot_install.share_root; remove_files_and_dir OpamPath.Switch.etc OpamFile.Dot_install.etc; remove_files (OpamPath.Switch.man_dir ?num:None) OpamFile.Dot_install.man; remove_files_and_dir OpamPath.Switch.doc OpamFile.Dot_install.doc; (* Remove the misc files *) log "Removing the misc files"; List.iter (fun (_,dst) -> if OpamFilename.exists dst then begin OpamConsole.msg "Removing %s." (OpamFilename.to_string dst); if OpamConsole.confirm "Continue?" then OpamFilename.remove dst end ) (OpamFile.Dot_install.misc install); in let revert_changes () = let changes = match changes with | None -> OpamFile.Changes.read_opt changes_file | some -> some in let title = Printf.sprintf "While removing %s" (OpamPackage.to_string nv) in OpamStd.Option.iter (OpamDirTrack.revert ~title ~verbose:(not silent) ?force (OpamPath.Switch.root root t.switch)) changes in (* Run the remove script *) let build_dir = OpamStd.Option.default_map (OpamFilename.opt_dir (OpamPath.Switch.remove root t.switch nv)) build_dir in let wrappers = get_wrappers t in let mk_cmd = make_command t opam ?dir:build_dir in OpamProcess.Job.of_fun_list ~keep_going:true (List.map (fun cmd () -> mk_cmd cmd) (get_wrapper t opam wrappers OpamFile.Wrappers.pre_remove)) @@+ fun error_pre -> OpamProcess.Job.of_fun_list ~keep_going:true (List.map (fun ((cmd,args) as ca) () -> mk_cmd ~text_command:ca @@ cmd_wrapper t opam wrappers OpamFile.Wrappers.wrap_remove cmd args) (remove_commands t nv)) @@+ fun error -> (* Remove according to the .install file *) if not OpamStateConfig.(!r.dryrun) then ( OpamFilename.remove (OpamFile.filename (OpamPath.Switch.config root t.switch nv.name)); uninstall_files (); OpamFilename.remove (OpamFile.filename dot_install) ); (* Run the post-remove commands *) let local = opam_local_env_of_status OpamStd.Option.Op.(error_pre ++ error >>| snd) in OpamProcess.Job.of_fun_list ~keep_going:true (List.map (fun cmd () -> mk_cmd cmd) (get_wrapper t opam wrappers ~local OpamFile.Wrappers.post_remove)) @@+ fun error_post -> (* Revert remaining changes *) if not OpamStateConfig.(!r.dryrun) then ( revert_changes (); OpamFilename.remove (OpamFile.filename changes_file); ); if silent then Done () else match OpamStd.Option.Op.(error_pre ++ error ++ error_post) with | Some (cmd, e) -> OpamConsole.warning "package uninstall script failed at %s:\n%s" (OpamProcess.string_of_command cmd) (OpamProcess.string_of_result e); Done () | None -> OpamConsole.msg "%s removed %s.%s\n" (if not (OpamConsole.utf8 ()) then "->" else OpamActionGraph.(action_color (`Remove ()) (action_strings (`Remove ())))) (OpamConsole.colorise `bold (OpamPackage.name_to_string nv)) (OpamPackage.version_to_string nv); Done () (* Removes build dir and source cache of package if unneeded *) let cleanup_package_artefacts t nv = log "Cleaning up artefacts of %a" (slog OpamPackage.to_string) nv; let build_dir = OpamPath.Switch.build t.switch_global.root t.switch nv in if not OpamClientConfig.(!r.keep_build_dir) then OpamFilename.rmdir build_dir; let remove_dir = OpamPath.Switch.remove t.switch_global.root t.switch nv in if OpamFilename.exists_dir remove_dir then OpamFilename.rmdir remove_dir; let dev_dir = OpamSwitchState.source_dir t nv in if OpamPackage.Set.mem nv t.installed then (if not (OpamSwitchState.is_dev_package t nv) then OpamFilename.rmdir dev_dir) else (log "Removing the local metadata"; OpamSwitchAction.remove_metadata t (OpamPackage.Set.singleton nv); if not (OpamPackage.Set.mem nv t.pinned) then OpamFilename.rmdir dev_dir) let sources_needed st g = PackageActionGraph.fold_vertex (fun act acc -> match act with | `Remove nv -> if removal_needs_download st nv then OpamPackage.Set.add nv acc else acc | `Install nv -> OpamPackage.Set.add nv acc | _ -> assert false) g OpamPackage.Set.empty let remove_package t ?silent ?changes ?force ?build_dir nv = if OpamClientConfig.(!r.fake) || OpamClientConfig.(!r.show) then Done (OpamConsole.msg "Would remove: %s.\n" (OpamPackage.to_string nv)) else remove_package_aux t ?silent ?changes ?force ?build_dir nv let local_vars ~test ~doc = OpamVariable.Map.of_list [ OpamVariable.of_string "with-test", Some (B test); OpamVariable.of_string "with-doc", Some (B doc); ] let build_package t ?(test=false) ?(doc=false) build_dir nv = let opam = OpamSwitchState.opam t nv in let commands = OpamFilter.commands (OpamPackageVar.resolve ~opam ~local:(local_vars ~test ~doc) t) (OpamFile.OPAM.build opam) @ (if test then OpamFilter.commands (OpamPackageVar.resolve ~opam t) (OpamFile.OPAM.run_test opam) else []) @ (if doc then OpamFilter.commands (OpamPackageVar.resolve ~opam t) (OpamFile.OPAM.deprecated_build_doc opam) else []) |> OpamStd.List.filter_map (function | [] -> None | cmd::args -> Some (cmd, args)) in let name = OpamPackage.name_to_string nv in let wrappers = get_wrappers t in let mk_cmd = make_command t opam ~dir:build_dir in let jobs = let check_result cmd r = if OpamProcess.is_success r then Done None else Done (Some (cmd, r)) in List.map (fun cmd -> function | None -> let cmd = mk_cmd cmd in cmd @@> check_result cmd | some -> Done some) (get_wrapper t opam wrappers OpamFile.Wrappers.pre_build) @ List.map (fun ((cmd,args) as cmd_args) -> function | None -> let base_cmd = OpamProcess.command cmd args in (mk_cmd ~text_command:cmd_args @@ cmd_wrapper t opam wrappers OpamFile.Wrappers.wrap_build cmd args) @@> check_result base_cmd | some -> Done some) commands in OpamProcess.Job.seq jobs None @@+ fun result -> let local = opam_local_env_of_status OpamStd.Option.Op.(result >>| snd) in OpamProcess.Job.of_fun_list ~keep_going:true (List.map (fun cmd () -> mk_cmd cmd) (get_wrapper t opam wrappers ~local OpamFile.Wrappers.post_build)) @@+ fun post_result -> match result, post_result with | Some (cmd, result), _ | _, Some (cmd, result) -> OpamConsole.error "The compilation of %s failed at %S." (OpamPackage.to_string nv) (OpamProcess.string_of_command cmd); Done (Some (OpamSystem.Process_error result)) | None, None -> if commands <> [] && OpamConsole.verbose () then OpamConsole.msg "%s compiled %s.%s\n" (if not (OpamConsole.utf8 ()) then "->" else OpamActionGraph. (action_color (`Build ()) (action_strings (`Build ())))) (OpamConsole.colorise `bold name) (OpamPackage.version_to_string nv); Done None (* Assumes the package has already been compiled in its build dir. Does not register the installation in the metadata! *) let install_package t ?(test=false) ?(doc=false) ?build_dir nv = let opam = OpamSwitchState.opam t nv in let commands = OpamFile.OPAM.install opam |> OpamFilter.commands (OpamPackageVar.resolve ~opam ~local:(local_vars ~test ~doc) t) |> OpamStd.List.filter_map (function [] -> None | cmd::args -> Some (cmd, args)) in let name = OpamPackage.name_to_string nv in let dir = match build_dir with | None -> OpamPath.Switch.build t.switch_global.root t.switch nv | Some d -> d in let wrappers = get_wrappers t in let mk_cmd = make_command t opam ~dir in let rec run_commands = function | (cmd,args as ca)::commands -> mk_cmd ~text_command:ca (cmd_wrapper t opam wrappers OpamFile.Wrappers.wrap_install cmd args) @@> fun result -> if OpamFile.OPAM.has_flag Pkgflag_Verbose opam then List.iter (OpamConsole.msg "%s\n") result.OpamProcess.r_stdout; if OpamProcess.is_success result then run_commands commands else ( OpamConsole.error "The installation of %s failed at %S." name (String.concat " " (cmd::args)); Done (Some (OpamSystem.Process_error result)) ) | [] -> Done None in let root = t.switch_global.root in let switch_prefix = OpamPath.Switch.root root t.switch in let pre_install_wrappers = get_wrapper t opam wrappers OpamFile.Wrappers.pre_install in let pre_install () = (* let text = OpamProcess.make_command_text name "install" in * OpamProcess.Job.with_text text *) OpamProcess.Job.of_fun_list (List.map (fun cmd () -> mk_cmd cmd) pre_install_wrappers) in let install_job () = pre_install () @@+ function | Some (_, result) -> Done (Right (OpamSystem.Process_error result)) | None -> run_commands commands @@| function | Some e -> Right e | None -> try let _, process_dot_install, config = preprocess_dot_install t nv dir in process_dot_install (); Left config with e -> Right e in let install_and_track_job () = pre_install () @@+ function | Some (_, result) -> Done (Right (OpamSystem.Process_error result), OpamStd.String.Map.empty) | None -> let installed_files, process_dot_install, config = preprocess_dot_install t nv dir in OpamDirTrack.track_files ~prefix:switch_prefix installed_files (fun () -> process_dot_install () ; Done None) @@+ function | _, changes -> Done (Left config, changes) in let post_install status changes = let local = let added = let open OpamDirTrack in OpamStd.List.filter_map (function | name, (Added _|Contents_changed _|Kind_changed _) -> Some name | _ -> None) (OpamStd.String.Map.bindings changes) in opam_local_env_of_status (match status with | Right (OpamSystem.Process_error r) -> Some r | _ -> None) |> OpamVariable.Map.add (OpamVariable.of_string "installed-files") (Some (L added)) in let hooks = get_wrapper t opam wrappers ~local OpamFile.Wrappers.post_install in let has_hooks = match hooks with [] -> false | _ -> true in OpamProcess.Job.of_fun_list ~keep_going:true (List.map (fun cmd () -> mk_cmd cmd) hooks) @@+ fun error_post -> match status, error_post with | Right err, _ -> Done (Right err, changes) | _, Some (_cmd, r) -> Done (Right (OpamSystem.Process_error r), changes) | Left config, None -> let changes = if has_hooks then OpamDirTrack.update switch_prefix changes else changes in Done (Left config, changes) in let rel_meta_dir = OpamFilename.(Base.of_string (remove_prefix_dir switch_prefix (OpamPath.Switch.meta root t.switch))) in (if commands = [] && pre_install_wrappers = [] then install_and_track_job () else OpamDirTrack.track switch_prefix ~except:(OpamFilename.Base.Set.singleton rel_meta_dir) install_job) @@+ fun (status, changes) -> post_install status changes @@+ function | Right e, changes -> remove_package t ~silent:true ~changes ~build_dir:dir nv @@+ fun () -> OpamStd.Exn.fatal e; Done (Right e) | Left config, changes -> let changes_f = OpamPath.Switch.changes root t.switch nv.name in OpamFile.Changes.write changes_f changes; OpamConsole.msg "%s installed %s.%s\n" (if not (OpamConsole.utf8 ()) then "->" else OpamActionGraph. (action_color (`Install ()) (action_strings (`Install ())))) (OpamConsole.colorise `bold name) (OpamPackage.version_to_string nv); if OpamFile.OPAM.has_flag Pkgflag_Plugin opam then ( let link = OpamPath.plugin_bin root (OpamPackage.name nv) in let target = OpamFilename.create (OpamPath.Switch.bin root t.switch t.switch_config) (OpamFilename.basename link) in if OpamFilename.exists target then OpamFilename.link ~relative:(not (OpamSwitch.is_external t.switch)) ~target ~link else OpamConsole.warning "%s claims to be a plugin but no %s file was found" name (OpamFilename.to_string target) ); Done (Left config) opam-2.1.5/src/client/opamRepositoryCommand.mli0000644000175000017500000000475714427463453020637 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Functions handling the "opam repository" subcommand *) open OpamTypes open OpamStateTypes (** List the selected repositories in the global default and/or selected switches. *) val list: 'a repos_state -> global:bool -> switches:switch list -> short:bool -> unit (** Lists all configured repositories, and, if not [short], the switches they are selected in. *) val list_all: 'a repos_state -> short:bool -> unit (** Add a new repository to ~/.opam/repos, without updating any selections *) val add: rw repos_state -> repository_name -> url -> trust_anchors option -> rw repos_state (** Remove a repository from ~/.opam/repos, without updating any selections *) val remove: rw repos_state -> repository_name -> rw repos_state (** Updates the global switch selection, used as default for switches that don't specify their selections (e.g. newly created switches) *) val update_global_selection: rw global_state -> (repository_name list -> repository_name list) -> rw global_state (** Updates the specified selections using the given functions, taking locks as required *) val update_selection: 'a global_state -> global:bool -> switches:switch list -> (repository_name list -> repository_name list) -> 'a global_state (** Change the registered address of a repo *) val set_url: rw repos_state -> repository_name -> url -> trust_anchors option -> rw repos_state (** Update the given repositories, as per [OpamUpdate.repositories], checks for their version and runs the upgrade script locally if they are for an earlier opam. Returns list of repositories that failed and the new repository state. *) val update_with_auto_upgrade: rw repos_state -> repository_name list -> repository_name list * rw repos_state opam-2.1.5/src/client/opamAuxCommands.ml0000644000175000017500000005102114427463453017211 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2017-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamStateTypes let log fmt = OpamConsole.log "AUXCMD" fmt let slog = OpamConsole.slog let package_file_changes st packages = OpamPackage.Set.fold (fun nv acc -> let f = OpamPath.Switch.changes st.switch_global.root st.switch nv.name in match OpamFile.Changes.read_opt f with | None -> acc | Some ch -> OpamStd.String.Map.union (fun _ x -> x) acc ch) packages OpamStd.String.Map.empty let copy_files_to_destdir st pfx packages = let switch_pfx = OpamPath.Switch.root st.switch_global.root st.switch in package_file_changes st packages |> OpamDirTrack.check switch_pfx |> List.iter @@ function | src, `Unchanged -> let relf = OpamFilename.remove_prefix switch_pfx src in let dst = OpamFilename.Op.(pfx // relf) in if OpamConsole.verbose () then OpamConsole.msg "%-40s %s %s\n" relf (OpamConsole.colorise `blue "=>") (OpamFilename.to_string dst); if not OpamStateConfig.(!r.dryrun) then if OpamFilename.exists src then OpamFilename.copy ~src ~dst else let as_dir f = OpamFilename.(Dir.of_string (to_string f)) in if OpamFilename.exists_dir (as_dir src) then OpamFilename.mkdir (as_dir dst) | src, (`Changed | `Removed as ch) -> OpamConsole.warning "Not installing %s, which was %s since" (OpamConsole.colorise `bold (OpamFilename.to_string src)) (match ch with `Changed -> "changed" | `Removed -> "removed") let remove_files_from_destdir st pfx packages = package_file_changes st packages |> OpamStd.String.Map.bindings |> List.rev |> (* Get the longer names first, their parent folders last *) List.iter @@ fun (rel_file, change) -> match change with | OpamDirTrack.Added _ | OpamDirTrack.Contents_changed _ | OpamDirTrack.Kind_changed _ -> let f = OpamFilename.Op.(pfx // rel_file) in let d = OpamFilename.Op.(pfx / rel_file) in if OpamFilename.exists f then (if OpamConsole.verbose () then OpamConsole.msg "Removing %s\n" (OpamConsole.colorise `bold (OpamFilename.to_string f)); if not OpamStateConfig.(!r.dryrun) then OpamFilename.remove f) else if OpamFilename.exists_dir d then if OpamFilename.dir_is_empty d then (if OpamConsole.verbose () then OpamConsole.msg "Removing %s\n" (OpamConsole.colorise `bold (OpamFilename.Dir.to_string d)); if not OpamStateConfig.(!r.dryrun) then OpamFilename.rmdir d) else OpamConsole.note "Not removing non-empty directory %s" (OpamConsole.colorise `bold (OpamFilename.Dir.to_string d)) | _ -> () let name_from_project_dirname d = try Some (OpamFilename.(Base.to_string (basename_dir d)) |> Re.(replace_string (compile (seq [char '.'; any]))) ~by:"" |> OpamPackage.Name.of_string) with Failure _ -> None let url_with_local_branch = function | { OpamUrl.backend = #OpamUrl.version_control; hash = None; _ } as url -> (match OpamProcess.Job.run (OpamRepository.current_branch url) with | Some b -> { url with OpamUrl.hash = Some b } | None -> url) | url -> url let opams_of_dir ?recurse ?subpath d = let files = OpamPinned.files_in_source ?recurse ?subpath d in List.fold_left (fun acc (n, f, subp) -> let name = let open OpamStd.Option.Op in n >>+ fun () -> OpamFile.OPAM.(name_opt (safe_read f)) >>+ fun () -> match files with | [] | _::_::_ -> None | [_] -> name_from_project_dirname d in match name with | Some n -> (n, f, subp) :: acc | None -> OpamConsole.warning "Ignoring file at %s: could not infer package name" (OpamFile.to_string f); acc) [] files let opams_of_dir_w_target ?(recurse=false) ?subpath ?(same_kind=fun _ -> OpamClientConfig.(!r.pin_kind_auto)) url dir = OpamStd.List.filter_map (fun (name, file, subp) -> let url = match url.OpamUrl.backend with | #OpamUrl.version_control as vc -> let module VCS = (val match vc with | `git -> (module OpamGit.VCS: OpamVCS.VCS) | `hg -> (module OpamHg.VCS: OpamVCS.VCS) | `darcs -> (module OpamDarcs.VCS: OpamVCS.VCS) : OpamVCS.VCS) in let open OpamProcess.Job.Op in let versioned_files = OpamProcess.Job.run @@ VCS.versioned_files dir @@| fun files -> files in let opamfile = OpamFilename.remove_prefix dir (OpamFile.filename file) in if List.mem opamfile versioned_files || not (OpamStd.String.contains opamfile ~sub:Filename.dir_sep) then url else { url with transport = "file"; hash = None; backend = `rsync } | _ -> url in if same_kind url then Some (name, file, url, subp) else None) (opams_of_dir ~recurse ?subpath dir) let name_and_dir_of_opam_file f = let srcdir = OpamFilename.dirname f in let srcdir = if OpamFilename.dir_ends_with ".opam" srcdir && OpamUrl.guess_version_control (OpamFilename.Dir.to_string srcdir) = None then OpamFilename.dirname_dir srcdir else srcdir in let name = let open OpamStd.Option.Op in OpamPinned.name_of_opam_filename srcdir f >>+ fun () -> OpamFile.OPAM.(name_opt (safe_read (OpamFile.make f))) >>+ fun () -> name_from_project_dirname srcdir in name, srcdir let resolve_locals_pinned st ?(recurse=false) ?subpath atom_or_local_list = let pinned_packages_of_dir st dir = OpamPackage.Set.filter (fun nv -> let open OpamStd.Option.Op in match subpath with | Some sp -> let dir_sp = OpamFilename.Op.(dir / sp) in let url_sp_dir = OpamSwitchState.primary_url_with_subpath st nv >>= OpamUrl.local_dir in if recurse then (url_sp_dir >>| OpamFilename.dir_starts_with dir_sp) +! false else url_sp_dir = Some dir_sp | None -> if recurse then (OpamSwitchState.primary_url st nv >>= OpamUrl.local_dir) = Some dir else (OpamSwitchState.primary_url_with_subpath st nv >>= OpamUrl.local_dir) = Some dir ) st.pinned in let atoms = List.fold_left (fun acc -> function | `Atom a -> a::acc | `Dirname d -> let pkgs = pinned_packages_of_dir st d in if OpamPackage.Set.is_empty pkgs then OpamConsole.warning "No pinned packages found at %s" (OpamFilename.Dir.to_string d); List.rev_append (OpamSolution.atoms_of_packages pkgs) acc | `Filename f -> OpamConsole.error_and_exit `Bad_arguments "This command doesn't support specifying a file name (%S)" (OpamFilename.to_string f)) [] atom_or_local_list in List.rev atoms let resolve_locals ?(quiet=false) ?recurse ?subpath atom_or_local_list = let target_dir dir = let d = OpamFilename.Dir.to_string dir in let backend = OpamUrl.guess_version_control d in OpamUrl.parse ?backend ~from_file:false d |> url_with_local_branch in let to_pin, atoms = List.fold_left (fun (to_pin, atoms) -> function | `Atom a -> to_pin, a :: atoms | `Dirname d -> let target = target_dir d in let names_files = opams_of_dir_w_target ?recurse ?subpath target d in if names_files = [] && not quiet then OpamConsole.warning "No package definitions found at %s" (OpamFilename.Dir.to_string d); let to_pin = List.map (fun (n,f,u,b) -> n, u, b, f) names_files @ to_pin in let atoms = List.map (fun (n,_,_,_) -> n, None) names_files @ atoms in to_pin, atoms | `Filename f -> match name_and_dir_of_opam_file f with | Some n, srcdir -> (n, target_dir srcdir, None, OpamFile.make f) :: to_pin, (n, None) :: atoms | None, _ -> OpamConsole.error_and_exit `Not_found "Could not infer package name from package definition file %s" (OpamFilename.to_string f)) ([], []) atom_or_local_list in let duplicates = List.filter (fun (n, _, _, f) -> List.exists (fun (n1, _, _, f1) -> n = n1 && f <> f1) to_pin) to_pin in match duplicates with | [] -> List.rev to_pin, List.rev atoms | _ -> OpamConsole.error_and_exit `Bad_arguments "Multiple files for the same package name were specified:\n%s" (OpamStd.Format.itemize (fun (n, t, _, f) -> Printf.sprintf "Package %s with definition %s %s %s" (OpamConsole.colorise `bold @@ OpamPackage.Name.to_string n) (OpamFile.to_string f) (OpamConsole.colorise `blue "=>") (OpamUrl.to_string t)) duplicates) let autopin_aux st ?quiet ?(for_view=false) ?recurse ?subpath atom_or_local_list = let to_pin, atoms = resolve_locals ?quiet ?recurse ?subpath atom_or_local_list in if to_pin = [] then atoms, to_pin, OpamPackage.Set.empty, OpamPackage.Set.empty else let pinning_dirs = OpamStd.List.filter_map (function | `Dirname d -> (match subpath with | Some s -> Some OpamFilename.Op.(d/s) | None -> Some d) | _ -> None) atom_or_local_list in log "autopin: %a" (slog @@ OpamStd.List.to_string (fun (name, target, subpath, _) -> Printf.sprintf "%s => %s%s" (OpamPackage.Name.to_string name) (OpamUrl.to_string target) (match subpath with None -> "" | Some s -> " ("^s^")"))) to_pin; let obsolete_pins = (* Packages not current but pinned to the same dirs *) OpamPackage.Set.filter (fun nv -> not (List.exists (fun (n,_,_,_) -> n = nv.name) to_pin) && let primary_url = if recurse = Some true then OpamSwitchState.primary_url else OpamSwitchState.primary_url_with_subpath in match OpamStd.Option.Op.( primary_url st nv >>= OpamUrl.local_dir) with | Some d -> List.mem d pinning_dirs | None -> false) st.pinned in let already_pinned, to_pin = List.partition (fun (name, target, _, opam) -> try (* check of the target to avoid repin of pin to update with `opam install .` and loose edited opams *) let pinned_pkg = OpamPinned.package st name in OpamSwitchState.primary_url st pinned_pkg = Some target && (* For `opam show`, we need to check does the opam file changed to perform a simulated pin if so *) (not for_view || match OpamSwitchState.opam_opt st pinned_pkg, OpamFile.OPAM.read_opt opam with | Some opam0, Some opam -> OpamFile.OPAM.equal opam0 opam | _, _ -> false) with Not_found -> false) to_pin in let already_pinned_set = List.fold_left (fun acc (name, _, _, _) -> OpamPackage.Set.add (OpamPinned.package st name) acc) OpamPackage.Set.empty already_pinned in atoms, to_pin, obsolete_pins, already_pinned_set let simulate_local_pinnings ?quiet ?(for_view=false) st to_pin = assert (not (for_view && OpamSystem.get_lock_flag st.switch_lock = `Lock_write)); let local_names = List.fold_left (fun set (name, _, _, _) -> OpamPackage.Name.Set.add name set) OpamPackage.Name.Set.empty to_pin in let local_opams = List.fold_left (fun map (name, target, subpath, file) -> match OpamPinCommand.read_opam_file_for_pinning ?quiet name file target with | None -> map | Some opam -> let opam = OpamFile.OPAM.with_name name opam in let opam = if for_view then opam else OpamFile.OPAM.with_url (OpamFile.URL.create ?subpath target) opam in let opam, version = match OpamFile.OPAM.version_opt opam with | Some v -> opam, v | None -> let v = OpamPinCommand.default_version st name in OpamFile.OPAM.with_version v opam, v in OpamPackage.Map.add (OpamPackage.create name version) opam map) OpamPackage.Map.empty to_pin in let local_packages = OpamPackage.keys local_opams in let pinned = if for_view then (* For `opam show`, to display local files instead of the stored on, we need to have on the pinned set only the new simulated pinned ones instead of really pinned ones. *) let open OpamPackage.Set.Op in st.pinned -- OpamPackage.packages_of_names st.pinned (OpamPackage.names_of_packages local_packages) ++ local_packages else st.pinned in let st = { st with opams = OpamPackage.Map.union (fun _ o -> o) st.opams local_opams; packages = OpamPackage.Set.union st.packages local_packages; available_packages = lazy ( OpamPackage.Set.union (OpamPackage.Set.filter (fun nv -> not (OpamPackage.Name.Set.mem nv.name local_names)) (Lazy.force st.available_packages)) (OpamSwitchState.compute_available_packages st.switch_global st.switch st.switch_config ~pinned:st.pinned ~opams:local_opams) ); pinned; } in st, local_packages let simulate_autopin st ?quiet ?(for_view=false) ?recurse ?subpath atom_or_local_list = let atoms, to_pin, obsolete_pins, already_pinned_set = autopin_aux st ?quiet ~for_view ?recurse ?subpath atom_or_local_list in if to_pin = [] then st, atoms else let st = OpamPackage.Set.fold (fun nv st -> OpamPinCommand.unpin_one st nv) obsolete_pins st in let st, pins = simulate_local_pinnings ?quiet ~for_view st to_pin in if not for_view then (let pins = OpamPackage.Set.union pins already_pinned_set in let pin_depends = OpamPackage.Set.fold (fun nv acc -> List.fold_left (fun acc (nv,target) -> OpamPackage.Map.add nv target acc) acc (OpamFile.OPAM.pin_depends (OpamSwitchState.opam st nv))) pins OpamPackage.Map.empty in if not (OpamPackage.Map.is_empty pin_depends) then (OpamConsole.msg "Would pin the following:\n%s" (OpamStd.Format.itemize (fun (nv, url) -> Printf.sprintf "%s to %s" (OpamConsole.colorise `bold (OpamPackage.to_string nv)) (OpamConsole.colorise `underline (OpamUrl.to_string url))) (OpamPackage.Map.bindings pin_depends)); OpamConsole.note "The following may not reflect the above pinnings (their \ package definitions are not available at this stage)"; OpamConsole.msg "\n")); st, atoms let autopin st ?(simulate=false) ?quiet ?recurse ?subpath atom_or_local_list = if OpamStateConfig.(!r.dryrun) || OpamClientConfig.(!r.show) then simulate_autopin st ?quiet atom_or_local_list else let atoms, to_pin, obsolete_pins, already_pinned_set = autopin_aux st ?quiet ?recurse ?subpath atom_or_local_list in if to_pin = [] && OpamPackage.Set.is_empty obsolete_pins && OpamPackage.Set.is_empty already_pinned_set then st, atoms else let st = if simulate then OpamPackage.Set.fold (fun nv st -> OpamPinCommand.unpin_one st nv) obsolete_pins st else OpamPinCommand.unpin st (OpamPackage.Name.Set.elements (OpamPackage.names_of_packages obsolete_pins)) in let already_pinned_diff_url = (* is pinned but no in already pinned because not same url *) List.fold_left (fun set (n,_,_,_) -> match OpamStd.Option.map (fun nv -> OpamPackage.Set.mem nv already_pinned_set) (OpamPinned.package_opt st n) with | Some false -> OpamPackage.Name.Set.add n set | _ -> set ) OpamPackage.Name.Set.empty to_pin in let st, pins = if simulate then simulate_local_pinnings ?quiet st to_pin else try List.fold_left (fun (st, pins) (name, target, subpath, file) -> match OpamPinCommand.read_opam_file_for_pinning ?quiet name file target with | None -> st, pins | Some opam -> let st = try OpamPinCommand.source_pin st name ~quiet:true ~opam ?subpath (Some target) with OpamPinCommand.Nothing_to_do -> st in st, OpamPackage.Set.add (OpamPinned.package st name) pins) (st, OpamPackage.Set.empty) to_pin with OpamPinCommand.Aborted -> OpamStd.Sys.exit_because `Aborted in let _result, st, _updated = let already_pinned = OpamPackage.Set.union already_pinned_set (OpamPackage.packages_of_names pins already_pinned_diff_url) in if OpamClientConfig.(!r.working_dir || !r.inplace_build) then OpamUpdate.dev_packages st ~working_dir:pins pins else OpamUpdate.dev_packages st ~working_dir:OpamPackage.Set.empty already_pinned in let st = if OpamClientConfig.(!r.ignore_pin_depends) then st else OpamPackage.Set.fold (fun nv st -> OpamPinCommand.handle_pin_depends st nv (OpamSwitchState.opam st nv)) (OpamPackage.Set.union pins already_pinned_set) st in st, atoms let check_and_revert_sandboxing root config = let sdbx_wrappers = let w = OpamFile.Config.wrappers config in let init_sdbx_cmds = List.map (function `build cmd | `install cmd | `remove cmd -> cmd) OpamInitDefaults.sandbox_wrappers |> List.flatten in List.filter (fun cmd -> List.mem cmd init_sdbx_cmds) OpamFile.Wrappers.(wrap_build w @ wrap_install w @ wrap_remove w) in let env = fun v -> let fv = OpamVariable.Full.variable v in match OpamVariable.Map.find_opt fv (OpamEnv.hook_env root) with | Some c -> c | None -> OpamStd.Option.Op.(OpamStd.Option.of_Not_found (List.assoc fv) OpamSysPoll.variables >>= Lazy.force) in match OpamFilter.commands env sdbx_wrappers with | [] -> config | cmd::_ -> (* All the provided sandboxing scripts are expected to define [TMPDIR] *) let test_file = "$TMPDIR/opam-sandbox-check-out" in let test_cmd = [ "sh"; "-c"; Printf.sprintf "echo SUCCESS >%s && cat %s; rm -f %s" test_file test_file test_file ] in let working_or_noop = let env = Array.append [| "OPAM_SWITCH_PREFIX=/dev/null" |] (Unix.environment ()) in try (* Don't assume that we can mount the CWD *) OpamSystem.in_tmp_dir @@ fun () -> OpamSystem.read_command_output ~env ~allow_stdin:false (cmd @ test_cmd) = ["SUCCESS"] with e -> (OpamConsole.error "Sandboxing is not working on your platform%s:\n%s" (OpamStd.Option.to_string (fun os -> " "^os) (OpamSysPoll.os_distribution ())) (Printexc.to_string e); not (OpamConsole.confirm ~default:false "Do you want to disable it? Note that this will result in \ less secure package builds, so please ensure that you have \ some other isolation mechanisms in place (such as running \ within a container or virtual machine).")) in if working_or_noop then config else let wrappers = let filter sdbx_cmd = List.filter (fun cmd_l -> not (List.mem cmd_l sdbx_cmd)) in List.fold_left OpamFile.Wrappers.(fun w -> function | `build sdbx_build -> { w with wrap_build = filter sdbx_build w.wrap_build } | `install sdbx_install -> { w with wrap_install = filter sdbx_install w.wrap_install } | `remove sdbx_remove -> { w with wrap_remove = filter sdbx_remove w.wrap_remove }) (OpamFile.Config.wrappers config) OpamInitDefaults.sandbox_wrappers in OpamFile.Config.with_wrappers wrappers config opam-2.1.5/src/client/opamInitDefaults.mli0000644000175000017500000000253514427463453017544 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2016-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** This module defines a few defaults, used at 'opam init', that bind opam to its default OCaml repository at https://opam.ocaml.org. All can be overridden through the init command flags or an init config file. *) open OpamTypes (** Url of the default Opam repository *) val repository_url: url val default_compiler: formula val eval_variables: (OpamVariable.t * string list * string) list val sandbox_wrappers: [> `build of command list | `install of command list | `remove of command list ] list (** Default initial configuration file for use by [opam init] if nothing is supplied. *) val init_config: ?sandboxing:bool -> unit -> OpamFile.InitConfig.t opam-2.1.5/src/client/opamMain.ml0000644000175000017500000000144014427463453015656 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) let () = OpamCliMain.main () opam-2.1.5/src/client/opamCliMain.ml0000644000175000017500000004526514427463453016323 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open Cmdliner open OpamTypes open OpamStateTypes open OpamTypesBase open OpamStd.Op exception InvalidCLI of OpamCLIVersion.Sourced.t (* [InvalidFlagContent (flag_name, Some (invalid_value, expected_value))] *) exception InvalidFlagContent of string * (string * string) option (* [InvalidNewFlag (requested_cli, flag_name, flag_valid_since)] *) exception InvalidNewFlag of OpamCLIVersion.Sourced.t * string * OpamCLIVersion.t let raise_invalid_cli : (OpamCLIVersion.Sourced.t, string option) OpamCompat.Result.t -> 'a = function | Ok ocli -> raise (InvalidCLI ocli) | Error None -> raise (InvalidFlagContent ("cli", None)) | Error (Some invalid) -> raise (InvalidFlagContent ("cli", Some (invalid, "major.minor"))) let raise_invalid_confirm_level invalid = let invalid = OpamStd.Option.map (fun i -> i, "one of " ^ (OpamArg.confirm_enum |> List.map (fun (_,s,_) -> Printf.sprintf "`%s'" s) |> OpamStd.Format.pretty_list ~last:"or")) invalid in raise (InvalidFlagContent ("confirm-level", invalid)) (* Filter and parse "--cli=v" or "--cli v" options *) let rec filter_cli_arg cli acc args = match args with | [] | "--" :: _ -> (cli, List.rev_append acc args) | "--cl" :: args -> filter_cli_arg cli acc ("--cli"::args) | ["--cli"] | "--cli" :: "--" :: _ -> raise_invalid_cli (Error None) | "--cli" :: arg :: args -> let version = match OpamCLIVersion.of_string_opt arg with | Some cli -> let ocli = cli, `Command_line in if OpamCLIVersion.is_supported cli then ocli else raise_invalid_cli (Ok ocli) | None -> raise_invalid_cli (Error (Some arg)) in filter_cli_arg (Some version) acc args | arg :: args -> match OpamStd.String.cut_at arg '=' with | Some ("--cl", value) | Some ("--cli", value) -> filter_cli_arg cli acc ("--cli"::value::args) | _ -> filter_cli_arg cli (arg::acc) args let is_confirm_level = OpamStd.String.is_prefix_of ~from:4 ~full:"--confirm-level" (* Pre-process argv processing the --yes, --confirm-level, and --cli. Returns Some cli, if --cli was encountered, a boolean indicating if --yes/-y and the list of arguments to continue with processing. *) let rec preprocess_argv cli yes_args confirm args = let yes = yes_args <> [] in match args with | [] -> (cli, yes, confirm, yes_args) | "--" :: _ -> (cli, yes, confirm, yes_args @ args) (* Note that because this is evaluated before a sub-command, all the prefixes of --yes are assumed to valid at all times. *) | ("-y" | "--y" | "--ye" | "--yes") as yes_opt :: args -> preprocess_argv cli [yes_opt] confirm args | ([c] | c :: "--" :: _) when is_confirm_level c -> raise_invalid_confirm_level None | confirm_level :: cl_arg :: args when is_confirm_level confirm_level -> let answer = match OpamStd.List.find_opt (fun (_,n,_) -> n = cl_arg) OpamArg.confirm_enum with | Some (_, _, a) -> a | None -> raise_invalid_confirm_level (Some cl_arg) in preprocess_argv cli yes_args (Some answer) args | "--cl" :: args -> preprocess_argv cli yes_args confirm ("--cli"::args) | ["--cli"] | "--cli" :: "--" :: _ -> raise_invalid_cli (Error None) | "--cli" :: arg :: args -> let version = match OpamCLIVersion.of_string_opt arg with | Some cli -> let ocli = cli, `Command_line in if OpamCLIVersion.is_supported cli then ocli else raise_invalid_cli (Ok ocli) | _ -> raise_invalid_cli (Error (Some arg)) in preprocess_argv (Some version) yes_args confirm args | arg :: rest -> match OpamStd.String.cut_at arg '=' with | Some ("--cl", value) | Some ("--cli", value) -> preprocess_argv cli yes_args confirm ("--cli"::value::rest) | Some (pre, value) when is_confirm_level pre -> preprocess_argv cli yes_args confirm ("--confirm-level"::value::rest) | _ -> if OpamCommands.is_builtin_command arg then let (cli, rest) = filter_cli_arg cli [] rest in (cli, yes, confirm, arg :: (yes_args @ rest)) else (cli, yes, confirm, args) (* Handle git-like plugins *) let check_and_run_external_commands () = (* Pre-process the --yes and --cli options *) let (cli, yes, confirm_level, argv) = match Array.to_list Sys.argv with | prog::args -> let (ocli, yes, confirm, args) = preprocess_argv None [] None args in let ocli = match ocli with | Some ((cli, _) as ocli) -> if OpamCLIVersion.(cli < (2, 1)) then begin let cli = OpamCLIVersion.to_string cli in OpamConsole.warning "%s cannot be understood by opam %s; set %s to %s instead." (OpamConsole.colorise `bold ("--cli=" ^ cli)) cli (OpamConsole.colorise `bold "OPAMCLI") (OpamConsole.colorise `bold cli) end; ocli | None -> match OpamCLIVersion.Sourced.env (OpamClientConfig.E.cli ()) with | Some ((cli, _) as ocli) -> if OpamCLIVersion.is_supported cli then let () = if OpamCLIVersion.(cli >= (2, 1)) then let flag = "--cli=" ^ OpamCLIVersion.(to_string cli) in OpamConsole.warning "OPAMCLI should only ever be set to %s - use '%s' instead." (OpamConsole.colorise `bold "2.0") (OpamConsole.colorise `bold flag) in ocli else raise_invalid_cli (Ok ocli) | None -> OpamCLIVersion.Sourced.current in let confirm = (* hardcoded cli validation *) match confirm with | Some _ when OpamCLIVersion.(fst ocli < (2,1)) -> raise (InvalidNewFlag (ocli, "confirm-level", OpamCLIVersion.of_string "2.1")) | _ -> confirm in (ocli, yes, confirm, prog::args) | args -> (OpamCLIVersion.Sourced.current, false, None, args) in match argv with | [] | [_] -> (cli, argv) | _ :: name :: args -> if String.length name > 0 && name.[0] = '-' || OpamCommands.is_builtin_command name then (cli, argv) else (* No such command, check if there is a matching plugin *) let command = OpamPath.plugin_prefix ^ name in OpamArg.init_opam_env_variabes cli; (* `--no` is not taken into account, only `--yes/--confirm-lzvel` are preprocessed *) let yes = if yes then Some (Some true) else None in OpamCoreConfig.init ?yes ?confirm_level (); OpamFormatConfig.init (); let root_dir = OpamStateConfig.opamroot () in let has_init, root_upgraded = match OpamStateConfig.load_defaults ~lock_kind:`Lock_read root_dir with | None -> (false, false) | Some config -> let root_upgraded = let cmp = OpamVersion.compare OpamFile.Config.root_version (OpamFile.Config.opam_root_version config) in if cmp < 0 then OpamConsole.error_and_exit `Configuration_error "%s reports a newer opam version, aborting." (OpamFilename.Dir.to_string root_dir) else cmp = 0 in (true, root_upgraded) in let plugins_bin = OpamPath.plugins_bin root_dir in let plugin_symlink_present = OpamFilename.is_symlink (OpamPath.plugin_bin root_dir (OpamPackage.Name.of_string name)) in let env = if has_init then let updates = ["PATH", OpamParserTypes.PlusEq, OpamFilename.Dir.to_string plugins_bin, None] in OpamStateConfig.init ~root_dir (); match OpamStateConfig.get_switch_opt () with | None -> env_array (OpamEnv.get_pure ~updates ()) | Some sw -> env_array (OpamEnv.full_with_path ~force_path:false ~updates root_dir sw) else Unix.environment () in match OpamSystem.resolve_command ~env command with | Some command when plugin_symlink_present && root_upgraded -> let argv = Array.of_list (command :: args) in raise (OpamStd.Sys.Exec (command, argv, env)) | None when not has_init -> (cli, argv) | cmd -> (* Look for a corresponding package *) match OpamStateConfig.get_switch_opt () with | None -> (cli, argv) | Some sw -> OpamGlobalState.with_ `Lock_none @@ fun gt -> OpamSwitchState.with_ `Lock_none gt ~switch:sw @@ fun st -> let prefixed_name = OpamPath.plugin_prefix ^ name in let candidates = OpamPackage.packages_of_names (Lazy.force st.available_packages) (OpamPackage.Name.Set.of_list @@ (OpamStd.List.filter_map (fun s -> try Some (OpamPackage.Name.of_string s) with Failure _ -> None) [ prefixed_name; name ])) in let plugins = OpamPackage.Set.filter (fun nv -> OpamFile.OPAM.has_flag Pkgflag_Plugin (OpamSwitchState.opam st nv)) candidates in let installed = OpamPackage.Set.inter plugins st.installed in if OpamPackage.Set.is_empty candidates then (cli, argv) else if not OpamPackage.Set.(is_empty installed) && cmd = None then (OpamConsole.error "Plugin %s is already installed, but no %s command was found.\n\ Try upgrading, and report to the package maintainer if \ the problem persists." (OpamPackage.to_string (OpamPackage.Set.choose installed)) command; exit (OpamStd.Sys.get_exit_code `Package_operation_error)) else if OpamPackage.Set.is_empty plugins then (OpamConsole.error "%s is not a known command or plugin (package %s does \ not have the 'plugin' flag set)." name (OpamPackage.to_string (OpamPackage.Set.max_elt candidates)); exit (OpamStd.Sys.get_exit_code `Bad_arguments)) else if (if cmd = None then OpamConsole.confirm "Opam plugin \"%s\" is not installed. \ Install it on the current switch?" else OpamConsole.confirm "Opam plugin \"%s\" may require upgrading/reinstalling. \ Reinstall the plugin on the current switch?") name then let nv = try (* If the command was resolved, attempt to find the package to reinstall. *) if cmd = None then raise Not_found else OpamPackage.package_of_name installed (OpamPackage.Name.of_string prefixed_name) with Not_found -> try OpamPackage.max_version plugins (OpamPackage.Name.of_string prefixed_name) with Not_found -> OpamPackage.max_version plugins (OpamPackage.Name.of_string name) in OpamRepositoryConfig.init (); OpamSolverConfig.init (); OpamClientConfig.init (); OpamSwitchState.with_ `Lock_write gt (fun st -> OpamSwitchState.drop @@ ( if cmd = None then OpamClient.install st [OpamSolution.eq_atom_of_package nv] else if root_upgraded then OpamClient.reinstall st [OpamSolution.eq_atom_of_package nv] else OpamClient.upgrade st ~all:false [OpamSolution.eq_atom_of_package nv]) ); match OpamSystem.resolve_command ~env command with | None -> OpamConsole.error_and_exit `Package_operation_error "Plugin %s was installed, but no %s command was found.\n\ This is probably an error in the plugin package." (OpamPackage.to_string nv) command | Some command -> OpamConsole.header_msg "Carrying on to \"%s\"" (String.concat " " (Array.to_list Sys.argv)); OpamConsole.msg "\n"; let argv = Array.of_list (command :: args) in raise (OpamStd.Sys.Exec (command, argv, env)) else (cli, argv) let display_cli_error msg = Format.eprintf "@[opam: @[%a@]@,@[Usage: @[opam COMMAND ...@]@]@,\ Try `opam --help' for more information.@]@." Format.pp_print_text msg let display_cli_error fmt = Format.ksprintf display_cli_error fmt let rec main_catch_all f = try f () with | OpamStd.Sys.Exit 0 -> () | OpamStd.Sys.Exec (cmd,args,env) -> OpamStd.Sys.exec_at_exit (); if Sys.win32 then OpamProcess.create_process_env cmd args env Unix.stdin Unix.stdout Unix.stderr |> Unix.waitpid [] |> function | _, Unix.WEXITED n -> exit n | _, (Unix.WSIGNALED n | Unix.WSTOPPED n) -> exit (128 - n) (* This is not how you should handle `WSTOPPED` ; but it doesn't happen on Windows anyway. *) else Unix.execvpe cmd args env | OpamFormatUpgrade.Upgrade_done (conf, reinit) -> main_catch_all @@ fun () -> OpamConsole.header_msg "Rerunning init and update"; (match reinit with | Some reinit -> reinit conf; OpamConsole.msg "Update done.\n"; exit (OpamStd.Sys.get_exit_code `Success) | None -> OpamClient.reinit ~interactive:true ~update_config:false ~bypass_checks:true conf (OpamStd.Sys.guess_shell_compat ()); OpamConsole.msg "Update done, please now retry your command.\n"; exit (OpamStd.Sys.get_exit_code `Aborted)) | e -> flush stdout; flush stderr; if (OpamConsole.verbose ()) then OpamConsole.errmsg "'%s' failed.\n" (String.concat " " (Array.to_list Sys.argv)); let exit_code = match e with | OpamStd.Sys.Exit i -> if (OpamConsole.debug ()) && i <> 0 then OpamConsole.errmsg "%s" (OpamStd.Exn.pretty_backtrace e); i | OpamSystem.Internal_error _ -> OpamConsole.errmsg "%s\n" (Printexc.to_string e); OpamStd.Sys.get_exit_code `Internal_error | OpamSystem.Process_error result -> OpamConsole.errmsg "%s Command %S failed:\n%s\n" (OpamConsole.colorise `red "[ERROR]") (try List.assoc "command" result.OpamProcess.r_info with | Not_found -> "") (Printexc.to_string e); OpamConsole.errmsg "%s" (OpamStd.Exn.pretty_backtrace e); OpamStd.Sys.get_exit_code `Internal_error | Sys.Break | OpamParallel.Errors (_, (_, Sys.Break)::_, _) -> OpamStd.Sys.get_exit_code `User_interrupt | Sys_error e when e = "Broken pipe" -> (* workaround warning 52, this is a fallback (we already handle the signal) and there is no way around at the moment *) 141 | InvalidCLI (cli, source) -> (* Unsupported CLI version *) let suffix = if source = `Env then " Please fix the value of the OPAMCLI environment variable, \ or use the '--cli .' flag" else "" in OpamConsole.error "opam command-line version %s is not supported.%s" (OpamCLIVersion.to_string cli) suffix; OpamStd.Sys.get_exit_code `Bad_arguments | InvalidFlagContent (flag, None) -> (* No argument given to flag *) display_cli_error "option `--%s' needs an argument" flag; OpamStd.Sys.get_exit_code `Bad_arguments | InvalidFlagContent (flag, Some (invalid, expected)) -> (* Wrong argument kind given to flag *) display_cli_error "option `--%s': invalid value `%s', expected %s" flag invalid expected; OpamStd.Sys.get_exit_code `Bad_arguments | InvalidNewFlag ((req_cli, _), flag, flag_cli) -> (* Requested cli is older than flag introduction *) display_cli_error "--%s was added in version %s of the opam CLI, \ but version %s has been requested, which is older." flag (OpamCLIVersion.to_string flag_cli) (OpamCLIVersion.to_string req_cli); OpamStd.Sys.get_exit_code `Bad_arguments | Failure msg -> OpamConsole.errmsg "Fatal error: %s\n" msg; OpamConsole.errmsg "%s" (OpamStd.Exn.pretty_backtrace e); OpamStd.Sys.get_exit_code `Internal_error | _ -> OpamConsole.errmsg "Fatal error:\n%s\n" (Printexc.to_string e); OpamConsole.errmsg "%s" (OpamStd.Exn.pretty_backtrace e); OpamStd.Sys.get_exit_code `Internal_error in exit exit_code let run () = OpamStd.Option.iter OpamVersion.set_git OpamGitVersion.version; OpamSystem.init (); OpamArg.preinit_opam_env_variables (); main_catch_all @@ fun () -> let cli, argv = check_and_run_external_commands () in let (default, commands), argv1 = match argv with | prog :: command :: argv when OpamCommands.is_admin_subcommand command -> OpamAdminCommand.get_cmdliner_parser cli, prog::argv | _ -> OpamCommands.get_cmdliner_parser cli, argv in let argv = Array.of_list argv1 in match Term.eval_choice ~catch:false ~argv default commands with | `Error _ -> exit (OpamStd.Sys.get_exit_code `Bad_arguments) | _ -> exit (OpamStd.Sys.get_exit_code `Success) let json_out () = match OpamClientConfig.(!r.json_out) with | None -> () | Some s -> let file_name () = match OpamStd.String.cut_at s '%' with | None -> OpamFilename.of_string s | Some (pfx, sfx) -> let rec getname i = let f = OpamFilename.of_string (Printf.sprintf "%s%d%s" pfx i sfx) in if OpamFilename.exists f then getname (i+1) else f in getname 1 in try let f = OpamFilename.open_out (file_name ()) in OpamJson.flush f; close_out f with e -> OpamConsole.warning "Couldn't write json log: %s" (Printexc.to_string e) let main () = OpamStd.Sys.at_exit (fun () -> flush stderr; flush stdout; if OpamClientConfig.(!r.print_stats) then ( OpamFile.Stats.print (); OpamSystem.print_stats (); ); json_out () ); run () opam-2.1.5/src/client/opamConfigCommand.ml0000644000175000017500000011432214427463453017502 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) let log fmt = OpamConsole.log "CONFIG" fmt let slog = OpamConsole.slog open OpamParserTypes.FullPos open OpamTypesBase open OpamStateTypes (* List all the available variables *) let list t ns = log "config-list"; if ns = [] then () else let list_vars name = if OpamPackage.Name.to_string name = "-" then let conf = t.switch_config in List.map (fun (v,c) -> OpamVariable.Full.global v, OpamVariable.string_of_variable_contents c, "") (conf.OpamFile.Switch_config.variables) else let nv = OpamSwitchState.get_package t name in let pkg_vars = try let opam = OpamSwitchState.opam t nv in let env = OpamPackageVar.resolve ~opam t in OpamStd.List.filter_map (fun (vname, desc) -> let v = OpamVariable.(Full.create name (of_string vname)) in try let c = OpamFilter.ident_string env (OpamFilter.ident_of_var v) in Some (v, c, desc) with Failure _ -> None) OpamPackageVar.package_variable_names with Not_found -> [] in let conf_vars = try let conf = OpamSwitchState.package_config t name in List.map (fun (v,c) -> OpamVariable.Full.create name v, OpamVariable.string_of_variable_contents c, "") (OpamFile.Dot_config.bindings conf) with Not_found -> [] in pkg_vars @ conf_vars in let vars = List.flatten (List.map list_vars ns) in let (%) s col = OpamConsole.colorise col s in List.map (fun (variable, value, descr) -> [ OpamVariable.Full.to_string variable % `bold; value % `blue; if descr = "" then "" else "# "^descr; ]) vars |> OpamStd.Format.align_table |> OpamConsole.print_table stdout ~sep:" " let rec print_env = function | [] -> () | (k, v, comment) :: r -> if OpamConsole.verbose () then OpamStd.Option.iter (OpamConsole.msg ": %s;\n") comment; if not (List.exists (fun (k1, _, _) -> k = k1) r) || OpamConsole.verbose () then OpamConsole.msg "%s='%s'; export %s;\n" k (OpamStd.Env.escape_single_quotes v) k; print_env r let rec print_csh_env = function | [] -> () | (k, v, comment) :: r -> if OpamConsole.verbose () then OpamStd.Option.iter (OpamConsole.msg ": %s;\n") comment; if not (List.exists (fun (k1, _, _) -> k = k1) r) || OpamConsole.verbose () then OpamConsole.msg "setenv %s '%s';\n" k (OpamStd.Env.escape_single_quotes v); print_csh_env r let print_sexp_env env = let rec aux = function | [] -> () | (k, v, _) :: r -> if not (List.exists (fun (k1, _, _) -> k = k1) r) then OpamConsole.msg " (%S %S)\n" k v; aux r in OpamConsole.msg "(\n"; aux env; OpamConsole.msg ")\n" let rec print_fish_env env = let set_arr_cmd ?(modf=fun x -> x) k v = let v = modf @@ OpamStd.String.split v ':' in OpamConsole.msg "set -gx %s %s;\n" k (OpamStd.List.concat_map " " (fun v -> Printf.sprintf "'%s'" (OpamStd.Env.escape_single_quotes ~using_backslashes:true v)) v) in (* set manpath if and only if fish version >= 2.7 *) let manpath_cmd v = OpamConsole.msg "%s" ( (* test for existence of `argparse` builtin, introduced in fish 2.7 . * use `grep' instead of `builtin string match' so that old fish versions do not * produce unwanted error messages on stderr. * use `grep' inside a `/bin/sh' fragment so that nothing is written to stdout or * stderr if `grep' does not exist. *) "builtin -n | /bin/sh -c 'grep -q \\'^argparse$\\'' 1>/dev/null 2>/dev/null; and " ) ; let modf = function | x::v' -> (":"^x)::v' | v -> v in set_arr_cmd ~modf "MANPATH" v in match env with | [] -> () | (k, v, _) :: r -> if not (List.exists (fun (k1, _, _) -> k = k1) r) then (match k with | "PATH" | "CDPATH" -> (* This function assumes that `v` does not include any variable * expansions and that the directory names are written in full. See the * opamState.ml for details *) set_arr_cmd k v | "MANPATH" -> manpath_cmd v | _ -> OpamConsole.msg "set -gx %s '%s';\n" k (OpamStd.Env.escape_single_quotes ~using_backslashes:true v)); print_fish_env r let print_eval_env ~csh ~sexp ~fish env = if sexp then print_sexp_env env else if csh then print_csh_env env else if fish then print_fish_env env else print_env env let ensure_env_aux ?(set_opamroot=false) ?(set_opamswitch=false) ?(force_path=true) gt switch = let env_file = OpamPath.Switch.environment gt.root switch in if not (OpamFile.exists env_file) then Some (OpamSwitchState.with_ `Lock_none gt @@ fun st -> let upd = OpamEnv.updates ~set_opamroot ~set_opamswitch ~force_path st in log "Missing environment file, regenerate it"; if not (OpamCoreConfig.(!r.safe_mode)) then (let _, st = OpamSwitchState.with_write_lock st @@ fun st -> (OpamFile.Environment.write env_file upd), st in OpamSwitchState.drop st); OpamEnv.add [] upd) else None let ensure_env gt switch = ignore (ensure_env_aux gt switch) let env gt switch ?(set_opamroot=false) ?(set_opamswitch=false) ~csh ~sexp ~fish ~inplace_path = log "config-env"; let opamroot_not_current = let current = gt.root in let default = OpamStateConfig.(default.root_dir) in match OpamStateConfig.E.root () with | None -> current <> default | Some r -> OpamFilename.Dir.of_string r <> current in let opamswitch_not_current = let default = OpamStd.Option.Op.(++) (OpamStateConfig.get_current_switch_from_cwd gt.root) (OpamFile.Config.switch gt.config) in match OpamStateConfig.E.switch () with | None | Some "" -> Some (OpamStateConfig.resolve_local_switch gt.root switch) <> default | Some s -> OpamStateConfig.resolve_local_switch gt.root (OpamSwitch.of_string s) <> OpamStateConfig.resolve_local_switch gt.root switch in if opamroot_not_current && not set_opamroot then OpamConsole.note "To make opam select %s as its root in the current shell, add %s or set \ %s" (OpamFilename.Dir.to_string gt.root) (OpamConsole.colorise `bold "--set-root") (OpamConsole.colorise `bold "OPAMROOT"); if opamswitch_not_current && not set_opamswitch then OpamConsole.note "To make opam select the switch %s in the current shell, add %s or set \ %s" (OpamSwitch.to_string switch) (OpamConsole.colorise `bold "--set-switch") (OpamConsole.colorise `bold "OPAMSWITCH"); let force_path = not inplace_path in let env = match ensure_env_aux ~set_opamroot ~set_opamswitch ~force_path gt switch with | Some env -> env | None -> OpamEnv.get_opam_raw ~set_opamroot ~set_opamswitch ~force_path gt.root switch in print_eval_env ~csh ~sexp ~fish env [@@ocaml.warning "-16"] let subst gt fs = log "config-substitute"; OpamSwitchState.with_ `Lock_none gt @@ fun st -> List.iter (OpamFilter.expand_interpolations_in_file (OpamPackageVar.resolve st)) fs let expand gt str = log "config-expand"; OpamSwitchState.with_ `Lock_none gt @@ fun st -> OpamConsole.msg "%s\n" (OpamFilter.expand_string ~default:(fun _ -> "") (OpamPackageVar.resolve st) str) let exec gt ~set_opamroot ~set_opamswitch ~inplace_path command = log "config-exec command=%a" (slog (String.concat " ")) command; let switch = OpamStateConfig.get_switch () in let st_lazy = lazy ( let rt = OpamRepositoryState.load `Lock_none gt in OpamSwitchState.load `Lock_none gt rt switch ) in let env_file = OpamPath.Switch.environment gt.root switch in let env = if OpamFile.exists env_file then let base = List.map (fun (v,va) -> v,va,None) (OpamStd.Env.list ()) in OpamEnv.get_opam_raw ~base ~set_opamroot ~set_opamswitch ~force_path:(not inplace_path) gt.root switch else OpamEnv.get_full ~set_opamroot ~set_opamswitch ~force_path:(not inplace_path) (Lazy.force st_lazy) in let env = OpamTypesBase.env_array env in let resolve var = OpamPackageVar.resolve (Lazy.force st_lazy) var in let cmd, args = match List.map (OpamFilter.expand_string ~default:(fun _ -> "") resolve) command with | [] -> OpamSystem.internal_error "Empty command" | h::_ as l -> h, Array.of_list l in (* it's OK not to release [st_lazy] since we are certain everything will be cleaned up anyway *) match OpamSystem.resolve_command ~env cmd with | Some cmd -> raise (OpamStd.Sys.Exec (cmd, args, env)) | None -> OpamConsole.error "Command not found '%s'" cmd; raise (OpamStd.Sys.Exit 127) (** Options and Variables settings *) (** Option settings *) (* For function that takes two config and update (add or remove) elements in a field. Used for appending or deleting element in config file fields *) type 'config fld_updater = ('config -> 'config -> 'config) (* Only some field can be modifiied. [Modifiable] is for user modifiable field, [InModifiable] for fields that can only be modified from inner opam code (see [set_var_global]). First argument is the addition function, the second the remove one. *) type 'config fld_policy = | Atomic | Modifiable of 'config fld_updater * 'config fld_updater | InModifiable of 'config fld_updater * 'config fld_updater (* "Configuration" of the [set_opt] function. As modification can be on global or config switch, on normal fields and sections, adding, removing, or overwritng values, this record type permits to aggregate all needed inputs. See [set_opt_global] and [set_opt_switch]. *) type 'config confset = { stg_fields: (string * ('config, value) OpamPp.field_parser) list; (* Config file fields: field name and parser *) stg_allwd_fields: (string * 'config fld_policy * ('config -> 'config)) list; (* Config file updatable fields: field name, update policy, and function to revert the given field in config file *) stg_sections: (string * ('config, (string option * opamfile_item list) list) OpamPp.field_parser) list; (* Same as [stg_field] but for sections *) stg_allwd_sections: ((string * 'config fld_policy * ('config -> 'config)) list); (* Same as [stg_allwd_fields] but for sections *) stg_config: 'config; (* The config *) stg_write_config: 'config -> unit; (* Function to write the config file *) stg_doc: string; (* Global or switch specification, used to print final user message *) } type whole_op = [ `Overwrite of string | `Revert ] type append_op = [ `Add of string | `Remove of string ] type update_op = [ append_op | whole_op ] let parse_update fv = let reg = Re.(compile @@ seq [ group @@ seq [ wordc; opt @@ (seq [ rep @@ alt [ wordc ; char '-' ]; wordc ]) ]; (opt @@ seq [ (group @@ (alt [ str "+="; str "-="; str "=="; char '='; ])); opt @@ (group @@ rep1 any) ]); ]) in let grs = Re.exec reg fv in let var = Re.Group.get grs 1 in let value = try let value = OpamStd.Option.of_Not_found (fun () -> Re.Group.get grs 3) () in match Re.Group.get grs 2, value with | "+=", Some value -> `Add value | "-=", Some value -> `Remove value | ("=" | "=="), Some value -> `Overwrite value | ("=" | "=="), None -> `Revert | ("+=" | "-="), None -> raise (Invalid_argument "parse_update: rhs needed") | _, _ -> raise (Invalid_argument "parse_update: illegal operator") with Not_found -> raise (Invalid_argument "parse_update: operator needed") in var, value let whole_of_update_op = function | #whole_op as w -> w | _ -> raise Not_found let parse_whole fv = let v, upd = parse_update fv in try v, (whole_of_update_op upd) with Not_found -> raise (Invalid_argument "parse_whole: append operator") let global_doc = "global configuration" let switch_doc switch = Printf.sprintf "switch %s" (OpamConsole.colorise `bold (OpamSwitch.to_string switch)) module OpamParser = OpamParser.FullPos module OpamPrinter = OpamPrinter.FullPos (* General setting option function. Takes the [field] to update, the [value] operation, [conf] the configuration according the config file (['config confest]). If [inner] is set, it allows the modification of [InModifiable] fields *) let set_opt ?(inner=false) field value conf = let wrap allowed all parse = List.map (fun (field, pp) -> match OpamStd.List.find_opt (fun (x,_,_) -> x = field) allowed with | None -> field, None | Some (_, modd, default) -> let parse elem config = OpamPp.parse ~pos:OpamTypesBase.pos_null pp (config, Some (parse elem)) in field, Some (parse, modd, default) ) all in let fields = (wrap conf.stg_allwd_fields conf.stg_fields (fun str_value -> OpamParser.value_from_string str_value "")) @ (wrap conf.stg_allwd_sections conf.stg_sections (fun str_value -> [None, (OpamParser.string str_value "").file_contents])) in let new_config = match OpamStd.List.assoc_opt field fields, value with | None, _ -> OpamConsole.error "There is no option named '%s'. The allowed options are:" (OpamConsole.colorise `underline field); OpamConsole.print_table stderr ~sep:" " (OpamStd.Format.as_aligned_table (OpamStd.List.filter_map (function fl, Some _ -> Some fl | _ -> None) fields)); OpamStd.Sys.exit_because `Bad_arguments | Some None, _ -> OpamConsole.error_and_exit `Bad_arguments "Field %s is not modifiable" (OpamConsole.colorise `underline field) | Some (Some (_, Atomic, _)), (#append_op as ar) -> OpamConsole.error_and_exit `Bad_arguments "Field %s can't be %s" (OpamConsole.colorise `underline field) (match ar with `Add _ -> "appended" | `Remove _ -> "substracted") | Some (Some (_, InModifiable (_,_), _)), (#append_op as ar) when not inner -> OpamConsole.error_and_exit `Bad_arguments "Field %s can't be directly %s, use `opam var` instead" (OpamConsole.colorise `underline field) (match ar with `Add _ -> "appended to" | `Remove _ -> "substracted from") | Some (Some (_, _, set_default)), `Revert -> set_default conf.stg_config | Some (Some (parse, fix_app, _)), ((`Add v | `Remove v | `Overwrite v) as req_value) -> (try let updf v = parse v conf.stg_config in match req_value, fix_app with | `Add value, (Modifiable (add, _) | InModifiable (add, _)) -> add (updf value) conf.stg_config | `Remove value, (Modifiable (_, rem) | InModifiable (_, rem)) -> rem (updf value) conf.stg_config | `Overwrite value, _ -> (updf value) | _, Atomic -> assert false with | (OpamPp.Bad_format (_,_) | Parsing.Parse_error) as e -> OpamConsole.error_and_exit `Bad_arguments "Parse error on the value of %s '%s': %s" (OpamConsole.colorise `underline field) v (OpamPp.string_of_bad_format e)) in if conf.stg_config = new_config then OpamConsole.msg "No modification in %s\n" conf.stg_doc else (conf.stg_write_config new_config; OpamConsole.msg "%s field %s in %s\n" (match value with | `Add value -> Printf.sprintf "Added '%s' to" value | `Remove value -> Printf.sprintf "Removed '%s' from" value | `Overwrite value -> Printf.sprintf "Set to '%s' the" value | `Revert -> "Reverted") (OpamConsole.colorise `underline field) conf.stg_doc); new_config let allwd_wrappers wdef wrappers with_wrappers = let open OpamFile in List.map (fun (n, set, get) -> n, Modifiable ( (fun nc c -> let w = wrappers c in let nw = wrappers nc in with_wrappers (set (get nw @ get w) w) c), (fun nc c -> let w = wrappers c in let nw = wrappers nc in let n_cmd = List.filter (fun cmd -> None = OpamStd.List.find_opt (fun cmd' -> cmd = cmd') (get nw)) (get w) in with_wrappers (set n_cmd w) c) ), fun c -> with_wrappers (set (get wdef) (wrappers c)) c) [ "pre-build-commands", Wrappers.with_pre_build, Wrappers.pre_build; "pre-install-commands", Wrappers.with_pre_install, Wrappers.pre_install; "pre-remove-commands", Wrappers.with_pre_remove, Wrappers.pre_remove; "pre-session-commands", Wrappers.with_pre_session, Wrappers.pre_session; "wrap-build-commands", Wrappers.with_wrap_build, Wrappers.wrap_build; "wrap-install-commands", Wrappers.with_wrap_install, Wrappers.wrap_install; "wrap-remove-commands", Wrappers.with_pre_remove, Wrappers.pre_remove; "post-build-commands", Wrappers.with_post_build, Wrappers.post_build; "post-install-commands", Wrappers.with_post_install, Wrappers.post_install; "post-remove-commands", Wrappers.with_post_remove, Wrappers.post_remove; "post-session-commands", Wrappers.with_post_session, Wrappers.post_session; ] let switch_allowed_fields, switch_allowed_sections = let allowed_fields = lazy ( OpamFile.Switch_config.( [ ("synopsis", Atomic, fun t -> { t with synopsis = empty.synopsis }); ("setenv", Modifiable ( (fun nc c -> { c with env = nc.env @ c.env }), (fun nc c -> let env = List.filter (fun (vr,op,vl,_) -> None = OpamStd.List.find_opt (fun (vr',op',vl',_) -> vr = vr' && op = op' && vl = vl') nc.env) c.env in { c with env })), fun t -> { t with env = empty.env }); "depext-bypass", OpamSysPkg.Set.Op.(Modifiable ( (fun nc c -> { c with depext_bypass = nc.depext_bypass ++ c.depext_bypass }), (fun nc c -> { c with depext_bypass = c.depext_bypass -- nc.depext_bypass }) )), (fun t -> { t with depext_bypass = empty.depext_bypass }); ] @ allwd_wrappers empty.wrappers wrappers (fun wrappers t -> { t with wrappers }))) in let allowed_sections = let rem_elem new_elems elems = List.filter (fun n -> not (List.mem n new_elems)) elems in lazy ( OpamFile.Switch_config.([ ("variables", InModifiable ( (fun nc c -> { c with variables = nc.variables @ c.variables }), (fun nc c -> { c with variables = rem_elem nc.variables c.variables })), (fun c -> { c with variables = empty.variables })); ])) in (fun () -> Lazy.force allowed_fields), fun () -> Lazy.force allowed_sections let confset_switch gt switch switch_config = let config_f = OpamPath.Switch.switch_config gt.root switch in let write new_config = OpamFile.Switch_config.write config_f new_config in { stg_fields = OpamFile.Switch_config.fields; stg_allwd_fields = switch_allowed_fields (); stg_sections = OpamFile.Switch_config.sections; stg_allwd_sections = switch_allowed_sections (); stg_config = switch_config; stg_write_config = write; stg_doc = switch_doc switch } let with_switch ~display gt lock_kind st k = match st with | Some st -> k st.switch st.switch_config | None -> match OpamStateConfig.get_switch_opt () with | None -> OpamConsole.error_and_exit `Configuration_error "No switch selected" | Some switch -> let switch_config = if lock_kind = `Lock_write then match OpamStateConfig.Switch.read_opt ~lock_kind gt switch with | Some c -> c | exception (OpamPp.Bad_version _ as e) -> OpamFormatUpgrade.hard_upgrade_from_2_1_intermediates gt.root; raise e | None -> OpamFile.Switch_config.empty else OpamStateConfig.Switch.safe_load ~lock_kind gt switch in let lock_file = OpamPath.Switch.lock gt.root switch in if switch_config = OpamFile.Switch_config.empty then if display then OpamConsole.error "switch %s not found, display default values" (OpamSwitch.to_string switch) else OpamConsole.error_and_exit `Bad_arguments "The selected switch %s is not installed" (OpamSwitch.to_string switch); OpamFilename.with_flock lock_kind lock_file @@ fun _ -> k switch switch_config let set_opt_switch_t ?inner gt switch switch_config field value = set_opt ?inner field value (confset_switch gt switch switch_config) let set_opt_switch gt ?st field value = with_switch ~display:false gt `Lock_write st @@ fun sw swc -> let switch_config = set_opt_switch_t ~inner:false gt sw swc field value in OpamStd.Option.map (fun st -> { st with switch_config }) st let global_allowed_fields, global_allowed_sections = let allowed_fields = let open OpamStd.Option.Op in let open OpamFile in let in_config = OpamInitDefaults.init_config () in let wrapper_init = InitConfig.wrappers in_config in let upd_vars get set = (fun nc c -> set (get nc @ get c) c), (fun nc c -> let gv = get nc in set (List.filter (fun (k,v,_) -> None = OpamStd.List.find_opt (fun (k',v',_) -> k = k' && v = v') gv) (get c)) c) in lazy ([ "download-command", Atomic, Config.with_dl_tool_opt (InitConfig.dl_tool in_config ++ Config.dl_tool Config.empty); "download-jobs", Atomic, Config.with_dl_jobs (InitConfig.dl_jobs in_config +! Config.dl_jobs Config.empty); "jobs", Atomic, Config.with_jobs_opt (InitConfig.jobs in_config ++ Config.jobs Config.empty); "best-effort-prefix-criteria", Atomic, Config.with_best_effort_prefix_opt (Config.best_effort_prefix Config.empty); "solver", Atomic, Config.with_solver_opt (InitConfig.solver in_config ++ Config.solver Config.empty); "global-variables", (let add, rem = upd_vars Config.global_variables Config.with_global_variables in InModifiable (add, rem)), Config.with_global_variables (InitConfig.global_variables in_config); "eval-variables", (let add, rem = upd_vars Config.eval_variables Config.with_eval_variables in InModifiable (add, rem)), Config.with_eval_variables (InitConfig.eval_variables in_config); "repository-validation-command", Atomic, Config.with_validation_hook_opt (Config.validation_hook Config.empty); "depext", Atomic, Config.with_depext (Config.depext Config.empty); "depext-run-installs", Atomic, Config.with_depext_run_installs (Config.depext_run_installs Config.empty); "depext-cannot-install", Atomic, Config.with_depext_cannot_install (Config.depext_cannot_install Config.empty); "depext-bypass", OpamSysPkg.Set.Op.(Modifiable ( (fun nc c -> Config.with_depext_bypass (Config.depext_bypass nc ++ Config.depext_bypass c) c), (fun nc c -> Config.with_depext_bypass (Config.depext_bypass c -- Config.depext_bypass nc) c) )), Config.with_depext_bypass (Config.depext_bypass Config.empty); ] @ List.map (fun f -> f, Atomic, Config.with_criteria (Config.criteria Config.empty)) [ "solver-criteria"; "solver-upgrade-criteria"; "solver-fixup-criteria" ] @ allwd_wrappers wrapper_init Config.wrappers Config.with_wrappers ) in (fun () -> Lazy.force allowed_fields), fun () -> [] let confset_global gt = let write new_config = OpamGlobalState.write {gt with config = new_config} in { stg_fields = OpamFile.Config.fields; stg_allwd_fields = global_allowed_fields (); stg_sections = []; stg_allwd_sections = global_allowed_sections (); stg_config = gt.config; stg_write_config = write; stg_doc = global_doc; } let set_opt_global_t ?inner gt field value = let config = set_opt ?inner field value (confset_global gt) in { gt with config } let set_opt_global = set_opt_global_t ~inner:false (** Variable settings *) (* "Configuration" of the [set_var] function. As these modification can be on global and switch config, this record aggregates all needed inputs. *) type ('var,'config) var_confset = { stv_vars: 'var list; (* Variables list *) stv_find: 'var -> bool; (* Find function embedding a wanted var *) stv_config: 'config; (* State to use *) stv_varstr: string -> string; (* [stv_vars value] returns the string of the variable with the new value. It is used to give the overall value to [set_opt] functions. *) stv_set_opt: 'config -> update_op -> 'config; (* The [set_opt] function call [stv_set_opt state var_value] *) stv_remove_elem: 'var list -> 'config -> 'config; (* As variable can't be duplicated, a function to remove it from the list *) stv_write: 'config -> unit; (* Write the config file *) stv_doc: string; (* Global or switch specification, used to print final user message *) } let set_var svar value conf = let var = OpamVariable.Full.of_string svar in let conf = conf (OpamVariable.Full.variable var) in if not (OpamVariable.Full.is_global var) then OpamConsole.error_and_exit `Bad_arguments "Only global variables may be set using this command"; let global_vars = conf.stv_vars in let rest = List.filter (fun v -> not (conf.stv_find v)) global_vars in let config = conf.stv_remove_elem rest conf.stv_config in match value with | `Overwrite value -> conf.stv_set_opt config (`Add (conf.stv_varstr value)) | `Revert -> (* only write, as the var is already removed *) if config = conf.stv_config then OpamConsole.msg "No modification in %s\n" conf.stv_doc else (conf.stv_write config; OpamConsole.msg "Removed variable %s in %s\n" (OpamConsole.colorise `underline svar) conf.stv_doc); config let set_var_global gt var value = let config = set_var var value @@ fun var -> let global_vars = OpamFile.Config.global_variables gt.config in { stv_vars = global_vars; stv_find = (fun (k,_,_) -> k = var); stv_config = gt.config; stv_varstr = (fun v -> OpamPrinter.Normalise.value (nullify_pos @@ List (nullify_pos @@ [ nullify_pos @@ Ident (OpamVariable.to_string var); nullify_pos @@ String v; nullify_pos @@ String "Set through 'opam var'" ]))); stv_set_opt = (fun config value -> let gt = set_opt_global_t ~inner:true { gt with config } "global-variables" value in gt.config); stv_remove_elem = (fun rest config -> OpamFile.Config.with_global_variables rest config |> OpamFile.Config.with_eval_variables (List.filter (fun (k,_,_) -> k <> var) (OpamFile.Config.eval_variables config))); stv_write = (fun config -> OpamGlobalState.write { gt with config }); stv_doc = global_doc; } in { gt with config } let set_var_switch gt ?st var value = let var_confset switch switch_config var = let switch_vars = switch_config.OpamFile.Switch_config.variables in { stv_vars = switch_vars; stv_find = (fun (k,_) -> k = var); stv_config = switch_config; stv_varstr = (fun v -> OpamStd.String.remove_suffix ~suffix:"\n" @@ OpamPrinter.Normalise.items [ nullify_pos @@ Variable (nullify_pos @@ OpamVariable.to_string var, nullify_pos @@ String v)]); stv_set_opt = (fun swc value -> set_opt_switch_t ~inner:true gt switch swc "variables" value); stv_remove_elem = (fun rest switch_config -> { switch_config with variables = rest }); stv_write = (fun swc -> OpamFile.Switch_config.write (OpamPath.Switch.switch_config gt.root switch) swc); stv_doc = switch_doc switch; } in let switch_config = with_switch ~display:false gt `Lock_write st @@ fun sw swc -> set_var var value (var_confset sw swc) in OpamStd.Option.map (fun st -> { st with switch_config }) st (** Option and var list display *) let print_fields fields = let fields = List.sort (fun (x,_) (x',_) -> compare x x') fields |> List.map (fun (name, value) -> let value = match value with | None -> "{}" | Some value -> (OpamPrinter.Normalise.value value) in [ OpamConsole.colorise `bold name ; OpamConsole.colorise `blue value ]) in OpamConsole.print_table stdout ~sep:" " (OpamStd.Format.align_table fields) let find_field field name_value = match OpamStd.List.find_opt (fun (name, _) -> name = field) name_value with | None -> (field, None) | Some (name, value) -> (name, Some value) let find_section section name_value = let sections = List.find_all (fun (name, _) -> match OpamStd.String.cut_at name '.' with | None -> false | Some (name,_) -> name = section) name_value in match sections with | [] -> [section, None] | section -> List.map (fun (n,v) -> n, Some v) section let options_list_t to_list conf = let name_value = to_list conf.stg_config in let fields = OpamStd.List.filter_map (fun (field, policy, _) -> match policy with | InModifiable _ -> None | _ -> Some (find_field field name_value)) conf.stg_allwd_fields in let sections = OpamStd.List.filter_map (fun (field, policy, _) -> match policy with | InModifiable _ -> None | _ -> Some (find_section field name_value)) conf.stg_allwd_sections |> List.flatten in print_fields (fields @ sections) let options_list_switch ?st gt = with_switch ~display:true gt `Lock_none st @@ fun sw swc -> options_list_t OpamFile.Switch_config.to_list (confset_switch gt sw swc) let options_list_global gt = options_list_t OpamFile.Config.to_list (confset_global gt) let options_list ?st gt = OpamConsole.header_msg "Global configuration"; options_list_global gt; let switch_header = OpamConsole.header_msg "Switch configuration%s" in match OpamStateConfig.get_switch_opt () with | None -> switch_header ""; OpamConsole.msg "No switch installed\n" | Some switch -> switch_header (Printf.sprintf " (%s)" (OpamSwitch.to_string switch)); options_list_switch ?st gt let vars_list_global gt = let (%) s col = OpamConsole.colorise col s in let all_global_vars = List.fold_left (fun acc (v,doc) -> OpamVariable.Map.add (OpamVariable.of_string v) doc acc) OpamVariable.Map.empty OpamPackageVar.global_variable_names in let all_global_vars = OpamVariable.Map.union (fun _ x -> x) all_global_vars (OpamVariable.Map.map snd gt.global_variables) in let env = OpamPackageVar.resolve_global gt in List.map (fun (var, doc) -> let content = OpamFilter.ident_string env ~default:"" ([],var,None) in let doc = if doc = OpamGlobalState.inferred_from_system then match OpamStd.Option.Op.( OpamVariable.Map.find_opt var gt.global_variables >>| fst >>= Lazy.force) with | Some c when (OpamVariable.string_of_variable_contents c) <> content -> "Set through local opam config or env" | _ -> doc else doc in [ OpamVariable.to_string var % `bold; content % `blue; "#"; doc ]) (List.sort (fun (x,_) (x',_) -> compare x x') (OpamVariable.Map.bindings all_global_vars)) |> OpamStd.Format.align_table |> OpamConsole.print_table stdout ~sep:" " let vars_list_switch ?st gt = let (%) s col = OpamConsole.colorise col s in let switch, config = match st with | Some st -> st.switch, st.switch_config | None -> let switch = OpamStateConfig.get_switch () in switch, OpamStateConfig.Switch.safe_load ~lock_kind:`Lock_read gt switch in List.map (fun stdpath -> [ OpamTypesBase.string_of_std_path stdpath % `bold; OpamPath.Switch.get_stdpath gt.root switch config stdpath |> OpamFilename.Dir.to_string |> OpamConsole.colorise `blue ]) OpamTypesBase.all_std_paths @ List.map (fun (var,value) -> [ OpamVariable.to_string var % `bold; OpamVariable.string_of_variable_contents value % `blue; ]) (List.sort (fun (x,_) (x',_) -> compare x' x) config.OpamFile.Switch_config.variables) |> OpamStd.Format.align_table |> OpamConsole.print_table stdout ~sep:" " let vars_list ?st gt = let (%) s col = OpamConsole.colorise col s in OpamConsole.header_msg "Global opam variables"; vars_list_global gt; OpamConsole.header_msg "Configuration variables from the current switch"; (match OpamStateConfig.get_switch_opt () with | None -> OpamConsole.msg "No switch installed\n" | Some _ -> vars_list_switch ?st gt); OpamConsole.header_msg "Package variables ('opam var --package PKG' to show)"; List.map (fun (var, doc) -> [ ("PKG:"^var) % `bold; ""; "#";doc ]) OpamPackageVar.package_variable_names |> OpamStd.Format.align_table |> OpamConsole.print_table stdout ~sep:" " (* Specified option/var display *) let option_show to_list conf field = match OpamStd.List.assoc_opt field conf.stg_fields with | Some pp -> (match OpamPp.print pp conf.stg_config with | _, Some value -> OpamConsole.msg "%s\n" (OpamPrinter.Normalise.value value) | _, None -> ()) | None -> if List.mem_assoc field conf.stg_sections then let name_value = to_list conf.stg_config in let sections = OpamStd.List.filter_map (fun (name, v) -> match OpamStd.String.cut_at name '.' with | Some (name,elem) when name = field -> Some [ elem; OpamPrinter.Normalise.value v ] | _ -> None ) name_value in OpamConsole.print_table stdout ~sep:" " (OpamStd.Format.align_table sections) else OpamConsole.error_and_exit `Not_found "Field or section %s not found" field let option_show_switch gt ?st field = with_switch ~display:true gt `Lock_none st @@ fun sw swc -> option_show OpamFile.Switch_config.to_list (confset_switch gt sw swc) field let option_show_global gt field = option_show OpamFile.Config.to_list (confset_global gt) field let var_show_t resolve ?switch v = match resolve (OpamVariable.Full.of_string v) with | Some c -> OpamConsole.msg "%s\n" (OpamVariable.string_of_variable_contents c) | None -> OpamConsole.error_and_exit `Not_found "Variable %s not found in %s" v (match switch with | None -> "global config" | Some switch -> "switch " ^ (OpamSwitch.to_string switch)) let is_switch_defined_var switch_config v = OpamFile.Switch_config.variable switch_config (OpamVariable.of_string v) <> None || (try let _path = OpamTypesBase.std_path_of_string v in true with Failure _ -> false) || OpamStd.String.contains_char v ':' let var_switch_raw gt v = match OpamStateConfig.get_switch_opt () with | Some switch -> let switch_config = OpamStateConfig.Switch.safe_load ~lock_kind:`Lock_read gt switch in let rsc = if is_switch_defined_var switch_config v then OpamPackageVar.resolve_switch_raw gt switch switch_config (OpamVariable.Full.of_string v) else None in (match rsc with | Some c -> OpamConsole.msg "%s\n" (OpamVariable.string_of_variable_contents c); rsc | None -> None) | None -> None let var_show_switch gt ?st v = if var_switch_raw gt v = None then let resolve_switch st = if is_switch_defined_var st.switch_config v then var_show_t (OpamPackageVar.resolve st) ~switch:st.switch v else OpamConsole.error_and_exit `Not_found "Variable %s not found in switch %s" v (OpamSwitch.to_string st.switch) in match st with | Some st -> resolve_switch st | None -> OpamSwitchState.with_ `Lock_none gt resolve_switch let var_show_global gt f = var_show_t (OpamPackageVar.resolve_global gt) f let var_show gt v = if var_switch_raw gt v = None then let resolve, switch = match OpamStateConfig.get_switch_opt () with | None -> OpamPackageVar.resolve_global gt, None | Some switch -> OpamSwitchState.with_ `Lock_none ~switch gt @@ fun st -> let resolve = (OpamPackageVar.resolve st ?opam:None ?local:None) in resolve, if is_switch_defined_var st.switch_config v then Some st.switch else None in var_show_t resolve ?switch v (* detect scope *) let get_scope field = let field = try fst (parse_update field) with Invalid_argument _ -> field in let find l = OpamStd.List.find_opt (fun (f,_) -> f = field) l in if OpamStateConfig.get_switch_opt () <> None && (find OpamFile.Switch_config.fields <> None || find OpamFile.Switch_config.sections <> None) then `Switch else if find OpamFile.Config.fields <> None then `Global else `None field opam-2.1.5/src/client/opamPinCommand.ml0000644000175000017500000007334214427463453017031 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamStateTypes open OpamStd.Op let log fmt = OpamConsole.log "COMMAND" fmt let slog = OpamConsole.slog let string_of_pinned opam = let bold = OpamConsole.colorise `bold in Printf.sprintf "pinned %s (version %s)" (OpamStd.Option.to_string ~none:(bold "locally") (fun u -> Printf.sprintf "to %s%s" (bold (OpamUrl.to_string (OpamFile.URL.url u))) (OpamStd.Option.map_default (fun s -> bold (" ("^s^")")) "" (OpamFile.URL.subpath u))) (OpamFile.OPAM.url opam)) (bold (OpamPackage.Version.to_string (OpamFile.OPAM.version opam))) let read_opam_file_for_pinning ?(quiet=false) name f url = let opam0 = let dir = OpamFilename.dirname (OpamFile.filename f) in (* don't add aux files for [project/opam] *) let add_files = OpamUrl.local_dir url = Some dir in let opam = (OpamFormatUpgrade.opam_file_with_aux ~quiet ~dir ~files:add_files ~filename:f) (OpamFile.OPAM.safe_read f) in if opam = OpamFile.OPAM.empty then None else Some opam in (match opam0 with | None -> let warns, _ = OpamFileTools.lint_file f in OpamConsole.error "Invalid opam file in %s source from %s:" (OpamPackage.Name.to_string name) (OpamUrl.to_string url); OpamConsole.errmsg "%s\n" (OpamFileTools.warns_to_string warns) | Some opam -> let warns = OpamFileTools.lint opam in if not quiet && warns <> [] then (OpamConsole.warning "Failed checks on %s package definition from source at %s:" (OpamPackage.Name.to_string name) (OpamUrl.to_string url); OpamConsole.errmsg "%s\n" (OpamFileTools.warns_to_string warns))); opam0 exception Fetch_Fail of string let get_source_definition ?version ?subpath ?locked st nv url = let root = st.switch_global.root in let srcdir = OpamPath.Switch.pinned_package root st.switch nv.name in let fix opam = OpamFile.OPAM.with_url url @@ (match version with | Some v -> OpamFile.OPAM.with_version v | None -> fun o -> o) @@ opam in let open OpamProcess.Job.Op in let url = let u = OpamFile.URL.url url in match OpamUrl.local_dir u, u.OpamUrl.backend with | Some dir, #OpamUrl.version_control -> OpamFile.URL.with_url (OpamUrl.of_string (OpamFilename.Dir.to_string dir)) url | _, _ -> url in OpamUpdate.fetch_dev_package url srcdir ?subpath nv @@| function | Not_available (_,s) -> raise (Fetch_Fail s) | Up_to_date _ | Result _ -> let subsrcdir = match OpamFile.URL.subpath url with | None -> srcdir | Some subpath -> OpamFilename.Op.(srcdir / subpath) in match OpamPinned.find_opam_file_in_source ?locked nv.name subsrcdir with | None -> None | Some f -> match read_opam_file_for_pinning nv.name f (OpamFile.URL.url url) with | None -> let dst = OpamFile.filename (OpamPath.Switch.Overlay.tmp_opam root st.switch nv.name) in OpamFilename.copy ~src:(OpamFile.filename f) ~dst; None | Some opam -> Some (fix opam) let copy_files st opam = let name = OpamFile.OPAM.name opam in let files = OpamFile.OPAM.get_extra_files ~repos_roots:(OpamRepositoryState.get_root st.switch_repos) opam in if files = [] then (match OpamFile.OPAM.extra_files opam with | Some [] | None -> () | Some files -> OpamConsole.warning "Ignoring overlay files of %s (files%s*) that were not found: %s" (OpamPackage.Name.to_string name) Filename.dir_sep (OpamStd.List.to_string (fun (b,_) -> OpamFilename.Base.to_string b) files)); let destdir = OpamPath.Switch.Overlay.files st.switch_global.root st.switch name in let files = List.fold_left (fun acc (src, rel_file, hash) -> if not (OpamFilename.exists src) then (OpamConsole.warning "Overlay file of %s %s not found, ignoring" (OpamPackage.Name.to_string name) (OpamFilename.to_string src); acc) else let hash = if not (OpamHash.check_file (OpamFilename.to_string src) hash) then if OpamFormatConfig.(!r.strict) then OpamConsole.error_and_exit `File_error "Hash mismatch on %s %s (strict mode)" (OpamPackage.Name.to_string name) (OpamFilename.to_string src) else (OpamConsole.warning "Hash doesn't match for overlay file of %s %s, adjusted" (OpamPackage.Name.to_string name) (OpamFilename.to_string src); OpamHash.compute (OpamFilename.to_string src)) else hash in OpamFilename.copy ~src ~dst:(OpamFilename.create destdir rel_file); (rel_file, hash) :: acc) [] files in OpamFile.OPAM.with_extra_files (List.rev files) opam (* Returns the new opam file, without writing it to disk *) let edit_raw name temp_file = let rec edit () = if OpamStd.Sys.tty_in then (OpamConsole.msg "Press enter to start \"%s\" (this can be customised by \ setting EDITOR or OPAMEDITOR)... " OpamClientConfig.(!r.editor); ignore (read_line ())); let edited_ok = try Sys.command (Printf.sprintf "%s %s" (OpamClientConfig.(!r.editor)) (OpamFile.to_string temp_file)) = 0 && match OpamFilename.read (OpamFile.filename temp_file) with "" | "\n" -> false | _ -> true with _ -> false in if not edited_ok then (OpamFilename.remove (OpamFile.filename temp_file); OpamConsole.error "Empty file or editor error, aborting."; None) else try let warnings, opam_opt = OpamFileTools.lint_file temp_file in let opam = match opam_opt with | None -> OpamConsole.msg "Invalid opam file:\n%s\n" (OpamFileTools.warns_to_string warnings); failwith "Syntax errors" | Some opam -> opam in let namecheck = match OpamFile.OPAM.name_opt opam with | Some n when n <> name -> OpamConsole.error "Bad \"name: %S\" field, package name is %s" (OpamPackage.Name.to_string n) (OpamPackage.Name.to_string name); false | _ -> true in let versioncheck = match OpamFile.OPAM.version_opt opam with | None -> OpamConsole.error "Missing \"version\" field."; false | Some _ -> true in if not namecheck || not versioncheck then failwith "Bad name/version"; match warnings with | [] -> Some opam | ws -> OpamConsole.warning "The opam file didn't pass validation:"; OpamConsole.errmsg "%s\n" (OpamFileTools.warns_to_string ws); if OpamConsole.confirm "Proceed anyway ('no' will re-edit)?" then Some opam else edit () with e -> OpamStd.Exn.fatal e; (match e with | Failure _ -> () | e -> OpamConsole.error "%s" (Printexc.to_string e)); if OpamStd.Sys.tty_in && OpamConsole.confirm "Errors in %s, edit again?" (OpamFile.to_string temp_file) then edit () else None in match edit () with | None -> None | Some new_opam -> OpamConsole.msg "You can edit this file again with \"opam pin edit %s\", export it with \ \"opam show %s --raw\"\n" (OpamPackage.Name.to_string name) (OpamPackage.Name.to_string name); Some new_opam let edit st ?version name = log "pin-edit %a" (slog OpamPackage.Name.to_string) name; let nv = try OpamPinned.package st name with Not_found -> OpamConsole.error_and_exit `Bad_arguments "%s is not pinned" (OpamPackage.Name.to_string name) in let new_nv = match version with | None -> nv | Some v -> OpamPackage.create name v in let path f = f st.switch_global.root st.switch name in let overlay_file = path OpamPath.Switch.Overlay.opam in let temp_file = path OpamPath.Switch.Overlay.tmp_opam in let current_opam = OpamSwitchState.opam_opt st nv in if not (OpamFile.exists temp_file) then (let base_opam = match current_opam with | None -> OpamFileTools.template new_nv | Some o -> OpamFile.OPAM.with_version new_nv.version o in OpamFile.OPAM.write_with_preserved_format ?format_from:(OpamPinned.orig_opam_file st name base_opam) temp_file base_opam); match edit_raw name temp_file with | None -> st | Some opam -> let opam = match current_opam with | Some cur -> OpamFile.OPAM.(with_metadata_dir (metadata_dir cur)) opam | None -> opam in let opam = copy_files st opam in match current_opam with | Some o when OpamFile.OPAM.equal opam o -> (OpamConsole.msg "Package metadata unchanged.\n"; st) | _ -> (* Remove obsolete auxiliary files, in case *) OpamFilename.remove (OpamFile.filename (path OpamPath.Switch.Overlay.url)); OpamFilename.remove (OpamFile.filename (path OpamPath.Switch.Overlay.descr)); let opam_extra = OpamStd.Option.default [] @@ OpamFile.OPAM.extra_files opam in List.iter (fun f -> let base = OpamFilename.Base.of_string @@ OpamFilename.remove_prefix (path OpamPath.Switch.Overlay.files) f in if not (List.mem_assoc base opam_extra) then (OpamConsole.note "Removing obsolete overlay file %s" (OpamFilename.to_string f); OpamFilename.remove f)) (OpamFilename.rec_files (path OpamPath.Switch.Overlay.files)); (* Write to overlay *) OpamFile.OPAM.write_with_preserved_format ~format_from:temp_file overlay_file opam; OpamFilename.remove (OpamFile.filename temp_file); (* Save back to source *) ignore OpamStd.Option.Op.( OpamFile.OPAM.get_url opam >>= OpamUrl.local_dir >>| fun dir -> let src_opam = OpamStd.Option.default (OpamFile.make OpamFilename.Op.(dir // "opam")) (OpamPinned.find_opam_file_in_source name dir) in let clean_opam = OpamFile.OPAM.with_url_opt None @* OpamFile.OPAM.with_extra_files [] in if (current_opam >>| fun o -> OpamFile.OPAM.equal (clean_opam opam) (clean_opam o)) <> Some true && OpamConsole.confirm "Save the new opam file back to %S?" (OpamFile.to_string src_opam) then OpamFile.OPAM.write_with_preserved_format src_opam (clean_opam opam) ); let nv = OpamPackage.create name (OpamFile.OPAM.version opam) in let st = OpamSwitchState.update_pin nv opam st in OpamUpdate.cleanup_source st current_opam opam; if not OpamClientConfig.(!r.show) then OpamSwitchAction.write_selections st; st let version_pin st name version = let root = st.switch_global.root in let nv = OpamPackage.create name version in let repo_opam = try OpamPackage.Map.find nv st.repos_package_index with Not_found -> OpamConsole.error_and_exit `Not_found "Package %s has no known version %s in the repositories" (OpamPackage.Name.to_string name) (OpamPackage.Version.to_string version) in begin match OpamPinned.package_opt st name with | Some pinned_nv -> let opam = OpamSwitchState.opam st pinned_nv in if Some opam = OpamPackage.Map.find_opt pinned_nv st.repos_package_index then (* already version-pinned *) (if pinned_nv <> nv then (OpamConsole.note "Package %s used to be pinned to version %s" (OpamPackage.Name.to_string name) (OpamPackage.Version.to_string pinned_nv.version); OpamFilename.rmdir (OpamPath.Switch.Overlay.package root st.switch name)) else OpamConsole.note "Pinning unchanged") else if OpamConsole.confirm "Package %s is already %s. Unpin and continue?" (OpamPackage.Name.to_string name) (string_of_pinned opam) then OpamFilename.rmdir (OpamPath.Switch.Overlay.package root st.switch name) else (OpamConsole.msg "Aborting.\n"; OpamStd.Sys.exit_because `Aborted) | None -> () end; let st = OpamSwitchState.update_pin nv repo_opam st in if not OpamClientConfig.(!r.show) then OpamSwitchAction.write_selections st; OpamConsole.msg "%s is now pinned to version %s\n" (OpamPackage.Name.to_string name) (OpamPackage.Version.to_string version); st exception Aborted exception Nothing_to_do let default_version st name = try OpamPackage.version (OpamSwitchState.get_package st name) with Not_found -> OpamPackage.Version.of_string "~dev" let fetch_all_pins st ?working_dir pins = let root = st.switch_global.root in let fetched = let cache_dir = OpamRepositoryPath.download_cache OpamStateConfig.(!r.root_dir) in let command (name, url, subpath) = let srcdir = OpamPath.Switch.pinned_package root st.switch name in let name = OpamPackage.Name.to_string name in OpamProcess.Job.Op.( OpamRepository.pull_tree ~cache_dir ?subpath ?working_dir name srcdir [] [url] @@| fun r -> (name, url, subpath, r)) in OpamParallel.map ~jobs:OpamStateConfig.(!r.dl_jobs) ~command pins in let errored, to_pin = List.fold_left (fun (err,ok) result -> let name, url, subpath, result = result in match result with | Not_available _ -> (* clean dir ? *) (name, url, subpath)::err, ok | _ -> err, (url, subpath)::ok) ([],[]) fetched in if errored = [] || OpamConsole.confirm "Could not retrieve some package sources, they will not be pinned nor \ installed:%s\n\ Continue anyway?" (OpamStd.Format.itemize (fun (name, url, subpath) -> name ^ ": " ^ OpamUrl.to_string url ^ (OpamStd.Option.to_string (fun s -> "("^s^")") subpath)) errored) then to_pin else OpamStd.Sys.exit_because `Aborted let rec handle_pin_depends st nv opam = let extra_pins = OpamFile.OPAM.pin_depends opam in let extra_pins = List.filter (fun (nv, url) -> not (OpamPackage.Set.mem nv st.pinned && OpamSwitchState.primary_url st nv = Some url)) extra_pins in if extra_pins = [] then st else (OpamConsole.msg "The following additional pinnings are required by %s:\n%s" (OpamPackage.to_string nv) (OpamStd.Format.itemize (fun (nv, url) -> Printf.sprintf "%s at %s" (OpamConsole.colorise `bold (OpamPackage.to_string nv)) (OpamConsole.colorise `underline (OpamUrl.to_string url))) extra_pins); if OpamConsole.confirm "Pin and install them?" then (let extra_pins = let urls_ok = fetch_all_pins st (List.map (fun (nv, u) -> OpamPackage.name nv, u, None) extra_pins) in List.filter (fun (_, url) -> List.mem (url, None) urls_ok) extra_pins in List.fold_left (fun st (nv, url) -> source_pin st nv.name ~version:nv.version (Some url) ~ignore_extra_pins:true) st extra_pins) else if OpamConsole.confirm "Try to install anyway, assuming `--ignore-pin-depends'?" then st else OpamStd.Sys.exit_because `Aborted) and source_pin st name ?version ?edit:(need_edit=false) ?opam:opam_opt ?(quiet=false) ?(force=false) ?(ignore_extra_pins=OpamClientConfig.(!r.ignore_pin_depends)) ?subpath ?locked target_url = log "pin %a to %a %a%a" (slog OpamPackage.Name.to_string) name (slog (OpamStd.Option.to_string OpamPackage.Version.to_string)) version (slog (OpamStd.Option.to_string ~none:"none" OpamUrl.to_string)) target_url (slog (OpamStd.Option.to_string ~none:"" (fun x -> " ("^x^")"))) subpath; (* let installed_version = try Some (OpamPackage.version (OpamSwitchState.find_installed_package_by_name st name)) with Not_found -> None in *) let open OpamStd.Option.Op in let cur_version, cur_urlf = try let cur_version = OpamPinned.version st name in let nv = OpamPackage.create name cur_version in let cur_opam = OpamSwitchState.opam st nv in let cur_urlf = OpamFile.OPAM.url cur_opam in let no_changes = target_url = OpamStd.Option.map OpamFile.URL.url cur_urlf && (version = Some cur_version || version = None) in if not (quiet && no_changes) then OpamConsole.note "Package %s is %s %s." (OpamPackage.Name.to_string name) (if no_changes then "already" else "currently") (string_of_pinned cur_opam); if no_changes then () else (* if OpamConsole.confirm "Proceed and change pinning target?" then *) OpamFilename.remove (OpamFile.filename (OpamPath.Switch.Overlay.tmp_opam st.switch_global.root st.switch name)) (* else raise Exns.Aborted *); cur_version, cur_urlf with Not_found -> let version = default_version st name in version, None in if not (OpamPackage.has_name st.packages name) && not (OpamConsole.confirm "Package %s does not exist, create as a %s package?" (OpamPackage.Name.to_string name) (OpamConsole.colorise `bold "NEW")) then raise Aborted; (match OpamStd.Option.map OpamFile.URL.url cur_urlf, target_url with | Some u, Some target when OpamUrl.( u.transport <> target.transport || u.path <> target.path || u.backend <> target.backend ) -> OpamFilename.rmdir (OpamPath.Switch.pinned_package st.switch_global.root st.switch name) | _ -> ()); let pin_version = version +! cur_version in let nv = OpamPackage.create name pin_version in let urlf = target_url >>| OpamFile.URL.create ?subpath in let temp_file = OpamPath.Switch.Overlay.tmp_opam st.switch_global.root st.switch name in let opam_local = OpamFile.OPAM.read_opt temp_file >>| OpamFormatUpgrade.opam_file in OpamFilename.remove (OpamFile.filename temp_file); let opam_opt = try opam_opt >>+ fun () -> urlf >>= fun url -> OpamProcess.Job.run @@ get_source_definition ?version ?subpath ?locked st nv url with Fetch_Fail err -> if force then None else (OpamConsole.error_and_exit `Sync_error "Error getting source from %s:\n%s" (OpamStd.Option.to_string OpamUrl.to_string target_url) (OpamStd.Format.itemize (fun x -> x) [err])); in let opam_opt = opam_opt >>| OpamFormatUpgrade.opam_file in let nv = match version with | Some _ -> nv | None -> OpamPackage.create name ((opam_opt >>= OpamFile.OPAM.version_opt) +! cur_version) in let opam_opt = opam_opt >>+ fun () -> OpamPackage.Map.find_opt nv st.installed_opams >>+ fun () -> OpamSwitchState.opam_opt st nv in let opam_opt = match opam_local, opam_opt with | Some local, None -> OpamConsole.warning "Couldn't retrieve opam file from versioned source, \ using the one found locally."; Some local | Some local, Some vers when not OpamFile.(OPAM.effectively_equal (OPAM.with_url URL.empty local) (OPAM.with_url URL.empty vers)) -> OpamConsole.warning "%s's opam file has uncommitted changes, using the versioned one" (OpamPackage.Name.to_string name); opam_opt | _ -> opam_opt in if not need_edit && opam_opt = None then OpamConsole.note "No package definition found for %s: please complete the template" (OpamConsole.colorise `bold (OpamPackage.to_string nv)); let need_edit = need_edit || opam_opt = None in let opam_opt = let opam_base = match opam_opt with | None -> OpamFileTools.template nv | Some opam -> opam in let opam_base = OpamFile.OPAM.with_url_opt urlf opam_base in if need_edit then (if not (OpamFile.exists temp_file) then OpamFile.OPAM.write_with_preserved_format ?format_from:(OpamPinned.orig_opam_file st name opam_base) temp_file opam_base; edit_raw name temp_file >>| (* Preserve metadata_dir so that copy_files below works *) OpamFile.OPAM.(with_metadata_dir (metadata_dir opam_base)) ) else Some opam_base in match opam_opt with | None -> OpamConsole.error_and_exit `Not_found "No valid package definition found" | Some opam -> let opam = match OpamFile.OPAM.get_url opam with | Some _ -> opam | None -> OpamFile.OPAM.with_url_opt urlf opam in let version = version +! (OpamFile.OPAM.version_opt opam +! nv.version) in let nv = OpamPackage.create nv.name version in let st = if ignore_extra_pins then st else handle_pin_depends st nv opam in let opam = opam |> OpamFile.OPAM.with_name name |> OpamFile.OPAM.with_version version in OpamFilename.rmdir (OpamPath.Switch.Overlay.package st.switch_global.root st.switch nv.name); let opam = copy_files st opam in OpamFile.OPAM.write_with_preserved_format ?format_from:(OpamPinned.orig_opam_file st name opam) (OpamPath.Switch.Overlay.opam st.switch_global.root st.switch nv.name) opam; OpamFilename.remove (OpamFile.filename temp_file); let st = OpamSwitchState.update_pin nv opam st in if not OpamClientConfig.(!r.show) then OpamSwitchAction.write_selections st; OpamConsole.msg "%s is now %s\n" (OpamPackage.Name.to_string name) (string_of_pinned opam); st (* pure *) let unpin_one st nv = let st = { st with pinned = OpamPackage.Set.remove nv st.pinned } in (* Restore availability of other versions of this package from the repos *) let repo_package = OpamPackage.Map.filter (fun nv2 _ -> nv2.name = nv.name) st.repos_package_index in let available_packages = lazy ( OpamSwitchState.compute_available_packages st.switch_global st.switch st.switch_config ~pinned:OpamPackage.Set.empty ~opams:repo_package |> OpamPackage.Set.union (OpamPackage.Set.remove nv (Lazy.force st.available_packages)) ) in match OpamPackage.Map.find_opt nv st.repos_package_index, OpamPackage.Map.find_opt nv st.installed_opams with | None, None -> OpamSwitchState.remove_package_metadata nv st | Some opam, _ | None, Some opam -> (* forget about overlay *) let st = OpamSwitchState.update_package_metadata nv opam st in { st with available_packages } let unpin st names = log "unpin %a" (slog @@ OpamStd.List.concat_map " " OpamPackage.Name.to_string) names; List.fold_left (fun st name -> OpamFilename.rmdir (OpamPath.Switch.pinned_package st.switch_global.root st.switch name); OpamFilename.rmdir (OpamPath.Switch.Overlay.package st.switch_global.root st.switch name); match OpamPinned.package_opt st name with | Some nv -> let pin_str = OpamStd.Option.to_string ~none:"pinned" string_of_pinned (OpamSwitchState.opam_opt st nv) in let st = unpin_one st nv in if not OpamClientConfig.(!r.show) then OpamSwitchAction.write_selections st; OpamConsole.msg "Ok, %s is no longer %s\n" (OpamPackage.Name.to_string name) pin_str; st | None -> OpamConsole.note "%s is not pinned." (OpamPackage.Name.to_string name); st) st names let list st ~short = log "pin_list"; if short then OpamPackage.Set.iter (fun nv -> OpamConsole.msg "%s\n" (OpamPackage.name_to_string nv)) st.pinned else let lines nv = try let opam = OpamSwitchState.opam st nv in let url = OpamFile.OPAM.url opam in let kind, target = if OpamSwitchState.is_version_pinned st nv.name then "version", OpamPackage.Version.to_string nv.version else match url with | Some url -> let u = OpamFile.URL.url url in let subpath = match OpamFile.URL.subpath url with | None -> "" | Some s -> " ("^s^")" in OpamUrl.string_of_backend u.OpamUrl.backend, OpamUrl.to_string u ^ subpath | None -> "local definition", "" in let state, extra = try let inst = OpamSwitchState.find_installed_package_by_name st nv.name in if inst.version = nv.version then "",[] else OpamConsole.colorise `red "(not in sync)", [Printf.sprintf "(installed:%s)" (OpamConsole.colorise `bold (OpamPackage.version_to_string inst))] with Not_found -> OpamConsole.colorise `yellow "(uninstalled)", [] in [ OpamPackage.to_string nv; state; OpamConsole.colorise `blue kind; String.concat " " (target::extra) ] with Not_found -> [ OpamPackage.to_string nv; OpamConsole.colorise `red " (no definition found)" ] in let table = List.map lines (OpamPackage.Set.elements st.pinned) in OpamConsole.print_table stdout ~sep:" " (OpamStd.Format.align_table table) (* Must not be contained in a package name, version, nor url *) let scan_sep = '^' let scan ~normalise ~recurse ?subpath url = let open OpamStd.Option.Op in let pins_of_dir dir = OpamPinned.files_in_source ~recurse ?subpath dir |> OpamStd.List.filter_map (fun (nf, opamf, sb) -> let opam = OpamFile.OPAM.safe_read opamf in match (nf ++ OpamFile.OPAM.name_opt opam) with | Some name -> Some (name, (OpamFile.OPAM.version_opt opam), sb) | None -> OpamConsole.warning "Can not retrieve a package name from %s" (OpamFilename.to_string (OpamFile.filename opamf)); None) in let pins, cleanup = match OpamUrl.local_dir url with | Some dir -> pins_of_dir dir, None | None -> let pin_cache_dir = OpamRepositoryPath.pin_cache url in let cleanup = fun () -> OpamFilename.rmdir @@ OpamRepositoryPath.pin_cache_dir () in let basename = match OpamStd.String.split (OpamUrl.basename url) '.' with | [] -> OpamConsole.error_and_exit `Bad_arguments "Can not retrieve a path from '%s'" (OpamUrl.to_string url) | b::_ -> b in try let open OpamProcess.Job.Op in OpamProcess.Job.run @@ OpamRepository.pull_tree ~cache_dir:(OpamRepositoryPath.download_cache OpamStateConfig.(!r.root_dir)) basename pin_cache_dir [] [url] @@| function | Not_available (_,u) -> OpamConsole.error_and_exit `Sync_error "Could not retrieve %s" u | Result _ | Up_to_date _ -> pins_of_dir pin_cache_dir, Some cleanup with e -> OpamStd.Exn.finalise e cleanup in let finalise = OpamStd.Option.default (fun () -> ()) cleanup in OpamStd.Exn.finally finalise @@ fun () -> if normalise then OpamConsole.msg "%s" (OpamStd.List.concat_map "\n" (fun (name, version, sb) -> Printf.sprintf "%s%s%c%s%s" (OpamPackage.Name.to_string name) (OpamStd.Option.to_string (fun v -> "." ^OpamPackage.Version.to_string v) version) scan_sep (OpamUrl.to_string url) (OpamStd.Option.to_string (fun sb -> (String.make 1 scan_sep) ^ sb) sb)) pins) else ["# Name"; "# Version"; "# Url" (*; "# Subpath"*)] :: List.map (fun (name, version, _sb) -> [ OpamPackage.Name.to_string name; (version >>| OpamPackage.Version.to_string) +! "-"; OpamUrl.to_string url; (*sb +! "-"*) ]) pins |> OpamStd.Format.align_table |> OpamConsole.print_table stdout ~sep:" " let looks_like_normalised args = List.for_all (fun s -> OpamStd.String.contains_char s scan_sep) args let parse_pins pins = let separator = Re.char scan_sep in let re = Re.(compile @@ whole_string @@ seq [ (* package name *) group @@ rep1 @@ alt [ alnum; diff punct (alt [char '.'; char scan_sep]) ]; (* optional version *) opt @@ seq [ char '.'; group @@ rep1 @@ alt [ alnum; diff punct separator ]]; separator; (* url *) group @@ rep1 @@ diff any separator; (* optional subpath *) opt @@ seq [ separator; group @@ rep1 any ]; ]) in let get s = try let groups = Re.exec re s in Some ( Re.Group.( OpamPackage.Name.of_string @@ get groups 1, OpamStd.Option.map OpamPackage.Version.of_string @@ OpamStd.Option.of_Not_found (get groups) 2, OpamUrl.parse @@ get groups 3, OpamStd.Option.of_Not_found (get groups) 4) ) with Not_found | Failure _ -> None in OpamStd.List.filter_map (fun str -> let pin = get str in if pin = None then (OpamConsole.warning "Argument %S is not correct" str; None) else pin) pins opam-2.1.5/src/client/opamSolution.ml0000644000175000017500000013766414427463453016630 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) let log fmt = OpamConsole.log "SOLUTION" fmt open OpamTypes open OpamTypesBase open OpamStateTypes open OpamProcess.Job.Op module PackageAction = OpamSolver.Action module PackageActionGraph = OpamSolver.ActionGraph exception Fetch_fail of string let post_message ?(failed=false) st action = match action, failed with | `Remove _, _ | `Reinstall _, _ | `Build _, false | `Fetch _, _ -> () | `Build pkg, true | `Install pkg, _ | `Change (_,_,pkg), _ -> let opam = OpamSwitchState.opam st pkg in let messages = OpamFile.OPAM.post_messages opam in let local_variables = OpamVariable.Map.empty in let local_variables = OpamVariable.Map.add (OpamVariable.of_string "success") (Some (B (not failed))) local_variables in let local_variables = OpamVariable.Map.add (OpamVariable.of_string "failure") (Some (B failed)) local_variables in let messages = let filter_env = OpamPackageVar.resolve ~opam ~local:local_variables st in OpamStd.List.filter_map (fun (message,filter) -> if OpamFilter.opt_eval_to_bool filter_env filter then Some (OpamFilter.expand_string ~default:(fun _ -> "") filter_env message) else None) messages in let mark = OpamConsole.colorise (if failed then `red else `green) "=> " in if messages <> [] then ( OpamConsole.header_msg "%s %s" (OpamPackage.to_string pkg) (if failed then "troubleshooting" else "installed successfully"); List.iter (fun msg -> OpamConsole.formatted_msg ~indent:(OpamStd.Format.visual_length mark) "%s%s\n" mark msg) messages ) let print_depexts_helper st actions = if OpamFile.Config.depext st.switch_global.config then () else let depexts = List.fold_left (fun depexts -> function | `Build nv -> OpamSysPkg.Set.union depexts (OpamSwitchState.depexts st nv) | _ -> depexts) OpamSysPkg.Set.empty actions in if not (OpamSysPkg.Set.is_empty depexts) then ( OpamConsole.formatted_msg "\nThe packages you requested declare the following system dependencies. \ Please make sure they are installed before retrying:\n"; OpamConsole.formatted_msg ~indent:4 " %s\n\n" (OpamStd.List.concat_map " " (fun s -> OpamConsole.colorise `bold (OpamSysPkg.to_string s)) (OpamSysPkg.Set.elements depexts)) ) let check_solution ?(quiet=false) st = function | Conflicts _ -> OpamConsole.msg "No solution found, exiting\n"; OpamStd.Sys.exit_because `No_solution | Success (Partial_error { actions_successes; actions_errors; _ }) -> List.iter (post_message st) actions_successes; List.iter (fun (a, _) -> post_message ~failed:true st a) actions_errors; print_depexts_helper st (List.map fst actions_errors); OpamEnv.check_and_print_env_warning st; let reason = if List.for_all (function _, Fetch_fail _ -> true | _ -> false) actions_errors then `Sync_error else `Package_operation_error in OpamStd.Sys.exit_because reason | Success (OK actions) -> List.iter (post_message st) actions; OpamEnv.check_and_print_env_warning st | Success Nothing_to_do -> if not quiet then OpamConsole.msg "Nothing to do.\n"; OpamEnv.check_and_print_env_warning st | Success Aborted -> if not OpamClientConfig.(!r.show) then OpamStd.Sys.exit_because `Aborted let sum stats = stats.s_install + stats.s_reinstall + stats.s_remove + stats.s_upgrade + stats.s_downgrade let eq_atom name version = name, Some (`Eq, version) let eq_atom_of_package nv = eq_atom nv.name nv.version let eq_atoms_of_packages set = List.rev_map eq_atom_of_package (OpamPackage.Set.elements set) let atom_of_package nv = nv.name, None let atoms_of_packages set = List.rev_map (fun n -> n, None) (OpamPackage.Name.Set.elements (OpamPackage.names_of_packages set)) (* unused? let atom_of_name name = name, None *) let check_availability ?permissive t set atoms = let available = OpamPackage.to_map set in let check_depexts atom = let pkgs = OpamFormula.packages_of_atoms t.packages [atom] in if OpamPackage.Set.is_empty pkgs then None else match OpamSwitchState.depexts_unavailable t (OpamPackage.Set.max_elt pkgs) with | Some missing -> let missing = List.rev_map OpamSysPkg.to_string (OpamSysPkg.Set.elements missing) in let msg = match missing with | [pkg] -> " '" ^ pkg ^ "'" | pkgs -> "s " ^ (OpamStd.Format.pretty_list (List.rev_map (Printf.sprintf "'%s'") pkgs)) in Some (Printf.sprintf "Package %s depends on the unavailable system package%s. You \ can use `--no-depexts' to attempt installation anyway.%s" (OpamFormula.short_string_of_atom atom) msg (OpamStd.Option.map_default (Printf.sprintf "\n%s.") "" (OpamSysInteract.repo_enablers ()))) | None -> None in let check_atom (name, cstr as atom) = let exists = try OpamPackage.Version.Set.exists (fun v -> OpamFormula.check atom (OpamPackage.create name v)) (OpamPackage.Name.Map.find name available) with Not_found -> false in if exists then None else match check_depexts atom with Some _ as some -> some | None -> if permissive = Some true then Some (OpamSwitchState.not_found_message t atom) else let f = name, match cstr with None -> Empty | Some c -> Atom c in Some (Printf.sprintf "%s %s" (OpamFormula.to_string (Atom f)) (OpamSwitchState.unavailable_reason ~default:"unavailable for unknown reasons (this may be a bug in \ opam)" t f)) in let errors = OpamStd.List.filter_map check_atom atoms in if errors <> [] then (List.iter (OpamConsole.error "%s") errors; OpamStd.Sys.exit_because `Not_found) let fuzzy_name t name = let lname = String.lowercase_ascii (OpamPackage.Name.to_string name) in let match_name nv = lname = String.lowercase_ascii (OpamPackage.name_to_string nv) in let matches = OpamPackage.Set.union (OpamPackage.Set.filter match_name t.installed) (OpamPackage.Set.filter match_name t.packages) in let names = OpamPackage.names_of_packages matches in match OpamPackage.Name.Set.elements names with | [name] -> name | _ -> name let sanitize_atom_list ?(permissive=false) t atoms = let atoms = List.map (fun (name,cstr) -> fuzzy_name t name, cstr) atoms in if permissive then check_availability ~permissive t (OpamPackage.Set.union t.packages t.installed) atoms else check_availability t (OpamPackage.Set.union (Lazy.force t.available_packages) t.installed) atoms; atoms (* Pretty-print errors *) let display_error (n, error) = let f action nv = let disp = OpamConsole.header_error "while %s %s" action (OpamPackage.to_string nv) in match error with | Sys.Break | OpamParallel.Aborted -> () | Failure s -> disp "%s" s | OpamSystem.Process_error e -> disp "%s" (OpamProcess.string_of_result e) | e -> disp "%s" (Printexc.to_string e); if OpamConsole.debug () then OpamConsole.errmsg "%s" (OpamStd.Exn.pretty_backtrace e) in match n with | `Change (`Up, _, nv) -> f "upgrading to" nv | `Change (`Down, _, nv) -> f "downgrading to" nv | `Install nv -> f "installing" nv | `Reinstall nv -> f "recompiling" nv | `Remove nv -> f "removing" nv | `Build nv -> f "compiling" nv | `Fetch nv -> f "fetching sources for" nv module Json = struct let output_request request user_action = if OpamClientConfig.(!r.json_out = None) then () else let atoms = List.map (fun a -> `String (OpamFormula.short_string_of_atom a)) in let j = `O [ "action", `String (string_of_user_action user_action); "install", `A (atoms request.wish_install); "remove", `A (atoms request.wish_remove); "upgrade", `A (atoms request.wish_upgrade); "criteria", `String (OpamSolverConfig.criteria request.criteria); ] in OpamJson.append "request" j let output_solution t solution = if OpamClientConfig.(!r.json_out = None) then () else match solution with | Success solution -> let action_graph = OpamSolver.get_atomic_action_graph solution in let to_proceed = PackageActionGraph.Topological.fold (fun a acc -> PackageAction.to_json a :: acc ) action_graph [] in OpamJson.append "solution" (`A (List.rev to_proceed)) | Conflicts cs -> let causes, cycles = OpamCudf.conflict_explanations t.packages (OpamSwitchState.unavailable_reason t) cs in let causes = List.map OpamCudf.string_of_conflict causes in let toj l = `A (List.map (fun s -> `String s) l) in OpamJson.append "conflicts" (`O ((if cycles <> [] then ["cycles", toj cycles] else []) @ (if causes <> [] then ["causes", toj causes] else []))) let exc e = let lmap f l = List.rev (List.rev_map f l) in if OpamClientConfig.(!r.json_out = None) then `O [] else match e with | OpamSystem.Process_error {OpamProcess.r_code; r_duration; r_info; r_stdout; r_stderr; _} -> `O [ ("process-error", `O ([ ("code", `String (string_of_int r_code)); ("duration", `Float r_duration); ("info", `O (lmap (fun (k,v) -> (k, `String v)) r_info)); ] @ if OpamCoreConfig.(!r.merged_output) then [("output", `A (lmap (fun s -> `String s) r_stdout))] else [("output", `A (lmap (fun s -> `String s) r_stdout)); ("stderr", `A (lmap (fun s -> `String s) r_stderr)); ]))] | OpamSystem.Internal_error s -> `O [ ("internal-error", `String s) ] | e -> `O [ ("exception", `String (Printexc.to_string e)) ] end (* Process the atomic actions in a graph in parallel, respecting graph order, and report to user. Takes a graph of atomic actions *) let parallel_apply t ~requested ?add_roots ~assume_built ~download_only ?(force_remove=false) action_graph = log "parallel_apply"; let remove_action_packages = PackageActionGraph.fold_vertex (function `Remove nv -> OpamPackage.Set.add nv | _ -> fun acc -> acc) action_graph OpamPackage.Set.empty in let install_action_packages = PackageActionGraph.fold_vertex (function `Install nv -> OpamPackage.Set.add nv | _ -> fun acc -> acc) action_graph OpamPackage.Set.empty in (* the core set of installed packages that won't change *) let minimal_install = OpamPackage.Set.Op.(t.installed -- remove_action_packages) in let wished_removed = OpamPackage.Set.filter (fun nv -> not (OpamPackage.has_name install_action_packages nv.name)) remove_action_packages in let root_installs = OpamPackage.Name.Set.union (OpamPackage.names_of_packages t.installed_roots) @@ match add_roots with | Some r -> r | None -> OpamPackage.Name.Set.diff (OpamPackage.names_of_packages requested) (OpamPackage.names_of_packages remove_action_packages) in (* We keep an imperative state up-to-date and flush it to disk as soon as an operation terminates *) let t_ref = ref t in (* only needed when --update-invariant is set. Use the configured invariant, not the current one which will be empty. *) let original_invariant = OpamStd.Option.default OpamFormula.Empty t.switch_config.OpamFile.Switch_config.invariant in let original_invariant_packages = OpamFormula.packages t.installed original_invariant in let invariant_ref = ref original_invariant in let bypass_ref = ref (t.switch_config.OpamFile.Switch_config.depext_bypass) in let add_to_install nv conf = let root = OpamPackage.Name.Set.mem nv.name root_installs in let t = !t_ref in let conf_files = let add_conf conf = OpamPackage.Name.Map.add nv.name conf t.conf_files in OpamStd.Option.map_default add_conf t.conf_files conf in t_ref := OpamSwitchAction.add_to_installed {t with conf_files} ~root nv; let missing_depexts = (* Turns out these depexts weren't needed after all. Remember that and make the bypass permanent. *) try (OpamPackage.Map.find nv (Lazy.force !t_ref.sys_packages)).s_available with Not_found -> OpamSysPkg.Set.empty in let bypass = OpamSysPkg.Set.union missing_depexts !bypass_ref in let invariant = if OpamStateConfig.(!r.unlock_base) then let update_cstr cstr = if OpamFormula.check_version_formula cstr nv.version then cstr else OpamFormula.map (fun (relop, _ as vat) -> if OpamFormula.check_version_formula (Atom vat) nv.version then Atom vat else match relop with | `Neq -> OpamFormula.Empty | `Gt -> Atom (`Geq, nv.version) | `Lt -> Atom (`Leq, nv.version) | `Eq | `Geq | `Leq -> Atom (relop, nv.version)) cstr in let nvset = OpamPackage.Set.singleton nv in let upd_packages = OpamSwitchState.conflicts_with t nvset original_invariant_packages in OpamFormula.map (fun (n, cstr as at) -> if OpamPackage.Set.exists (OpamFormula.verifies (Atom at)) upd_packages then (* a package in the previous base validated this atom but is in conflict with what we just installed *) Atom (nv.name, update_cstr cstr) else if n = nv.name then Atom (n, update_cstr cstr) else Atom at) !invariant_ref else !invariant_ref in if bypass <> !bypass_ref || invariant <> !invariant_ref then (if bypass <> !bypass_ref then (let spkgs = OpamSysPkg.Set.Op.(bypass -- !bypass_ref) in OpamConsole.note "Requirement for system package%s %s overridden in this switch. Use \ `opam option depext-bypass-=%s' to revert." (if OpamSysPkg.Set.cardinal spkgs > 1 then "s" else "") (OpamStd.Format.pretty_list (List.map OpamSysPkg.to_string (OpamSysPkg.Set.elements spkgs))) (OpamStd.List.concat_map "," OpamSysPkg.to_string (OpamSysPkg.Set.elements spkgs))); bypass_ref := bypass; invariant_ref := invariant; let switch_config = {!t_ref.switch_config with invariant = Some invariant; depext_bypass = bypass } in t_ref := {!t_ref with switch_invariant = invariant; switch_config}; if not OpamStateConfig.(!r.dryrun) then OpamSwitchAction.install_switch_config t.switch_global.root t.switch switch_config) in let remove_from_install ?keep_as_root nv = t_ref := OpamSwitchAction.remove_from_installed ?keep_as_root !t_ref nv in let inplace = if OpamClientConfig.(!r.inplace_build) || assume_built then OpamPackage.Set.fold (fun nv acc -> match OpamStd.Option.Op.(OpamSwitchState.url t nv >>| OpamFile.URL.url >>= OpamUrl.local_dir) with | None -> acc | Some path -> OpamPackage.Map.add nv path acc) requested OpamPackage.Map.empty else OpamPackage.Map.empty in let sources_needed = let sources_needed = OpamAction.sources_needed t action_graph in if not OpamClientConfig.(!r.working_dir) then sources_needed else OpamPackage.Set.Op.(sources_needed -- requested) in (* 1/ process the package actions (fetch, build, installations and removals) *) let action_graph = (* Add build and fetch actions *) let noop_remove nv = OpamAction.noop_remove_package t nv in PackageActionGraph.explicit ~noop_remove ~sources_needed:(fun p -> OpamPackage.Set.mem p sources_needed) action_graph in let action_graph = if download_only then (* remove actions other than fetches *) let g = PackageActionGraph.copy action_graph in PackageActionGraph.iter_vertex (fun v -> match v with | `Fetch _ -> () | `Install _ | `Reinstall _ | `Change _ | `Remove _ | `Build _ -> PackageActionGraph.remove_vertex g v ) action_graph; g else action_graph in (match OpamSolverConfig.(!r.cudf_file) with | None -> () | Some f -> let filename = Printf.sprintf "%s-actions-explicit.dot" f in let oc = open_out filename in OpamSolver.ActionGraph.Dot.output_graph oc action_graph; close_out oc); let timings = Hashtbl.create 17 in (* the child job to run on each action *) let job ~pred action = let installed, removed, failed = List.fold_left (fun (inst,rem,fail) -> function | _, `Successful (inst1, rem1) -> OpamPackage.Set.Op.(inst ++ inst1, rem ++ rem1, fail) | _, `Error (`Aborted a) -> inst, rem, PackageAction.Set.Op.(a ++ fail) | a, (`Exception _ | `Error _) -> inst, rem, PackageAction.Set.add a fail) (OpamPackage.Set.empty, OpamPackage.Set.empty, PackageAction.Set.empty) pred in (* Check whether prerequisites failed *) let action_is_remove = match action with `Remove _ -> true | _ -> false in let has_failure = not (PackageAction.Set.is_empty failed) in let has_nonfetch_failure = List.exists (function | (_, `Successful _) | (`Fetch _, _) -> false | _ -> true) pred in if has_failure && (not action_is_remove || has_nonfetch_failure) then (* fatal error *) Done (`Error (`Aborted failed)) else let store_time = let t0 = Unix.gettimeofday () in fun () -> Hashtbl.add timings action (Unix.gettimeofday () -. t0) in let not_yet_removed = match action with | `Remove _ -> PackageActionGraph.fold_descendants (function | `Remove nv -> OpamPackage.Set.add nv | _ -> fun acc -> acc) OpamPackage.Set.empty action_graph action | _ -> OpamPackage.Set.empty in let visible_installed = OpamPackage.Set.Op.(minimal_install ++ not_yet_removed ++ installed) in let t = { !t_ref with installed = visible_installed; conf_files = OpamPackage.Name.Map.filter (fun name _ -> OpamPackage.Set.exists (fun pkg -> OpamPackage.Name.equal name pkg.name) visible_installed) !t_ref.conf_files; } in let nv = action_contents action in let opam = OpamSwitchState.opam t nv in let source_dir = let raw = OpamSwitchState.source_dir t nv in match OpamFile.OPAM.url opam with | None -> raw | Some url -> match OpamFile.URL.subpath url with | None -> raw | Some subpath -> OpamFilename.Op.(raw / subpath) in if OpamClientConfig.(!r.fake) then match action with | `Build _ | `Fetch _ -> Done (`Successful (installed, removed)) | `Install nv -> OpamConsole.msg "Faking installation of %s\n" (OpamPackage.to_string nv); add_to_install nv None; Done (`Successful (OpamPackage.Set.add nv installed, removed)) | `Remove nv -> remove_from_install nv; Done (`Successful (installed, OpamPackage.Set.add nv removed)) | _ -> assert false else match action with | `Fetch nv -> log "Fetching sources for %s" (OpamPackage.to_string nv); (OpamAction.download_package t nv @@+ function | None -> store_time (); Done (`Successful (installed, removed)) | Some (_short_error, long_error) -> Done (`Exception (Fetch_fail long_error))) | `Build nv -> if assume_built && OpamPackage.Set.mem nv requested then (log "Skipping build for %s, just install%s" (OpamPackage.to_string nv) (OpamStd.Option.map_default (fun p -> " from " ^ OpamFilename.Dir.to_string p) "" (OpamPackage.Map.find_opt nv inplace)); Done (`Successful (installed, removed))) else let is_inplace, build_dir = try true, OpamPackage.Map.find nv inplace with Not_found -> let dir = OpamPath.Switch.build t.switch_global.root t.switch nv in if not OpamClientConfig.(!r.reuse_build_dir) then OpamFilename.rmdir dir; false, dir in let test = OpamStateConfig.(!r.build_test) && OpamPackage.Set.mem nv requested in let doc = OpamStateConfig.(!r.build_doc) && OpamPackage.Set.mem nv requested in (if OpamFilename.exists_dir source_dir then (if not is_inplace then OpamFilename.copy_dir ~src:source_dir ~dst:build_dir) else OpamFilename.mkdir build_dir; OpamAction.prepare_package_source t nv build_dir @@+ function | Some exn -> store_time (); Done (`Exception exn) | None -> OpamAction.build_package t ~test ~doc build_dir nv @@+ function | Some exn -> store_time (); Done (`Exception exn) | None -> store_time (); Done (`Successful (installed, removed))) | `Install nv -> let test = OpamStateConfig.(!r.build_test) && OpamPackage.Set.mem nv requested in let doc = OpamStateConfig.(!r.build_doc) && OpamPackage.Set.mem nv requested in let build_dir = OpamPackage.Map.find_opt nv inplace in (OpamAction.install_package t ~test ~doc ?build_dir nv @@+ function | Left conf -> add_to_install nv conf; store_time (); Done (`Successful (OpamPackage.Set.add nv installed, removed)) | Right exn -> store_time (); Done (`Exception exn)) | `Remove nv -> (if OpamAction.removal_needs_download t nv then let d = OpamPath.Switch.remove t.switch_global.root t.switch nv in OpamFilename.rmdir d; if OpamFilename.exists_dir source_dir then OpamFilename.copy_dir ~src:source_dir ~dst:d else OpamFilename.mkdir d; OpamAction.prepare_package_source t nv d else Done None) @@+ fun _ -> OpamProcess.Job.ignore_errors ~default:() (fun () -> OpamAction.remove_package ~force:force_remove t nv) @@| fun () -> remove_from_install ~keep_as_root:(not (OpamPackage.Set.mem nv wished_removed)) nv; store_time (); `Successful (installed, OpamPackage.Set.add nv removed) | _ -> assert false in let action_results = OpamConsole.header_msg "Processing actions"; try let installs_removes, fetches = PackageActionGraph.fold_vertex (fun a (installs_removes, fetches as acc) -> match a with | `Install _ | `Remove _ as i -> (i::installs_removes, fetches) | `Fetch _ as i -> (installs_removes, i::fetches) | _ -> acc) action_graph ([],[]) in let same_inplace_source = OpamPackage.Map.fold (fun nv dir acc -> OpamFilename.Dir.Map.update dir (fun l -> nv::l) [] acc) inplace OpamFilename.Dir.Map.empty |> OpamFilename.Dir.Map.values in let pools = (installs_removes, 1) :: (fetches, OpamStateConfig.(!r.dl_jobs)) :: OpamStd.List.filter_map (fun excl -> match OpamStd.List.filter_map (fun nv -> let act = `Build nv in if PackageActionGraph.mem_vertex action_graph act then Some act else None) excl with [] | [_] -> None | l -> Some (l,1)) same_inplace_source in let results = PackageActionGraph.Parallel.map ~jobs:(Lazy.force OpamStateConfig.(!r.jobs)) ~command:job ~dry_run:OpamStateConfig.(!r.dryrun) ~pools action_graph in (* For backwards-compatibility reasons, we separate the json report for download failures from the json report for the rest *) if OpamClientConfig.(!r.json_out <> None) then begin (* Report download failures *) let failed_downloads = List.fold_left (fun failed (a, err) -> match (a, err) with | `Fetch pkg, `Exception (Fetch_fail long_error) -> OpamPackage.Map.add pkg long_error failed | _ -> failed ) OpamPackage.Map.empty results in if not (OpamPackage.Map.is_empty failed_downloads) then OpamJson.append "download-failures" (`O (List.map (fun (nv, err) -> OpamPackage.to_string nv, `String err) (OpamPackage.Map.bindings failed_downloads))); (* Report build/install/remove failures *) let j = PackageActionGraph.Topological.fold (fun a acc -> match a with | `Fetch _ -> acc | _ -> let r = match List.assoc a results with | `Successful _ -> `String "OK" | `Exception e -> Json.exc e | `Error (`Aborted deps) -> let deps = OpamSolver.Action.Set.elements deps in `O ["aborted", `A (List.map OpamSolver.Action.to_json deps)] in let duration = try [ "duration", `Float (Hashtbl.find timings a) ] with Not_found -> [] in `O ([ "action", PackageAction.to_json a; "result", r ] @ duration) :: acc ) action_graph [] in OpamJson.append "results" (`A (List.rev j)) end; let success, failure, aborted = List.fold_left (fun (success, failure, aborted) -> function | a, `Successful _ -> a::success, failure, aborted | a, `Exception e -> success, (a,e)::failure, aborted | a, `Error (`Aborted _) -> success, failure, a::aborted ) ([], [], []) results in let actions_result = { actions_successes = success; actions_errors = failure; actions_aborted = aborted; } in if failure = [] && aborted = [] then `Successful success else ( List.iter display_error failure; `Error (Partial_error actions_result) ) with | PackageActionGraph.Parallel.Errors (success, errors, remaining) -> let actions_result = { actions_successes = success; actions_errors = errors; actions_aborted = remaining; } in List.iter display_error errors; `Error (Partial_error actions_result) | e -> `Exception e in let t = !t_ref in (* 2/ Display errors and finalize *) OpamSwitchState.Installed_cache.save (OpamPath.Switch.installed_opams_cache t.switch_global.root t.switch) (OpamPackage.Set.fold (fun nv opams -> let opam = OpamSwitchState.opam t nv |> OpamFile.OPAM.with_metadata_dir None in OpamPackage.Map.add nv opam opams) t.installed OpamPackage.Map.empty); let cleanup_artefacts graph = PackageActionGraph.iter_vertex (function | `Remove nv when not (OpamPackage.has_name t.pinned nv.name) -> OpamAction.cleanup_package_artefacts t nv (* if reinstalled, only removes build dir *) | `Install nv when not (OpamPackage.has_name t.pinned nv.name) || OpamSwitchState.is_version_pinned t nv.name -> let build_dir = OpamPath.Switch.build t.switch_global.root t.switch nv in if not OpamClientConfig.(!r.keep_build_dir) then OpamFilename.rmdir build_dir | `Remove _ | `Install _ | `Build _ | `Fetch _ -> () | _ -> assert false) graph in let t = if OpamStateConfig.(!r.unlock_base) && (match action_results with `Successful _ -> true | _ -> false) && not (OpamFormula.satisfies_depends t.installed t.switch_invariant) then (* Fix the invariant to account for removed base packages *) let invariant = OpamFormula.map_formula (function | OpamFormula.And _ as f -> f | f when OpamFormula.satisfies_depends t.installed f -> f | _ -> OpamFormula.Empty) t.switch_invariant in let switch_config = {t.switch_config with invariant = Some invariant} in if not OpamStateConfig.(!r.dryrun) then OpamSwitchAction.install_switch_config t.switch_global.root t.switch switch_config; {t with switch_invariant = invariant; switch_config} else t in if t.switch_invariant <> original_invariant then OpamConsole.note "Switch invariant %s updated to %s\n\ Use `opam switch set-invariant' to change it." (if OpamStateConfig.(!r.dryrun) then "would have been" else "was") (match t.switch_invariant with | OpamFormula.Empty -> "" | f -> OpamFileTools.dep_formula_to_string f); match action_results with | `Successful successful -> cleanup_artefacts action_graph; OpamConsole.msg "Done.\n"; t, OK successful | `Exception (OpamStd.Sys.Exit _ | Sys.Break as e) -> OpamConsole.msg "Aborting.\n"; raise e | `Exception (OpamSolver.ActionGraph.Parallel.Cyclic cycles as e) -> OpamConsole.error "Cycles found during dependency resolution:\n%s" (OpamStd.Format.itemize (OpamStd.List.concat_map (OpamConsole.colorise `yellow " -> ") OpamSolver.Action.to_string) cycles); raise e | `Exception (OpamSystem.Process_error _ | Unix.Unix_error _ as e) -> OpamConsole.error "Actions cancelled because of a system error:"; OpamConsole.errmsg "%s\n" (Printexc.to_string e); raise e | `Exception e -> OpamConsole.error "Actions cancelled because of %s" (Printexc.to_string e); raise e | `Error err -> match err with | Aborted -> t, err | Partial_error solution_res -> let successful = solution_res.actions_successes in let failed = List.map fst solution_res.actions_errors in let remaining = solution_res.actions_aborted in (* Cleanup build/install actions when one of them failed, it's verbose and doesn't add information *) let successful = List.filter (function | `Fetch p | `Build p when List.mem (`Install p) failed -> false | _ -> true) successful in let remaining = List.filter (function | `Remove p | `Install p when List.mem (`Build p) failed -> false | `Remove p | `Install p | `Build p when List.mem (`Fetch p) failed -> false | _ -> true) remaining in let removes_missing_source = List.filter (function | `Remove p as rem -> let fetch = `Fetch p in List.mem fetch failed && PackageActionGraph.mem_edge action_graph fetch rem | _ -> false ) successful in let failed = (* Filter out failed fetches that were just for removals, there is a shorter message for them *) List.filter (function | `Fetch _ as a -> let succ = PackageActionGraph.succ action_graph a in not (List.for_all (fun a -> List.mem a removes_missing_source) succ) | _ -> true) failed in let filter_graph l = if l = [] then PackageActionGraph.create () else let g = PackageActionGraph.copy action_graph in PackageActionGraph.iter_vertex (fun v -> if not (List.mem v l) then PackageActionGraph.remove_vertex g v) g; g in let successful = filter_graph successful in cleanup_artefacts successful; let successful = PackageActionGraph.reduce successful in let failed = PackageActionGraph.reduce (filter_graph failed) in let print_actions filter tint header ?empty actions = let actions = PackageActionGraph.fold_vertex (fun v acc -> if filter v then v::acc else acc) actions [] in let actions = List.sort PackageAction.compare actions in if actions <> [] then OpamConsole.(msg "%s%s\n%s%s\n" (colorise tint (Printf.sprintf "%s%s " (utf8_symbol Symbols.box_drawings_light_down_and_right "+") (utf8_symbol Symbols.box_drawings_light_horizontal "-"))) header (OpamStd.Format.itemize ~bullet:(colorise tint (utf8_symbol Symbols.box_drawings_light_vertical "|" ^ " ")) (fun x -> x) (List.map (String.concat " ") @@ OpamStd.Format.align_table (PackageAction.to_aligned_strings actions))) (colorise tint (Printf.sprintf "%s%s " (utf8_symbol Symbols.box_drawings_light_up_and_right "+") (utf8_symbol Symbols.box_drawings_light_horizontal "-")))) else match empty with | Some s -> OpamConsole.(msg "%s%s\n" (colorise tint (Printf.sprintf "%s%s " (utf8_symbol Symbols.box_drawings_light_right "-") (utf8_symbol Symbols.box_drawings_light_horizontal ""))) s) | None -> () in if removes_missing_source <> [] then (OpamConsole.msg "\n"; OpamConsole.warning "The sources of the following couldn't be obtained, they may be \ uncleanly removed:\n%s" (OpamStd.Format.itemize (fun rm -> OpamPackage.to_string (action_contents rm)) removes_missing_source)); OpamConsole.msg "\n"; OpamConsole.header_msg "Error report"; if OpamConsole.debug () || OpamConsole.verbose () then print_actions (fun _ -> true) `yellow (Printf.sprintf "The following actions were %s" (OpamConsole.colorise `yellow "aborted")) (PackageActionGraph.reduce (filter_graph remaining)); print_actions (fun _ -> true) `red (Printf.sprintf "The following actions %s" (OpamConsole.colorise `red "failed")) failed; print_actions (function `Build _ | `Fetch _ -> false | _ -> true) `cyan ("The following changes have been performed" ^ if remaining <> [] then " (the rest was aborted)" else "") ~empty:"No changes have been performed" successful; t, err | _ -> assert false let simulate_new_state state t = let installed = OpamSolver.ActionGraph.Topological.fold (fun action installed -> match action with | `Install p | `Change (_,_,p) | `Reinstall p -> OpamPackage.Set.add p installed | `Remove p -> OpamPackage.Set.remove p installed | `Build _ | `Fetch _ -> installed ) t state.installed in { state with installed } (* Ask confirmation whenever the packages to modify are not exactly the packages in the user request *) let confirmation ?ask requested solution = OpamCoreConfig.answer_is_yes () || match ask with | Some false -> true | Some true -> OpamConsole.confirm "Do you want to continue?" | None -> let open PackageActionGraph in let solution_packages = fold_vertex (fun v acc -> OpamPackage.Name.Set.add (OpamPackage.name (action_contents v)) acc) solution OpamPackage.Name.Set.empty in OpamPackage.Name.Set.equal requested solution_packages || OpamConsole.confirm "Do you want to continue?" let run_hook_job t name ?(local=[]) ?(allow_stdout=false) w = let shell_env = OpamEnv.get_full ~set_opamroot:true ~set_opamswitch:true ~force_path:true t in let mk_cmd = function | cmd :: args -> let text = OpamProcess.make_command_text name ~args cmd in Some (fun () -> OpamSystem.make_command ~verbose:(OpamConsole.verbose ()) ~env:(OpamTypesBase.env_array shell_env) ~name ~text cmd args) | [] -> None in let env v = try Some (List.assoc v local) with Not_found -> OpamPackageVar.resolve_switch t v in let rec iter_commands = function | [] -> Done None | None :: commands -> iter_commands commands | Some cmdf :: commands -> let cmd = cmdf () in cmd @@> fun result -> if allow_stdout then List.iter (OpamConsole.msg "%s\n") result.r_stdout; if OpamProcess.is_success result then iter_commands commands else Done (Some (cmd, result)) in iter_commands (List.map mk_cmd (OpamFilter.commands env w)) @@+ function | Some (cmd, _err) -> OpamConsole.error "The %s hook failed at %S" name (OpamProcess.string_of_command cmd); Done false | None -> Done true let syspkgs_to_string spkgs = OpamStd.List.concat_map " " (fun p -> OpamConsole.colorise `bold (OpamSysPkg.to_string p)) (OpamSysPkg.Set.elements spkgs) let print_depext_msg (avail, nf) = if not (OpamSysPkg.Set.is_empty nf) then OpamConsole.warning "These additional system packages are required, but not available on \ your system: %s" (syspkgs_to_string nf); if not (OpamSysPkg.Set.is_empty avail) then (OpamConsole.formatted_msg "\nThe following system packages will first need to be installed:\n"; OpamConsole.formatted_msg ~indent:4 " %s\n" (syspkgs_to_string avail)) (* Gets depexts from the state, without checking again, unless [recover] is true. *) let get_depexts ?(recover=false) t packages = let sys_packages = if recover then OpamSwitchState.depexts_status_of_packages t packages else Lazy.force t.sys_packages in let avail, nf = OpamPackage.Set.fold (fun pkg (avail,nf) -> match OpamPackage.Map.find_opt pkg sys_packages with | Some sys -> OpamSysPkg.(Set.union avail sys.s_available), OpamSysPkg.(Set.union nf sys.s_not_found) | None -> avail, nf) packages (OpamSysPkg.Set.empty, OpamSysPkg.Set.empty) in print_depext_msg (avail, nf); avail let install_depexts ?(force_depext=false) ?(confirm=true) t packages = let sys_packages = if force_depext || OpamFile.Config.depext t.switch_global.config then get_depexts ~recover:force_depext t packages else OpamSysPkg.Set.empty in if OpamSysPkg.Set.is_empty sys_packages || OpamClientConfig.(!r.show) || OpamClientConfig.(!r.assume_depexts) then t else let print () = let commands = OpamSysInteract.install_packages_commands sys_packages |> List.map (fun (c,a) -> c::a) in OpamConsole.formatted_msg (match commands with | [_] -> "This command should get the requirements installed:\n" | _ -> "These commands should get the requirements installed:\n"); OpamConsole.msg "\n %s\n\n" (OpamStd.List.concat_map "\n " (String.concat " ") commands) in let map_sysmap f t = let sys_packages = OpamPackage.Set.fold (fun nv sys_map -> match OpamPackage.Map.find_opt nv sys_map with | Some status -> OpamPackage.Map.add nv { status with OpamSysPkg.s_available = f status.OpamSysPkg.s_available } sys_map | None -> sys_map) packages (Lazy.force t.sys_packages) in { t with sys_packages = lazy sys_packages } in let recheck t sys_packages = let needed, _notfound = OpamSysInteract.packages_status sys_packages in let installed = OpamSysPkg.Set.diff sys_packages needed in map_sysmap (fun sysp -> OpamSysPkg.Set.diff sysp installed) t, needed in let rec wait msg sys_packages = let give_up () = OpamConsole.formatted_msg "You can retry with '--assume-depexts' to skip this check, or run \ 'opam option depext=false' to permanently disable handling of \ system packages altogether.\n"; OpamStd.Sys.exit_because `Aborted in if not (OpamStd.Sys.tty_in && OpamCoreConfig.answer_is `ask) then give_up () else if OpamConsole.confirm "%s\nWhen you are done: check again and continue?" msg then let t, to_install = recheck t sys_packages in if OpamSysPkg.Set.is_empty to_install then t else let msg = Printf.sprintf "\nThe following remain to be installed: %s" (syspkgs_to_string to_install) in wait msg to_install else if OpamConsole.confirm ~default:false "Do you want to attempt to proceed anyway?" then t else give_up () in OpamConsole.header_msg "Handling external dependencies"; if not (OpamFile.Config.depext_run_installs t.switch_global.config) then (print (); wait "You may now install the packages on your system." sys_packages) else if OpamClientConfig.(!r.fake) then (print (); t) else if not confirm || OpamConsole.confirm ~require_unsafe_yes:true "Let opam run your package manager to install the required system \ packages?\n(answer 'n' for other options)" then try OpamSysInteract.install sys_packages; (* handles dry_run *) map_sysmap (fun _ -> OpamSysPkg.Set.empty) t with Failure msg -> OpamConsole.error "%s" msg; if not confirm then (print (); t) else wait "You can now try to get them installed manually." sys_packages else (OpamConsole.note "Use 'opam option depext-run-installs=false' \ if you don't want to be prompted again."; print (); wait "You may now install the packages manually on your system." sys_packages) (* Apply a solution *) let apply ?ask t ~requested ?add_roots ?(assume_built=false) ?(download_only=false) ?force_remove solution = log "apply"; if OpamSolver.solution_is_empty solution then (* The current state satisfies the request contraints *) t, Nothing_to_do else ( (* Otherwise, compute the actions to perform *) let stats = OpamSolver.stats solution in let show_solution = ask <> Some false in let action_graph = OpamSolver.get_atomic_action_graph solution in let new_state = simulate_new_state t action_graph in OpamPackage.Set.iter (fun p -> try OpamFile.OPAM.print_errors (OpamSwitchState.opam new_state p) with Not_found -> OpamConsole.error "No opam file found for %s" (OpamPackage.to_string p)) (OpamSolver.all_packages solution); if show_solution then ( OpamConsole.msg "The following actions %s be %s:\n" (if OpamClientConfig.(!r.show) then "would" else "will") (if OpamStateConfig.(!r.dryrun) then "simulated" else if OpamClientConfig.(!r.fake) then "faked" else "performed"); let messages p = let opam = OpamSwitchState.opam new_state p in let messages = OpamFile.OPAM.messages opam in OpamStd.List.filter_map (fun (s,f) -> if OpamFilter.opt_eval_to_bool (OpamPackageVar.resolve ~opam new_state) f then Some s else None ) messages in let append nv = (* mark pinned packages with a star *) if OpamPackage.Set.mem nv t.pinned then "*" else "" in OpamSolver.print_solution ~messages ~append ~requested ~reinstall:(Lazy.force t.reinstall) solution; let total_actions = sum stats in if total_actions >= 2 then OpamConsole.msg "===== %s =====\n" (OpamSolver.string_of_stats stats); ); if not OpamClientConfig.(!r.show) && (download_only || confirmation ?ask requested action_graph) then ( let t = install_depexts t @@ OpamPackage.Set.inter new_state.installed (OpamSolver.all_packages solution) in let requested = OpamPackage.packages_of_names new_state.installed requested in let run_job = if OpamStateConfig.(!r.dryrun) || OpamClientConfig.(!r.fake) then OpamProcess.Job.dry_run else OpamProcess.Job.run in let var_def name l = OpamVariable.Full.of_string name, L l in let var_def_pset name set = var_def name (List.map OpamPackage.to_string (OpamPackage.Set.elements set)) in let var_def_spset name set = var_def name (List.map OpamSysPkg.to_string (OpamSysPkg.Set.elements set)) in let depexts = OpamPackage.Set.fold (fun nv depexts -> OpamSysPkg.Set.union depexts (OpamSwitchState.depexts t nv)) new_state.installed OpamSysPkg.Set.empty in let wrappers = OpamFile.Wrappers.add ~outer:(OpamFile.Config.wrappers t.switch_global.config) ~inner:(OpamFile.Switch_config.wrappers t.switch_config) in let pre_session = let open OpamPackage.Set.Op in let local = [ var_def_pset "installed" new_state.installed; var_def_pset "new" (new_state.installed -- t.installed); var_def_pset "removed" (t.installed -- new_state.installed); var_def_spset "depexts" depexts; ] in run_job @@ run_hook_job t "pre-session" ~local ~allow_stdout:true (OpamFile.Wrappers.pre_session wrappers) in if not pre_session then OpamStd.Sys.exit_because `Configuration_error; let t0 = t in let t, r = parallel_apply t ~requested ?add_roots ~assume_built ~download_only ?force_remove action_graph in let success = match r with | OK _ -> true | _ -> false in let post_session = let open OpamPackage.Set.Op in let local = [ var_def_pset "installed" t.installed; var_def_pset "new" (t.installed -- t0.installed); var_def_pset "removed" (t0.installed -- t.installed); OpamVariable.Full.of_string "success", B (success); OpamVariable.Full.of_string "failure", B (not success); ] in run_job @@ run_hook_job t "post-session" ~local ~allow_stdout:true (OpamFile.Wrappers.post_session wrappers) in if not post_session then OpamStd.Sys.exit_because `Configuration_error; t, r ) else t, Aborted ) let resolve t action ~orphans ?reinstall ~requested request = if OpamClientConfig.(!r.json_out <> None) then ( OpamJson.append "command-line" (`A (List.map (fun s -> `String s) (Array.to_list Sys.argv))); OpamJson.append "switch" (OpamSwitch.to_json t.switch) ); let universe = OpamSwitchState.universe t ~requested ?reinstall action in Json.output_request request action; let r = OpamSolver.resolve universe ~orphans request in Json.output_solution t r; r let resolve_and_apply ?ask t action ~orphans ?reinstall ~requested ?add_roots ?(assume_built=false) ?download_only ?force_remove request = match resolve t action ~orphans ?reinstall ~requested request with | Conflicts cs -> log "conflict!"; OpamConsole.msg "%s" (OpamCudf.string_of_conflicts t.packages (OpamSwitchState.unavailable_reason t) cs); t, Conflicts cs | Success solution -> let t, res = apply ?ask t ~requested ?add_roots ~assume_built ?download_only ?force_remove solution in t, Success res opam-2.1.5/src/core/0002755000175000017500000000000014427463453013240 5ustar stephstephopam-2.1.5/src/core/opamCached.mli0000644000175000017500000000247314427463453015773 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Argument type for the [Make] functor *) module type ARG = sig type t val name: string end (** Module handling a simple marshalled cache for a given data structure. A magic number is added to validate the version of the cache. *) module Make (X: ARG): sig type t = X.t (** Marshal and write the cache to disk *) val save: OpamFilename.t -> t -> unit (** Load the cache if it exists and is valid and compatible with the current binary. Clear it otherwise. *) val load: OpamFilename.t -> t option val remove: OpamFilename.t -> unit end opam-2.1.5/src/core/opamFilename.ml0000644000175000017500000004044114427463453016170 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) module Base = struct include OpamStd.AbstractString let check_suffix filename s = Filename.check_suffix filename s let add_extension filename suffix = filename ^ "." ^ suffix end let log fmt = OpamConsole.log "FILENAME" fmt let slog = OpamConsole.slog module Dir = struct include OpamStd.AbstractString let of_string dirname = let dirname = if dirname = "~" then OpamStd.Sys.home () else if OpamStd.String.starts_with ~prefix:("~"^Filename.dir_sep) dirname then Filename.concat (OpamStd.Sys.home ()) (OpamStd.String.remove_prefix ~prefix:("~"^Filename.dir_sep) dirname) else dirname in OpamSystem.real_path (OpamSystem.forward_to_back dirname) let to_string dirname = dirname end let raw_dir s = s let mk_tmp_dir () = Dir.of_string @@ OpamSystem.mk_temp_dir () let with_tmp_dir fn = OpamSystem.with_tmp_dir (fun dir -> fn (Dir.of_string dir)) let with_tmp_dir_job fjob = OpamSystem.with_tmp_dir_job (fun dir -> fjob (Dir.of_string dir)) let rmdir dirname = OpamSystem.remove_dir (Dir.to_string dirname) let rec rmdir_cleanup dirname = let sd = Dir.to_string dirname in if OpamSystem.dir_is_empty sd then ( rmdir dirname; let parent = Filename.dirname sd in if parent <> sd then rmdir_cleanup parent ) let cwd () = Dir.of_string (Unix.getcwd ()) let mkdir dirname = OpamSystem.mkdir (Dir.to_string dirname) let cleandir dirname = log "cleandir %a" (slog Dir.to_string) dirname; OpamSystem.remove (Dir.to_string dirname); mkdir dirname let rec_dirs d = let fs = OpamSystem.rec_dirs (Dir.to_string d) in List.rev (List.rev_map Dir.of_string fs) let dirs d = let fs = OpamSystem.dirs (Dir.to_string d) in List.rev (List.rev_map Dir.of_string fs) let dir_is_empty d = OpamSystem.dir_is_empty (Dir.to_string d) let in_dir dirname fn = OpamSystem.in_dir dirname fn let env_of_list l = Array.of_list (List.rev_map (fun (k,v) -> k^"="^v) l) let exec dirname ?env ?name ?metadata ?keep_going cmds = let env = match env with | None -> None | Some l -> Some (env_of_list l) in in_dir dirname (fun () -> OpamSystem.commands ?env ?name ?metadata ?keep_going cmds) let move_dir ~src ~dst = OpamSystem.command ~verbose:(OpamSystem.verbose_for_base_commands ()) [ "mv"; Dir.to_string src; Dir.to_string dst ] let exists_dir dirname = try (Unix.stat (Dir.to_string dirname)).Unix.st_kind = Unix.S_DIR with Unix.Unix_error _ -> false let opt_dir dirname = if exists_dir dirname then Some dirname else None let basename_dir dirname = Base.of_string (Filename.basename (Dir.to_string dirname)) let dirname_dir dirname = Filename.dirname (Dir.to_string dirname) let link_dir ~target ~link = if exists_dir link then OpamSystem.internal_error "Cannot link: %s already exists." (Dir.to_string link) else OpamSystem.link (Dir.to_string target) (Dir.to_string link) let to_list_dir dir = let base d = Dir.of_string (Filename.basename (Dir.to_string d)) in let rec aux acc dir = let d = dirname_dir dir in if d <> dir then aux (base dir :: acc) d else base dir :: acc in aux [] dir let (/) d1 s2 = let s1 = Dir.to_string d1 in raw_dir (Filename.concat s1 s2) let concat_and_resolve d1 s2 = let s1 = Dir.to_string d1 in Dir.of_string (Filename.concat s1 s2) type t = { dirname: Dir.t; basename: Base.t; } let create dirname basename = let b1 = OpamSystem.forward_to_back (Filename.dirname (Base.to_string basename)) in let b2 = Base.of_string (Filename.basename (Base.to_string basename)) in let dirname = OpamSystem.forward_to_back dirname in if basename = b2 then { dirname; basename } else { dirname = dirname / b1; basename = b2 } let of_basename basename = let dirname = Dir.of_string Filename.current_dir_name in { dirname; basename } let raw str = let dirname = raw_dir (Filename.dirname str) in let basename = Base.of_string (Filename.basename str) in create dirname basename let to_string t = Filename.concat (Dir.to_string t.dirname) (Base.to_string t.basename) let touch t = OpamSystem.write (to_string t) "" let chmod t p = Unix.chmod (to_string t) p let written_since file = let last_update = (Unix.stat (to_string file)).Unix.st_mtime in (Unix.time () -. last_update) let of_string s = let dirname = Filename.dirname s in let basename = Filename.basename s in { dirname = Dir.of_string dirname; basename = Base.of_string basename; } let dirname t = t.dirname let basename t = t.basename let read filename = OpamSystem.read (to_string filename) let open_in filename = try open_in (to_string filename) with Sys_error _ -> raise (OpamSystem.File_not_found (to_string filename)) let open_in_bin filename = try open_in_bin (to_string filename) with Sys_error _ -> raise (OpamSystem.File_not_found (to_string filename)) let open_out filename = try open_out (to_string filename) with Sys_error _ -> raise (OpamSystem.File_not_found (to_string filename)) let open_out_bin filename = try open_out_bin (to_string filename) with Sys_error _ -> raise (OpamSystem.File_not_found (to_string filename)) let write filename raw = OpamSystem.write (to_string filename) raw let remove filename = OpamSystem.remove_file (to_string filename) let exists filename = try (Unix.stat (to_string filename)).Unix.st_kind = Unix.S_REG with Unix.Unix_error _ -> false let opt_file filename = if exists filename then Some filename else None let with_contents fn filename = fn (read filename) let check_suffix filename s = Filename.check_suffix (to_string filename) s let add_extension filename suffix = of_string ((to_string filename) ^ "." ^ suffix) let chop_extension filename = of_string (Filename.chop_extension (to_string filename)) let rec_files d = let fs = OpamSystem.rec_files (Dir.to_string d) in List.rev_map of_string fs let files d = let fs = OpamSystem.files (Dir.to_string d) in List.rev_map of_string fs let files_and_links d = let fs = OpamSystem.files_all_not_dir (Dir.to_string d) in List.rev_map of_string fs let copy ~src ~dst = if src <> dst then OpamSystem.copy_file (to_string src) (to_string dst) let copy_dir ~src ~dst = if src <> dst then OpamSystem.copy_dir (Dir.to_string src) (Dir.to_string dst) let install ?warning ?exec ~src ~dst () = if src <> dst then OpamSystem.install ?warning ?exec (to_string src) (to_string dst) let move ~src ~dst = if src <> dst then OpamSystem.command ~verbose:(OpamSystem.verbose_for_base_commands ()) [ "mv"; to_string src; to_string dst ] let readlink src = if exists src then try let rl = Unix.readlink (to_string src) in if Filename.is_relative rl then of_string (Filename.concat (dirname src) rl) else of_string rl with Unix.Unix_error _ -> src else OpamSystem.internal_error "%s does not exist." (to_string src) let is_symlink src = try let s = Unix.lstat (to_string src) in s.Unix.st_kind = Unix.S_LNK with Unix.Unix_error _ -> false let is_symlink_dir src = try let s = Unix.lstat (Dir.to_string src) in s.Unix.st_kind = Unix.S_LNK with Unix.Unix_error _ -> false let is_exec file = try OpamSystem.is_exec (to_string file) with Unix.Unix_error _ -> OpamSystem.internal_error "%s does not exist." (to_string file) let starts_with dirname filename = OpamStd.String.starts_with ~prefix:(Dir.to_string dirname) (to_string filename) let dir_starts_with pfx dir = OpamStd.String.starts_with ~prefix:(Dir.to_string pfx) (Dir.to_string dir) let remove_prefix prefix filename = let prefix = let str = Dir.to_string prefix in if str = "" then "" else Filename.concat str "" in let filename = to_string filename in OpamStd.String.remove_prefix ~prefix filename let remove_prefix_dir prefix dir = let prefix = Dir.to_string prefix in let dirname = Dir.to_string dir in if prefix = "" then dirname else OpamStd.String.remove_prefix ~prefix dirname |> OpamStd.String.remove_prefix ~prefix:Filename.dir_sep let process_in ?root fn src dst = let basename = match root with | None -> basename src | Some r -> if starts_with r src then remove_prefix r src else OpamSystem.internal_error "%s is not a prefix of %s" (Dir.to_string r) (to_string src) in let dst = Filename.concat (Dir.to_string dst) basename in fn ~src ~dst:(of_string dst) let copy_in ?root = process_in ?root copy let is_archive filename = OpamSystem.is_archive (to_string filename) let extract filename dirname = OpamSystem.extract (to_string filename) ~dir:(Dir.to_string dirname) let extract_job filename dirname = OpamSystem.extract_job (to_string filename) ~dir:(Dir.to_string dirname) let extract_in filename dirname = OpamSystem.extract_in (to_string filename) ~dir:(Dir.to_string dirname) let extract_in_job filename dirname = OpamSystem.extract_in_job (to_string filename) ~dir:(Dir.to_string dirname) let make_tar_gz_job filename dirname = OpamSystem.make_tar_gz_job (to_string filename) ~dir:(Dir.to_string dirname) type generic_file = | D of Dir.t | F of t let extract_generic_file filename dirname = match filename with | F f -> log "extracting %a to %a" (slog to_string) f (slog Dir.to_string) dirname; extract f dirname | D d -> if d <> dirname then ( log "copying %a to %a" (slog Dir.to_string) d (slog Dir.to_string) dirname; copy_dir ~src:d ~dst:dirname ) let ends_with suffix filename = OpamStd.String.ends_with ~suffix (to_string filename) let dir_ends_with suffix dirname = OpamStd.String.ends_with ~suffix (Dir.to_string dirname) let remove_suffix suffix filename = let suffix = Base.to_string suffix in let filename = to_string filename in OpamStd.String.remove_suffix ~suffix filename let rec find_in_parents f dir = if f dir then Some dir else let parent = dirname_dir dir in if parent = dir then None else find_in_parents f parent let link ?(relative=false) ~target ~link = if target = link then () else let target = if not relative then to_string target else match find_in_parents (fun d -> d <> "/" && starts_with d link) (dirname target) with | None -> to_string target | Some ancestor -> let back = let rel = remove_prefix_dir ancestor (dirname link) in OpamStd.List.concat_map Filename.dir_sep (fun _ -> "..") (OpamStd.String.split rel Filename.dir_sep.[0]) in let forward = remove_prefix ancestor target in Filename.concat back forward in OpamSystem.link target (to_string link) [@@ocaml.warning "-16"] let patch ?preprocess filename dirname = OpamSystem.patch ?preprocess ~dir:(Dir.to_string dirname) (to_string filename) let flock flag ?dontblock file = OpamSystem.flock flag ?dontblock (to_string file) let with_flock flag ?dontblock file f = let lock = OpamSystem.flock flag ?dontblock (to_string file) in try let open OpamCompat in let (fd, ch) = match OpamSystem.get_lock_fd lock with | exception Not_found -> let null = if OpamStd.Sys.(os () = Win32) then "nul" else "/dev/null" in let ch = Stdlib.open_out null in Unix.descr_of_out_channel ch, Some ch | fd -> fd, None in let r = f fd in OpamSystem.funlock lock; OpamStd.Option.iter Stdlib.close_out ch; r with e -> OpamStd.Exn.finalise e @@ fun () -> OpamSystem.funlock lock let with_flock_upgrade flag ?dontblock lock f = if OpamSystem.lock_isatleast flag lock then f (OpamSystem.get_lock_fd lock) else ( let old_flag = OpamSystem.get_lock_flag lock in OpamSystem.flock_update flag ?dontblock lock; try let r = f (OpamSystem.get_lock_fd lock) in OpamSystem.flock_update old_flag lock; r with e -> OpamStd.Exn.finalise e @@ fun () -> OpamSystem.flock_update old_flag lock ) let with_flock_write_then_read ?dontblock file write read = let lock = OpamSystem.flock `Lock_write ?dontblock (to_string file) in try let r = write (OpamSystem.get_lock_fd lock) in OpamSystem.flock_update `Lock_read lock; let r = read r in OpamSystem.funlock lock; r with e -> OpamStd.Exn.finalise e @@ fun () -> OpamSystem.funlock lock let prettify_path s = let aux ~short ~prefix = let prefix = Filename.concat prefix "" in if OpamStd.String.starts_with ~prefix s then let suffix = OpamStd.String.remove_prefix ~prefix s in Some (Filename.concat short suffix) else None in try match aux ~short:"~" ~prefix:(OpamStd.Sys.home ()) with | Some p -> p | None -> s with Not_found -> s let prettify_dir d = prettify_path (Dir.to_string d) let prettify s = prettify_path (to_string s) let to_json x = `String (to_string x) let of_json = function | `String x -> (try Some (of_string x) with _ -> None) | _ -> None module O = struct type tmp = t type t = tmp let compare = compare let to_string = to_string let to_json = to_json let of_json = of_json end module Map = OpamStd.Map.Make(O) module Set = OpamStd.Set.Make(O) module Op = struct let (/) = (/) let (//) d1 s2 = let d = Filename.dirname s2 in let b = Filename.basename s2 in if d <> "." then create (d1 / d) (Base.of_string b) else create d1 (Base.of_string s2) end module Attribute = struct type t = { base: Base.t; md5 : OpamHash.t; perm: int option; } let base t = t.base let md5 t = t.md5 let perm t = t.perm let create base md5 perm = { base; md5; perm=perm } let to_string_list t = let perm = match t.perm with | None -> [] | Some p -> [Printf.sprintf "0o%o" p] in Base.to_string t.base :: OpamHash.to_string t.md5 :: perm let of_string_list = function | [base; md5] -> { base=Base.of_string base; md5=OpamHash.of_string md5; perm=None } | [base;md5; perm] -> { base=Base.of_string base; md5=OpamHash.of_string md5; perm=Some (int_of_string perm) } | k -> OpamSystem.internal_error "remote_file: '%s' is not a valid line." (String.concat " " k) let to_string t = String.concat " " (to_string_list t) let of_string s = of_string_list (OpamStd.String.split s ' ') let to_json x = `O ([ ("base" , Base.to_json x.base); ("md5" , `String (OpamHash.to_string x.md5))] @ match x. perm with | None -> [] | Some p -> ["perm", `String (string_of_int p)]) let of_json = function | `O dict -> begin try let open OpamStd.Option.Op in Base.of_json (List.assoc "base" dict) >>= fun base -> OpamHash.of_json (List.assoc "md5" dict) >>= fun md5 -> let perm = if not (List.mem_assoc "perm" dict) then None else match List.assoc "perm" dict with | `String hash -> (try Some (int_of_string hash) with _ -> raise Not_found) | _ -> raise Not_found in Some { base; md5; perm } with Not_found -> None end | _ -> None module O = struct type tmp = t type t = tmp let to_string = to_string let compare = compare let to_json = to_json let of_json = of_json end module Set = OpamStd.Set.Make(O) module Map = OpamStd.Map.Make(O) end let to_attribute root file = let basename = Base.of_string (remove_prefix root file) in let perm = let s = Unix.stat (to_string file) in s.Unix.st_perm in let digest = OpamHash.compute ~kind:`MD5 (to_string file) in Attribute.create basename digest (Some perm) opam-2.1.5/src/core/opamStubs.ml.win320000644000175000017500000000201014427463453016477 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2018 MetaStack Solutions Ltd. *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) include OpamStubsTypes include OpamWin32Stubs let getpid () = Int32.to_int (getCurrentProcessID ()) external win_create_process : string -> string -> string option -> Unix.file_descr -> Unix.file_descr -> Unix.file_descr -> int = "win_create_process" "win_create_process_native" opam-2.1.5/src/core/opamDirTrack.mli0000644000175000017500000000552514427463453016330 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2016-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** uniquely identifies a filesystem item value *) type digest (** Defines a change concerning a fs item; The [digest] parameter is the new value of the item *) type change = | Added of digest | Removed | Contents_changed of digest (** For links, corresponds to a change of target *) | Perm_changed of digest | Kind_changed of digest (** Used e.g. when a file is replaced by a directory, a link or a fifo *) type t = change OpamStd.String.Map.t (** Returns a printable, multi-line string *) val to_string: t -> string val digest_of_string: string -> digest val string_of_digest: digest -> string (** Return the [change] action, with digest if [full] is set to true *) val string_of_change: ?full:bool -> change -> string (** Wraps a job to track the changes that happened under [dirname] during its execution (changes done by the application of the job function to [()] are tracked too, for consistency with jobs without commands) *) val track: OpamFilename.Dir.t -> ?except:OpamFilename.Base.Set.t -> (unit -> 'a OpamProcess.job) -> ('a * t) OpamProcess.job (** [track_files prefix paths ?except job] as [track] wraps a job to track changes for a predefined list of [paths] (files and directories). [paths] are relative to [prefix]. *) val track_files: prefix:OpamFilename.Dir.t -> string list -> ?except:OpamFilename.Base.Set.t -> (unit -> 'a OpamProcess.job) -> ('a * t) OpamProcess.job (** Removes the added and kind-changed items unless their contents changed and [force] isn't set, and prints warnings for other changes unless [verbose] is set to [false]. Ignores non-existing files. [title] is used to prefix messages if specified. *) val revert: ?title:string -> ?verbose:bool -> ?force:bool -> ?dryrun:bool -> OpamFilename.Dir.t -> t -> unit (** Checks the items that were added or kind-changed in the given diff, and returns their status *) val check: OpamFilename.Dir.t -> t -> (OpamFilename.t * [`Unchanged | `Removed | `Changed]) list (** Reload all the digests from the directory [prefix]. Remove a file from the map if it has been removed from the file-system. *) val update : OpamFilename.Dir.t -> t -> t opam-2.1.5/src/core/opamProcess.ml0000644000175000017500000007374514427463453016103 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCompat let log ?level fmt = OpamConsole.log "PROC" ?level fmt let cygwin_create_process_env prog args env fd1 fd2 fd3 = (* * Unix.create_process_env correctly converts arguments to a command line for * native Windows execution, but it does not correctly handle Cygwin's quoting * requirements. * * The process followed here is based on an analysis of the sources for the * Cygwin DLL (git://sourceware.org/git/newlib-cygwin.git, * winsup/cygwin/dcrt0.cc) and a lack of refutation on the Cygwin mailing list * in May 2016! * * In case this seems terminally stupid, it's worth noting that Cygwin's * implementation of the exec system calls do not pass argv using the Windows * command line, these weird and wonderful rules exist for corner cases and, * as here, for invocations from native Windows processes. * * There are two forms of escaping which can apply, controlled by the CYGWIN * environment variable option noglob. * * If none of the strings in argv contains the double-quote character, then * the process should be invoked with the noglob option (to ensure that no * characters are unexpectedly expanded). In this mode of escaping, it is * necessary to protect any whitespace characters (\r, \n, \t, and space * itself) by surrounding sequences of them with double-quotes). Additionally, * if any string in argv begins with the @ sign, this should be double-quoted. * * If any one of the strings in argv does contain a double-quote character, * then the process should be invoked with the glob option (this is the * default). Every string in argv should have double-quotes put around it. Any * double-quote characters within the string should be translated to "'"'". * * The reason for supporting both mechanisms is that the noglob method has * shorter command lines and Windows has an upper limit of 32767 characters * for the command line. * * COMBAK If the command line does exceed 32767 characters, then Cygwin allows * a parameter beginning @ to refer to a file from which to read the * rest of the command line. This support is not implemented at this * time in OPAM. * * [This stray " is here to terminate a previous part of the comment!] *) let make_args argv = let b = Buffer.create 128 in let gen_quote ~quote ~pre ?(post = pre) s = log ~level:3 "gen_quote: %S" s; Buffer.clear b; let l = String.length s in let rec f i = let j = try OpamStd.String.find_from (fun c -> try String.index quote c >= 0 with Not_found -> false) s (succ i) with Not_found -> l in Buffer.add_string b (String.sub s i (j - i)); if j < l then begin Buffer.add_string b pre; let i = j in let j = try OpamStd.String.find_from (fun c -> try String.index quote c < 0 with Not_found -> true) s (succ i) with Not_found -> l in Buffer.add_string b (String.sub s i (j - i)); Buffer.add_string b post; if j < l then f j else Buffer.contents b end else Buffer.contents b in let r = if s = "" then "\"\"" else f 0 in log ~level:3 "result: %S" r; r in (* Setting noglob is causing some problems for ocamlbuild invoking Cygwin's find. The reason for using it is to try to keep command line lengths below the maximum, but for now disable the use of noglob. *) if true || List.exists (fun s -> try String.index s '"' >= 0 with Not_found -> false) argv then ("\"" ^ String.concat "\" \"" (List.map (gen_quote ~quote:"\"" ~pre:"\"'" ~post:"'\"") argv) ^ "\"", false) else (String.concat " " (List.map (gen_quote ~quote:"\b\r\n " ~pre:"\"") argv), true) in let (command_line, no_glob) = make_args (Array.to_list args) in log "cygvoke(%sglob): %s" (if no_glob then "no" else "") command_line; let env = Array.to_list env in let set = ref false in let f item = let (key, value) = match OpamStd.String.cut_at item '=' with Some pair -> pair | None -> (item, "") in match String.lowercase_ascii key with | "cygwin" -> let () = if key = "CYGWIN" then set := true in let settings = OpamStd.String.split value ' ' in let set = ref false in let f setting = let setting = String.trim setting in let setting = match OpamStd.String.cut_at setting ':' with Some (setting, _) -> setting | None -> setting in match setting with "glob" -> if no_glob then begin log ~level:2 "Removing glob from %s" key; false end else begin log ~level:2 "Leaving glob in %s" key; set := true; true end | "noglob" -> if no_glob then begin log ~level:2 "Leaving noglob in %s" key; set := true; true end else begin log ~level:2 "Removing noglob from %s" key; false end | _ -> true in let settings = List.filter f settings in let settings = if not !set && no_glob then begin log ~level:2 "Setting noglob in %s" key; "noglob"::settings end else settings in if settings = [] then begin log ~level:2 "Removing %s completely" key; None end else Some (key ^ "=" ^ String.concat " " settings) | "path" -> let path_dirs = OpamStd.Sys.split_path_variable item in let winsys = Filename.concat (OpamStd.Sys.system ()) "." |> String.lowercase_ascii in let rec f prefix suffix = function | dir::dirs -> let contains_cygpath = Sys.file_exists (Filename.concat dir "cygpath.exe") in if suffix = [] then if String.lowercase_ascii (Filename.concat dir ".") = winsys then f prefix [dir] dirs else if contains_cygpath then path_dirs else f (dir::prefix) [] dirs else if contains_cygpath then begin log ~level:2 "Moving %s to after %s in PATH" dir (List.hd prefix); List.rev_append prefix (dir::(List.rev_append suffix dirs)) end else f prefix (dir::suffix) dirs | [] -> assert false in Some (String.concat ";" (f [] [] path_dirs)) | _ -> Some item in let env = OpamStd.List.filter_map f env in let env = if !set then env else if no_glob then begin log ~level:2 "Adding CYGWIN=noglob"; "CYGWIN=noglob"::env end else env in OpamStubs.win_create_process prog command_line (Some(String.concat "\000" env ^ "\000")) fd1 fd2 fd3 (** Shell commands *) type command = { cmd: string; args: string list; cmd_text: string option; cmd_dir: string option; cmd_env: string array option; cmd_stdin: bool option; cmd_stdout: string option; cmd_verbose: bool option; cmd_name: string option; cmd_metadata: (string * string) list option; } let string_of_command c = String.concat " " (c.cmd::c.args) let text_of_command c = c.cmd_text let default_verbose () = OpamCoreConfig.(!r.verbose_level) >= 2 let is_verbose_command c = OpamStd.Option.default (default_verbose ()) c.cmd_verbose let make_command_text ?(color=`green) str ?(args=[]) cmd = let summary = match List.filter (fun s -> String.length s > 0 && s.[0] <> '-' && not (String.contains s '/') && not (String.contains s '=')) args with | hd::_ -> String.concat " " [cmd; hd] | [] -> cmd in Printf.sprintf "[%s: %s]" (OpamConsole.colorise color str) summary let command ?env ?verbose ?name ?metadata ?dir ?allow_stdin ?stdout ?text cmd args = { cmd; args; cmd_env=env; cmd_verbose=verbose; cmd_name=name; cmd_metadata=metadata; cmd_dir=dir; cmd_stdin=allow_stdin; cmd_stdout=stdout; cmd_text=text; } (** Running processes *) type t = { p_name : string; p_args : string list; p_pid : int; p_cwd : string; p_time : float; p_stdout : string option; p_stderr : string option; p_env : string option; p_info : string option; p_metadata: (string * string) list; p_verbose: bool; p_tmp_files: string list; } let open_flags = [Unix.O_WRONLY; Unix.O_CREAT; Unix.O_APPEND] let output_lines oc lines = List.iter (fun line -> output_string oc line; output_string oc "\n"; flush oc; ) lines; output_string oc "\n"; flush oc let make_info ?code ?signal ~cmd ~args ~cwd ~env_file ~stdout_file ~stderr_file ~metadata () = let b = ref [] in let home = OpamStd.Sys.home () in let print name str = let str = if OpamStd.String.starts_with ~prefix:home str then "~"^OpamStd.String.remove_prefix ~prefix:home str else str in b := (name, str) :: !b in let print_opt name = function | None -> () | Some s -> print name s in List.iter (fun (k,v) -> print k v) metadata; print "path" cwd; print "command" (String.concat " " (cmd :: args)); print_opt "exit-code" (OpamStd.Option.map string_of_int code); print_opt "signalled" (OpamStd.Option.map string_of_int signal); print_opt "env-file" env_file; if stderr_file = stdout_file then print_opt "output-file" stdout_file else ( print_opt "stdout-file" stdout_file; print_opt "stderr-file" stderr_file; ); List.rev !b let string_of_info ?(color=`yellow) info = let b = Buffer.create 1024 in List.iter (fun (k,v) -> Printf.bprintf b "%s %-20s %s\n" (OpamConsole.colorise color "#") (OpamConsole.colorise color k) v) info; Buffer.contents b let resolve_command_fn = ref (fun ?env:_ ?dir:_ _ -> None) let set_resolve_command = let called = ref false in fun resolve_command -> if !called then invalid_arg "Just what do you think you're doing, Dave?"; called := true; resolve_command_fn := resolve_command let resolve_command cmd = !resolve_command_fn cmd let create_process_env = if Sys.win32 then fun cmd -> let resolved_cmd = resolve_command cmd in if OpamStd.(Option.map_default Sys.is_cygwin_variant `Native resolved_cmd) = `Cygwin then cygwin_create_process_env cmd else Unix.create_process_env cmd else Unix.create_process_env (** [create cmd args] create a new process to execute the command [cmd] with arguments [args]. If [stdout_file] or [stderr_file] are set, the channels are redirected to the corresponding files. The outputs are discarded is [verbose] is set to false. The current environment can also be overridden if [env] is set. The environment which is used to run the process is recorded into [env_file] (if set). *) let create ?info_file ?env_file ?(allow_stdin=true) ?stdout_file ?stderr_file ?env ?(metadata=[]) ?dir ~verbose ~tmp_files cmd args = let nothing () = () in let tee f = let fd = Unix.openfile f open_flags 0o644 in let close_fd () = Unix.close fd in fd, close_fd in let oldcwd = Sys.getcwd () in let cwd = OpamStd.Option.default oldcwd dir in OpamStd.Option.iter Unix.chdir dir; let stdin_fd,close_stdin = if allow_stdin then Unix.stdin, nothing else let fd,outfd = Unix.pipe () in let close_stdin () = Unix.close fd in Unix.close outfd; fd, close_stdin in let stdout_fd, close_stdout = match stdout_file with | None -> Unix.stdout, nothing | Some f -> tee f in let stderr_fd, close_stderr = match stderr_file with | None -> Unix.stderr, nothing | Some f -> if stdout_file = Some f then stdout_fd, nothing else tee f in let env = match env with | None -> Unix.environment () | Some e -> e in let time = Unix.gettimeofday () in let () = (* write the env file before running the command*) match env_file with | None -> () | Some f -> let chan = open_out f in let env = Array.to_list env in (* Remove dubious variables *) let env = List.filter (fun line -> not (OpamStd.String.contains_char line '$')) env in output_lines chan env; close_out chan in let () = (* write the info file *) match info_file with | None -> () | Some f -> let chan = open_out f in let info = make_info ~cmd ~args ~cwd ~env_file ~stdout_file ~stderr_file ~metadata () in output_string chan (string_of_info info); close_out chan in let pid = let cmd, args = if Sys.win32 then try let actual_command = if Sys.file_exists cmd then cmd else if Sys.file_exists (cmd ^ ".exe") then cmd ^ ".exe" else raise Exit in let actual_image, args = let c = open_in actual_command in set_binary_mode_in c true; try if really_input_string c 2 = "#!" then begin (* The input_line will only fail for a 2-byte file consisting of exactly #! (with no \n), which is acceptable! *) let l = String.trim (input_line c) in let cmd, arg = try let i = String.index l ' ' in let cmd = Filename.basename (String.trim (String.sub l 0 i)) in let arg = String.trim (String.sub l i (String.length l - i)) in if cmd = "env" then arg, None else cmd, Some arg with Not_found -> Filename.basename l, None in close_in c; try let cmd = OpamStd.Option.default cmd (resolve_command cmd) in (*Printf.eprintf "Deduced %s => %s to be executed via %s\n%!" cmd actual_command cmd;*) let args = actual_command::args in cmd, OpamStd.Option.map_default (fun arg -> arg::args) args arg with Not_found -> (* Script interpreter isn't available - fall back *) raise Exit end else begin close_in c; actual_command, args end with End_of_file -> close_in c; (* A two-byte image can't be executable! *) raise Exit in (*Printf.eprintf "Final deduction: %s -> %s\n%!" cmd actual_image;*) actual_image, args with Exit -> (* Fall back to default behaviour if anything went wrong - almost certainly means a broken package *) cmd, args else cmd, args in let create_process, cmd, args = if Sys.win32 && OpamStd.Sys.is_cygwin_variant cmd = `Cygwin then cygwin_create_process_env, cmd, args else Unix.create_process_env, cmd, args in try create_process cmd (Array.of_list (cmd :: args)) env stdin_fd stdout_fd stderr_fd with e -> close_stdin (); close_stdout (); close_stderr (); raise e in close_stdin (); close_stdout (); close_stderr (); Unix.chdir oldcwd; { p_name = cmd; p_args = args; p_pid = pid; p_cwd = cwd; p_time = time; p_stdout = stdout_file; p_stderr = stderr_file; p_env = env_file; p_info = info_file; p_metadata = metadata; p_verbose = verbose; p_tmp_files = tmp_files; } type result = { r_code : int; r_signal : int option; r_duration : float; r_info : (string * string) list; r_stdout : string list; r_stderr : string list; r_cleanup : string list; } let empty_result = { r_code = 0; r_signal = None; r_duration = 0.; r_info = []; r_stdout = []; r_stderr = []; r_cleanup = []; } (* XXX: the function might block for ever for some channels kinds *) let read_lines f = try let ic = open_in f in let lines = ref [] in begin try while true do let line = input_line ic in lines := line :: !lines; done with End_of_file | Sys_error _ -> () end; close_in ic; List.rev !lines with Sys_error _ -> [] (* Compat function (Windows) *) let interrupt p = if Sys.win32 then Unix.kill p.p_pid Sys.sigkill else Unix.kill p.p_pid Sys.sigint let run_background command = let { cmd; args; cmd_env=env; cmd_verbose=_; cmd_name=name; cmd_text=_; cmd_metadata=metadata; cmd_dir=dir; cmd_stdin=allow_stdin; cmd_stdout } = command in let verbose = is_verbose_command command in let allow_stdin = OpamStd.Option.default false allow_stdin in let env = match env with Some e -> e | None -> Unix.environment () in let file ext = match name with | None -> None | Some n -> let d = if Filename.is_relative n then match dir with | Some d -> d | None -> OpamCoreConfig.(!r.log_dir) else "" in Some (Filename.concat d (Printf.sprintf "%s.%s" n ext)) in let stdout_file = OpamStd.Option.Op.(cmd_stdout >>+ fun () -> file "out") in let stderr_file = if OpamCoreConfig.(!r.merged_output) then file "out" else file "err" in let env_file = file "env" in let info_file = file "info" in let tmp_files = OpamStd.List.filter_some [ info_file; env_file; stderr_file; if cmd_stdout <> None || stderr_file = stdout_file then None else stdout_file; ] in create ~env ?info_file ?env_file ?stdout_file ?stderr_file ~verbose ?metadata ~allow_stdin ?dir ~tmp_files cmd args let dry_run_background c = { p_name = c.cmd; p_args = c.args; p_pid = -1; p_cwd = OpamStd.Option.default (Sys.getcwd ()) c.cmd_dir; p_time = Unix.gettimeofday (); p_stdout = None; p_stderr = None; p_env = None; p_info = None; p_metadata = OpamStd.Option.default [] c.cmd_metadata; p_verbose = is_verbose_command c; p_tmp_files = []; } let verbose_print_cmd p = OpamConsole.msg "%s %s %s%s\n" (OpamConsole.colorise `yellow "+") p.p_name (OpamStd.List.concat_map " " (Printf.sprintf "%S") p.p_args) (if p.p_cwd = Sys.getcwd () then "" else Printf.sprintf " (CWD=%s)" p.p_cwd) let verbose_print_out = let pfx = lazy (OpamConsole.colorise `yellow "- ") in fun s -> OpamConsole.msg "%s%s\n" (Lazy.force pfx) s (** Semi-synchronous printing of the output of a command *) let set_verbose_f, print_verbose_f, isset_verbose_f, stop_verbose_f = let verbose_f = ref None in let stop () = match !verbose_f with | None -> () | Some (ics,_) -> List.iter close_in_noerr ics; verbose_f := None in let set files = stop (); (* implem relies on sigalrm, not implemented on win32. This will fall back to buffered output. *) if Sys.win32 then () else let files = OpamStd.List.sort_nodup compare files in let ics = List.map (open_in_gen [Open_nonblock;Open_rdonly;Open_text;Open_creat] 0o600) files in let f () = List.iter (fun ic -> try while true do verbose_print_out (input_line ic) done with End_of_file -> flush stdout ) ics in verbose_f := Some (ics, f) in let print () = match !verbose_f with | Some (_, f) -> f () | None -> () in let isset () = !verbose_f <> None in let flush_and_stop () = print (); stop () in set, print, isset, flush_and_stop let set_verbose_process p = if p.p_verbose then let fs = OpamStd.List.filter_some [p.p_stdout;p.p_stderr] in if fs <> [] then ( verbose_print_cmd p; set_verbose_f fs ) let exit_status p return = let duration = Unix.gettimeofday () -. p.p_time in let stdout = OpamStd.Option.default [] (OpamStd.Option.map read_lines p.p_stdout) in let stderr = OpamStd.Option.default [] (OpamStd.Option.map read_lines p.p_stderr) in let cleanup = p.p_tmp_files in let code,signal = match return with | Unix.WEXITED r -> Some r, None | Unix.WSIGNALED s | Unix.WSTOPPED s -> None, Some s in if isset_verbose_f () then stop_verbose_f () else if p.p_verbose then (List.iter verbose_print_out stdout; if p.p_stdout <> p.p_stderr then List.iter verbose_print_out stderr; flush Stdlib.stdout); let info = make_info ?code ?signal ~cmd:p.p_name ~args:p.p_args ~cwd:p.p_cwd ~metadata:p.p_metadata ~env_file:p.p_env ~stdout_file:p.p_stdout ~stderr_file:p.p_stderr () in { r_code = OpamStd.Option.default 256 code; r_signal = signal; r_duration = duration; r_info = info; r_stdout = stdout; r_stderr = stderr; r_cleanup = cleanup; } let safe_wait fallback_pid f x = let sh = if isset_verbose_f () then let hndl _ = print_verbose_f () in Some (Sys.signal Sys.sigalrm (Sys.Signal_handle hndl)) else None in let cleanup () = match sh with | Some sh -> ignore (Unix.alarm 0); (* cancels the alarm *) Sys.set_signal Sys.sigalrm sh | None -> () in let rec aux () = if sh <> None then ignore (Unix.alarm 1); match try f x with | Unix.Unix_error (Unix.EINTR,_,_) -> aux () (* handled signal *) | Unix.Unix_error (Unix.ECHILD,_,_) -> log "Warn: no child to wait for %d" fallback_pid; fallback_pid, Unix.WEXITED 256 with | _, Unix.WSTOPPED _ -> (* shouldn't happen as we don't use WUNTRACED *) aux () | r -> r in try let r = aux () in cleanup (); r with e -> cleanup (); raise e let wait p = set_verbose_process p; let _, return = safe_wait p.p_pid (Unix.waitpid []) p.p_pid in exit_status p return let dontwait p = match safe_wait p.p_pid (Unix.waitpid [Unix.WNOHANG]) p.p_pid with | 0, _ -> None | _, return -> Some (exit_status p return) let dead_childs = Hashtbl.create 13 let wait_one processes = if processes = [] then raise (Invalid_argument "wait_one"); try let p = List.find (fun p -> Hashtbl.mem dead_childs p.p_pid) processes in let return = Hashtbl.find dead_childs p.p_pid in Hashtbl.remove dead_childs p.p_pid; p, exit_status p return with Not_found -> let rec aux () = let pid, return = if Sys.win32 then (* No Unix.wait on Windows, so use a stub wrapping WaitForMultipleObjects *) let pids, len = let f (l, n) t = (t.p_pid::l, succ n) in List.fold_left f ([], 0) processes in OpamStubs.waitpids pids len else safe_wait (List.hd processes).p_pid Unix.wait () in try let p = List.find (fun p -> p.p_pid = pid) processes in p, exit_status p return with Not_found -> Hashtbl.add dead_childs pid return; aux () in aux () let dry_wait_one = function | {p_pid = -1; _} as p :: _ -> if p.p_verbose then (verbose_print_cmd p; flush stdout); p, empty_result | _ -> raise (Invalid_argument "dry_wait_one") let run command = let command = { command with cmd_stdin = OpamStd.Option.Op.(command.cmd_stdin ++ Some true) } in let p = run_background command in try wait p with e -> match (try dontwait p with _ -> raise e) with | None -> (* still running *) (try interrupt p with Unix.Unix_error _ -> ()); raise e | _ -> raise e let is_failure r = r.r_code <> 0 || r.r_signal <> None let is_success r = not (is_failure r) let safe_unlink f = try log ~level:2 "safe_unlink: %s" f; Unix.unlink f with Unix.Unix_error _ -> log ~level:2 "safe_unlink: %s (FAILED)" f let cleanup ?(force=false) r = if force || (not (OpamConsole.debug ()) && is_success r) then List.iter safe_unlink r.r_cleanup let check_success_and_cleanup r = List.iter safe_unlink r.r_cleanup; is_success r let log_line_limit = 5 * 80 let truncate_str = "[...]" (* Truncate long lines *) let truncate_line str = if String.length str <= log_line_limit then str else String.sub str 0 (log_line_limit - String.length truncate_str) ^ truncate_str (* Take the last [n] elements of [l] (trying to keep an unindented header line for context, like diff) *) let truncate l = let unindented s = String.length s > 0 && s.[0] <> ' ' && s.[0] <> '\t' in let rec cut n acc = function | [] -> acc | [x] when n = 0 -> truncate_line x :: acc | _ when n = 0 -> truncate_str :: acc | x::l when n = 1 -> (if unindented x then truncate_str :: truncate_line x :: acc else try truncate_line (List.find unindented l) :: truncate_str :: acc with Not_found -> truncate_str :: truncate_line x :: acc) | x::r -> cut (n-1) (truncate_line x :: acc) r in let len = OpamCoreConfig.(!r.errlog_length) in if len <= 0 then l else cut len [] (List.rev l) let string_of_result ?(color=`yellow) r = let b = Buffer.create 2048 in let print = Buffer.add_string b in let println str = print str; Buffer.add_char b '\n' in print (string_of_info ~color r.r_info); if r.r_stdout <> [] then if r.r_stderr = r.r_stdout then print (OpamConsole.colorise color "### output ###\n") else print (OpamConsole.colorise color "### stdout ###\n"); List.iter (fun s -> print (OpamConsole.colorise color "# "); println s) (truncate r.r_stdout); if r.r_stderr <> [] && r.r_stderr <> r.r_stdout then ( print (OpamConsole.colorise color "### stderr ###\n"); List.iter (fun s -> print (OpamConsole.colorise color "# "); println s) (truncate r.r_stderr) ); Buffer.contents b let result_summary r = Printf.sprintf "%S exited with code %d%s" (try List.assoc "command" r.r_info with Not_found -> "command") r.r_code (if r.r_code = 0 then "" else match r.r_stderr, r.r_stdout with | [e], _ | [], [e] -> Printf.sprintf " \"%s\"" e | [], es | es, _ -> try Printf.sprintf " \"%s\"" (List.find Re.(execp (compile (seq [ bos; rep (diff any alpha); no_case (str "error") ]))) (List.rev es)) with Not_found -> "" | _ -> "") (* Higher-level interface to allow parallelism *) module Job = struct module Op = struct type 'a job = (* Open the variant type *) | Done of 'a | Run of command * (result -> 'a job) (* Parallelise shell commands *) let (@@>) command f = Run (command, f) (* Sequentialise jobs *) let rec (@@+) job1 fjob2 = match job1 with | Done x -> fjob2 x | Run (cmd,cont) -> Run (cmd, fun r -> cont r @@+ fjob2) let (@@|) job f = job @@+ fun x -> Done (f x) end open Op let run = let rec aux = function | Done x -> x | Run (cmd,cont) -> OpamStd.Option.iter (if OpamConsole.disp_status_line () then OpamConsole.status_line "Processing: %s" else if OpamConsole.verbose () then OpamConsole.msg "%s\n" else fun _ -> ()) (text_of_command cmd); let r = run cmd in let k = try cont r with e -> cleanup r; OpamConsole.clear_status (); raise e in cleanup r; OpamConsole.clear_status (); aux k in aux let rec dry_run = function | Done x -> x | Run (_command,cont) -> dry_run (cont empty_result) let rec catch handler fjob = try match fjob () with | Done x -> Done x | Run (cmd,cont) -> Run (cmd, fun r -> catch handler (fun () -> cont r)) with e -> handler e let ignore_errors ~default ?message job = catch (fun e -> OpamStd.Exn.fatal e; OpamStd.Option.iter (OpamConsole.error "%s") message; Done default) job let rec finally fin fjob = try match fjob () with | Done x -> fin (); Done x | Run (cmd,cont) -> Run (cmd, fun r -> finally fin (fun () -> cont r)) with e -> fin (); raise e let of_list ?(keep_going=false) l = let rec aux err = function | [] -> Done err | cmd::commands -> let cont = fun r -> if is_success r then aux err commands else if keep_going then aux OpamStd.Option.Op.(err ++ Some (cmd,r)) commands else Done (Some (cmd,r)) in Run (cmd,cont) in aux None l let of_fun_list ?(keep_going=false) l = let rec aux err = function | [] -> Done err | cmdf::commands -> let cmd = cmdf () in let cont = fun r -> if is_success r then aux err commands else if keep_going then aux OpamStd.Option.Op.(err ++ Some (cmd,r)) commands else Done (Some (cmd,r)) in Run (cmd,cont) in aux None l let seq job start = List.fold_left (@@+) (Done start) job let seq_map f l = List.fold_left (fun job x -> job @@+ fun acc -> f x @@| fun y -> y :: acc) (Done []) l @@| List.rev let rec with_text text = function | Done _ as j -> j | Run (cmd, cont) -> Run ({cmd with cmd_text = Some text}, fun r -> with_text text (cont r)) end type 'a job = 'a Job.Op.job opam-2.1.5/src/core/opamHash.mli0000644000175000017500000000306214427463453015502 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2016-2017 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Stored as hexadecimal strings *) type kind = [ `MD5 | `SHA256 | `SHA512 ] type t val kind: t -> kind (** The value of the hash, as a string of hexadecimal characters *) val contents: t -> string val string_of_kind: kind -> string val md5: string -> t val sha256: string -> t val sha512: string -> t include OpamStd.ABSTRACT with type t := t val of_string_opt: string -> t option (** returns a sub-path specific to this hash, e.g. "md5/d4/d41d8cd98f00b204e9800998ecf8427e", as a list *) val to_path: t -> string list val check_file: string -> t -> bool (** Like [check_file], but returns the actual mismatching hash of the file, or [None] in case of match *) val mismatch: string -> t -> t option (** Compute hash of the given file *) val compute: ?kind:kind -> string -> t (** Compute the hash of the given string *) val compute_from_string: ?kind:kind -> string -> t opam-2.1.5/src/core/dune0000644000175000017500000000246714427463453014125 0ustar stephsteph(library (name opam_core) (public_name opam-core) (synopsis "OCaml Package Manager core internal stdlib") (libraries re ocamlgraph unix bigarray (select opamACL.ml from (opam-core.libacl -> opamACL.ml.libacl) ( -> opamACL.ml.dummy)) (select opamStubs.ml from (opam-core.stubs -> opamStubs.ml.win32) ( -> opamStubs.ml.dummy))) (flags (:standard (:include ../ocaml-flags-standard.sexp) (:include ../ocaml-flags-configure.sexp) (:include ../ocaml-context-flags.sexp))) (preprocess (per_module ((action (run %{bin:cppo} -V OCAML:%{ocaml_version} %{input-file})) opamCompat) ((action (run %{bin:cppo} %{read-lines:developer} %{input-file})) opamCoreConfig) ((action (run %{bin:cppo} -D "VERSION %{read-lines:version}" %{input-file})) opamVersion))) (wrapped false)) (rule (targets version) (deps ../../shell/get_version.ml ../../configure.ac) (action (with-stdout-to %{targets} (run ocaml ../../shell/get_version.ml ../../configure.ac)))) (rule (targets developer) (mode fallback) (action (with-stdout-to %{targets} (echo "")))) opam-2.1.5/src/core/opamStubs.mli0000644000175000017500000001436114427463453015723 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2018 MetaStack Solutions Ltd. *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** OS-specific functions requiring C code on at least one platform. Most functions are Windows-specific and raise an exception on other platforms. *) include module type of struct include OpamStubsTypes end val getpid : unit -> int (** On Windows, this returns the actual process ID, rather than the non-unique faked process ID returned by the Microsoft C Runtime (see https://caml.inria.fr/mantis/view.php?id=4034). On all other platforms, this is just an alias for [Unix.getpid]. *) val getCurrentProcessID : unit -> int32 (** Windows only. As {!getpid}, but without the possibility of truncating the ID on 32-bit platforms. *) val getStdHandle : stdhandle -> handle (** Windows only. Return a standard handle. *) val getConsoleScreenBufferInfo : handle -> console_screen_buffer_info (** Windows only. Return current Console screen buffer information. *) val setConsoleTextAttribute : handle -> int -> unit (** Windows only. Set the console's text attribute setting. *) val fillConsoleOutputCharacter : handle -> char -> int -> int * int -> bool (** Windows only. [fillConsoleOutputCharacter buffer c n (x, y)] writes [c] [n] times starting at the given coordinate (and wrapping if required). *) val getConsoleMode : handle -> int (** Windows only. Returns the input/output mode of the console screen buffer referred to by the handle. @raise Not_found If the handle does not refer to a console. *) val setConsoleMode : handle -> int -> bool (** Windows only. Sets the input/output mode of the console screen buffer referred to by the handle, returning [true] if the operation isr successful. *) val getWindowsVersion : unit -> int * int * int * int (** Windows only. Returns the Windows version as [(major, minor, build, revision)]. This function only works if opam is compiled OCaml 4.06.0 or later, it returns [(0, 0, 0, 0)] otherwise. *) val isWoW64 : unit -> bool (** Returns [false] unless this process is a 32-bit Windows process running in the WoW64 sub-system (i.e. is being run on 64-bit Windows). *) val waitpids : int list -> int -> int * Unix.process_status (** Windows only. Given a list [pids] with [length] elements, [waitpids pids length] behaves like [Unix.wait], returning the pid and exit status of the first process to terminate. *) val writeRegistry : registry_root -> string -> string -> 'a registry_value -> 'a -> unit (** Windows only. [writeRegistry root key name value_type value] sets the value [name] of type [value_type] in registry key [key] of [root] to [value]. @raise Failure If the value could not be set. @raise Not_found If [key] does not exist. *) val getConsoleOutputCP : unit -> int (** Windows only. Retrieves the current Console Output Code Page. *) val getCurrentConsoleFontEx : handle -> bool -> console_font_infoex (** Windows only. Gets information on the current console output font. *) val create_glyph_checker : string -> handle * handle (** Windows only. Given a font name, returns a pair consisting of a screen DC and a font object, which will have been selected into the DC. @raise Failure If anything goes wrong with the GDI calls. *) val delete_glyph_checker : handle * handle -> unit (** Windows only. Given [(dc, font)], deletes the font object and releases the DC. *) val has_glyph : handle * handle -> OpamCompat.Uchar.t -> bool (** Windows only. [has_glyph (dc, font) scalar] returns [true] if [font] contains a glyph for [scalar]. @raise Failure If the call to [GetGlyphIndicesW] fails. *) val isWoW64Process : int32 -> bool (** Windows only. General version of {!isWoW64} for any given process ID. See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684139.aspx *) val process_putenv : int32 -> string -> string -> bool (** Windows only. [process_putenv pid name value] sets the environment variable [name] to [value] in given process ID ([Unix.putenv] must also be called to update the value in the current process). This function must not be called if the target process is 32-bit and the current process is 64-bit or vice versa (outcomes vary from a no-op to a segfault). *) val shGetFolderPath : int -> shGFP_type -> string (** Windows only. [shGetFolderPath nFolder dwFlags] retrieves the location of a special folder by CSIDL value. See https://msdn.microsoft.com/en-us/library/windows/desktop/bb762181.aspx *) val sendMessageTimeout : nativeint -> int -> int -> ('a, 'b, 'c) winmessage -> 'a -> 'b -> int * 'c (** Windows only. [sendMessageTimeout hwnd timeout flags message wParam lParam] sends a message to the given handle, but is guaranteed to return within [timeout] milliseconds. The result consists of two parts, [fst] is the return value from SendMessageTimeout, [snd] depends on both the message and [fst]. See https://msdn.microsoft.com/en-us/library/windows/desktop/ms644952.aspx *) val getParentProcessID : int32 -> int32 (** Windows only. [getParentProcessID pid] returns the process ID of the parent of [pid]. @raise Failure If walking the process tree fails to find the process. *) val getConsoleAlias : string -> string -> string (** Windows only. [getConsoleAlias alias exeName] retrieves the value for a given executable or [""] if the alias is not defined. See https://docs.microsoft.com/en-us/windows/console/getconsolealias *) val win_create_process : string -> string -> string option -> Unix.file_descr -> Unix.file_descr -> Unix.file_descr -> int (** Windows only. Provided by OCaml's win32unix library. *) opam-2.1.5/src/core/opamProcess.mli0000644000175000017500000002106014427463453016233 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2018 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Process and job handling, with logs, termination status, etc. *) (** The type of shell commands *) type command (** Builds a shell command for later execution. @param env environment for the command @param verbose force verbosity @param name title, used to name log files, etc. @param metadata additional info to log @param dir CWD for the command @param allow_stdin whether to forward stdin @param stdout redirect stdout to the given file instead of the logs @param text Short text that may be displayed in the status-line @param command The command itself @param args Command-line arguments *) val command: ?env:string array -> ?verbose:bool -> ?name:string -> ?metadata:(string*string) list -> ?dir:string -> ?allow_stdin:bool -> ?stdout:string -> ?text:string -> string -> string list -> command val string_of_command: command -> string val text_of_command: command -> string option val is_verbose_command: command -> bool (** Returns a label suitable for printing the summary of running commands. First string is the topic (e.g. package), second the action (e.g. command name). Optional command arguments may be used for details (e.g. make action). *) val make_command_text: ?color:OpamConsole.text_style -> string -> ?args:string list -> string -> string (** The type for processes *) type t = { p_name : string; (** Command name *) p_args : string list; (** Command args *) p_pid : int; (** Process PID *) p_cwd : string; (** Process initial working directory *) p_time : float; (** Process start time *) p_stdout : string option; (** stdout dump file *) p_stderr : string option; (** stderr dump file *) p_env : string option; (** dump environment variables *) p_info : string option; (** dump process info *) p_metadata: (string * string) list; (** Metadata associated to the process *) p_verbose: bool; (** whether output of the process should be displayed *) p_tmp_files: string list; (** temporary files that should be cleaned up upon completion *) } (** Process results *) type result = { r_code : int; (** Process exit code, or 256 on error *) r_signal : int option; (** Signal received if the processed was killed *) r_duration : float; (** Process duration *) r_info : (string * string) list; (** Process info *) r_stdout : string list; (** Content of stdout dump file *) r_stderr : string list; (** Content of stderr dump file *) r_cleanup : string list; (** List of files to clean-up *) } (** [run command] synchronously call the command [command.cmd] with arguments [command.args]. It waits until the process is finished. The files [name.info], [name.env], [name.out] and [name.err], with [name = command.cmd_name] are created, and contain the process main description, the environment variables, the standard output and the standard error. Don't forget to call [cleanup result] afterwards *) val run : command -> result (** Same as [run], but doesn't wait. Use wait_one to wait and collect results; Don't forget to call [cleanup result] afterwards *) val run_background: command -> t (** Similar to [run_background], except that no process is created, and a dummy process (suitable for dry_wait_one) is returned. *) val dry_run_background: command -> t (** [wait p] waits for the processus [p] to end and returns its results. Be careful to handle Sys.Break *) val wait: t -> result (** Like [wait], but returns None immediately if the process hasn't ended *) val dontwait: t -> result option (** Wait for the first of the listed processes to terminate, and return its termination status *) val wait_one: t list -> t * result (** Similar to [wait_one] for simulations, to be used with [dry_run_background] *) val dry_wait_one: t list -> t * result (** Send SIGINT to a process (or SIGKILL on Windows) *) val interrupt: t -> unit (** Is the process result a success? *) val is_success : result -> bool (** Is the process result a failure? *) val is_failure : result -> bool (** Should be called after process termination, to cleanup temporary files. Leaves artefacts in case OpamGlobals.debug is on and on failure, unless force has been set. *) val cleanup : ?force:bool -> result -> unit (** Like [is_success], with an added cleanup side-effect (as [cleanup ~force:true]). Use this when not returning 0 is not an error case: since the default behaviour is to cleanup only when the command returned 0, which is not what is expected in that case. *) val check_success_and_cleanup : result -> bool (** {2 Misc} *) (** Reads a text file and returns a list of lines *) val read_lines: string -> string list (** Detailed report on process outcome *) val string_of_result: ?color:OpamConsole.text_style -> result -> string (** Short report on process outcome *) val result_summary: result -> string (** Higher-level interface to allow parallelism *) module Job: sig (** Open type and add combinators. Meant to be opened *) module Op: sig type 'a job = | Done of 'a | Run of command * (result -> 'a job) (** Stage a shell command with its continuation, eg: {[ command "ls" ["-a"] @@> fun result -> if OpamProcess.is_success result then Done result.r_stdout else failwith "ls" ]} *) val (@@>): command -> (result -> 'a job) -> 'a job (** [job1 @@+ fun r -> job2] appends the computation of tasks in [job2] after [job1] *) val (@@+): 'a job -> ('a -> 'b job) -> 'b job (** [job @@| f] maps [f] on the results of [job]. Equivalent to [job @@+ fun r -> Done (f r)] *) val (@@|): 'a job -> ('a -> 'b) -> 'b job end (** Sequential run of a job *) val run: 'a Op.job -> 'a (** Same as [run] but doesn't actually run any shell command, and feed a dummy result to the cont. *) val dry_run: 'a Op.job -> 'a (** Catch exceptions raised within a job *) val catch: (exn -> 'a Op.job) -> (unit -> 'a Op.job) -> 'a Op.job (** Ignore all non-fatal exceptions raised by job and return default *) val ignore_errors: default:'a -> ?message:string -> (unit -> 'a Op.job) -> 'a Op.job (** Register an exception-safe finaliser in a job. [finally job fin] is equivalent to [catch job (fun e -> fin (); raise e) @@+ fun r -> fin (); Done r] *) val finally: (unit -> unit) -> (unit -> 'a Op.job) -> 'a Op.job (** Converts a list of commands into a job that returns None on success, or the first failed command and its result. Unless [keep_going] is true, stops on first error. *) val of_list: ?keep_going:bool -> command list -> (command * result) option Op.job (** As [of_list], but takes a list of functions that return the commands. The functions will only be evaluated when the command needs to be run. *) val of_fun_list: ?keep_going:bool -> (unit -> command) list -> (command * result) option Op.job (** Returns the job made of the the given homogeneous jobs run sequentially *) val seq: ('a -> 'a Op.job) list -> 'a -> 'a Op.job (** Sequentially maps jobs on a list *) val seq_map: ('a -> 'b Op.job) -> 'a list -> 'b list Op.job (** Sets and overrides text of the underlying commands *) val with_text: string -> 'a Op.job -> 'a Op.job end type 'a job = 'a Job.Op.job (**/**) val set_resolve_command : (?env:string array -> ?dir:string -> string -> string option) -> unit (** Like Unix.create_process_env, but with correct escaping of arguments when invoking a cygwin executable from a native Windows executable. *) val create_process_env : string -> string array -> string array -> Unix.file_descr -> Unix.file_descr -> Unix.file_descr -> int opam-2.1.5/src/core/opamSystem.ml0000644000175000017500000014032214427463453015733 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCompat type install_warning = [ `Add_exe | `Install_dll | `Install_script | `Install_unknown | `Cygwin | `Cygwin_libraries ] type install_warning_fn = string -> install_warning -> unit exception Process_error of OpamProcess.result exception Internal_error of string exception Command_not_found of string exception File_not_found of string exception Permission_denied of string let log ?level fmt = OpamConsole.log "SYSTEM" ?level fmt let slog = OpamConsole.slog let internal_error fmt = Printf.ksprintf (fun str -> log "error: %s" str; raise (Internal_error str) ) fmt let process_error r = if r.OpamProcess.r_signal = Some Sys.sigint then raise Sys.Break else raise (Process_error r) let raise_on_process_error r = if OpamProcess.is_failure r then raise (Process_error r) let command_not_found cmd = raise (Command_not_found cmd) let permission_denied cmd = raise (Permission_denied cmd) module Sys2 = struct (* same as [Sys.is_directory] except for symlinks, which returns always [false]. *) let is_directory file = try Unix.( (lstat file).st_kind = S_DIR ) with Unix.Unix_error _ as e -> raise (Sys_error (Printexc.to_string e)) end let file_or_symlink_exists f = try ignore (Unix.lstat f); true with Unix.Unix_error (Unix.ENOENT, _, _) -> false let (/) = Filename.concat let temp_basename prefix = Printf.sprintf "%s-%d-%06x" prefix (OpamStubs.getpid ()) (Random.int 0xFFFFFF) let rec mk_temp_dir ?(prefix="opam") () = let s = Filename.get_temp_dir_name () / temp_basename prefix in if Sys.file_exists s then mk_temp_dir () else s let safe_mkdir dir = try log "mkdir %s" dir; Unix.mkdir dir 0o755 with Unix.Unix_error(Unix.EEXIST,_,_) -> () let mkdir dir = let rec aux dir = if not (Sys.file_exists dir) then begin aux (Filename.dirname dir); safe_mkdir dir; end in aux dir let rm_command = if Sys.win32 then "cmd /d /v:off /c rd /s /q" else "rm -rf" let remove_dir dir = log "rmdir %s" dir; if Sys.file_exists dir then ( let err = Sys.command (Printf.sprintf "%s %s" rm_command (Filename.quote dir)) in if err <> 0 then internal_error "Cannot remove %s (error %d)." dir err ) let temp_files = Hashtbl.create 1024 let logs_cleaner = let to_clean = ref OpamStd.String.Set.empty in OpamStd.Sys.at_exit (fun () -> OpamStd.String.Set.iter (fun f -> try Unix.unlink f; (* Only log the item if unlink succeeded *) log "logs_cleaner: rm: %s" f with Unix.Unix_error _ -> ()) !to_clean; if OpamCoreConfig.(!r.log_dir = default.log_dir) then try Unix.rmdir OpamCoreConfig.(default.log_dir) with Unix.Unix_error _ -> ()); fun tmp_dir -> if OpamCoreConfig.(!r.keep_log_dir) then to_clean := OpamStd.String.Set.remove tmp_dir !to_clean else to_clean := OpamStd.String.Set.add tmp_dir !to_clean let rec temp_file ?(auto_clean=true) ?dir prefix = let temp_dir = match dir with | None -> OpamCoreConfig.(!r.log_dir) | Some d -> d in mkdir temp_dir; let file = temp_dir / temp_basename prefix in if Hashtbl.mem temp_files file then temp_file ~auto_clean ?dir prefix else ( Hashtbl.add temp_files file true; if auto_clean then logs_cleaner file; file ) let remove_file file = if try ignore (Unix.lstat file); true with Unix.Unix_error _ -> false then ( try log "rm %s" file; Unix.unlink file with Unix.Unix_error _ as e -> internal_error "Cannot remove %s (%s)." file (Printexc.to_string e) ) let string_of_channel ic = let n = 32768 in let s = Bytes.create n in let b = Buffer.create 1024 in let rec iter ic b s = let nread = try input ic s 0 n with End_of_file -> 0 in if nread > 0 then ( Buffer.add_subbytes b s 0 nread; iter ic b s ) in iter ic b s; Buffer.contents b let read file = let ic = try open_in_bin file with Sys_error _ -> raise (File_not_found file) in Unix.lockf (Unix.descr_of_in_channel ic) Unix.F_RLOCK 0; let s = string_of_channel ic in close_in ic; s let write file contents = mkdir (Filename.dirname file); let oc = try open_out_bin file with Sys_error _ -> raise (File_not_found file) in Unix.lockf (Unix.descr_of_out_channel oc) Unix.F_LOCK 0; output_string oc contents; close_out oc let setup_copy ?(chmod = fun x -> x) ~src ~dst () = let ic = open_in_bin src in try let perm = (Unix.fstat (Unix.descr_of_in_channel ic)).st_perm |> chmod in let () = try if Unix.((lstat dst).st_kind <> S_REG) then remove_file dst with Unix.Unix_error(ENOENT, _, _) -> () in let oc = open_out_gen [ Open_wronly; Open_creat; Open_trunc; Open_binary ] perm dst in let fd = Unix.descr_of_out_channel oc in try if Unix.((fstat fd).st_perm) <> perm then Unix.fchmod fd perm; (ic, oc) with exn -> OpamStd.Exn.finalise exn (fun () -> close_out oc) with exn -> OpamStd.Exn.finalise exn (fun () -> close_in ic) let copy_channels = let buf_len = 4096 in let buf = Bytes.create buf_len in let rec loop ic oc = match input ic buf 0 buf_len with | 0 -> () | n -> output oc buf 0 n; loop ic oc in loop let copy_file_aux ?chmod ~src ~dst () = let close_channels ic oc = OpamStd.Exn.finally (fun () -> close_in ic) (fun () -> close_out oc) in try let ic, oc = setup_copy ?chmod ~src ~dst () in OpamStd.Exn.finally (fun () -> close_channels ic oc) (fun () -> copy_channels ic oc); with Unix.Unix_error _ as e -> (* Remove the partial destination file, if any. *) (try Unix.unlink dst with Unix.Unix_error _ -> ()); internal_error "Cannot copy %s to %s (%s)." src dst (Printexc.to_string e) let chdir dir = try Unix.chdir dir with Unix.Unix_error _ -> raise (File_not_found dir) let in_dir dir fn = let reset_cwd = let cwd = try Some (Sys.getcwd ()) with Sys_error _ -> None in fun () -> match cwd with | None -> () | Some cwd -> try chdir cwd with File_not_found _ -> () in chdir dir; try let r = fn () in reset_cwd (); r with e -> OpamStd.Exn.finalise e reset_cwd let list kind dir = try in_dir dir (fun () -> let d = Sys.readdir (Sys.getcwd ()) in let d = Array.to_list d in let l = List.filter kind d in List.map (Filename.concat dir) (List.sort compare l) ) with File_not_found _ -> [] let ls dir = list (fun _ -> true) dir let files_with_links = list (fun f -> try not (Sys.is_directory f) with Sys_error _ -> false) let files_all_not_dir = list (fun f -> try not (Sys2.is_directory f) with Sys_error _ -> false) let directories_strict = list (fun f -> try Sys2.is_directory f with Sys_error _ -> false) let directories_with_links = list (fun f -> try Sys.is_directory f with Sys_error _ -> false) let rec_files dir = let rec aux accu dir = let d = directories_with_links dir in let f = files_with_links dir in List.fold_left aux (f @ accu) d in aux [] dir let files dir = files_with_links dir let rec_dirs dir = let rec aux accu dir = let d = directories_with_links dir in List.fold_left aux (d @ accu) d in aux [] dir let dirs dir = directories_with_links dir let dir_is_empty dir = try in_dir dir (fun () -> Sys.readdir (Sys.getcwd ()) = [||]) with File_not_found _ -> false let with_tmp_dir fn = let dir = mk_temp_dir () in try mkdir dir; let e = fn dir in remove_dir dir; e with e -> OpamStd.Exn.finalise e @@ fun () -> remove_dir dir let in_tmp_dir fn = with_tmp_dir @@ fun dir -> in_dir dir fn let with_tmp_dir_job fjob = let dir = mk_temp_dir () in mkdir dir; OpamProcess.Job.finally (fun () -> remove_dir dir) (fun () -> fjob dir) let remove file = if (try Sys2.is_directory file with Sys_error _ -> false) then remove_dir file else remove_file file (* Sets path to s and returns the old path *) let getchdir s = let p = try Sys.getcwd () with Sys_error _ -> let p = OpamCoreConfig.(!r.log_dir) in mkdir p; p in chdir s; p let normalize s = try getchdir (getchdir s) with File_not_found _ -> s let real_path p = (* if Filename.is_relative p then *) match (try Some (Sys.is_directory p) with Sys_error _ -> None) with | None -> let rec resolve dir = if Sys.file_exists dir then normalize dir else let parent = Filename.dirname dir in if dir = parent then dir else Filename.concat (resolve parent) (Filename.basename dir) in let p = if Filename.is_relative p then Filename.concat (Sys.getcwd ()) p else p in resolve p | Some true -> normalize p | Some false -> let dir = normalize (Filename.dirname p) in match Filename.basename p with | "." -> dir | base -> dir / base (* else p *) type command = string list let default_env () = OpamStd.Env.list () |> List.map (fun (var, v) -> var^"="^v) |> Array.of_list let env_var env var = let len = Array.length env in let f = if Sys.win32 then String.uppercase_ascii else fun x -> x in let prefix = f var^"=" in let pfxlen = String.length prefix in let rec aux i = if i >= len then "" else let s = env.(i) in if OpamStd.String.starts_with ~prefix (f s) then String.sub s pfxlen (String.length s - pfxlen) else aux (i+1) in aux 0 let forward_to_back = if Sys.win32 then String.map (function '/' -> '\\' | c -> c) else fun x -> x let back_to_forward = if Sys.win32 then String.map (function '\\' -> '/' | c -> c) else fun x -> x (* OCaml 4.05.0 no longer follows the updated PATH to resolve commands. This makes unqualified commands absolute as a workaround. *) let t_resolve_command = let is_external_cmd name = let name = forward_to_back name in OpamStd.String.contains_char name Filename.dir_sep.[0] in let check_perms = if Sys.win32 then fun f -> try (Unix.stat f).Unix.st_kind = Unix.S_REG with e -> OpamStd.Exn.fatal e; false else fun f -> try let open Unix in let uid = geteuid () in let groups = OpamStd.IntSet.of_list (getegid () :: Array.to_list (getgroups ())) in let {st_uid; st_gid; st_perm; _} = stat f in let mask = if uid = st_uid then 0o100 else if OpamStd.IntSet.mem st_gid groups then 0o010 else 0o001 in if (st_perm land mask) <> 0 then true else match OpamACL.get_acl_executable_info f st_uid with | None -> false | Some [] -> true | Some gids -> OpamStd.IntSet.(not (is_empty (inter (of_list gids) groups))) with e -> OpamStd.Exn.fatal e; false in let resolve ?dir env name = if not (Filename.is_relative name) then begin (* absolute path *) if not (Sys.file_exists name) then `Not_found else if not (check_perms name) then `Denied else `Cmd name end else if is_external_cmd name then begin (* relative path *) let cmd = match dir with | None -> name | Some d -> Filename.concat d name in if not (Sys.file_exists cmd) then `Not_found else if not (check_perms cmd) then `Denied else `Cmd cmd end else (* bare command, lookup in PATH *) (* Following the shell sematics for looking up PATH, programs with the expected name but not the right permissions are skipped silently. Therefore, only two outcomes are possible in that case, [`Cmd ..] or [`Not_found]. *) let path = OpamStd.Sys.split_path_variable (env_var env "PATH") in let name = if Sys.win32 && not (Filename.check_suffix name ".exe") then name ^ ".exe" else name in let possibles = OpamStd.List.filter_map (fun path -> let candidate = Filename.concat path name in if Sys.file_exists candidate then Some candidate else None) path in match List.find check_perms possibles with | cmdname -> `Cmd cmdname | exception Not_found -> if possibles = [] then `Not_found else `Denied in fun ?env ?dir name -> let env = match env with None -> default_env () | Some e -> e in resolve env ?dir name let resolve_command ?env ?dir name = match t_resolve_command ?env ?dir name with | `Cmd cmd -> Some cmd | `Denied | `Not_found -> None let apply_cygpath name = let r = OpamProcess.run (OpamProcess.command ~name:(temp_file "command") ~verbose:false "cygpath" ["--"; name]) in OpamProcess.cleanup ~force:true r; if OpamProcess.is_success r then List.hd r.OpamProcess.r_stdout else OpamConsole.error_and_exit `Internal_error "Could not apply cygpath to %s" name let get_cygpath_function = if Sys.win32 then fun ~command -> lazy (if OpamStd.(Option.map_default Sys.is_cygwin_variant `Native (resolve_command command)) = `Cygwin then apply_cygpath else fun x -> x) else let f = Lazy.from_val (fun x -> x) in fun ~command:_ -> f let runs = ref [] let print_stats () = match !runs with | [] -> () | l -> OpamConsole.msg "%d external processes called:\n%s" (List.length l) (OpamStd.Format.itemize ~bullet:" " (String.concat " ") l) let log_file ?dir name = temp_file ?dir (OpamStd.Option.default "log" name) let make_command ?verbose ?env ?name ?text ?metadata ?allow_stdin ?stdout ?dir ?(resolve_path=true) cmd args = let env = match env with None -> default_env () | Some e -> e in let name = log_file name in let verbose = OpamStd.Option.default OpamCoreConfig.(!r.verbose_level >= 2) verbose in (* Check that the command doesn't contain whitespaces *) if None <> try Some (String.index cmd ' ') with Not_found -> None then OpamConsole.warning "Command %S contains space characters" cmd; let full_cmd = if resolve_path then t_resolve_command ~env ?dir cmd else `Cmd cmd in match full_cmd with | `Cmd cmd -> OpamProcess.command ~env ~name ?text ~verbose ?metadata ?allow_stdin ?stdout ?dir cmd args | `Not_found -> command_not_found cmd | `Denied -> permission_denied cmd let run_process ?verbose ?env ~name ?metadata ?stdout ?allow_stdin command = let env = match env with None -> default_env () | Some e -> e in let chrono = OpamConsole.timer () in runs := command :: !runs; match command with | [] -> invalid_arg "run_process" | cmd :: args -> if OpamStd.String.contains_char cmd ' ' then OpamConsole.warning "Command %S contains space characters" cmd; match t_resolve_command ~env cmd with | `Cmd full_cmd -> let verbose = match verbose with | None -> OpamCoreConfig.(!r.verbose_level) >= 2 | Some b -> b in let r = OpamProcess.run (OpamProcess.command ~env ~name ~verbose ?metadata ?allow_stdin ?stdout full_cmd args) in let str = String.concat " " (cmd :: args) in log ~level:2 "[%a] (in %.3fs) %s" (OpamConsole.slog Filename.basename) name (chrono ()) str; r | `Not_found -> command_not_found cmd | `Denied -> permission_denied cmd let command ?verbose ?env ?name ?metadata ?allow_stdin cmd = let name = log_file name in let r = run_process ?verbose ?env ~name ?metadata ?allow_stdin cmd in OpamProcess.cleanup r; raise_on_process_error r let commands ?verbose ?env ?name ?metadata ?(keep_going=false) commands = let name = log_file name in let run = run_process ?verbose ?env ~name ?metadata in let command r0 c = match r0, keep_going with | (`Error _ | `Exception _), false -> r0 | _ -> let r1 = try let r = run c in if OpamProcess.is_success r then `Successful r else `Error r with Command_not_found _ as e -> `Exception e in match r0 with `Start | `Successful _ -> r1 | _ -> r0 in match List.fold_left command `Start commands with | `Start -> () | `Successful r -> OpamProcess.cleanup r | `Error e -> process_error e | `Exception e -> raise e let read_command_output ?verbose ?env ?metadata ?allow_stdin cmd = let name = log_file None in let r = run_process ?verbose ?env ~name ?metadata ?allow_stdin ~stdout:(name^".out") cmd in OpamProcess.cleanup r; raise_on_process_error r; r.OpamProcess.r_stdout let verbose_for_base_commands () = OpamCoreConfig.(!r.verbose_level) >= 3 let cygify f = if Sys.win32 then List.map (Lazy.force f) else fun x -> x let copy_file src dst = if (try Sys.is_directory src with Sys_error _ -> raise (File_not_found src)) then internal_error "Cannot copy %s: it is a directory." src; if (try Sys.is_directory dst with Sys_error _ -> false) then internal_error "Cannot copy to %s: it is a directory." dst; if file_or_symlink_exists dst then remove_file dst; mkdir (Filename.dirname dst); log "copy %s -> %s" src dst; copy_file_aux ~src ~dst () let copy_dir src dst = if Sys.file_exists dst then if Sys.is_directory dst then match ls src with | [] -> () | srcfiles -> command ~verbose:(verbose_for_base_commands ()) ([ "cp"; "-PRp" ] @ srcfiles @ [ dst ]) else internal_error "Can not copy dir %s to %s, which is not a directory" src dst else (mkdir (Filename.dirname dst); command ~verbose:(verbose_for_base_commands ()) [ "cp"; "-PRp"; src; dst ]) let mv_aux f src dst = if file_or_symlink_exists dst then remove_file dst; mkdir (Filename.dirname dst); command ~verbose:(verbose_for_base_commands ()) ("mv"::(cygify f [src; dst])) let mv = mv_aux (get_cygpath_function ~command:"mv") let is_exec file = let stat = Unix.stat file in stat.Unix.st_kind = Unix.S_REG && stat.Unix.st_perm land 0o111 <> 0 let file_is_empty f = Unix.((stat f).st_size = 0) let classify_executable file = let c = open_in file in (* On a 32-bit system, this could fail for a PE image with a 2GB+ DOS header =-o *) let input_int_little c = let b1 = input_byte c in let b2 = input_byte c in let b3 = input_byte c in let b4 = input_byte c in b1 lor (b2 lsl 8) lor (b3 lsl 16) lor (b4 lsl 24) in let input_short_little c = let b1 = input_byte c in let b2 = input_byte c in b1 lor (b2 lsl 8) in set_binary_mode_in c true; try match really_input_string c 2 with "#!" -> close_in c; `Script | "MZ" -> let is_pe = try (* Offset to PE header at 0x3c (but we've already read two bytes) *) ignore (really_input_string c 0x3a); ignore (really_input_string c (input_int_little c - 0x40)); let magic = really_input_string c 4 in magic = "PE\000\000" with End_of_file -> close_in c; false in if is_pe then try let arch = (* NB It's not necessary to determine PE/PE+ headers for x64/x86 determination *) match input_short_little c with 0x8664 -> `x86_64 | 0x14c -> `x86 | _ -> raise End_of_file in ignore (really_input_string c 14); let size_of_opt_header = input_short_little c in let characteristics = input_short_little c in (* Executable images must have a PE "optional" header and be marked executable *) (* Could also validate IMAGE_FILE_32BIT_MACHINE (0x100) for x86 and IMAGE_FILE_LARGE_ADDRESS_AWARE (0x20) for x64 *) if size_of_opt_header <= 0 || characteristics land 0x2 = 0 then raise End_of_file; close_in c; if characteristics land 0x2000 <> 0 then `Dll arch else `Exe arch with End_of_file -> close_in c; `Unknown else `Exe `i386 | _ -> close_in c; `Unknown with End_of_file -> close_in c; `Unknown let default_install_warning dst = function | `Add_exe -> OpamConsole.warning "Automatically adding .exe to %s" dst | `Install_dll -> (* TODO Installation of .dll to bin is unfortunate, but not sure if it should be a warning *) () | `Install_script -> (* TODO Generate a .cmd wrapper (and warn about it - they're not perfect) *) OpamConsole.warning "%s is a script; the command won't be available" dst; | `Install_unknown -> (* TODO Installation of a non-executable file is unexpected, but not sure if it should be a warning/error *) () | `Cygwin -> OpamConsole.warning "%s is a Cygwin-linked executable" dst | `Cygwin_libraries -> OpamConsole.warning "%s links with a Cygwin-compiled DLL (almost certainly a packaging or environment error)" dst let install ?(warning=default_install_warning) ?exec src dst = if Sys.is_directory src then internal_error "Cannot install %s: it is a directory." src; if (try Sys.is_directory dst with Sys_error _ -> false) then internal_error "Cannot install to %s: it is a directory." dst; mkdir (Filename.dirname dst); let exec = match exec with | Some e -> e | None -> is_exec src in let perm = if exec then 0o755 else 0o644 in log "install %s -> %s (%o)" src dst perm; if Sys.win32 then if exec then begin let (dst, cygcheck) = match classify_executable src with `Exe _ -> if not (Filename.check_suffix dst ".exe") && not (Filename.check_suffix dst ".dll") then begin warning dst `Add_exe; (dst ^ ".exe", true) end else (dst, true) | `Dll _ -> warning dst `Install_dll; (dst, true) | `Script -> warning dst `Install_script; (dst, false) | `Unknown -> warning dst `Install_unknown; (dst, false) in copy_file_aux ~src ~dst (); if cygcheck then match OpamStd.Sys.is_cygwin_variant dst with `Native -> () | `Cygwin -> warning dst `Cygwin | `CygLinked -> warning dst `Cygwin_libraries end else copy_file_aux ~src ~dst () else copy_file_aux ~chmod:(fun _ -> perm) ~src ~dst () let cpu_count () = try let ans = let open OpamStd in match Sys.os () with | Sys.Win32 -> [Env.get "NUMBER_OF_PROCESSORS"] | Sys.FreeBSD -> read_command_output ~verbose:(verbose_for_base_commands ()) ["sysctl"; "-n"; "hw.ncpu"] | _ -> read_command_output ~verbose:(verbose_for_base_commands ()) ["getconf"; "_NPROCESSORS_ONLN"] in int_of_string (List.hd ans) with Not_found | Process_error _ | Failure _ -> 1 open OpamProcess.Job.Op module Tar = struct type extract = | Bzip2 | Gzip | Lzma | Xz let extract_command = function | Bzip2 -> "bzip2" | Gzip -> "gzip" | Lzma -> "lzma" | Xz -> "xz" let extract_option = function | Bzip2 -> 'j' | Gzip -> 'z' | Lzma -> 'Y' | Xz -> 'J' let extensions = [ [ "tar.gz" ; "tgz" ], Gzip ; [ "tar.bz2" ; "tbz" ], Bzip2 ; [ "tar.xz" ; "txz" ], Xz ; [ "tar.lzma" ; "tlz" ], Lzma ] let guess_type f = try let ic = open_in f in let c1 = input_char ic in let c2 = input_char ic in close_in ic; match c1, c2 with | '\031', '\139' -> Some Gzip | 'B' , 'Z' -> Some Bzip2 | '\xfd', '\x37' -> Some Xz | '\x5d', '\x00' -> Some Lzma | _ -> None with Sys_error _ -> None let match_ext file ext = List.exists (Filename.check_suffix file) ext let get_type file = let ext = List.fold_left (fun acc (ext, t) -> match acc with | Some t -> Some t | None -> if match_ext file ext then Some t else None) None extensions in match ext with | Some t -> Some t | None -> match guess_type file with | Some t -> Some t | _ -> None let is_archive file = get_type file <> None let check_extract file = OpamStd.Option.Op.( get_type file >>= fun typ -> let cmd = extract_command typ in let res = resolve_command cmd <> None in if not res then Some (Printf.sprintf "Tar needs %s to extract the archive" cmd) else None) let tar_cmd = lazy ( match OpamStd.Sys.os () with | OpamStd.Sys.OpenBSD -> "gtar" | _ -> "tar" ) let cygpath_tar = lazy ( Lazy.force (get_cygpath_function ~command:(Lazy.force tar_cmd)) ) let extract_command = fun file -> OpamStd.Option.Op.( get_type file >>| fun typ -> let f = Lazy.force cygpath_tar in let tar_cmd = Lazy.force tar_cmd in let command c dir = make_command tar_cmd [ Printf.sprintf "xf%c" c ; f file; "-C" ; f dir ] in command (extract_option typ)) let compress_command = fun file dir -> let f = Lazy.force cygpath_tar in let tar_cmd = Lazy.force tar_cmd in make_command tar_cmd [ "cfz"; f file; "-C" ; f (Filename.dirname dir); f (Filename.basename dir) ] end module Zip = struct let is_archive f = try let ic = open_in f in let c1 = input_char ic in let c2 = input_char ic in let c3 = input_char ic in let c4 = input_char ic in close_in ic; match c1, c2, c3, c4 with | '\x50', '\x4b', '\x03', '\x04' -> true | _ -> false with Sys_error _ | End_of_file -> false let extract_command file = Some (fun dir -> make_command "unzip" [ file; "-d"; dir ]) end let is_archive file = Tar.is_archive file || Zip.is_archive file let extract_command file = if Zip.is_archive file then Zip.extract_command file else Tar.extract_command file let make_tar_gz_job ~dir file = let tmpfile = file ^ ".tmp" in remove_file tmpfile; Tar.compress_command tmpfile dir @@> fun r -> OpamProcess.cleanup r; if OpamProcess.is_success r then (mv tmpfile file; Done None) else (remove_file tmpfile; Done (Some (Process_error r))) let extract_job ~dir file = if not (Sys.file_exists file) then Done (Some (File_not_found file)) else with_tmp_dir_job @@ fun tmp_dir -> match extract_command file with | None -> Done (Some (Failure ("Unknown archive type: "^file))) | Some cmd -> cmd tmp_dir @@> fun r -> if not (OpamProcess.is_success r) then if Zip.is_archive file then Done (Some (Process_error r)) else match Tar.check_extract file with | None -> Done (Some (Process_error r)) | Some s -> Done (Some (Failure s)) else if try not (Sys.is_directory dir) with Sys_error _ -> false then internal_error "Extracting the archive would overwrite %s." dir else let flist = OpamStd.Op.( files_all_not_dir tmp_dir |> List.filter (not @* OpamStd.String.contains ~sub:"pax_global_header")) in match flist with | [] -> begin match directories_strict tmp_dir with | [x] -> (try mkdir (Filename.dirname dir); copy_dir x dir; Done None with e -> OpamStd.Exn.fatal e; Done (Some e)) | _ -> internal_error "The archive %S contains multiple root directories." file end | _ -> mkdir (Filename.dirname dir); try copy_dir tmp_dir dir; Done None with e -> OpamStd.Exn.fatal e; Done (Some e) let extract ~dir file = match OpamProcess.Job.run (extract_job ~dir file) with | Some e -> raise e | None -> () let extract_in_job ~dir file = OpamProcess.Job.catch (fun e -> Done (Some e)) @@ fun () -> mkdir dir; match extract_command file with | None -> internal_error "%s is not a valid tar or zip archive." file | Some cmd -> cmd dir @@> fun r -> if not (OpamProcess.is_success r) then if Zip.is_archive file then Done (Some (Process_error r)) else match Tar.check_extract file with | None -> Done (Some (Failure (Printf.sprintf "Failed to extract archive %s: %s" file (OpamProcess.result_summary r)))) | Some s -> Done (Some (Failure s)) else Done None let extract_in ~dir file = match OpamProcess.Job.run (extract_in_job ~dir file) with | Some e -> raise e | None -> () let link src dst = mkdir (Filename.dirname dst); if file_or_symlink_exists dst then remove_file dst; try log "ln -s %s %s" src dst; Unix.symlink src dst with Unix.Unix_error (Unix.EXDEV, _, _) -> (* Fall back to copy if symlinks are not supported *) let src = if Filename.is_relative src then Filename.dirname dst / src else src in if Sys.is_directory src then copy_dir src dst else copy_file src dst type actual_lock_flag = [ `Lock_read | `Lock_write ] type lock_flag = [ `Lock_none | actual_lock_flag ] type lock = { mutable fd: Unix.file_descr option; file: string; mutable kind: lock_flag; } exception Locked let unix_lock_op ~dontblock = function | `Lock_read -> if dontblock then Unix.F_TRLOCK else Unix.F_RLOCK | `Lock_write -> if OpamCoreConfig.(!r.safe_mode) then OpamConsole.error_and_exit `Locked "Write lock attempt in safe mode" else if dontblock then Unix.F_TLOCK else Unix.F_LOCK let string_of_lock_kind = function | `Lock_none -> "none" | `Lock_read -> "read" | `Lock_write -> "write" let locks = Hashtbl.create 16 let release_all_locks () = Hashtbl.iter (fun fd _ -> Unix.close fd) locks; Hashtbl.clear locks let rec flock_update : 'a. ([< lock_flag ] as 'a) -> ?dontblock:bool -> lock -> unit = fun flag ?(dontblock=OpamCoreConfig.(!r.safe_mode)) lock -> log "LOCK %s (%a => %a)" ~level:2 lock.file (slog string_of_lock_kind) (lock.kind) (slog string_of_lock_kind) flag; if lock.kind = (flag :> lock_flag) then () else match flag, lock with | `Lock_none, { fd = Some fd; kind = (`Lock_read | `Lock_write); _ } -> Hashtbl.remove locks fd; Unix.close fd; (* implies Unix.lockf fd Unix.F_ULOCK 0 *) lock.kind <- (flag :> lock_flag); lock.fd <- None | (`Lock_read | `Lock_write), { fd = None; kind = `Lock_none; file } -> let new_lock = flock flag ~dontblock file in lock.kind <- (flag :> lock_flag); lock.fd <- new_lock.fd | `Lock_write, { fd = Some fd; file; kind = `Lock_read } -> Unix.close fd; (* fd needs read-write reopen *) let new_lock = flock flag ~dontblock file in lock.kind <- (flag :> lock_flag); lock.fd <- new_lock.fd | (`Lock_read | `Lock_write) as flag, { fd = Some fd; file; kind } -> (* Write locks are not recursive on Windows, so only call lockf if necessary *) if kind <> flag then (try (* Locks can't be promoted (or demoted) on Windows - see PR#7264 *) if Sys.win32 && kind <> `Lock_none then Unix.(lockf fd F_ULOCK 0); Unix.lockf fd (unix_lock_op ~dontblock:true flag) 0 with Unix.Unix_error (Unix.EAGAIN,_,_) -> if dontblock then OpamConsole.error_and_exit `Locked "Another process has locked %s and non blocking mode enabled" file; OpamConsole.formatted_msg "Another process has locked %s, waiting (%s to abort)... " file (if Sys.win32 then "CTRL+C" else "C-c"); let rec lock_w_ignore_sig () = try Unix.lockf fd (unix_lock_op ~dontblock:false flag) 0; with Sys.Break as e -> (OpamConsole.msg "\n"; raise e) | Unix.Unix_error (Unix.EINTR,_,_) -> lock_w_ignore_sig () in lock_w_ignore_sig (); OpamConsole.msg "lock acquired.\n"); lock.kind <- (flag :> lock_flag) | _ -> assert false and flock: 'a. ([< lock_flag ] as 'a) -> ?dontblock:bool -> string -> lock = fun flag ?dontblock file -> match flag with | `Lock_none -> { fd = None; file; kind = `Lock_none } | `Lock_write when OpamCoreConfig.(!r.safe_mode) -> OpamConsole.error_and_exit `Locked "Write lock attempt in safe mode"; | flag -> mkdir (Filename.dirname file); let rdflag = if (flag :> lock_flag) = `Lock_write then Unix.O_RDWR else Unix.O_RDONLY in let fd = Unix.openfile file Unix.([O_CREAT; O_CLOEXEC; rdflag]) 0o666 in Hashtbl.add locks fd (); let lock = { fd = Some fd; file; kind = `Lock_none } in flock_update flag ?dontblock lock; lock let funlock lock = flock_update `Lock_none lock let get_lock_flag lock = lock.kind let get_lock_fd lock = match lock.fd with Some fd -> fd | None -> raise Not_found let lock_max flag1 flag2 = match flag1, flag2 with | `Lock_write, _ | _, `Lock_write -> `Lock_write | `Lock_read, _ | _, `Lock_read -> `Lock_read | `Lock_none, `Lock_none -> `Lock_none let lock_none = { fd = None; file = ""; kind = `Lock_none; } let lock_isatleast flag lock = lock_max flag lock.kind = lock.kind let get_eol_encoding file = let ch = try open_in_bin file with Sys_error _ -> raise (File_not_found file) in let has_cr line = let length = String.length line in length > 0 && line.[length - 1] = '\r' in let last_char ch = seek_in ch (in_channel_length ch - 1); input_char ch in let rec read_lines cr line = let has_cr = has_cr line in match input_line ch with | line -> if has_cr = cr then read_lines cr line else begin close_in ch; None end | exception End_of_file -> let result = if cr = has_cr then Some cr else if cr && last_char ch <> '\n' then Some true else None in close_in ch; result in match input_line ch with | line_one -> let has_cr = has_cr line_one in begin match input_line ch with | line_two -> read_lines has_cr line_two | exception End_of_file -> let result = if last_char ch = '\n' then Some has_cr else None in close_in ch; result end | exception End_of_file -> close_in ch; None let translate_patch ~dir orig corrected = (* It's unnecessarily complicated to infer whether the entire file is CRLF encoded and also the status of individual files, so accept scanning the file three times instead of two. *) let log ?level fmt = OpamConsole.log "PATCH" ?level fmt in let strip_cr = get_eol_encoding orig = Some true in let ch = try open_in_bin orig with Sys_error _ -> raise (File_not_found orig) in (* CRLF detection with patching can be more complicated than that used here, especially in the presence of files with mixed LF/CRLF endings. The processing done here aims to allow patching to succeed on files which are wholly encoded CRLF or LF against patches which may have been translated to be the opposite. The resulting patch will *always* have LF line endings for the patch metadata (headers, chunk locations, etc.) but uses either CRLF or LF depending on the target file. Endings in the patch are always preserved for new files. The benefit of always using LF endings for the metadata is that patch's "Stripping trailing CRs from patch" behaviour won't be triggered. There are various patch formats, though only the Unified and Context formats allow multiple files to be patched. I tired of trying to get sufficient documented detail of Context diffs to be able to parse them without resorting to reverse-engineering code. It is unusual to see them these days, so for now opam just emits a warning if a Context diff file is encountered and does no processing to it. There are various semantic aspects of Unified diffs which are not handled (at least at present) by this function which are documented in the code with the marker "Weakness". *) let process_chunk_header result line = match OpamStd.String.split line ' ' with | "@@"::a::b::"@@"::_ -> (* Weakness: for a new file [a] should always be -0,0 (not checked) *) let l_a = String.length a in let l_b = String.length b in if l_a > 1 && l_b > 1 && a.[0] = '-' && b.[0] = '+' then try let f (_, v) = int_of_string v in let neg = OpamStd.String.cut_at (String.sub a 1 (l_a - 1)) ',' |> OpamStd.Option.map_default f 1 in let pos = OpamStd.String.cut_at (String.sub b 1 (l_b - 1)) ',' |> OpamStd.Option.map_default f 1 in result neg pos with e -> OpamStd.Exn.fatal e; (* TODO Should display some kind of re-sync warning *) `Header else (* TODO Should display some kind of re-sync warning *) `Header | _ -> (* TODO Should display some kind of warning that there were no chunks *) `Header in let process_state_transition next_state state transforms = match (state, next_state) with | (`Processing _, `Processing _) -> transforms | (`Processing (_, target, crlf, patch_crlf, chunks, _), _) -> let compute_transform patch_crlf = (* Emit the patch *) let transform = match (crlf, patch_crlf) with | (None, _) | (_, None) -> log ~level:3 "CRLF adaptation skipped for %s" target; None | (Some crlf, Some patch_crlf) -> if crlf = patch_crlf then begin log ~level:3 "No CRLF adaptation necessary for %s" target; None end else if crlf then begin log ~level:3 "Adding \\r to patch chunks for %s" target; Some true end else begin log ~level:3 "Stripping \\r to patch chunks for %s" target; Some false end in let record_transform transform = let augment_record (first_line, last_line) = (first_line, last_line, transform) in List.rev_append (List.rev_map augment_record chunks) transforms in OpamStd.Option.map_default record_transform transforms transform in OpamStd.Option.map_default compute_transform transforms patch_crlf | _ -> transforms in let rec fold_lines state n transforms = match input_line ch with | line -> let line = if strip_cr then String.sub line 0 (String.length line - 1) else line in let length = String.length line in let next_state = match state with | `Header -> begin match (if length > 4 then String.sub line 0 4 else "") with | "--- " -> (* Start of a unified diff header. *) let file = let file = String.sub line 4 (length - 4) in let open OpamStd in Option.map_default fst file (String.cut_at file '\t') in (* Weakness: new files are also marked with a time-stamp at the start of the epoch, however it's localised, making it a bit tricky to identify! New files are also identified by their absence on disk, so this weakness isn't particularly critical. *) if file = "/dev/null" then `NewHeader else let target = OpamStd.String.cut_at (back_to_forward file) '/' |> OpamStd.Option.map_default snd file |> Filename.concat dir in if Sys.file_exists target then let crlf = get_eol_encoding target in `Patching (file, crlf) else `NewHeader | "*** " -> OpamConsole.warning "File %s uses context diffs which are \ less portable; consider using unified \ diffs" orig; `SkipFile | _ -> (* Headers will contain other lines, which are ignored (e.g. the diff command which generated the diff, or Git commit messages) *) `Header end | `NewHeader -> if (if length > 4 then String.sub line 0 4 else "") = "+++ " then `New else (* TODO Should display some kind of re-sync warning *) `Header | `New -> process_chunk_header (fun neg pos -> `NewChunk (neg, pos)) line | `NewChunk (neg, pos) -> (* Weakness: new files should only have + lines *) let neg = if line = "" || line.[0] = ' ' || line.[0] = '-' then neg - 1 else neg in let pos = if line = "" || line.[0] = ' ' || line.[0] = '+' then pos - 1 else pos in if neg = 0 && pos = 0 then `New else (* Weakness: there should only be one chunk for a new file *) `NewChunk (neg, pos) | `Patching (orig, crlf) -> if (if length > 4 then String.sub line 0 4 else "") = "+++ " then let file = let file = String.sub line 4 (length - 4) in let open OpamStd in Option.map_default fst file (String.cut_at file '\t') in `Processing (orig, file, crlf, None, [], `Head) else `Header | `Processing (orig, target, crlf, patch_crlf, chunks, `Head) -> if line = "\\ No newline at end of file" then (* If the no eol-at-eof indicator is found, never add \r to final chunk line *) let chunks = match chunks with | (a, b)::chunks -> (a, b - 1)::chunks | _ -> chunks in `Processing (orig, target, crlf, patch_crlf, chunks, `Head) else process_chunk_header (fun neg pos -> `Processing (orig, target, crlf, patch_crlf, chunks, `Chunk (succ n, neg, pos))) line | `Processing (orig, target, crlf, patch_crlf, chunks, `Chunk (first_line, neg, pos)) -> let neg = if line = "" || line.[0] = ' ' || line.[0] = '-' then neg - 1 else neg in let pos = if line = "" || line.[0] = ' ' || line.[0] = '+' then pos - 1 else pos in let patch_crlf = let has_cr = (length > 0 && line.[length - 1] = '\r') in match patch_crlf with | None -> Some (Some has_cr) | Some (Some think_cr) when think_cr <> has_cr -> log ~level:2 "Patch adaptation disabled for %s: \ mixed endings or binary file" target; Some None | _ -> patch_crlf in if neg = 0 && pos = 0 then let chunks = (first_line, n)::chunks in `Processing (orig, target, crlf, patch_crlf, chunks, `Head) else `Processing (orig, target, crlf, patch_crlf, chunks, `Chunk (first_line, neg, pos)) | `SkipFile -> `SkipFile in if next_state = `SkipFile then [] else process_state_transition next_state state transforms |> fold_lines next_state (succ n) | exception End_of_file -> process_state_transition `Header state transforms |> List.rev in let transforms = fold_lines `Header 1 [] in if transforms = [] then copy_file orig corrected else begin seek_in ch 0; let ch_out = try open_out_bin corrected with Sys_error _ -> close_in ch; raise (File_not_found corrected) in let (normal, add_cr, strip_cr) = let strip n s = String.sub s 0 (String.length s - n) in let id x = x in if strip_cr then (strip 1, id, strip 2) else (id, (fun s -> s ^ "\r"), strip 1) in if OpamConsole.debug () then let log_transform (first_line, last_line, add_cr) = let indicator = if add_cr then '+' else '-' in log ~level:3 "Transform %d-%d %c\\r" first_line last_line indicator in List.iter log_transform transforms; let rec fold_lines n transforms = match input_line ch with | line -> let (f, transforms) = match transforms with | (first_line, last_line, add_cr_to_chunks)::next_transforms -> let transforms = if n = last_line then next_transforms else transforms in let f = if n >= first_line then if add_cr_to_chunks then add_cr else strip_cr else normal in (f, transforms) | [] -> (normal, []) in output_string ch_out (f line); output_char ch_out '\n'; fold_lines (succ n) transforms | exception End_of_file -> close_out ch_out in fold_lines 1 transforms end; close_in ch let patch ?(preprocess=true) ~dir p = if not (Sys.file_exists p) then (OpamConsole.error "Patch file %S not found." p; raise Not_found); let p' = if preprocess then let p' = temp_file ~auto_clean:false "processed-patch" in translate_patch ~dir p p'; p' else p in let patch_cmd = match OpamStd.Sys.os () with | OpamStd.Sys.OpenBSD | OpamStd.Sys.FreeBSD -> "gpatch" | _ -> "patch" in make_command ~name:"patch" ~dir patch_cmd ["-p1"; "-i"; p'] @@> fun r -> if not (OpamConsole.debug ()) then Sys.remove p'; if OpamProcess.is_success r then Done None else Done (Some (Process_error r)) let register_printer () = Printexc.register_printer (function | Process_error r -> Some (OpamProcess.result_summary r) | Internal_error m -> Some m | Command_not_found c -> Some (Printf.sprintf "%S: command not found." c) | Permission_denied c -> Some (Printf.sprintf "%S: permission denied." c) | Sys.Break -> Some "User interruption" | Unix.Unix_error (e, fn, msg) -> let msg = if msg = "" then "" else " on " ^ msg in let error = Printf.sprintf "%s: %S failed%s: %s" Sys.executable_name fn msg (Unix.error_message e) in Some error | _ -> None ) let init () = register_printer (); Sys.catch_break true; try Sys.set_signal Sys.sigpipe (Sys.Signal_handle (fun _ -> ())) with Invalid_argument _ -> () let () = OpamProcess.set_resolve_command resolve_command opam-2.1.5/src/core/opamUrl.mli0000644000175000017500000000700614427463453015363 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** URL parsing and printing, with support for our different backends *) type version_control = [ `git | `darcs | `hg ] type backend = [ `http | `rsync | version_control ] val string_of_backend: backend -> string exception Parse_error of string (** Tolerates lots of backward compatibility names; @raise Parse_error on unknown protocol *) val backend_of_string: string -> [> backend] type t = { transport: string; (** the part just before '://' *) path: string; (** the part after '://' *) hash: string option; (** the optional branch/ref specification, at the end after a '#' *) backend: backend; (** the backend that opam should use to handle this url *) } (** Same as [of_string], but allows enforcing the expected backend, and may otherwise guess version control from the suffix by default (for e.g. https://foo/bar.git). (this should be disabled when parsing from files). Note that [handle_suffix] also handles user-name in ssh addresses (e.g. "ssh://git@github.com/..."). If [from_file] is set to false, it resolves rsync/file relative path. @raise Parse_error *) val parse: ?backend:backend -> ?handle_suffix:bool -> ?from_file:bool -> string -> t (** Same as [parse], but catch [Parse_error]. In this case, display a warning if [quiet] is not set to true. *) val parse_opt: ?quiet:bool -> ?backend:backend -> ?handle_suffix:bool -> ?from_file:bool -> string -> t option include OpamStd.ABSTRACT with type t := t (** Dummy filler url *) val empty: t (** Returns the url string without the VC part (i.e. "git+foo://bar" returns "foo://bar") *) val base_url: t -> string (** The last part of the url path, e.g. ["http://foo/bar/this"] or ["http://that.here/"] *) val basename: t -> string (** Returns the url with all path components but the first one (the hostname) dropped, e.g. ["http://some.host/some/path"] becomes ["http://some.host"] *) val root: t -> t val has_trailing_slash: t -> bool (** Check if the URL matches an existing local directory, and return it *) val local_dir: t -> OpamFilename.Dir.t option (** Check if the URL matches an existing local file, and return it *) val local_file: t -> OpamFilename.t option (** If the given url-string has no 'transport://' specification and corresponds to an existing local path, check for version-control clues at that path *) val guess_version_control: string -> [> version_control ] option (** [map_file_url f url] applies [f] to the [path] portion of [url] if [transport] is ["file"]. *) val map_file_url : (string -> string) -> t -> t module Op: sig (** Appends at the end of an URL path with '/' separator. Gets back to the root if the second argument starts with '/' *) val ( / ) : t -> string -> t end opam-2.1.5/src/core/opamCompat.ml0000644000175000017500000000625614427463453015701 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2018-2020 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) module String = #if OCAML_VERSION >= (4, 3, 0) String #else struct include String let lowercase_ascii = lowercase let uppercase_ascii = uppercase let capitalize_ascii = capitalize end #endif module Char = #if OCAML_VERSION >= (4, 3, 0) Char #else struct include Char let lowercase_ascii = lowercase let uppercase_ascii = uppercase end #endif module Either = #if OCAML_VERSION >= (4, 12, 0) Either #else struct type ('a, 'b) t = | Left of 'a | Right of 'b end #endif module Printexc = #if OCAML_VERSION >= (4, 5, 0) Printexc #else struct include Printexc let raise_with_backtrace e _bt = raise e end #endif module Unix = #if OCAML_VERSION >= (4, 6, 0) Unix #else struct include Unix let map_file = Bigarray.Genarray.map_file end #endif module Uchar = #if OCAML_VERSION >= (4, 3, 0) Uchar #else struct type t = int let of_int i = i external to_int : t -> int = "%identity" end #endif module Buffer = #if OCAML_VERSION >= (4, 6, 0) Buffer #else struct include Buffer let add_utf_8_uchar b u = match Uchar.to_int u with | u when u < 0 -> assert false | u when u <= 0x007F -> add_char b (Char.unsafe_chr u) | u when u <= 0x07FF -> add_char b (Char.unsafe_chr (0xC0 lor (u lsr 6))); add_char b (Char.unsafe_chr (0x80 lor (u land 0x3F))) | u when u <= 0xFFFF -> add_char b (Char.unsafe_chr (0xE0 lor (u lsr 12))); add_char b (Char.unsafe_chr (0x80 lor ((u lsr 6) land 0x3F))); add_char b (Char.unsafe_chr (0x80 lor (u land 0x3F))) | u when u <= 0x10FFFF -> add_char b (Char.unsafe_chr (0xF0 lor (u lsr 18))); add_char b (Char.unsafe_chr (0x80 lor ((u lsr 12) land 0x3F))); add_char b (Char.unsafe_chr (0x80 lor ((u lsr 6) land 0x3F))); add_char b (Char.unsafe_chr (0x80 lor (u land 0x3F))) | _ -> assert false end #endif module Filename = #if OCAML_VERSION >= (4, 4, 0) Filename #else struct include Filename let extension fn = match Filename.chop_extension fn with | base -> let l = String.length base in String.sub fn l (String.length fn - l) | exception Invalid_argument _ -> "" end #endif module Result = #if OCAML_VERSION >= (4, 8, 0) Result #else struct type ('a, 'e) t #if OCAML_VERSION >= (4, 3, 0) = ('a, 'e) result #endif = Ok of 'a | Error of 'e end #endif #if OCAML_VERSION < (4, 7, 0) module Stdlib = Pervasives #endif module Lazy = #if OCAML_VERSION >= (4, 13, 0) Lazy #else struct include Lazy let map f x = lazy (f (force x)) end #endif opam-2.1.5/src/core/opamVersion.mli0000644000175000017500000000305614427463453016247 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2016 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** (generated) Current OPAM version *) include OpamStd.ABSTRACT (** The current OPAM version *) val current: t (** Extracts the major version *) val major: t -> t (** Major+minor version, strips the patch version *) val nopatch: t -> t (** The current OPAM version, truncated (only MAJOR.MINOR) *) val current_nopatch: t (** The 'git' version of OPAM *) val git: unit -> t option (** Side-effect to set the git version later in the build *) val set_git: string -> unit (** [true] if this is a development version of opam *) val is_dev_version : unit -> bool (** The full version (current + git) *) val full: unit -> t (** Magic string, always of length 8 *) val magic: unit -> string (** Display the version message *) val message: unit -> unit (** Version comparison *) val compare: t -> t -> int opam-2.1.5/src/core/opamStd.ml0000644000175000017500000012306114427463453015202 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCompat module type SET = sig include Set.S val map: (elt -> elt) -> t -> t val is_singleton: t -> bool val choose_one : t -> elt val choose_opt : t -> elt option val of_list: elt list -> t val to_string: t -> string val to_json: t -> OpamJson.t val of_json: OpamJson.t -> t option val find: (elt -> bool) -> t -> elt val find_opt: (elt -> bool) -> t -> elt option val safe_add: elt -> t -> t val fixpoint: (elt -> t) -> t -> t val map_reduce: ?default:'a -> (elt -> 'a) -> ('a -> 'a -> 'a) -> t -> 'a module Op : sig val (++): t -> t -> t val (--): t -> t -> t val (%%): t -> t -> t end end module type MAP = sig include Map.S val to_string: ('a -> string) -> 'a t -> string val to_json: ('a -> OpamJson.t) -> 'a t -> OpamJson.t val of_json: (OpamJson.t -> 'a option) -> OpamJson.t -> 'a t option val keys: 'a t -> key list val values: 'a t -> 'a list val find_opt: key -> 'a t -> 'a option val choose_opt: 'a t -> (key * 'a) option val union: ('a -> 'a -> 'a) -> 'a t -> 'a t -> 'a t val is_singleton: 'a t -> bool val of_list: (key * 'a) list -> 'a t val safe_add: key -> 'a -> 'a t -> 'a t val update: key -> ('a -> 'a) -> 'a -> 'a t -> 'a t val map_reduce: ?default:'b -> (key -> 'a -> 'b) -> ('b -> 'b -> 'b) -> 'a t -> 'b end module type ABSTRACT = sig type t val of_string: string -> t val to_string: t -> string val to_json: t -> OpamJson.t val of_json: OpamJson.t -> t option module Set: SET with type elt = t module Map: MAP with type key = t end module type OrderedType = sig include Set.OrderedType val to_string: t -> string val to_json: t -> OpamJson.t val of_json: OpamJson.t -> t option end let max_print = 100 module OpamList = struct let cons x xs = x :: xs let concat_map ?(left="") ?(right="") ?nil ?last_sep sep f = let last_sep = match last_sep with None -> sep | Some sep -> sep in function | [] -> (match nil with Some s -> s | None -> left^right) | l -> let seplen = String.length sep in let strs,len = List.fold_left (fun (strs,len) x -> let s = f x in s::strs, String.length s + seplen + len) ([], String.length left + String.length right - seplen) l in let len = match l with | _::_::_ -> len + String.length last_sep - seplen | _ -> len in let buf = Bytes.create len in let prepend i s = let slen = String.length s in Bytes.blit_string s 0 buf (i - slen) slen; i - slen in let pos = prepend len right in let pos = prepend pos (List.hd strs) in let pos = List.fold_left (fun (pos, cur_sep) s -> (prepend (prepend pos cur_sep) s, sep)) (pos, last_sep) (List.tl strs) |> fst in let pos = prepend pos left in assert (pos = 0); Bytes.to_string buf let rec find_opt f = function | [] -> None | x::r -> if f x then Some x else find_opt f r let to_string f = concat_map ~left:"{ " ~right:" }" ~nil:"{}" ", " f let rec remove_duplicates_eq eq = function | a::(b::_ as r) when eq a b -> remove_duplicates_eq eq r | a::r -> a::remove_duplicates_eq eq r | [] -> [] let remove_duplicates l = remove_duplicates_eq ( = ) l let sort_nodup cmp l = remove_duplicates_eq (fun a b -> cmp a b = 0) (List.sort cmp l) let filter_map f l = let rec loop accu = function | [] -> List.rev accu | h :: t -> match f h with | None -> loop accu t | Some x -> loop (x::accu) t in loop [] l let filter_some l = filter_map (fun x -> x) l let rec find_map f = function | [] -> raise Not_found | x::r -> match f x with | Some r -> r | None -> find_map f r let insert comp x l = let rec aux = function | [] -> [x] | h::t when comp h x < 0 -> h::aux t | l -> x :: l in aux l let rec insert_at index value = function | [] -> [value] | l when index <= 0 -> value :: l | x::l -> x :: insert_at (index - 1) value l let rec assoc_opt x = function [] -> None | (a,b)::l -> if compare a x = 0 then Some b else assoc_opt x l let pick_assoc x l = let rec aux acc = function | [] -> None, l | (k,v) as b::r -> if k = x then Some v, List.rev_append acc r else aux (b::acc) r in aux [] l let update_assoc k v l = let rec aux acc = function | [] -> List.rev ((k,v)::acc) | (k1,_) as b::r -> if k1 = k then List.rev_append acc ((k,v)::r) else aux (b::acc) r in aux [] l end module Set = struct module Make (O : OrderedType) = struct module S = Set.Make(O) include S let fold f set i = let r = ref i in S.iter (fun elt -> r := f elt !r ) set; !r let is_singleton s = not (is_empty s) && min_elt s == max_elt s let choose_one s = if is_empty s then raise Not_found else if is_singleton s then choose s else failwith "choose_one" let choose_opt s = try Some (choose s) with Not_found -> None let of_list l = List.fold_left (fun set e -> add e set) empty l let to_string s = if S.cardinal s > max_print then Printf.sprintf "%d elements" (S.cardinal s) else let l = S.fold (fun nv l -> O.to_string nv :: l) s [] in OpamList.to_string (fun x -> x) (List.rev l) let map f t = S.fold (fun e set -> S.add (f e) set) t S.empty exception Found of elt let find_opt fn t = try iter (fun x -> if fn x then raise (Found x)) t; None with Found x -> Some x let find fn t = match find_opt fn t with | Some x -> x | None -> raise Not_found let to_json t = let elements = S.elements t in let jsons = List.map O.to_json elements in `A jsons let of_json = function | `A jsons -> begin try let get = function | None -> raise Not_found | Some v -> v in let elems = List.map get (List.map O.of_json jsons) in Some (S.of_list elems) with Not_found -> None end | _ -> None module Op = struct let (++) = union let (--) = diff let (%%) = inter end let safe_add elt t = if mem elt t then failwith (Printf.sprintf "duplicate entry %s" (O.to_string elt)) else add elt t let fixpoint f = let open Op in let rec aux fullset curset = if is_empty curset then fullset else let newset = fold (fun nv set -> set ++ f nv) curset empty in let fullset = fullset ++ curset in aux fullset (newset -- fullset) in aux empty let map_reduce ?default f op t = match choose_opt t with | Some x -> fold (fun x acc -> op acc (f x)) (remove x t) (f x) | None -> match default with | Some d -> d | None -> invalid_arg "Set.map_reduce" end end module Map = struct module Make (O : OrderedType) = struct module M = Map.Make(O) include M let fold f map i = let r = ref i in M.iter (fun key value-> r:= f key value !r ) map; !r let map f map = fold (fun key value map -> add key (f value) map ) map empty let mapi f map = fold (fun key value map -> add key (f key value) map ) map empty let values map = List.rev (M.fold (fun _ v acc -> v :: acc) map []) let keys map = List.rev (M.fold (fun k _ acc -> k :: acc) map []) let union f m1 m2 = M.merge (fun _ a b -> match a, b with | Some _ as s, None | None, (Some _ as s) -> s | Some v1, Some v2 -> Some (f v1 v2) | None, None -> assert false) m1 m2 let is_singleton s = not (is_empty s) && fst (min_binding s) == fst (max_binding s) let to_string string_of_value m = if M.cardinal m > max_print then Printf.sprintf "%d elements" (M.cardinal m) else let s (k,v) = Printf.sprintf "%s:%s" (O.to_string k) (string_of_value v) in let l = fold (fun k v l -> s (k,v)::l) m [] in OpamList.to_string (fun x -> x) l let of_list l = List.fold_left (fun map (k,v) -> add k v map) empty l let to_json json_of_value t = let bindings = M.bindings t in let jsons = List.map (fun (k,v) -> `O [ ("key" , O.to_json k); ("value", json_of_value v) ] ) bindings in `A jsons let of_json value_of_json = function | `A jsons -> begin try let get_pair = function | `O binding -> begin match O.of_json (List.assoc "key" binding), value_of_json (List.assoc "value" binding) with | Some key, Some value -> (key, value) | _ -> raise Not_found end | _ -> raise Not_found in let pairs = List.map get_pair jsons in Some (of_list pairs) with Not_found -> None end | _ -> None let find_opt k map = try Some (find k map) with Not_found -> None let choose_opt m = try Some (choose m) with Not_found -> None let safe_add k v map = if mem k map then failwith (Printf.sprintf "duplicate entry %s" (O.to_string k)) else add k v map let update k f zero map = let v = try find k map with Not_found -> zero in add k (f v) map let map_reduce ?default f op t = match choose_opt t with | Some (k, v) -> fold (fun k v acc -> op acc (f k v)) (remove k t) (f k v) | None -> match default with | Some d -> d | None -> invalid_arg "Map.map_reduce" end end module AbstractString = struct type t = string let of_string x = x let to_string x = x let to_json x = `String x let of_json = function | `String x -> Some x | _ -> None module O = struct type t = string let to_string = to_string let compare = compare let to_json = to_json let of_json = of_json end module Set = Set.Make(O) module Map = Map.Make(O) end module OInt = struct type t = int let compare = compare let to_string = string_of_int let to_json i = `String (string_of_int i) let of_json = function | `String s -> (try Some (int_of_string s) with _ -> None) | _ -> None end module IntMap = Map.Make(OInt) module IntSet = Set.Make(OInt) module Option = struct let map f = function | None -> None | Some x -> Some (f x) let iter f = function | None -> () | Some x -> f x let default dft = function | None -> dft | Some x -> x let default_map dft = function | None -> dft | some -> some let replace f = function | None -> None | Some x -> f x let map_default f dft = function | None -> dft | Some x -> f x let compare cmp o1 o2 = match o1,o2 with | None, None -> 0 | Some _, None -> 1 | None, Some _ -> -1 | Some x1, Some x2 -> cmp x1 x2 let to_string ?(none="") f = function | Some x -> f x | None -> none let to_list = function | None -> [] | Some x -> [x] let some x = Some x let none _ = None let of_Not_found f x = try Some (f x) with Not_found -> None module Op = struct let (>>=) = function | None -> fun _ -> None | Some x -> fun f -> f x let (>>|) opt f = map f opt let (>>+) opt f = match opt with | None -> f () | some -> some let (+!) opt dft = default dft opt let (++) = function | None -> fun opt -> opt | some -> fun _ -> some end end module OpamString = struct module OString = struct type t = string let compare = compare let to_string x = x let to_json x = `String x let of_json = function | `String s -> Some s | _ -> None end module StringSet = Set.Make(OString) module StringMap = Map.Make(OString) module SetSet = Set.Make(StringSet) module SetMap = Map.Make(StringSet) module Set = StringSet module Map = StringMap let starts_with ~prefix s = let x = String.length prefix in let n = String.length s in n >= x && let rec chk i = i >= x || prefix.[i] = s.[i] && chk (i+1) in chk 0 let ends_with ~suffix s = let x = String.length suffix in let n = String.length s in n >= x && let rec chk i = i >= x || suffix.[i] = s.[i+n-x] && chk (i+1) in chk 0 let contains_char s c = try let _ = String.index s c in true with Not_found -> false let contains ~sub = Re.(execp (compile (str sub))) let exact_match re s = try let subs = Re.exec re s in let subs = Array.to_list (Re.Group.all_offset subs) in let n = String.length s in let subs = List.filter (fun (s,e) -> s=0 && e=n) subs in List.length subs > 0 with Not_found -> false let find_from f s i = let l = String.length s in if i < 0 || i > l then invalid_arg "find_from" else let rec g i = if i < l then if f s.[i] then i else g (succ i) else raise Not_found in g i let map f s = let len = String.length s in let b = Bytes.create len in for i = 0 to len - 1 do Bytes.set b i (f s.[i]) done; Bytes.to_string b let is_whitespace = function | ' ' | '\t' | '\r' | '\n' -> true | _ -> false let strip str = let p = ref 0 in let l = String.length str in while !p < l && is_whitespace (String.unsafe_get str !p) do incr p; done; let p = !p in let l = ref (l - 1) in while !l >= p && is_whitespace (String.unsafe_get str !l) do decr l; done; String.sub str p (!l - p + 1) let strip_right str = let rec aux i = if i < 0 || not (is_whitespace str.[i]) then i else aux (i-1) in let l = String.length str in let i = aux (l-1) in if i = l - 1 then str else String.sub str 0 (i+1) let sub_at n s = if String.length s <= n then s else String.sub s 0 n let remove_prefix ~prefix s = if starts_with ~prefix s then let x = String.length prefix in let n = String.length s in String.sub s x (n - x) else s let remove_suffix ~suffix s = if ends_with ~suffix s then let x = String.length suffix in let n = String.length s in String.sub s 0 (n - x) else s let cut_at_aux fn s sep = try let i = fn s sep in let name = String.sub s 0 i in let version = String.sub s (i+1) (String.length s - i - 1) in Some (name, version) with Invalid_argument _ | Not_found -> None let cut_at = cut_at_aux String.index let rcut_at = cut_at_aux String.rindex let split s c = (* old compat version (Re 1.2.0) {[Re_str.split (Re_str.regexp (Printf.sprintf "[%c]+" c)) s]} *) Re.(split (compile (rep1 (char c)))) s let split_delim s c = let tokens = Re.(split_full (compile (char c)) s) in let rec aux acc = function | [] -> acc | (`Delim _)::[] -> ""::acc | (`Text s)::tl -> aux (s::acc) tl | (`Delim _)::tl -> aux acc tl in let acc0 = match tokens with | (`Delim _)::_ -> [""] |_ -> [] in List.rev (aux acc0 tokens) let fold_left f acc s = let acc = ref acc in for i = 0 to String.length s - 1 do acc := f !acc s.[i] done; !acc let compare_case s1 s2 = let l1 = String.length s1 and l2 = String.length s2 in let len = min l1 l2 in let rec aux i = if i < len then let c1 = s1.[i] and c2 = s2.[i] in match Char.compare (Char.lowercase_ascii c1) (Char.lowercase_ascii c2) with | 0 -> (match Char.compare c1 c2 with | 0 -> aux (i+1) | c -> c) | c -> c else if l1 < l2 then -1 else if l1 > l2 then 1 else 0 in aux 0 let is_prefix_of ~from ~full s = let length_s = String.length s in let length_full = String.length full in if from < 0 || from > length_full then invalid_arg "is_prefix_of" else length_s <= length_full && length_s > from && String.sub full 0 length_s = s end type warning_printer = {mutable warning : 'a . ('a, unit, string, unit) format4 -> 'a} let console = ref {warning = fun fmt -> Printf.ksprintf prerr_string fmt} module Env = struct (* Remove from a c-separated list of string the one with the given prefix *) let reset_value ~prefix c v = let v = OpamString.split v c in List.filter (fun v -> not (OpamString.starts_with ~prefix v)) v (* Split the list in two according to the first occurrence of the string starting with the given prefix. *) let cut_value ~prefix c v = let v = OpamString.split v c in let rec aux before = function | [] -> [], List.rev before | curr::after when OpamString.starts_with ~prefix curr -> before, after | curr::after -> aux (curr::before) after in aux [] v let list = let lazy_env = lazy ( let e = Unix.environment () in List.rev_map (fun s -> match OpamString.cut_at s '=' with | None -> s, "" | Some p -> p ) (Array.to_list e) ) in fun () -> Lazy.force lazy_env let get = if Sys.win32 then fun n -> let n = String.uppercase_ascii n in snd (List.find (fun (k,_) -> String.uppercase_ascii k = n) (list ())) else fun n -> List.assoc n (list ()) let getopt n = try Some (get n) with Not_found -> None let escape_single_quotes ?(using_backslashes=false) = if using_backslashes then Re.(replace (compile (set "\\\'")) ~f:(fun g -> "\\"^Group.get g 0)) else Re.(replace_string (compile (char '\'')) ~by:"'\"'\"'") end (** To use when catching default exceptions: ensures we don't catch fatal errors like C-c *) let fatal e = match e with | Sys.Break -> prerr_newline (); raise e | Assert_failure _ | Match_failure _ -> raise e | _ -> () module OpamSys = struct let path_sep = if Sys.win32 then ';' else ':' let split_path_variable ?(clean=true) = if Sys.win32 then fun path -> let length = String.length path in let rec f acc index current last normal = if index = length then let current = current ^ String.sub path last (index - last) in List.rev (if current <> "" then current::acc else acc) else let c = path.[index] and next = succ index in if c = ';' && normal || c = '"' then let current = current ^ String.sub path last (index - last) in if c = '"' then f acc next current next (not normal) else let acc = if current = "" then acc else current::acc in f acc next "" next true else f acc next current last normal in f [] 0 "" 0 true else fun path -> let split = if clean then OpamString.split else OpamString.split_delim in split path path_sep let with_process_in cmd args f = if Sys.win32 then assert false; let path = split_path_variable (Env.get "PATH") in let cmd = List.find Sys.file_exists (List.map (fun d -> Filename.concat d cmd) path) in let ic = Unix.open_process_in (cmd^" "^args) in try let r = f ic in ignore (Unix.close_process_in ic) ; r with exn -> ignore (Unix.close_process_in ic) ; raise exn let tty_out = Unix.isatty Unix.stdout let tty_in = Unix.isatty Unix.stdin let default_columns = lazy ( let default = 16_000_000 in let cols = try int_of_string (Env.get "COLUMNS") with | Not_found | Failure _ -> default in if cols > 0 then cols else default ) let get_terminal_columns () = let fallback = 80 in let cols = try (* terminfo *) with_process_in "tput" "cols" (fun ic -> int_of_string (input_line ic)) with | Unix.Unix_error _ | Sys_error _ | Failure _ | End_of_file | Not_found -> try (* GNU stty *) with_process_in "stty" "size" (fun ic -> match OpamString.split (input_line ic) ' ' with | [_ ; v] -> int_of_string v | _ -> failwith "stty") with | Unix.Unix_error _ | Sys_error _ | Failure _ | End_of_file | Not_found -> fallback in if cols > 0 then cols else fallback let win32_get_console_width default_columns = try let hConsoleOutput = OpamStubs.(getStdHandle STD_OUTPUT_HANDLE) in let {OpamStubs.size = (width, _); _} = OpamStubs.getConsoleScreenBufferInfo hConsoleOutput in width with Not_found -> Lazy.force default_columns let terminal_columns = let v = ref (lazy (get_terminal_columns ())) in let () = try Sys.set_signal 28 (* SIGWINCH *) (Sys.Signal_handle (fun _ -> v := lazy (get_terminal_columns ()))) with Invalid_argument _ -> () in if Sys.win32 then fun () -> win32_get_console_width default_columns else fun () -> if tty_out then Lazy.force !v else Lazy.force default_columns let home = (* Note: we ask Unix.getenv instead of Env.get to avoid forcing the environment in this function that is used before the .init() functions are called -- see OpamStateConfig.default. *) let home = lazy (try Unix.getenv "HOME" with Not_found -> Sys.getcwd ()) in fun () -> Lazy.force home let etc () = "/etc" let uname = let memo = Hashtbl.create 7 in fun arg -> try Hashtbl.find memo arg with Not_found -> let r = try with_process_in "uname" arg (fun ic -> Some (OpamString.strip (input_line ic))) with Unix.Unix_error _ | Sys_error _ | Not_found -> None in Hashtbl.add memo arg r; r let system () = (* CSIDL_SYSTEM = 0x25 *) OpamStubs.(shGetFolderPath 0x25 SHGFP_TYPE_CURRENT) type os = | Darwin | Linux | FreeBSD | OpenBSD | NetBSD | DragonFly | Cygwin | Win32 | Unix | Other of string let os = let os = lazy ( match Sys.os_type with | "Unix" -> begin match uname "-s" with | Some "Darwin" -> Darwin | Some "Linux" -> Linux | Some "FreeBSD" -> FreeBSD | Some "OpenBSD" -> OpenBSD | Some "NetBSD" -> NetBSD | Some "DragonFly" -> DragonFly | _ -> Unix end | "Win32" -> Win32 | "Cygwin" -> Cygwin | s -> Other s ) in fun () -> Lazy.force os type shell = SH_sh | SH_bash | SH_zsh | SH_csh | SH_fish let shell_of_string = function | "tcsh" | "bsd-csh" | "csh" -> Some SH_csh | "zsh" -> Some SH_zsh | "bash" -> Some SH_bash | "fish" -> Some SH_fish | "sh" -> Some SH_sh | _ -> None let executable_name = if Sys.win32 then fun name -> if Filename.check_suffix name ".exe" then name else name ^ ".exe" else fun x -> x let guess_shell_compat () = let parent_guess = if Sys.win32 then None else let ppid = Unix.getppid () in let dir = Filename.concat "/proc" (string_of_int ppid) in try Some (Unix.readlink (Filename.concat dir "exe")) with e -> fatal e; try with_process_in "ps" (Printf.sprintf "-p %d -o comm= 2>/dev/null" ppid) (fun ic -> Some (input_line ic)) with | Unix.Unix_error _ | Sys_error _ | Failure _ | End_of_file | Not_found -> try let c = open_in_bin ("/proc/" ^ string_of_int ppid ^ "/cmdline") in begin try let s = input_line c in close_in c; Some (String.sub s 0 (String.index s '\000')) with | Not_found -> None | e -> close_in c; fatal e; None end with e -> fatal e; None in let test shell = shell_of_string (Filename.basename shell) in let shell = match Option.replace test parent_guess with | None -> Option.of_Not_found Env.get "SHELL" |> Option.replace test | some -> some in Option.default SH_sh shell let guess_dot_profile shell = let home f = try Filename.concat (home ()) f with Not_found -> f in match shell with | SH_fish -> List.fold_left Filename.concat (home ".config") ["fish"; "config.fish"] | SH_zsh -> home ".zshrc" | SH_bash -> (try List.find Sys.file_exists [ (* Bash looks up these 3 files in order and only loads the first, for LOGIN shells *) home ".bash_profile"; home ".bash_login"; home ".profile"; (* Bash loads .bashrc INSTEAD, for interactive NON login shells only; but it's often included from the above. We may include our variables in both to be sure ; for now we rely on non-login shells inheriting their env from a login shell somewhere... *) ] with Not_found -> (* iff none of the above exist, creating this should be safe *) home ".bash_profile") | SH_csh -> let cshrc = home ".cshrc" in let tcshrc = home ".tcshrc" in if Sys.file_exists cshrc then cshrc else tcshrc | SH_sh -> home ".profile" let registered_at_exit = ref [] let at_exit f = Stdlib.at_exit f; registered_at_exit := f :: !registered_at_exit let exec_at_exit () = List.iter (fun f -> try f () with _ -> ()) !registered_at_exit let is_cygwin_variant = if Sys.win32 then let results = Hashtbl.create 17 in let requires_cygwin name = let cmd = Printf.sprintf "cygcheck \"%s\"" name in let ((c, _, _) as process) = Unix.open_process_full cmd (Unix.environment ()) in let rec f a = match input_line c with | x -> if OpamString.ends_with ~suffix:"cygwin1.dll" (String.trim x) then if OpamString.starts_with ~prefix:" " x then f `Cygwin else if a <> `Cygwin then f `CygLinked else f a else f a | exception e -> Unix.close_process_full process |> ignore; fatal e; a in f `Native in fun name -> if Filename.is_relative name then requires_cygwin name else try Hashtbl.find results name with Not_found -> let result = requires_cygwin name in Hashtbl.add results name result; result else fun _ -> `Native exception Exit of int exception Exec of string * string array * string array let exit i = raise (Exit i) type exit_reason = [ `Success | `False | `Bad_arguments | `Not_found | `Aborted | `Locked | `No_solution | `File_error | `Package_operation_error | `Sync_error | `Configuration_error | `Solver_failure | `Internal_error | `User_interrupt ] let exit_codes : (exit_reason * int) list = [ (* Normal return values *) `Success, 0; `False, 1; (* Errors happening in normal use (user related, or impossible requests) *) `Bad_arguments, 2; `Not_found, 5; `Aborted, 10; `Locked, 15; `No_solution, 20; (* Errors related to the database (repository and package definitions) *) `File_error, 30; `Package_operation_error, 31; (* Network related error *) `Sync_error, 40; (* Opam setup error *) `Configuration_error, 50; (* Errors that shouldn't happen and are likely bugs *) `Solver_failure, 60; `Internal_error, 99; (* Received signals *) `User_interrupt, 130; ] let get_exit_code reason = List.assoc reason exit_codes let exit_because reason = exit (get_exit_code reason) type nonrec warning_printer = warning_printer = {mutable warning : 'a . ('a, unit, string, unit) format4 -> 'a} let set_warning_printer = let called = ref false in fun printer -> if !called then invalid_arg "Just what do you think you're doing, Dave?"; called := true; console := printer end module Win32 = struct module RegistryHive = struct let to_string = function | OpamStubs.HKEY_CLASSES_ROOT -> "HKEY_CLASSES_ROOT" | OpamStubs.HKEY_CURRENT_CONFIG -> "HKEY_CURRENT_CONFIG" | OpamStubs.HKEY_CURRENT_USER -> "HKEY_CURRENT_USER" | OpamStubs.HKEY_LOCAL_MACHINE -> "HKEY_LOCAL_MACHINE" | OpamStubs.HKEY_USERS -> "HKEY_USERS" let of_string = function | "HKCR" | "HKEY_CLASSES_ROOT" -> OpamStubs.HKEY_CLASSES_ROOT | "HKCC" | "HKEY_CURRENT_CONFIG" -> OpamStubs.HKEY_CURRENT_CONFIG | "HKCU" | "HKEY_CURRENT_USER" -> OpamStubs.HKEY_CURRENT_USER | "HKLM" | "HKEY_LOCAL_MACHINE" -> OpamStubs.HKEY_LOCAL_MACHINE | "HKU" | "HKEY_USERS" -> OpamStubs.HKEY_USERS | _ -> failwith "RegistryHive.of_string" end let (set_parent_pid, parent_putenv) = let ppid = ref (lazy (OpamStubs.(getCurrentProcessID () |> getParentProcessID))) in let parent_putenv = lazy ( let ppid = Lazy.force !ppid in if OpamStubs.isWoW64 () <> OpamStubs.isWoW64Process ppid then (* * Expect to see opam-putenv.exe in the same directory as opam.exe, * rather than PATH (allow for crazy users like developers who may have * both builds of opam) *) let putenv_exe = Filename.(concat (dirname Sys.executable_name) "opam-putenv.exe") in let ctrl = ref stdout in let quit_putenv () = if !ctrl <> stdout then let () = Printf.fprintf !ctrl "::QUIT\n%!" in ctrl := stdout in at_exit quit_putenv; if Sys.file_exists putenv_exe then fun key value -> if !ctrl = stdout then begin let (inCh, outCh) = Unix.pipe () in let _ = Unix.create_process putenv_exe [| putenv_exe; Int32.to_string ppid |] inCh Unix.stdout Unix.stderr in ctrl := (Unix.out_channel_of_descr outCh); set_binary_mode_out !ctrl true; end; Printf.fprintf !ctrl "%s\n%s\n%!" key value; if key = "::QUIT" then ctrl := stdout; true else let warning = lazy ( !console.warning "opam-putenv was not found - \ OPAM is unable to alter environment variables"; false) in fun _ _ -> Lazy.force warning else function "::QUIT" -> fun _ -> true | key -> OpamStubs.process_putenv ppid key) in ((fun pid -> if Lazy.is_val parent_putenv then failwith "Target parent already known"; ppid := Lazy.from_val pid), (fun key -> (Lazy.force parent_putenv) key)) let persistHomeDirectory dir = (* Update our environment *) Unix.putenv "HOME" dir; (* Update our parent's environment *) ignore (parent_putenv "HOME" dir); (* Persist the value to the user's environment *) OpamStubs.(writeRegistry HKEY_CURRENT_USER "Environment" "HOME" REG_SZ dir); (* Broadcast the change (or a reboot would be required) *) (* These constants are defined in WinUser.h *) let hWND_BROADCAST = 0xffffn in let sMTO_ABORTIFHUNG = 0x2 in OpamStubs.(sendMessageTimeout hWND_BROADCAST 5000 sMTO_ABORTIFHUNG WM_SETTINGCHANGE 0 "Environment") |> ignore end module OpamFormat = struct let visual_length_substring s ofs len = let rec aux acc i = if i >= len then acc else match s.[ofs + i] with | '\xc2'..'\xdf' -> aux (acc - min 1 (len - i)) (i + 2) | '\xe0'..'\xef' -> aux (acc - min 2 (len - i)) (i + 3) | '\xf0'..'\xf4' -> aux (acc - min 3 (len - i)) (i + 4) | '\027' -> (try let j = String.index_from s (ofs+i+1) 'm' - ofs in if j > len then acc - (len - i) else aux (acc - (j - i + 1)) (j + 1) with Not_found | Invalid_argument _ -> acc - (len - i)) | _ -> aux acc (i + 1) in aux len 0 let visual_length s = visual_length_substring s 0 (String.length s) let visual_width s = List.fold_left max 0 (List.map visual_length (OpamString.split s '\n')) let cut_at_visual s width = let rec aux extra i = try let j = String.index_from s i '\027' in let k = String.index_from s (j+1) 'm' in if j - extra > width then width + extra else aux (extra + k - j + 1) (k + 1) with Not_found -> min (String.length s) (width + extra) | Invalid_argument _ -> String.length s in let cut_at = aux 0 0 in if cut_at = String.length s then s else let sub = String.sub s 0 cut_at in let rec rem_escapes i = try let j = String.index_from s i '\027' in let k = String.index_from s (j+1) 'm' in String.sub s j (k - j + 1) :: rem_escapes (k+1) with Not_found | Invalid_argument _ -> [] in String.concat "" (sub :: rem_escapes cut_at) let indent_left s ?(visual=s) nb = let nb = nb - String.length visual in if nb <= 0 then s else s ^ String.make nb ' ' let indent_right s ?(visual=s) nb = let nb = nb - String.length visual in if nb <= 0 then s else String.make nb ' ' ^ s let align_table ll = let rec transpose ll = if List.for_all ((=) []) ll then [] else let col, rest = List.fold_left (fun (col,rest) -> function | hd::tl -> hd::col, tl::rest | [] -> ""::col, []::rest) ([],[]) ll in List.rev col::transpose (List.rev rest) in let columns = transpose ll in let pad n s = let sn = visual_length s in if sn >= n then s else s ^ (String.make (n - sn) ' ') in let pad_multi n s = match OpamString.split s '\n' with | [] | [_] -> pad n s ^"\n" | ls -> String.concat "\n" (List.map (pad n) ls) in let align sl = let (len, multiline) = List.fold_left (fun (len,ml) s -> if String.contains s '\n' then max len (visual_width s), true else max len (visual_length s), ml) (0, false) sl in List.map (if multiline then pad_multi len else pad len) sl in let rec map_but_last f = function | ([] | [_]) as l -> l | x::r -> f x :: map_but_last f r in transpose (map_but_last align columns) let reformat ?(start_column=0) ?(indent=0) ?(width=OpamSys.terminal_columns ()) s = let slen = String.length s in let buf = Buffer.create 1024 in let rec find_nonsp i = if i >= slen then i else match s.[i] with ' ' -> find_nonsp (i+1) | _ -> i in let rec find_split i = if i >= slen then i else match s.[i] with ' ' | '\n' -> i | _ -> find_split (i+1) in let newline i = Buffer.add_char buf '\n'; if i+1 < slen && s.[i+1] <> '\n' then for _i = 1 to indent do Buffer.add_char buf ' ' done in let rec print i col = if i >= slen then () else if s.[i] = '\n' then (newline i; print (i+1) indent) else let j = find_nonsp i in let k = find_split j in let len_visual = visual_length_substring s i (k - i) in if col + len_visual >= width && col > indent then (newline i; Buffer.add_substring buf s j (k - j); print k (indent + len_visual - j + i)) else (Buffer.add_substring buf s i (k - i); print k (col + len_visual)) in print 0 start_column; Buffer.contents buf let itemize ?(bullet=" - ") f = let indent = visual_length bullet in OpamList.concat_map ~left:bullet ~right:"\n" ~nil:"" ("\n"^bullet) (fun s -> reformat ~start_column:indent ~indent (f s)) let rec pretty_list ?(last="and") = function | [] -> "" | [a] -> a | [a;b] -> Printf.sprintf "%s %s %s" a last b | h::t -> Printf.sprintf "%s, %s" h (pretty_list ~last t) let as_aligned_table ?(width=OpamSys.terminal_columns ()) l = let itlen = List.fold_left (fun acc s -> max acc (visual_length s)) 0 l in let by_line = (width + 1) / (itlen + 1) in if by_line <= 1 then List.map (fun x -> [x]) l else let rec aux rline n = function | [] -> [List.rev rline] | x::r as line -> if n = 0 then List.rev rline :: aux [] by_line line else aux (x :: rline) (n-1) r in align_table (aux [] by_line l) end module Exn = struct let fatal = fatal let register_backtrace, get_backtrace = let registered_backtrace = ref None in (fun e -> registered_backtrace := match !registered_backtrace with | Some (e1, _) as reg when e1 == e -> reg | _ -> Some (e, Printexc.get_backtrace ())), (fun e -> match !registered_backtrace with | Some(e1,bt) when e1 == e -> bt | _ -> Printexc.get_backtrace ()) let pretty_backtrace e = match get_backtrace e with | "" -> "" | b -> let b = OpamFormat.itemize ~bullet:" " (fun x -> x) (OpamString.split b '\n') in Printf.sprintf "Backtrace:\n%s" b let finalise e f = let bt = Printexc.get_raw_backtrace () in f (); Printexc.raise_with_backtrace e bt let finally f k = match k () with | r -> f (); r | exception e -> finalise e f end module Op = struct let (@@) f x = f x let (|>) x f = f x let (@*) g f x = g (f x) let (@>) f g x = g (f x) end module Config = struct module type Sig = sig type t type 'a options_fun val default: t val set: t -> (unit -> t) options_fun val setk: (t -> 'a) -> t -> 'a options_fun val r: t ref val update: ?noop:_ -> (unit -> unit) options_fun val init: ?noop:_ -> (unit -> unit) options_fun val initk: 'a -> 'a options_fun end type env_var = string type when_ = [ `Always | `Never | `Auto ] type when_ext = [ `Extended | when_ ] type answer = [ `unsafe_yes | `all_yes | `all_no | `ask ] let env conv var = try Option.map conv (Env.getopt ("OPAM"^var)) with Failure _ -> flush stdout; !console.warning "Invalid value for environment variable OPAM%s, ignored." var; None let bool_of_string s = match String.lowercase_ascii s with | "" | "0" | "no" | "false" -> Some false | "1" | "yes" | "true" -> Some true | _ -> None let bool s = match bool_of_string s with | Some s -> s | None -> failwith "env_bool" let env_bool var = env bool var let env_int var = env int_of_string var type level = int let env_level var = env (function s -> if s = "" then 0 else match bool_of_string s with | Some true -> 0 | Some false -> 1 | None -> int_of_string s) var type sections = int option OpamString.Map.t let env_sections var = env (fun s -> let f map elt = let parse_value (section, value) = try (section, Some (int_of_string value)) with Failure _ -> (section, None) in let (section, level) = Option.map_default parse_value (elt, None) (OpamString.cut_at elt ':') in OpamString.Map.add section level map in List.fold_left f OpamString.Map.empty (OpamString.split s ' ')) var let env_string var = env (fun s -> s) var let env_float var = env float_of_string var let when_ext s = match String.lowercase_ascii s with | "extended" -> `Extended | "always" -> `Always | "never" -> `Never | "auto" -> `Auto | _ -> failwith "env_when" let env_when_ext var = env when_ext var let env_when var = env (fun v -> match when_ext v with | (`Always | `Never | `Auto) as w -> w | `Extended -> failwith "env_when") var let resolve_when ~auto = function | `Always -> true | `Never -> false | `Auto -> Lazy.force auto let answer s = match String.lowercase_ascii s with | "ask" -> `ask | "yes" -> `all_yes | "no" -> `all_no | "unsafe-yes" -> `unsafe_yes | _ -> failwith "env_answer" let env_answer = env (fun s -> try if bool s then `all_yes else `all_no with Failure _ -> answer s) module E = struct type t = .. let (r : t list ref) = ref [] let update v = r := v :: !r let updates l = r := l @ !r let find var = OpamList.find_map var !r let value var = let l = lazy (try Some (find var); with Not_found -> None) in fun () -> Lazy.force l end end module List = OpamList module String = OpamString module Sys = OpamSys module Format = OpamFormat opam-2.1.5/src/core/opamJson.mli0000644000175000017500000000213714427463453015532 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Json encoder; only needed for some debug options {b Warning.} Assumes given strings are UTF-8 encoded this is not checked by the module. *) type t = [ `Null | `Bool of bool | `Float of float| `String of string | `A of t list | `O of (string * t) list ] type 'a encoder = 'a -> t type 'a decoder = t -> 'a option val to_string : t -> string val append: string -> t -> unit val flush: out_channel -> unit opam-2.1.5/src/core/opamParallel.ml0000644000175000017500000004077014427463453016211 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamStd.Op open OpamProcess.Job.Op let log fmt = OpamConsole.log "PARALLEL" fmt let slog = OpamConsole.slog exception Aborted module type VERTEX = sig include OpamStd.OrderedType include Graph.Sig.COMPARABLE with type t := t end type dependency_label = unit module type G = sig include Graph.Sig.I with type E.label = dependency_label module Vertex: VERTEX with type t = V.t module Topological: sig val fold: (V.t -> 'a -> 'a) -> t -> 'a -> 'a end val has_cycle: t -> bool val scc_list: t -> V.t list list end module type SIG = sig module G : G val iter: jobs:int -> command:(pred:(G.V.t * 'a) list -> G.V.t -> 'a OpamProcess.job) -> ?dry_run:bool -> ?pools:((G.V.t list * int) list) -> G.t -> unit val map: jobs:int -> command:(pred:(G.V.t * 'a) list -> G.V.t -> 'a OpamProcess.job) -> ?dry_run:bool -> ?pools:((G.V.t list * int) list) -> G.t -> (G.V.t * 'a) list exception Errors of G.V.t list * (G.V.t * exn) list * G.V.t list exception Cyclic of G.V.t list list end module Make (G : G) = struct module G = G module V = G.Vertex module M = OpamStd.Map.Make (V) module S = OpamStd.Set.Make (V) exception Errors of G.V.t list * (G.V.t * exn) list * G.V.t list exception Cyclic of V.t list list open S.Op (* Returns a map (node -> return value) *) let aux_map ~jobs ~command ?(dry_run=false) ?(pools=[]) g = log "Iterate over %a task(s) with %d process(es)" (slog @@ G.nb_vertex @> string_of_int) g jobs; let njobs = G.nb_vertex g in let all_jobs = G.fold_vertex S.add g S.empty in let pools = let defined = List.map (fun (elts, jobs) -> S.of_list elts, jobs) pools in let default = List.fold_left (fun acc (pool, _) -> acc -- pool) all_jobs defined, jobs in default :: defined in if G.has_cycle g then ( let sccs = G.scc_list g in let sccs = List.filter (function _::_::_ -> true | _ -> false) sccs in raise (Cyclic sccs) ); let print_status (finished: int) (running: (OpamProcess.t * 'a * string option) M.t) = let texts = OpamStd.List.filter_map (fun (_,_,t) -> t) (M.values running) in let rec limit_width acc rem_cols = function | [] -> List.rev acc | t::ts -> let len = OpamStd.Format.visual_length t in if ts = [] && len < rem_cols then List.rev (t::acc) else if len > rem_cols - 5 then List.rev (Printf.sprintf "%s+%2d" (String.make (rem_cols - 4) ' ') (List.length ts + 1) :: acc) else limit_width (t::acc) (rem_cols - len - 1) ts in let title = Printf.sprintf "Processing %2d/%d:" (finished + M.cardinal running) njobs in let texts = if OpamConsole.disp_status_line () then limit_width [] (OpamStd.Sys.terminal_columns ()) (title::texts) else if OpamConsole.verbose () then title::texts else [] in if texts <> [] then OpamConsole.status_line "%s" (String.concat " " texts) in (* nslots is the number of free slots *) let rec loop (nslots: (S.t * int) list) (* number of free slots *) (results: 'b M.t) (running: (OpamProcess.t * 'a * string option) M.t) (ready: S.t) = let get_slots nslots n = List.filter (fun (pool, _) -> S.mem n pool) nslots in let take_slot nslots n = List.map (fun (pool, slots) -> if S.mem n pool then (assert (slots > 0); pool, slots - 1) else pool, slots) nslots in let release_slot nslots n = List.map (fun (pool, slots) -> if S.mem n pool then (pool, slots + 1) else pool, slots) nslots in let run_seq_command nslots ready n = function | Done r -> log "Job %a finished" (slog (string_of_int @* V.hash)) n; let results = M.add n r results in let running = M.remove n running in if not (M.is_empty running) then print_status (M.cardinal results) running; let nslots = release_slot nslots n in let new_ready = S.filter (fun n -> not (M.mem n running) && not (M.mem n results) && List.for_all (fun n -> M.mem n results) (G.pred g n) && List.for_all (fun (_, slots) -> slots > 0) (get_slots nslots n)) (List.fold_left (fun acc (pool, slots) -> if slots = 1 then acc ++ pool else acc) (S.of_list (G.succ g n)) (get_slots nslots n)) in loop nslots results running (ready ++ new_ready) | Run (cmd, cont) -> log "Next task in job %a: %a" (slog (string_of_int @* V.hash)) n (slog OpamProcess.string_of_command) cmd; let p = if dry_run then OpamProcess.dry_run_background cmd else OpamProcess.run_background cmd in let running = M.add n (p, cont, OpamProcess.text_of_command cmd) running in print_status (M.cardinal results) running; loop nslots results running ready in let fail node error = log "Exception while computing job %a: %a" (slog (string_of_int @* V.hash)) node (slog V.to_string) node; if error = Sys.Break then OpamConsole.error "User interruption"; let running = M.remove node running in (* Cleanup *) let errors,pend = if dry_run then [node,error],[] else M.fold (fun n (p,cont,_text) (errors,pend) -> try match OpamProcess.dontwait p with | None -> (* process still running *) OpamProcess.interrupt p; (n,Aborted) :: errors, p::pend | Some result -> match cont result with | Done _ -> errors, pend | Run _ -> (n,Aborted) :: errors, pend with | Unix.Unix_error _ -> errors, pend | e -> (n,e)::errors, pend) running ([node,error],[]) in (try List.iter (fun _ -> ignore (OpamProcess.wait_one pend)) pend with e -> log "%a in sub-process cleanup" (slog Printexc.to_string) e); (* Generate the remaining nodes in topological order *) let remaining = G.Topological.fold (fun n remaining -> if M.mem n results || List.mem_assoc n errors then remaining else n::remaining) g [] in raise (Errors (M.keys results, List.rev errors, List.rev remaining)) in if M.is_empty running && S.is_empty ready then results else if not (S.is_empty ready) && List.exists (fun (_, slots) -> slots > 0) nslots then (* Start a new process *) let n = S.choose ready in log "Starting job %a (worker %a): %a" (slog (string_of_int @* V.hash)) n (slog (fun pools -> let slots = get_slots nslots n in OpamStd.List.concat_map " " (fun (pool, jobs) -> let nslots = OpamStd.Option.of_Not_found (List.assoc pool) slots in Printf.sprintf "%s/%d" (match nslots with | None -> "-" | Some n -> string_of_int (jobs - n + 1)) jobs) pools)) pools (slog V.to_string) n; let pred = G.pred g n in let pred = List.map (fun n -> n, M.find n results) pred in let cmd = try command ~pred n with e -> fail n e in let nslots = take_slot nslots n in let ready = List.fold_left (fun acc (pool, slots) -> if slots = 0 then acc -- pool else acc) (S.remove n ready) (get_slots nslots n) in run_seq_command nslots ready n cmd else (* Wait for a process to end *) let processes = M.fold (fun n (p,x,_) acc -> (p,(n,x)) :: acc) running [] in let process, result = if dry_run then OpamProcess.dry_wait_one (List.map fst processes) else try match processes with | [p,_] -> p, OpamProcess.wait p | _ -> OpamProcess.wait_one (List.map fst processes) with e -> fail (fst (snd (List.hd processes))) e in let n,cont = List.assoc process processes in log "Collected task for job %a (ret:%d)" (slog (string_of_int @* V.hash)) n result.OpamProcess.r_code; let next = try cont result with e -> OpamProcess.cleanup result; fail n e in OpamProcess.cleanup result; run_seq_command nslots ready n next in let roots = G.fold_vertex (fun n roots -> if G.in_degree g n = 0 then S.add n roots else roots) g S.empty in let r = loop pools M.empty M.empty roots in OpamConsole.clear_status (); r let iter ~jobs ~command ?dry_run ?pools g = ignore (aux_map ~jobs ~command ?dry_run ?pools g) let map ~jobs ~command ?dry_run ?pools g = M.bindings (aux_map ~jobs ~command ?dry_run ?pools g) (* Only print the originally raised exception, which should come first. Ignore Aborted exceptions due to other commands termination, and simultaneous exceptions in other command's continuations (unlikely as that would require both commands to have terminated simultaneously) *) let error_printer = function | Errors (_, (_,exc)::_, _) -> Some (Printexc.to_string exc) | _ -> None let () = Printexc.register_printer error_printer end module type GRAPH = sig include Graph.Sig.I with type E.label = dependency_label include Graph.Oper.S with type g = t module Topological : sig val fold : (V.t -> 'a -> 'a) -> t -> 'a -> 'a val iter : (V.t -> unit) -> t -> unit end module Parallel : SIG with type G.t = t and type G.V.t = vertex module Dot : sig val output_graph : out_channel -> t -> unit end val transitive_closure: ?reflexive:bool -> t -> unit val build: V.t list -> E.t list -> t val compare : t -> t -> int val to_json : t OpamJson.encoder val of_json : t OpamJson.decoder end module MakeGraph (X: VERTEX) = struct module Vertex = X module PG = Graph.Imperative.Digraph.ConcreteBidirectional (Vertex) module Topological = Graph.Topological.Make (PG) module Traverse = Graph.Traverse.Dfs(PG) module Components = Graph.Components.Make(PG) module Parallel = Make (struct include PG module Vertex = Vertex module Topological = Topological include Traverse include Components end) module Dot = Graph.Graphviz.Dot (struct let edge_attributes _ = [] let default_edge_attributes _ = [] let get_subgraph _ = None let vertex_attributes _ = [] let vertex_name v = Printf.sprintf "\"%s\"" (Vertex.to_string v) let default_vertex_attributes _ = [] let graph_attributes _ = [] include PG end) include PG include Graph.Oper.I (PG) let transitive_closure ?reflexive g = ignore (add_transitive_closure ?reflexive g) let build vertices edges = let graph = create ~size:(List.length vertices) () in List.iter (add_vertex graph) vertices; List.iter (add_edge_e graph) edges; graph let compare g1 g2 = let module Vertices = Set.Make(Vertex) in let module Edges = Set.Make(E) in let vertices g = fold_vertex Vertices.add g Vertices.empty in let edges g = fold_edges_e Edges.add g Edges.empty in match Vertices.compare (vertices g1) (vertices g2) with | 0 -> Edges.compare (edges g1) (edges g2) | n -> n let to_json (graph : t) : OpamJson.t = let vertex_map = (* we ensure that the map indexing respects the vertex ordering *) let module Vertices = Set.Make(Vertex) in let vertices = fold_vertex Vertices.add graph Vertices.empty in List.mapi (fun i v -> (i, v)) (Vertices.elements vertices) in let vertices = let vertex_to_json (i, v) = (string_of_int i, X.to_json v) in `O (List.map vertex_to_json vertex_map) in let edges = let vertex_inv_map = List.map (fun (i, v) -> (v, i)) vertex_map in let index v = List.assoc v vertex_inv_map in let index_to_json v = `String (string_of_int (index v)) in let edge_to_json edge = let () = E.label edge in (* labels carry no information; if this changes, we should add a "label" field in the JSON output *) `O [ ("src", index_to_json (E.src edge)); ("dst", index_to_json (E.dst edge)); ] in `A (fold_edges_e (fun edge li -> edge_to_json edge :: li) graph []) in `O [ ("vertices", vertices); ("edges", edges); ] let of_json : t OpamJson.decoder = function | `O dict -> begin try let vertices_json = match List.assoc "vertices" dict with | `O vertices -> vertices | _ -> raise Not_found in let edges_json = match List.assoc "edges" dict with | `A edges -> edges | _ -> raise Not_found in let vertex_map = let vertex_of_json (ij, vj) = let i = try int_of_string ij with _ -> raise Not_found in let v = match X.of_json vj with | None -> raise Not_found | Some v -> v in (i, v) in List.map vertex_of_json vertices_json in let edges = let int_of_jsonstring = function | `String s -> (try int_of_string s with _ -> raise Not_found) | _ -> raise Not_found in let find kj = List.assoc (int_of_jsonstring kj) vertex_map in let edge_of_json = function | `O dict -> let src = find (List.assoc "src" dict) in let label = () in let dst = find (List.assoc "dst" dict) in E.create src label dst | _ -> raise Not_found in List.map edge_of_json edges_json in Some (build (List.map snd vertex_map) edges) with Not_found -> None end | _ -> None end (* Simple polymorphic implem on lists when we don't need full graphs. We piggy-back on the advanced implem using an array and an int-graph *) module IntGraph = MakeGraph(struct type t = int let compare x y = x - y let hash x = x let equal x y = x = y let to_string = string_of_int let to_json x = `Float (float_of_int x) let of_json = function | `Float x -> (try Some (int_of_float x) with _ -> None) | _ -> None end) let flat_graph_of_array a = let g = IntGraph.create () in Array.iteri (fun i _ -> IntGraph.add_vertex g i) a; g exception Errors = IntGraph.Parallel.Errors let iter ~jobs ~command ?dry_run l = let a = Array.of_list l in let g = flat_graph_of_array a in let command ~pred:_ i = command a.(i) in ignore (IntGraph.Parallel.iter ~jobs ~command ?dry_run g) let map ~jobs ~command ?dry_run l = let a = Array.of_list l in let g = flat_graph_of_array a in let command ~pred:_ i = command a.(i) in let r = IntGraph.Parallel.aux_map ~jobs ~command ?dry_run g in let rec mklist acc n = if n < 0 then acc else mklist (IntGraph.Parallel.M.find n r :: acc) (n-1) in mklist [] (Array.length a - 1) let reduce ~jobs ~command ~merge ~nil ?dry_run l = let a = Array.of_list l in let g = flat_graph_of_array a in let command ~pred:_ i = command a.(i) in let r = IntGraph.Parallel.aux_map ~jobs ~command ?dry_run g in IntGraph.Parallel.M.fold (fun _ -> merge) r nil opam-2.1.5/src/core/opamSHA.mli0000644000175000017500000000230114427463453015225 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2016-2017 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Pure OCaml implementation of SHA256/512 hashing functions. The hash is returned as an hex string. *) val sha256_file: string -> string val sha512_file: string -> string val hash_file: [< `SHA256 | `SHA512 ] -> string -> string val sha256_bytes: Bytes.t -> string val sha512_bytes: Bytes.t -> string val hash_bytes: [< `SHA256 | `SHA512 ] -> Bytes.t -> string (** For compat, use the above *) val sha256: string -> string val sha512: string -> string val hash: [< `SHA256 | `SHA512 ] -> string -> string opam-2.1.5/src/core/opamHash.ml0000644000175000017500000000726714427463453015344 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2016-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCompat type kind = [ `MD5 | `SHA256 | `SHA512 ] let default_kind = `MD5 type t = kind * string let kind = fst let contents = snd let log msg = OpamConsole.log "HASH" msg let pfx_sep_char = '=' let pfx_sep_str = String.make 1 pfx_sep_char let string_of_kind = function | `MD5 -> "md5" | `SHA256 -> "sha256" | `SHA512 -> "sha512" let kind_of_string s = match String.lowercase_ascii s with | "md5" -> `MD5 | "sha256" -> `SHA256 | "sha512" -> `SHA512 | _ -> invalid_arg "OpamHash.kind_of_string" let is_hex_str len s = String.length s = len && try String.iter (function | '0'..'9' | 'A'..'F' | 'a'..'f' -> () | _ -> raise Exit) s; true with Exit -> false let len = function | `MD5 -> 32 | `SHA256 -> 64 | `SHA512 -> 128 let valid kind = is_hex_str (len kind) let make kind s = if valid kind s then kind, String.lowercase_ascii s else invalid_arg ("OpamHash.make_"^string_of_kind kind) let md5 = make `MD5 let sha256 = make `SHA256 let sha512 = make `SHA512 let of_string_opt s = try let kind, s = match OpamStd.String.cut_at s pfx_sep_char with | None -> `MD5, s | Some (skind, s) -> kind_of_string skind, s in if valid kind s then Some (kind, String.lowercase_ascii s) else None with Invalid_argument _ -> None let of_string s = match of_string_opt s with | Some h -> h | None -> invalid_arg "OpamHash.of_string" let to_string (kind,s) = String.concat pfx_sep_str [string_of_kind kind; s] let to_json s = `String (to_string s) let of_json = function | `String s -> of_string_opt s | _ -> None let to_path (kind,s) = [string_of_kind kind; String.sub s 0 2; s] let compute ?(kind=default_kind) file = match kind with | `MD5 -> md5 (Digest.to_hex (Digest.file file)) | (`SHA256 | `SHA512) as kind -> let sha = if not OpamCoreConfig.(!r.use_openssl) then OpamSHA.hash kind file else try match OpamSystem.read_command_output ["openssl"; string_of_kind kind; file] with | [l] -> let len = len kind in String.sub l (String.length l - len) len | _ -> log "openssl error, use internal sha library"; OpamSHA.hash kind file with OpamSystem.Command_not_found _ | OpamSystem.Process_error _ | OpamSystem.Permission_denied _ -> log "openssl not found, use internal sha library"; OpamSHA.hash kind file in make kind sha let compute_from_string ?(kind=default_kind) str = match kind with | `MD5 -> md5 (Digest.to_hex (Digest.string str)) | (`SHA256 | `SHA512) as kind -> make kind (OpamSHA.hash_bytes kind (Bytes.of_string str)) let check_file f (kind, _ as h) = compute ~kind f = h let mismatch f (kind, _ as h) = let hf = compute ~kind f in if hf = h then None else Some hf module O = struct type _t = t type t = _t let to_string = to_string let to_json = to_json let of_json = of_json let compare = compare end module Set = OpamStd.Set.Make(O) module Map = OpamStd.Map.Make(O) opam-2.1.5/src/core/opamDirTrack.ml0000644000175000017500000002635214427463453016160 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2016-2020 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCompat open OpamStd.Op open OpamProcess.Job.Op let log ?level fmt = OpamConsole.log ?level "TRACK" fmt let slog = OpamConsole.slog module SM = OpamStd.String.Map type digest = string let digest_of_string dg = dg let string_of_digest dg = dg type change = | Added of digest | Removed | Contents_changed of digest | Perm_changed of digest | Kind_changed of digest type t = change SM.t let string_of_change ?(full=false) = let str s d = if not full then s else Printf.sprintf "%s %s" s (string_of_digest d) in function | Added d -> str "addition" d | Removed -> "removal" | Contents_changed d -> str "modifications" d | Perm_changed d -> str "permission change" d | Kind_changed d -> str "kind change" d let to_string t = OpamStd.Format.itemize (fun (f, change) -> Printf.sprintf "%s of %s" (String.capitalize_ascii (string_of_change change)) f) (SM.bindings t) (** uid, gid, perm *) type perms = int * int * int type item_value = | File of string | Dir | Link of string | Special of (int * int) type item = perms * item_value let cached_digest = let item_cache = Hashtbl.create 749 in fun f size mtime -> try let csize, cmtime, digest = Hashtbl.find item_cache f in if csize = size && mtime = cmtime then Digest.to_hex digest else raise Not_found with Not_found -> let digest = Digest.file f in Hashtbl.replace item_cache f (size, mtime, digest); Digest.to_hex digest let quick_digest _f size mtime = Printf.sprintf "S%dT%s" size (string_of_float mtime) let get_digest ?(precise=OpamCoreConfig.(!r.precise_tracking)) f size mtime = if precise then cached_digest f size mtime else quick_digest f size mtime let item_of_filename ?precise f : item = let stats = Unix.lstat f in Unix.(stats.st_uid, stats.st_gid, stats.st_perm), match stats.Unix.st_kind with | Unix.S_REG -> File (get_digest ?precise f stats.Unix.st_size stats.Unix.st_mtime) | Unix.S_DIR -> Dir | Unix.S_LNK -> Link (Unix.readlink f) | Unix.S_CHR | Unix.S_BLK | Unix.S_FIFO | Unix.S_SOCK -> Special Unix.(stats.st_dev, stats.st_rdev) let item_of_filename_opt ?precise f = try Some (item_of_filename ?precise f) with Unix.Unix_error _ -> None let item_digest = function | _perms, File d -> "F:" ^ d | _perms, Dir -> "D" | _perms, Link l -> "L:" ^ l | _perms, Special (a,b) -> Printf.sprintf "S:%d:%d" a b let is_precise_digest d = not (OpamStd.String.starts_with ~prefix:"F:S" d) let track_t to_track ?(except=OpamFilename.Base.Set.empty) job_f = let module SM = OpamStd.String.Map in let rec make_index_topdir acc prefix dir = let files = try Sys.readdir (Filename.concat prefix dir) with Sys_error _ as e -> log "Error at dir %s: %a" (Filename.concat prefix dir) (slog Printexc.to_string) e; [||] in Array.fold_left (fun acc f -> let rel = Filename.concat dir f in if OpamFilename.Base.(Set.mem (of_string rel) except) then acc else let f = Filename.concat prefix rel in try let item = item_of_filename f in let acc = SM.add rel item acc in match item with | _, Dir -> make_index_topdir acc prefix rel | _ -> acc with Unix.Unix_error _ as e -> log "Error at %s: %a" f (slog Printexc.to_string) e; acc) acc files in let make_index = match to_track with | `Top dir -> fun () -> make_index_topdir SM.empty (OpamFilename.Dir.to_string dir) "" | `Paths (prefix, files) -> fun () -> List.fold_left (fun acc f -> let prefix = OpamFilename.Dir.to_string prefix in let rel = Filename.concat prefix f in let item = item_of_filename_opt rel in match item with | None -> acc | Some item -> SM.add f item acc) SM.empty files in let scan_timer = OpamConsole.timer () in let before = make_index () in log ~level:2 "before install: %a elements scanned in %.3fs" (slog @@ string_of_int @* SM.cardinal) before (scan_timer ()); job_f () @@| fun result -> let scan_timer = OpamConsole.timer () in let after = make_index () in let diff = SM.merge (fun _ before after -> match before, after with | None, None -> assert false | Some _, None -> Some Removed | None, Some item -> Some (Added (item_digest item)) | Some (perma, a), Some ((permb, b) as item) -> if a = b then if perma = permb then None else Some (Perm_changed (item_digest item)) else match a, b with | File _, File _ | Link _, Link _ | Dir, Dir | Special _, Special _ -> Some (Contents_changed (item_digest item)) | _ -> Some (Kind_changed (item_digest item))) before after in log "after install: %a elements, %a added, scanned in %.3fs" (slog @@ string_of_int @* SM.cardinal) after (slog @@ string_of_int @* SM.cardinal @* SM.filter (fun _ -> function Added _ -> true | _ -> false)) diff (scan_timer ()); result, diff let track_files ~prefix files ?except job_f = track_t (`Paths (prefix, files)) ?except job_f let track dir ?except job_f = track_t (`Top dir) ?except job_f let check_digest file digest = let precise = is_precise_digest digest in let it = item_of_filename ~precise file in try if item_digest it = digest then `Unchanged else `Changed with Unix.Unix_error _ -> `Removed let check prefix changes = let str_pfx = OpamFilename.Dir.to_string prefix in SM.fold (fun fname op acc -> let f = Filename.concat str_pfx fname in match op with | Added dg | Kind_changed dg | Contents_changed dg -> (OpamFilename.of_string f, check_digest f dg) :: acc | Perm_changed _ | Removed -> acc) changes [] |> List.rev let revert ?title ?(verbose=OpamConsole.verbose()) ?(force=false) ?(dryrun=false) prefix changes = let title = match title with | None -> "" | Some t -> t ^ ": " in let rmdir d = if not dryrun then OpamFilename.rmdir d in let rmfile f = if not dryrun then OpamFilename.remove f in let changes = (* Reverse the list so that dirnames come after the files they contain *) List.rev (OpamStd.String.Map.bindings changes) in let already, modified, nonempty, cannot = List.fold_left (fun (already,modified,nonempty,cannot as acc) (fname,op) -> let f = Filename.concat (OpamFilename.Dir.to_string prefix) fname in match op with | Added dg | Kind_changed dg -> let cur_item_ct, cur_dg = try let precise = is_precise_digest dg in let item = item_of_filename ~precise f in Some (snd item), Some (item_digest item) with Unix.Unix_error _ -> None, None in if cur_dg = None then (fname::already, modified, nonempty, cannot) else if cur_dg <> Some dg && not force then (already, fname::modified, nonempty, cannot) else if cur_item_ct = Some Dir then let d = OpamFilename.Dir.of_string f in if OpamFilename.dir_is_empty d then (rmdir d; acc) else let nonempty = if List.exists (OpamStd.String.starts_with ~prefix:fname) nonempty then nonempty else fname::nonempty in (already, modified, nonempty, cannot) else let f = OpamFilename.of_string f in rmfile f; acc | Contents_changed dg -> if check_digest f dg = `Changed then (already, modified, nonempty, (op,fname)::cannot) else acc (* File has changed, assume the removal script reverted it *) | (Removed | Perm_changed _) -> (already, modified, nonempty, (op,fname)::cannot)) ([], [], [], []) changes in if already <> [] then log ~level:2 "%sfiles %s were already removed" title (String.concat ", " (List.rev already)); if modified <> [] then if OpamConsole.confirm ~default:false "%sthese files have been modified since installation:\n%s\ Remove them anyway?" title (OpamStd.Format.itemize (fun s -> s) (List.rev modified)) then List.iter (fun f -> OpamFilename.remove (OpamFilename.Op.(prefix // f))) modified; if nonempty <> [] && verbose then OpamConsole.note "%snot removing non-empty directories:\n%s" title (OpamStd.Format.itemize (fun s -> s) (List.rev nonempty)); if cannot <> [] && verbose then let cannot = let rem, modf, perm = List.fold_left (fun (rem, modf, perm as acc) (op,f) -> match op with | Removed -> (None, f)::rem, modf, perm | Contents_changed dg -> let precise = Some (is_precise_digest dg) in rem, (precise, f)::modf, perm | Perm_changed dg -> let precise = Some (is_precise_digest dg) in rem, modf, (precise, f)::perm | _ -> acc) ([],[],[]) cannot in (if rem = [] then [] else [Removed, rem]) @ (if modf = [] then [] else [Contents_changed "_", modf]) @ (if perm = [] then [] else [Perm_changed "_", perm]) in (OpamConsole.warning "%scannot revert:" title; OpamConsole.errmsg "%s" (OpamStd.Format.itemize (fun (op,lf) -> Printf.sprintf "%s of:\n%s" (string_of_change op) (OpamStd.Format.itemize (fun (pre,x) -> (OpamStd.Option.to_string (fun pr -> if pr then "[hash] " else "[tms] ") pre) ^ x) lf)) cannot)) let update prefix t = let removed = ref [] in let prefix = OpamFilename.Dir.to_string prefix in let update_digest file digest = match let filename = Filename.concat prefix file in let precise = is_precise_digest digest in item_digest ( item_of_filename ~precise filename ) with | exception Unix.Unix_error ( ENOENT, _, _) -> removed := file :: !removed; digest | exception _exn -> digest | digest -> digest in let t = SM.mapi (fun file change -> match change with | Added digest -> Added (update_digest file digest) | Removed -> Removed | Contents_changed digest -> Contents_changed (update_digest file digest) | Perm_changed digest -> Perm_changed (update_digest file digest) | Kind_changed digest -> Kind_changed (update_digest file digest) ) t in List.fold_left (fun t file -> SM.remove file t ) t !removed opam-2.1.5/src/core/opamVersion.ml0000644000175000017500000000500314427463453016070 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2015 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) type t = string let to_string x = x let of_string x = x let to_json x = `String x let of_json = function | `String x -> Some x | _ -> None let compare v w = OpamVersionCompare.compare v w module O = struct type t = string let to_string = to_string let to_json = to_json let of_json = of_json let compare = compare end module Set = OpamStd.Set.Make(O) module Map = OpamStd.Map.Make(O) let current_raw = STRINGIFY(VERSION) let current = of_string current_raw let major v = try let i = String.index v '.' in of_string (String.sub v 0 i) with Not_found -> v let nopatch v = try let i = String.index v '.' in let i = String.index_from v (i+1) '.' in (String.sub v 0 i) with Not_found -> let rec f i = if i >= String.length v then v else match String.get v i with | '0'..'9' | '.' -> f (i+1) | _ -> String.sub v 0 i in f 0 let current_nopatch = nopatch current_raw let message () = OpamConsole.msg "\n\ %s version %s\n\ \n\ Copyright (C) 2012 OCamlPro - INRIA, 2013-2015 OCamlPro\n\ \n\ This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" Sys.executable_name current_raw; exit 0 let gitversion = ref None let set_git s = gitversion := Some s let git () = match !gitversion with | None -> None | Some v -> Some (of_string v) let is_dev_version () = (!gitversion <> None) let full () = let git_version = match git () with | None -> "" | Some v -> Printf.sprintf " (%s)" (to_string v) in Printf.sprintf "%s%s" (to_string current) git_version let magic () = let hash = Hashtbl.hash (full ()) in String.sub (Printf.sprintf "%08X" hash) 0 8 opam-2.1.5/src/core/opamACL.ml.dummy0000644000175000017500000000133514427463453016200 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2020 David Allsopp Ltd. *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) let get_acl_executable_info _ _ = None opam-2.1.5/src/core/opamFilename.mli0000644000175000017500000002414714427463453016346 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Higher level file and directory name manipulation AND file operations, wrappers on OpamSystem using the filename type *) (** Basenames *) module Base: sig include OpamStd.ABSTRACT (** Check whether a basename has a given suffix *) val check_suffix: t -> string -> bool (** Add a file extension *) val add_extension: t -> string -> t end (** Directory names *) module Dir: OpamStd.ABSTRACT (** Return the current working directory *) val cwd: unit -> Dir.t (** Remove a directory *) val rmdir: Dir.t -> unit (** Cleans the contents of a directory, but keeps the directory in place. *) val cleandir: Dir.t -> unit (** Removes an empty directory, as well as any empty leading path components. Must be called only on a directory that is known to not have empty parents, only internal opam directory (and not tmp dir). *) val rmdir_cleanup: Dir.t -> unit (** Create a directory *) val mkdir: Dir.t -> unit (** List the sub-directory recursively *) val rec_dirs: Dir.t -> Dir.t list val dir_is_empty: Dir.t -> bool (** List the sub-directory (do not recurse) *) val dirs: Dir.t -> Dir.t list (** Evaluate a function in a given directory *) val in_dir: Dir.t -> (unit -> 'a) -> 'a (** Turns an assoc list into an array suitable to be provided as environment *) val env_of_list: (string * string) list -> string array (** Execute a list of commands in a given directory *) val exec: Dir.t -> ?env:(string * string) list -> ?name:string -> ?metadata:(string * string) list -> ?keep_going:bool -> string list list -> unit (** Move a directory *) val move_dir: src:Dir.t -> dst:Dir.t -> unit (** Copy directory [src] to [dst], that is, recursively copy the contents of [src] into [dst], overwriting any existing files. *) val copy_dir: src:Dir.t -> dst:Dir.t -> unit (** Link a directory *) val link_dir: target:Dir.t -> link:Dir.t -> unit (** Does the directory exist? *) val exists_dir: Dir.t -> bool (** Returns the argument as option, if the directory exists *) val opt_dir: Dir.t -> Dir.t option (** Return the parent directory *) val dirname_dir: Dir.t -> Dir.t (** Return the deeper directory name *) val basename_dir: Dir.t -> Base.t (** Turn a full path into a list of directory names *) val to_list_dir: Dir.t -> Dir.t list (** Creation from a raw string, without resolving symlinks etc. *) val raw_dir: string -> Dir.t (** Execute a function in a temp directory *) val with_tmp_dir: (Dir.t -> 'a) -> 'a (** Provide an automatically cleaned up temp directory to a job *) val with_tmp_dir_job: (Dir.t -> 'a OpamProcess.job) -> 'a OpamProcess.job (** Raw function to create a temporary directory. No automatic cleanup *) val mk_tmp_dir: unit -> Dir.t (** Create a new Dir.t and resolve symlinks *) val concat_and_resolve: Dir.t -> string -> Dir.t include OpamStd.ABSTRACT (** Generic filename *) type generic_file = | D of Dir.t | F of t (** Create a filename from a Dir.t and a basename *) val create: Dir.t -> Base.t -> t (** Create a file from a basename and the current working directory as dirname *) val of_basename: Base.t -> t (** Creation from a raw string, without resolving symlinks, etc. *) val raw: string -> t (** Prettify a filename: - replace /path/to/opam/foo by /foo - replace /path/to/home/foo by ~/foo *) val prettify: t -> string (** Prettify a dirname. *) val prettify_dir: Dir.t -> string (** Return the directory name *) val dirname: t -> Dir.t (** Return the base name *) val basename: t -> Base.t (** Retrieves the contents from the hard disk. *) val read: t -> string (** Open a channel from a given file. *) val open_in: t -> in_channel val open_in_bin: t -> in_channel val open_out: t -> out_channel val open_out_bin: t -> out_channel (** Removes everything in [filename] if existed. *) val remove: t -> unit (** Removes everything in [filename] if existed, then write [contents] instead. *) val write: t -> string -> unit (** Returns true if the file exists and is a regular file or a symlink to one *) val exists: t -> bool (** Returns the argument as option if it exists and is either a regular file or a symlink to one *) val opt_file: t -> t option (** Check whether a file has a given suffix *) val check_suffix: t -> string -> bool (** Adds a dot and the given file extension *) val add_extension: t -> string -> t (** Remove the file extension *) val chop_extension: t -> t (** List all the filenames, recursively *) val rec_files: Dir.t -> t list (** List all the filename. Do not recurse. *) val files: Dir.t -> t list (** Returns alll the files, including dangling symlinks (which means that not all entries will satisfy {!exists}). *) val files_and_links: Dir.t -> t list (** Apply a function on the contents of a file *) val with_contents: (string -> 'a) -> t -> 'a (** Copy a file in a directory. If [root] is set, copy also the sub-directories. For instance, [copy_in ~root:"/foo" "/foo/bar/gni" "/toto"] creates ["/toto/bar/gni"]. *) val copy_in: ?root:Dir.t -> t -> Dir.t -> unit (** Move a file *) val move: src:t -> dst:t -> unit (** Read a symlinked file *) val readlink: t -> t (** Is a symlink? *) val is_symlink: t -> bool val is_symlink_dir: Dir.t -> bool (** Is an executable? *) val is_exec: t -> bool (** Copy a file *) val copy: src:t -> dst:t -> unit (** Installs a file to a destination. Optionally set if the destination should be set executable *) val install: ?warning:OpamSystem.install_warning_fn -> ?exec:bool -> src:t -> dst:t -> unit -> unit (** Symlink a file. If symlink is not possible on the system, use copy instead. With [relative], creates a relative link through the closest common ancestor directory if possible. Otherwise, the symlink is absolute. *) val link: ?relative:bool -> target:t -> link:t -> unit (** Returns true if the given file is an archive (zip or tar) *) val is_archive: t -> bool (** Extract an archive in a given directory (it rewrites the root to match [Dir.t] dir if needed) *) val extract: t -> Dir.t -> unit (** Same as [extract], as an OpamProcess.job *) val extract_job: t -> Dir.t -> exn option OpamProcess.job (** Extract an archive in a given directory *) val extract_in: t -> Dir.t -> unit val extract_in_job: t -> Dir.t -> exn option OpamProcess.job val make_tar_gz_job: t -> Dir.t -> exn option OpamProcess.job (** Extract a generic file *) val extract_generic_file: generic_file -> Dir.t -> unit (** Check whether a filename starts by a given Dir.t *) val starts_with: Dir.t -> t -> bool (** Check whether a filename ends with a given suffix *) val ends_with: string -> t -> bool (** [dir starts_with pfx dir] Check whether [dir] starts with [pfx] *) val dir_starts_with: Dir.t -> Dir.t -> bool (** Check whether a dirname ends with a given suffix *) val dir_ends_with: string -> Dir.t -> bool (** Remove a prefix from a file name *) val remove_prefix: Dir.t -> t -> string val remove_prefix_dir: Dir.t -> Dir.t -> string (** Remove a suffix from a filename *) val remove_suffix: Base.t -> t -> string (** Apply a patch in a directory. If [preprocess] is set to false, there is no CRLF translation. Returns [None] on success, the process error otherwise *) val patch: ?preprocess:bool -> t -> Dir.t -> exn option OpamProcess.job (** Create an empty file *) val touch: t -> unit (** Change file permissions *) val chmod: t -> int -> unit (** Returns delay since last file update, based on mtime *) val written_since: t -> float (** Returns the closest parent of a directory (including itself) for which the predicate holds, if any *) val find_in_parents: (Dir.t -> bool) -> Dir.t -> Dir.t option (** {2 Locking} *) (** See [OpamSystem.flock]. Prefer the higher level [with_flock] functions when possible *) val flock: [< OpamSystem.lock_flag ] -> ?dontblock:bool -> t -> OpamSystem.lock (** Calls [f] while holding a lock file. Ensures the lock is properly released on [f] exit. Raises [OpamSystem.Locked] if [dontblock] is set and the lock can't be acquired. [f] is passed the file_descr of the lock. *) val with_flock: [< OpamSystem.lock_flag ] -> ?dontblock:bool -> t -> (Unix.file_descr -> 'a) -> 'a (** Calls [f] with the file lock upgraded to at least [flag], then restores the previous lock level. Upgrade to [`Lock_write] should never be used in blocking mode as it would deadlock. Raises [OpamSystem.Locked] (but keeps the lock as is) if [dontblock] is set and the lock can't be upgraded. *) val with_flock_upgrade: [< OpamSystem.actual_lock_flag ] -> ?dontblock:bool -> OpamSystem.lock -> (Unix.file_descr -> 'a) -> 'a (** Runs first function with a write lock on the given file, then releases it to a read lock and runs the second function. *) val with_flock_write_then_read: ?dontblock:bool -> t -> (Unix.file_descr -> 'a) -> ('a -> 'b) -> 'b module Op: sig (** Create a new directory *) val (/): Dir.t -> string -> Dir.t (** Create a new filename *) val (//): Dir.t -> string -> t end (** Simple structure to handle file attributes *) module Attribute: sig include OpamStd.ABSTRACT val to_string_list: t -> string list val of_string_list: string list -> t (** Get remote filename *) val base: t -> Base.t (** MD5 digest of the remote file *) val md5: t -> OpamHash.t (** File permission *) val perm: t -> int option (** Constructor*) val create: Base.t -> OpamHash.t -> int option -> t end (** Convert a filename to an attribute, relatively to a root *) val to_attribute: Dir.t -> t -> Attribute.t opam-2.1.5/src/core/opamConsole.ml0000644000175000017500000007017114427463453016055 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCompat (* Global configuration *) let debug () = abs OpamCoreConfig.(!r.debug_level) > 0 let verbose () = OpamCoreConfig.(!r.verbose_level) > 0 let dumb_term = lazy ( try OpamStd.Env.get "TERM" = "dumb" with Not_found -> not Sys.win32 ) let color = let auto = lazy ( OpamStd.Sys.tty_out && not (Lazy.force dumb_term) ) in fun () -> match OpamCoreConfig.(!r.color) with | `Always -> true | `Never -> false | `Auto -> Lazy.force auto let disp_status_line () = match OpamCoreConfig.(!r.disp_status_line) with | `Always -> true | `Never -> false | `Auto -> OpamStd.Sys.tty_out && (color () || not (Lazy.force dumb_term)) let utf8, utf8_extended = let auto = lazy ( if Sys.win32 then let attempt handle = let (info : OpamStubs.console_font_infoex) = let hConsoleOutput = OpamStubs.getStdHandle handle in OpamStubs.getCurrentConsoleFontEx hConsoleOutput false in (* * The Windows Console will be able to output Unicode as long as a * TrueType font has been selected (Consolas or Lucida Console are * installed by default) and the output code page has been set to * CP_UTF8 (65001) * TMPF_TRUETYPE = 0x4 (wingdi.h) *) info.fontFamily land 0x4 <> 0 && OpamStubs.getConsoleOutputCP () = 65001 in try attempt OpamStubs.STD_OUTPUT_HANDLE with Not_found -> try attempt OpamStubs.STD_INPUT_HANDLE with Not_found -> false else let checkv v = try Some (OpamStd.String.ends_with ~suffix:"UTF-8" (OpamStd.Env.get v)) with Not_found -> None in OpamStd.Option.Op.(checkv "LC_ALL" ++ checkv "LANG" +! false) ) in (fun () -> match OpamCoreConfig.(!r.utf8) with | `Always | `Extended -> true | `Never -> false | `Auto -> Lazy.force auto), (fun () -> match OpamCoreConfig.(!r.utf8) with | `Extended -> not Sys.win32 | `Always | `Never -> false | `Auto -> Lazy.force auto && OpamStd.Sys.(os () = Darwin)) module Symbols = struct let rightwards_arrow = Uchar.of_int 0x2192 let box_drawings_light_down_and_right = Uchar.of_int 0x250c let box_drawings_light_horizontal = Uchar.of_int 0x2500 let box_drawings_light_vertical = Uchar.of_int 0x2502 let box_drawings_light_up_and_right = Uchar.of_int 0x2514 let box_drawings_light_right = Uchar.of_int 0x2576 let circled_division_slash = Uchar.of_int 0x2298 let asterisk_operator = Uchar.of_int 0x2217 let north_east_arrow = Uchar.of_int 0x2197 let south_east_arrow = Uchar.of_int 0x2198 let clockwise_open_circle_arrow = Uchar.of_int 0x21bb let greek_small_letter_lambda = Uchar.of_int 0x03bb let latin_capital_letter_o_with_stroke = Uchar.of_int 0x00d8 let six_pointed_black_star = Uchar.of_int 0x2736 let upwards_arrow = Uchar.of_int 0x2191 let downwards_arrow = Uchar.of_int 0x2193 let up_down_arrow = Uchar.of_int 0x2195 let downwards_double_arrow = Uchar.of_int 0x21d3 let black_down_pointing_triangle = Uchar.of_int 0x25bc let downwards_black_arrow = Uchar.of_int 0x2b07 end type win32_glyph_checker = { font: string; checker: OpamStubs.handle * OpamStubs.handle; glyphs: (Uchar.t, bool) Hashtbl.t; } let win32_glyph_checker = ref None let () = if Sys.win32 then let release_checker checker () = match checker with | {contents = Some {checker; _}} -> OpamStubs.delete_glyph_checker checker | _ -> () in at_exit (release_checker win32_glyph_checker) let utf8_symbol main ?(alternates=[]) s = if utf8 () then try let scalar = if Sys.win32 then let current_font = let open OpamStubs in try let stdout = getStdHandle OpamStubs.STD_OUTPUT_HANDLE in (getCurrentConsoleFontEx stdout false).faceName with Not_found -> let stderr = getStdHandle OpamStubs.STD_ERROR_HANDLE in (getCurrentConsoleFontEx stderr false).faceName in let checker = let new_checker = lazy {font = current_font; checker = OpamStubs.create_glyph_checker current_font; glyphs = Hashtbl.create 16} in match win32_glyph_checker with | {contents = Some {font; checker; _}} when font <> current_font -> OpamStubs.delete_glyph_checker checker; let checker = Lazy.force new_checker in win32_glyph_checker := Some checker; checker | {contents = None} -> let checker = Lazy.force new_checker in win32_glyph_checker := Some checker; checker | {contents = Some checker} -> checker in let check_glyph scalar = try Hashtbl.find checker.glyphs scalar with Not_found -> let has_glyph = OpamStubs.has_glyph checker.checker scalar in Hashtbl.add checker.glyphs scalar has_glyph; has_glyph in List.find check_glyph (main::alternates) else main in let b = Buffer.create 4 in Buffer.add_utf_8_uchar b scalar; Buffer.contents b with Failure _ | Not_found -> s else s let timer () = if OpamCoreConfig.(!r.debug_level) > 0 then let t = Unix.gettimeofday () in fun () -> Unix.gettimeofday () -. t else fun () -> 0. let global_start_time = Unix.gettimeofday () type text_style = [ `bold | `underline | `crossed | `black | `red | `green | `yellow | `blue | `magenta | `cyan | `white ] let style_code (c: text_style) = match c with | `bold -> "01" | `underline -> "04" | `crossed -> "09" | `black -> "30" | `red -> "31" | `green -> "32" | `yellow -> "33" | `blue -> "1;34" (* most terminals make blue unreadable unless bold *) | `magenta -> "35" | `cyan -> "36" | `white -> "37" (* not nestable *) let colorise style s = if not (color ()) then s else Printf.sprintf "\027[%sm%s\027[0m" (style_code style) s let colorise' styles s = if not (color ()) then s else Printf.sprintf "\027[%sm%s\027[0m" (String.concat ";" (List.map style_code styles)) s let acolor_with_width width c () s = let str = colorise c s in str ^ match width with | None -> "" | Some w -> if String.length str >= w then "" else String.make (w-String.length str) ' ' let acolor c () = colorise c let acolor_w width c f s = Format.pp_print_string f (acolor_with_width (Some width) c () s) type win32_color_mode = Shim | VT100 of (unit -> unit) type _ shim_return = | Handle : (OpamStubs.stdhandle * win32_color_mode) shim_return | Mode : win32_color_mode shim_return | Peek : bool shim_return let force_win32_vt100 handle () = try let hConsoleOutput = OpamStubs.getStdHandle handle in let mode = OpamStubs.getConsoleMode hConsoleOutput in (* ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4 *) let vt100_on = 0x4 in if mode land vt100_on = 0 then OpamStubs.setConsoleMode hConsoleOutput (mode lor vt100_on) |> ignore with Not_found -> () let enable_win32_vt100 ch = try let hConsoleOutput = OpamStubs.getStdHandle ch in let mode = OpamStubs.getConsoleMode hConsoleOutput in (* ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4 *) let vt100_on = 0x4 in if mode land vt100_on <> 0 then (ch, VT100(force_win32_vt100 ch)) else if OpamStubs.setConsoleMode hConsoleOutput (mode lor vt100_on) then begin let restore_console () = try let hConsoleOutput = OpamStubs.getStdHandle ch in let mode = OpamStubs.getConsoleMode hConsoleOutput land (lnot vt100_on) in OpamStubs.setConsoleMode hConsoleOutput mode |> ignore with Not_found -> () in at_exit restore_console; (ch, VT100(force_win32_vt100 ch)) end else (ch, Shim) with Not_found -> (ch, VT100 ignore) let stdout_state = lazy (enable_win32_vt100 OpamStubs.STD_OUTPUT_HANDLE) let stderr_state = lazy (enable_win32_vt100 OpamStubs.STD_ERROR_HANDLE) let get_win32_console_shim : type s . [ `stdout | `stderr ] -> s shim_return -> s = fun ch -> let ch = if ch = `stdout then stdout_state else stderr_state in function | Handle -> Lazy.force ch | Mode -> Lazy.force ch |> snd | Peek -> if Lazy.is_val ch then match Lazy.force ch with | (_, Shim) -> false | (_, VT100 force) -> force (); true else false (* * Layout of attributes (wincon.h) * * Bit 0 - Blue --\ * Bit 1 - Green } Foreground * Bit 2 - Red / * Bit 3 - Bold -/ * Bit 4 - Blue --\ * Bit 5 - Green } Background * Bit 6 - Red / * Bit 7 - Bold -/ * Bit 8 - Leading Byte * Bit 9 - Trailing Byte * Bit a - Top horizontal * Bit b - Left vertical * Bit c - Right vertical * Bit d - unused * Bit e - Reverse video * Bit f - Underscore *) let is_windows_10 = lazy (let (v, _, _, _) = OpamStubs.getWindowsVersion () in v >= 10) let win32_print_message ch msg = let ocaml_ch = match ch with | `stdout -> stdout | `stderr -> stderr in if get_win32_console_shim ch Peek then Printf.fprintf ocaml_ch "%s%!" msg else let (ch, mode) = get_win32_console_shim ch Handle in match mode with | VT100 force -> force (); output_string ocaml_ch msg; flush ocaml_ch | Shim -> let hConsoleOutput = OpamStubs.getStdHandle ch in let {OpamStubs.attributes; _} = OpamStubs.getConsoleScreenBufferInfo hConsoleOutput in let background = (attributes land 0b1110000) lsr 4 in let length = String.length msg in let execute_code = let color = ref (attributes land 0b1111) in let blend ?(inheritbold = true) bits = let bits = if inheritbold then (!color land 0b1000) lor (bits land 0b111) else bits in let result = (attributes land (lnot 0b1111)) lor (bits land 0b1000) lor ((bits land 0b111) lxor background) in color := (result land 0b1111); result in fun code -> let l = String.length code in assert (l > 0 && code.[0] = '['); let attributes = OpamStd.String.split (String.sub code 1 (l - 1)) ';' in let attributes = if attributes = [] then [""] else attributes in let f attributes attribute = match attribute with | "1" | "01" -> blend ~inheritbold:false (!color lor 0b1000) | "4" | "04" -> if Lazy.force is_windows_10 then attributes lor 0b1000000000000000 else (* Don't have underline, so change the background *) (attributes land (lnot 0b11111111)) lor 0b01110000 | "30" -> blend 0b000 | "31" -> blend 0b100 | "32" -> blend 0b010 | "33" -> blend 0b110 | "34" -> blend ~inheritbold:false 0b001 | "35" -> blend 0b101 | "36" -> blend 0b011 | "37" -> blend 0b111 | "0" | "" -> blend ~inheritbold:false 0b0111 | _ -> assert false in let attrs = (List.fold_left f (blend !color) attributes) in OpamStubs.setConsoleTextAttribute hConsoleOutput attrs in let rec f index start in_code = if index < length then let c = msg.[index] in if c = '\027' then begin assert (not in_code); let fragment = String.sub msg start (index - start) in let index = succ index in if fragment <> "" then Printf.fprintf ocaml_ch "%s%!" fragment; f index index true end else if in_code && c = 'm' then let fragment = String.sub msg start (index - start) in let index = succ index in execute_code fragment; f index index false else f (succ index) start in_code else let fragment = String.sub msg start (index - start) in if fragment <> "" then if in_code then execute_code fragment else Printf.fprintf ocaml_ch "%s%!" fragment else flush ocaml_ch in flush ocaml_ch; f 0 0 false let carriage_delete_unix _ = print_string "\r\027[K" let carriage_delete_windows () = match get_win32_console_shim `stdout Handle with | (ch, Shim) -> let hConsoleOutput = OpamStubs.getStdHandle ch in let {OpamStubs.size = (w, _); cursorPosition = (_, row); _} = OpamStubs.getConsoleScreenBufferInfo hConsoleOutput in Printf.printf "\r%!"; OpamStubs.fillConsoleOutputCharacter hConsoleOutput '\000' w (0, row) |> ignore | (_, VT100 force) -> force (); carriage_delete_unix () let carriage_delete = if Sys.win32 then let carriage_delete = lazy ( match get_win32_console_shim `stdout Mode with | Shim -> carriage_delete_windows | VT100 force -> fun () -> force (); carriage_delete_unix ()) in fun () -> Lazy.force carriage_delete () else carriage_delete_unix let displaying_status = ref false let clear_status_unix () = if !displaying_status then begin flush stdout; displaying_status := false end let clear_status = if Sys.win32 then let clear_status = lazy ( match get_win32_console_shim `stdout Mode with | Shim -> fun () -> carriage_delete_windows (); displaying_status := false | VT100 force -> fun () -> force (); clear_status_unix ()) in fun () -> Lazy.force clear_status () else clear_status_unix let print_message = if Sys.win32 then fun ch fmt -> flush (if ch = `stdout then stderr else stdout); clear_status (); (* win32_print_message *always* flushes *) Printf.ksprintf (win32_print_message ch) fmt else fun ch fmt -> let output_string = let output_string ch s = output_string ch s; flush ch in match ch with | `stdout -> flush stderr; output_string stdout | `stderr -> flush stdout; output_string stderr in Printf.ksprintf output_string fmt let timestamp () = let time = Unix.gettimeofday () -. global_start_time in let tm = Unix.gmtime time in let msec = time -. (floor time) in Printf.ksprintf (colorise `blue) "%.2d:%.2d.%.3d" (tm.Unix.tm_hour * 60 + tm.Unix.tm_min) tm.Unix.tm_sec (int_of_float (1000.0 *. msec)) let log_formatter, finalise_output = if Sys.win32 then let b = Buffer.create 128 in let f _ = win32_print_message `stderr (Buffer.contents b); Buffer.clear b in Format.formatter_of_buffer b, f else Format.formatter_of_out_channel stderr, ignore let () = Format.pp_set_margin log_formatter 0 let pending = Queue.create () let clear_pending debug_level = let f (level, timestamp, msg) = if level <= abs debug_level then let timestamp = if debug_level < 0 then "" else timestamp in Format.kfprintf finalise_output log_formatter "%s%s%!" timestamp msg in Queue.iter f pending; Queue.clear pending let log section ?(level=1) fmt = let debug_level = let debug_level = OpamCoreConfig.(!r.debug_level) in let sections = OpamCoreConfig.(!r.debug_sections) in if OpamStd.String.Map.is_empty sections then debug_level else match OpamStd.String.Map.find section sections with | Some level -> level | None -> debug_level | exception Not_found -> 0 in if not OpamCoreConfig.(!r.set) then let b = Buffer.create 128 in let timestamp = timestamp () ^ " " in let k _ = Queue.push (level, timestamp, Buffer.contents b) pending in Format.kfprintf k (Format.formatter_of_buffer b) ("%a " ^^ fmt ^^ "\n%!") (acolor_w 30 `yellow) section else if level <= abs debug_level then let () = clear_status () in let () = clear_pending debug_level in let timestamp = if debug_level < 0 then "" else timestamp () ^ " " in Format.kfprintf finalise_output log_formatter ("%s%a " ^^ fmt ^^ "\n%!") timestamp (acolor_w 30 `yellow) section else Format.ifprintf Format.err_formatter fmt (* Helper to pass stringifiers to log (use [log "%a" (slog to_string) x] rather than [log "%s" (to_string x)] to avoid costly unneeded stringifications *) let slog to_string f x = Format.pp_print_string f (to_string x) let error fmt = Printf.ksprintf (fun str -> print_message `stderr "%a %s\n" (acolor `red) "[ERROR]" (OpamStd.Format.reformat ~start_column:8 ~indent:8 str) ) fmt let warning fmt = Printf.ksprintf (fun str -> print_message `stderr "%a %s\n" (acolor `yellow) "[WARNING]" (OpamStd.Format.reformat ~start_column:10 ~indent:10 str) ) fmt let note fmt = Printf.ksprintf (fun str -> print_message `stderr "%a %s\n" (acolor `blue) "[NOTE]" (OpamStd.Format.reformat ~start_column:7 ~indent:7 str) ) fmt let errmsg fmt = print_message `stderr fmt let error_and_exit reason fmt = Printf.ksprintf (fun str -> error "%s" str; OpamStd.Sys.exit_because reason ) fmt let msg fmt = print_message `stdout fmt let formatted_msg ?indent fmt = Printf.ksprintf (fun s -> print_message `stdout "%s" (OpamStd.Format.reformat ?indent s)) fmt let last_status = ref "" let write_status_unix print_string fmt = let print_string s = print_string s; flush stdout; carriage_delete_unix (); displaying_status := true in Printf.ksprintf print_string ("\r\027[K" ^^ fmt) let write_status_windows fmt = let print_string s = carriage_delete (); win32_print_message `stdout s; displaying_status := true in Printf.ksprintf print_string fmt let win32_print_functions = lazy ( match get_win32_console_shim `stdout Mode with | Shim -> (true, (fun s -> win32_print_message `stdout (s ^ "\n")), print_string) | VT100 force -> (false, (fun s -> force (); print_endline s), (fun s -> force (); print_string s))) let status_line fmt = let batch = debug () || not (disp_status_line ()) in let (use_shim, print_msg, print_string) = if Sys.win32 then Lazy.force win32_print_functions else (false, print_endline, print_string) in if batch then Printf.ksprintf (fun s -> if s <> !last_status then (last_status := s; print_msg s)) fmt else if use_shim then write_status_windows fmt else write_status_unix print_string fmt let header_width () = min 80 (OpamStd.Sys.terminal_columns ()) let header_msg fmt = let utf8camel = "\xF0\x9F\x90\xAB " in (* UTF-8 *) let padding = "<><><><><><><><><><><><><><><><><><><><>\ <><><><><><><><><><><><><><><><><><><><><>" in Printf.ksprintf (fun str -> let wpad = header_width () - String.length str - 2 in let wpadl = 4 in let wpadr = wpad - wpadl - if utf8_extended () then 4 else 0 in print_message `stdout "\n%s %s %s%s\n" (colorise `cyan (String.sub padding 0 wpadl)) (colorise `bold str) (if wpadr > 0 then let padding = String.sub padding (String.length padding - wpadr) wpadr in colorise `cyan padding else "") (if wpadr >= 0 && utf8_extended () then " " ^ (colorise `yellow utf8camel) else ""); ) fmt let header_error fmt = let padding = "#=======================================\ ========================================#" in Printf.ksprintf (fun head fmt -> Printf.ksprintf (fun contents -> let wpad = header_width () - String.length head - 8 in let wpadl = 4 in let wpadr = wpad - wpadl in print_message `stderr "\n%s %s %s %s\n%s\n" (colorise `red (String.sub padding 0 wpadl)) (colorise `bold "ERROR") (colorise `bold head) (if wpadr > 0 then let padding = String.sub padding (String.length padding - wpadr) wpadr in colorise `red padding else "") contents ) fmt ) fmt let confirm ?(require_unsafe_yes=false) ?(default=true) fmt = Printf.ksprintf (fun s -> try if OpamCoreConfig.(!r.safe_mode) then false else let prompt () = formatted_msg "%s [%s] " s (if default then "Y/n" else "y/N") in if (require_unsafe_yes && OpamCoreConfig.answer_is `unsafe_yes) || (not require_unsafe_yes && OpamCoreConfig.answer_is_yes ()) then (prompt (); msg "y\n"; true) else if OpamCoreConfig.answer_is `all_no || OpamStd.Sys.(not tty_in) then (prompt (); msg "n\n"; false) else if OpamStd.Sys.(not tty_out || os () = Win32 || os () = Cygwin) then let rec loop () = prompt (); match String.lowercase_ascii (read_line ()) with | "y" | "yes" -> true | "n" | "no" -> false | "" -> default | _ -> loop () in loop () else let open Unix in prompt (); let buf = Bytes.create 1 in let rec loop () = let ans = try if read stdin buf 0 1 = 0 then raise End_of_file else Some (Char.lowercase_ascii (Bytes.get buf 0)) with | Unix.Unix_error (Unix.EINTR,_,_) -> None | Unix.Unix_error _ -> raise End_of_file in match ans with | Some 'y' -> print_endline (Bytes.to_string buf); true | Some 'n' -> print_endline (Bytes.to_string buf); false | Some '\n' -> print_endline (if default then "y" else "n"); default | _ -> loop () in let attr = tcgetattr stdin in let reset () = tcsetattr stdin TCSAFLUSH attr; tcflush stdin TCIFLUSH; in try tcsetattr stdin TCSAFLUSH {attr with c_icanon = false; c_echo = false}; tcflush stdin TCIFLUSH; let r = loop () in reset (); r with e -> reset (); raise e with | Unix.Unix_error _ | End_of_file -> msg "%s\n" (if default then "y" else "n"); default | Sys.Break as e -> msg "\n"; raise e ) fmt let read fmt = Printf.ksprintf (fun s -> formatted_msg "%s " s; if OpamCoreConfig.(answer_is `ask && not !r.safe_mode) then ( try match read_line () with | "" -> None | s -> Some s with | End_of_file -> msg "\n"; None | Sys.Break as e -> msg "\n"; raise e ) else None ) fmt let print_table ?cut oc ~sep table = let open OpamStd.Format in let cut = match cut with | None -> if oc = stdout || oc = stderr then `Wrap "" else `None | Some c -> c in let output_string s = if oc = stdout then msg "%s\n" s else if oc = stderr then errmsg "%s\n" s else begin output_string oc s; output_char oc '\n' end in let replace_newlines by = Re.(replace_string (compile (char '\n')) ~by) in let cleanup_trailing sl = let rec clean acc = function | s::r -> let s' = OpamStd.String.strip_right s in if s' = "" then clean acc r else List.rev_append r (s'::acc) | [] -> acc in clean [] (List.rev sl) in let print_line l = match cut with | `None -> let s = List.map (replace_newlines "\\n") l |> String.concat sep in output_string s; | `Truncate -> let s = List.map (replace_newlines " ") l |> String.concat sep in output_string (cut_at_visual s (OpamStd.Sys.terminal_columns ())); | `Wrap wrap_sep -> let width = OpamStd.Sys.terminal_columns () in let base_indent = 10 in let sep_len = visual_length sep in let wrap_sep_len = visual_length wrap_sep in let max_sep_len = max sep_len wrap_sep_len in let indent_string = String.make (max 0 (base_indent - wrap_sep_len)) ' ' ^ wrap_sep in let margin = visual_length indent_string in let min_reformat_width = 30 in let rec split_at_overflows start_col acc cur = let append = function | [] -> acc | last::r -> List.rev (OpamStd.String.strip_right last :: r) :: acc in function | [] -> List.rev (append cur) | cell::rest -> let multiline = String.contains cell '\n' in let cell_lines = OpamStd.String.split cell '\n' in let cell_width = List.fold_left max 0 (List.map visual_length cell_lines) in let text_width = List.fold_left max 0 (List.map (fun s -> visual_length (OpamStd.String.strip_right s)) cell_lines) in let end_col = start_col + sep_len + cell_width in let indent ~sep n cell = let spc = if sep then String.make (max 0 (if sep then n - wrap_sep_len else n)) ' ' ^ wrap_sep else String.make n ' ' in OpamStd.List.concat_map ("\n"^spc) OpamStd.String.strip_right (OpamStd.String.split cell '\n') in if start_col + sep_len + text_width <= width then if multiline then let cell = indent ~sep:true start_col (OpamStd.String.strip_right cell) in split_at_overflows margin (append (cell::cur)) [] rest else split_at_overflows end_col acc (cell::cur) rest else if rest = [] && acc = [] && not multiline && width - start_col - max_sep_len >= min_reformat_width then let cell = OpamStd.String.strip_right cell |> fun cell -> reformat ~width:(width - start_col - max_sep_len) cell |> indent ~sep:true start_col in split_at_overflows margin acc (cell::cur) [] else if multiline || margin + cell_width >= width then let cell = OpamStd.String.strip_right cell |> fun cell -> reformat ~width:(width - margin) cell |> fun cell -> OpamStd.String.split cell '\n' |> OpamStd.List.concat_map ("\n" ^ indent_string) OpamStd.String.strip_right in split_at_overflows margin ([cell]::append cur) [] rest else split_at_overflows (margin + cell_width) (append cur) [cell] rest in let splits = split_at_overflows 0 [] [] l in let str = OpamStd.List.concat_map ("\n" ^ String.make base_indent ' ') (String.concat sep) splits in output_string str; in List.iter (fun l -> print_line (cleanup_trailing l)) table (* This allows OpamStd.Config.env to display warning messages *) let () = OpamStd.Sys.(set_warning_printer {warning}) opam-2.1.5/src/core/opamVersionCompare.ml0000644000175000017500000001527414427463453017412 0ustar stephsteph(******************************************************************************) (* This file is part of the Dose library http://www.irill.org/software/dose *) (* *) (* Copyright (C) 2011 Ralf Treinen *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (* Work developed with the support of the Mancoosi Project *) (* http://www.mancoosi.org *) (* *) (******************************************************************************) let is_digit = function | '0'..'9' -> true | _ -> false ;; (* [skip_while_from i f w m] yields the index of the leftmost character * in the string [s], starting from [i], and ending at [m], that does * not satisfy the predicate [f], or [length w] if no such index exists. *) let skip_while_from i f w m = let rec loop i = if i = m then i else if f w.[i] then loop (i + 1) else i in loop i ;; (* splits a version into (epoch,rest), without the separating ':'. The * epoch is delimited by the leftmost occurrence of ':' in x, and is "" * in case there is no ':' in x. *) let extract_epoch x = try let ci = String.index x ':' in let epoch = String.sub x 0 ci and rest = String.sub x (ci + 1) (String.length x - ci - 1) in (epoch,rest) with | Not_found -> ("",x) ;; (* splits a version into (prefix,revision). The revision starts on the * right-most occurrence of '-', or is empty in case the version does * not contain '-'. *) let extract_revision x = try let di = String.rindex x '-' in let before = String.sub x 0 di in let after = String.sub x (di+1) (String.length x - di -1) in (before,after) with | Not_found -> (x,"") ;; (* character comparison uses a modified character ordering: '~' first, then letters, then anything else *) let compare_chars c1 c2 = match c1 with | '~' -> (match c2 with | '~' -> 0 | _ -> -1) | 'a'..'z'|'A'..'Z' -> (match c2 with | '~' -> 1 | 'a'..'z'|'A'..'Z' -> Char.compare c1 c2 | _ -> -1) | _ -> (match c2 with | '~'|'a'..'z'|'A'..'Z' -> 1 | _ -> Char.compare c1 c2) ;; (* return the first index of x, starting from xi, of a nun-null * character in x. or (length x) in case x contains only 0's starting * from xi on. *) let skip_zeros x xi xl = skip_while_from xi (fun c -> c = '0') x xl;; (* compare versions chunks, that is parts of version strings that are * epoch, upstream version, or revisision. Alternates string comparison * and numerical comparison. *) let compare_chunks x y = (* x and y may be empty *) let xl = String.length x and yl = String.length y in let rec loop_lexical xi yi = assert (xi <= xl && yi <= yl); match (xi=xl,yi=yl) with (* which of x and y is exhausted? *) | true,true -> 0 | true,false -> (* if y continues numerically than we have to continue by * comparing numerically. In this case the x part is * interpreted as 0 (since empty). If the y part consists * only of 0's then both parts are equal, otherwise the y * part is larger. If y continues non-numerically then y is * larger anyway, so we only have to skip 0's in the y part * and check whether this exhausts the y part. *) let ys = skip_zeros y yi yl in if ys = yl then 0 else if y.[ys]='~' then 1 else -1 | false,true -> (* symmetric to the preceding case *) let xs = skip_zeros x xi xl in if xs = xl then 0 else if x.[xs]='~' then -1 else 1 | false,false -> (* which of x and y continues numerically? *) match (is_digit x.[xi], is_digit y.[yi]) with | true,true -> (* both continue numerically. Skip leading zeros in the * remaining parts, and then continue by * comparing numerically. *) compare_numerical (skip_zeros x xi xl) (skip_zeros y yi yl) | true,false -> (* '~' is smaller than any numeric part *) if y.[yi]='~' then 1 else -1 | false,true -> (* '~' is smaller than any numeric part *) if x.[xi]='~' then -1 else 1 | false,false -> (* continue comparing lexically *) let comp = compare_chars x.[xi] y.[yi] in if comp = 0 then loop_lexical (xi+1) (yi+1) else comp and compare_numerical xi yi = assert (xi = xl || (xi < xl && x.[xi] <> '0')); (* leading zeros have been stripped *) assert (yi = yl || (yi < yl && y.[yi] <> '0')); (* leading zeros have been stripped *) let xn = skip_while_from xi is_digit x xl (* length of numerical part *) and yn = skip_while_from yi is_digit y yl (* length of numerical part *) in let comp = compare (xn-xi) (yn-yi) in if comp = 0 then (* both numerical parts have same length: compare digit by digit *) loop_numerical xi yi yn else (* if one numerical part is longer than the other we have found the * answer since leading 0 have been striped when switching * to numerical comparison. *) comp and loop_numerical xi yi yn = assert (xi <= xl && yi <= yn && yn <= yl); (* invariant: the two numerical parts that remain to compare are of the same length *) if yi=yn then (* both numerical parts are exhausted, we switch to lexical comparison *) loop_lexical xi yi else (* both numerical parts are not exhausted, we continue comparing digit by digit *) let comp = Char.compare x.[xi] y.[yi] in if comp = 0 then loop_numerical (xi+1) (yi+1) yn else comp in loop_lexical 0 0 ;; let compare (x : string) (y : string) = let normalize_comp_result x = if x=0 then 0 else if x < 0 then -1 else 1 in if x = y then 0 else let (e1,rest1) = extract_epoch x and (e2,rest2) = extract_epoch y in let e_comp = compare_chunks e1 e2 in if e_comp <> 0 then normalize_comp_result e_comp else let (u1,r1) = extract_revision rest1 and (u2,r2) = extract_revision rest2 in let u_comp = compare_chunks u1 u2 in if u_comp <> 0 then normalize_comp_result u_comp else normalize_comp_result (compare_chunks r1 r2) ;; let equal (x : string) (y : string) = if x = y then true else (compare x y) = 0 ;; opam-2.1.5/src/core/opamParallel.mli0000644000175000017500000001021614427463453016352 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Parallel execution of jobs following a directed graph *) module type VERTEX = sig include OpamStd.OrderedType include Graph.Sig.COMPARABLE with type t := t end type dependency_label = unit module type G = sig include Graph.Sig.I with type E.label = dependency_label module Vertex: VERTEX with type t = V.t module Topological: sig val fold: (V.t -> 'a -> 'a) -> t -> 'a -> 'a end val has_cycle: t -> bool val scc_list: t -> V.t list list end (** When one job fails due to an exception, other running jobs are interrupted and reported with this sub-exception in the Errors list *) exception Aborted (** Simply parallel execution of tasks *) (** In the simple iter, map and reduce cases, ints are the indexes of the jobs in the list. First list is return code of sucessfull commands, second those which raised expcetions, and third one those which were canceled. *) exception Errors of int list * (int * exn) list * int list val iter: jobs:int -> command:('a -> unit OpamProcess.job) -> ?dry_run:bool -> 'a list -> unit val map: jobs:int -> command:('a -> 'b OpamProcess.job) -> ?dry_run:bool -> 'a list -> 'b list val reduce: jobs:int -> command:('a -> 'b OpamProcess.job) -> merge:('b -> 'b -> 'b) -> nil:'b -> ?dry_run:bool -> 'a list -> 'b (** More complex parallelism with dependency graphs *) module type SIG = sig module G : G (** Runs the job [command ~pred v] for every node [v] in a graph, in topological order using [jobs] concurrent processes. Separate (possibly intersecting) node pools can be specified, with a separate number of allowed processes. The [jobs] maximum applies to the remaining nodes. The [pred] argument provided to the [command] function is the associative list of job results on direct predecessors of [v]. *) val iter: jobs:int -> command:(pred:(G.V.t * 'a) list -> G.V.t -> 'a OpamProcess.job) -> ?dry_run:bool -> ?pools:((G.V.t list * int) list) -> G.t -> unit (** Same as [iter], but returns the results of all jobs as a [vertex,result] associative list *) val map: jobs:int -> command:(pred:(G.V.t * 'a) list -> G.V.t -> 'a OpamProcess.job) -> ?dry_run:bool -> ?pools:((G.V.t list * int) list) -> G.t -> (G.V.t * 'a) list (** Raised when the [command] functions raised exceptions. Parameters are (successfully traversed nodes, exception nodes and corresponding exceptions, remaining nodes that weren't traversed) *) exception Errors of G.V.t list * (G.V.t * exn) list * G.V.t list (** Raised when the graph to traverse has cycles. Returns the cycles found. *) exception Cyclic of G.V.t list list end module Make (G : G) : SIG with module G = G and type G.V.t = G.V.t module type GRAPH = sig include Graph.Sig.I with type E.label = dependency_label include Graph.Oper.S with type g = t module Topological : sig val fold : (V.t -> 'a -> 'a) -> t -> 'a -> 'a val iter : (V.t -> unit) -> t -> unit end module Parallel : SIG with type G.t = t and type G.V.t = vertex module Dot : sig val output_graph : out_channel -> t -> unit end val transitive_closure: ?reflexive:bool -> t -> unit val build: V.t list -> E.t list -> t val compare : t -> t -> int val to_json : t OpamJson.encoder val of_json : t OpamJson.decoder end module MakeGraph (V: VERTEX) : GRAPH with type V.t = V.t opam-2.1.5/src/core/opamCoreConfig.ml0000644000175000017500000001455114427463453016471 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2015-2018 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamCompat module E = struct type OpamStd.Config.E.t += | COLOR of OpamStd.Config.when_ option | CONFIRMLEVEL of OpamStd.Config.answer option | DEBUG of int option | DEBUGSECTIONS of OpamStd.Config.sections option | ERRLOGLEN of int option | KEEPLOGS of bool option | LOGS of string option | MERGEOUT of bool option | NO of bool option | PRECISETRACKING of bool option | SAFE of bool option | STATUSLINE of OpamStd.Config.when_ option | USEOPENSSL of bool option | UTF8 of OpamStd.Config.when_ext option | UTF8MSGS of bool option | VERBOSE of OpamStd.Config.level option | YES of bool option open OpamStd.Config.E let color = value (function COLOR c -> c | _ -> None) let confirmlevel = value (function CONFIRMLEVEL c -> c | _ -> None) let debug = value (function DEBUG i -> i | _ -> None) let debugsections = value (function DEBUGSECTIONS s -> s | _ -> None) let errloglen = value (function ERRLOGLEN i -> i | _ -> None) let keeplogs = value (function KEEPLOGS b -> b | _ -> None) let logs = value (function LOGS s -> s | _ -> None) let mergeout = value (function MERGEOUT b -> b | _ -> None) let no = value (function NO b -> b | _ -> None) let precisetracking = value (function PRECISETRACKING b -> b | _ -> None) let safe = value (function SAFE b -> b | _ -> None) let statusline = value (function STATUSLINE c -> c | _ -> None) let useopenssl = value (function USEOPENSSL b -> b | _ -> None) let utf8 = value (function UTF8 c -> c | _ -> None) let utf8msgs = value (function UTF8MSGS b -> b | _ -> None) let verbose = value (function VERBOSE l -> l | _ -> None) let yes = value (function YES b -> b | _ -> None) end type t = { debug_level: int; debug_sections: OpamStd.Config.sections; verbose_level: OpamStd.Config.level; color: OpamStd.Config.when_; utf8: OpamStd.Config.when_ext; disp_status_line: OpamStd.Config.when_; confirm_level: [ OpamStd.Config.answer | `undefined ]; yes: bool option; safe_mode: bool; log_dir: string; keep_log_dir: bool; errlog_length: int; merged_output: bool; use_openssl: bool; precise_tracking: bool; set: bool; } type 'a options_fun = ?debug_level:int -> ?debug_sections:OpamStd.Config.sections -> ?verbose_level:OpamStd.Config.level -> ?color:OpamStd.Config.when_ -> ?utf8:OpamStd.Config.when_ext -> ?disp_status_line:OpamStd.Config.when_ -> ?confirm_level:OpamStd.Config.answer -> ?yes:bool option -> ?safe_mode:bool -> ?log_dir:string -> ?keep_log_dir:bool -> ?errlog_length:int -> ?merged_output:bool -> ?use_openssl:bool -> ?precise_tracking:bool -> 'a let default = { debug_level = 0; debug_sections = OpamStd.String.Map.empty; verbose_level = 0; color = `Auto; utf8 = `Auto; disp_status_line = `Auto; confirm_level = `undefined; yes = None; safe_mode = false; log_dir = (let user = try Unix.getlogin() with Unix.Unix_error _ -> "xxx" in let base = Printf.sprintf "opam-%s-%d" user (OpamStubs.getpid()) in Filename.(concat (get_temp_dir_name ()) base)); keep_log_dir = false; errlog_length = 12; merged_output = true; use_openssl = true; precise_tracking = false; set = false; } let setk k t ?debug_level ?debug_sections ?verbose_level ?color ?utf8 ?disp_status_line ?confirm_level ?yes ?safe_mode ?log_dir ?keep_log_dir ?errlog_length ?merged_output ?use_openssl ?precise_tracking = let (+) x opt = match opt with Some x -> x | None -> x in k { debug_level = t.debug_level + debug_level; debug_sections = t.debug_sections + debug_sections; verbose_level = t.verbose_level + verbose_level; color = t.color + color; utf8 = t.utf8 + utf8; disp_status_line = t.disp_status_line + disp_status_line; confirm_level = (match confirm_level with | Some (`all_yes|`all_no|`ask|`unsafe_yes as c) -> c | None -> t.confirm_level); yes = t.yes + yes; safe_mode = t.safe_mode + safe_mode; log_dir = t.log_dir + log_dir; keep_log_dir = t.keep_log_dir + keep_log_dir; errlog_length = t.errlog_length + errlog_length; merged_output = t.merged_output + merged_output; use_openssl = t.use_openssl + use_openssl; precise_tracking = t.precise_tracking + precise_tracking; set = true; } let set t = setk (fun x () -> x) t (* Global configuration reference *) let r = ref default let update ?noop:_ = setk (fun cfg () -> r := cfg) !r let initk k = let open OpamStd in let utf8 = Option.Op.( E.utf8 () ++ (E.utf8msgs () >>= function | true -> Some `Extended | false -> None) ) in let yes = match E.yes (), E.no () with | Some true, _ -> Some (Some true) | _, Some true -> Some (Some false) | _, _ -> None in (setk (setk (fun c -> r := c; k)) !r) ?debug_level:(E.debug ()) ?debug_sections:(E.debugsections ()) ?verbose_level:(E.verbose ()) ?color:(E.color ()) ?utf8 ?disp_status_line:(E.statusline ()) ?confirm_level:(E.confirmlevel ()) ?yes ?safe_mode:(E.safe ()) ?log_dir:(E.logs ()) ?keep_log_dir:(E.keeplogs ()) ?errlog_length:(E.errloglen ()) ?merged_output:(E.mergeout ()) ?use_openssl:(E.useopenssl ()) ?precise_tracking:(E.precisetracking ()) let init ?noop:_ = initk (fun () -> ()) let answer () = match !r.confirm_level, !r.yes with | #OpamStd.Config.answer as c, _ -> c | _, Some true -> `all_yes | _, Some false -> `all_no | _ -> `ask let answer_is = let answer = lazy (answer ()) in fun a -> Lazy.force answer = a let answer_is_yes () = answer_is `all_yes || answer_is `unsafe_yes #ifdef DEVELOPER let developer = true #else let developer = false #endif opam-2.1.5/src/core/opamStubsTypes.ml0000644000175000017500000000573414427463453016603 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2018 MetaStack Solutions Ltd. *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Types for C stubs modules. *) (** CONSOLE_SCREEN_BUFFER_INFO struct (see https://docs.microsoft.com/en-us/windows/console/console-screen-buffer-info-str) *) type console_screen_buffer_info = { size: int * int; (** Width and height of the screen buffer *) cursorPosition: int * int; (** Current position of the console cursor (caret) *) attributes: int; (** Screen attributes; see https://docs.microsoft.com/en-us/windows/console/console-screen-buffers#_win32_character_attributes *) window: int * int * int * int; (** Coordinates of the upper-left and lower-right corners of the display window within the screen buffer *) maximumWindowSize: int * int; (** Maximum displayable size of the console for this screen buffer *) } (** CONSOLE_FONT_INFOEX struct (see https://docs.microsoft.com/en-us/windows/console/console-font-infoex) *) type console_font_infoex = { font: int; (** Index in the system's console font table *) fontSize: int * int; (** Size, in logical units, of the font *) fontFamily: int; (** Font pitch and family (low 8 bits only). See tmPitchAndFamily in https://msdn.microsoft.com/library/windows/desktop/dd145132 *) fontWeight: int; (** Font weight. Normal = 400; Bold = 700 *) faceName: string; (** Name of the typeface *) } (** Win32 API handles *) type handle (** Standard handle constants (see https://docs.microsoft.com/en-us/windows/console/getstdhandle) *) type stdhandle = STD_INPUT_HANDLE | STD_OUTPUT_HANDLE | STD_ERROR_HANDLE (** Win32 Root Registry Hives (see https://msdn.microsoft.com/en-us/library/windows/desktop/ms724836.aspx) *) type registry_root = | HKEY_CLASSES_ROOT | HKEY_CURRENT_CONFIG | HKEY_CURRENT_USER | HKEY_LOCAL_MACHINE | HKEY_USERS (** Win32 Registry Value Types (see https://msdn.microsoft.com/en-us/library/windows/desktop/ms724884.aspx *) type _ registry_value = | REG_SZ : string registry_value (** SHGetFolderPath flags *) type shGFP_type = | SHGFP_TYPE_CURRENT (** Retrieve the current path *) | SHGFP_TYPE_DEFAULT (** Retrieve the default path *) (** Windows Messages (at least, one of them!) *) type ('a, 'b, 'c) winmessage = | WM_SETTINGCHANGE : (int, string, int) winmessage (** See https://msdn.microsoft.com/en-us/library/windows/desktop/ms725497.aspx *) opam-2.1.5/src/core/opamCached.ml0000644000175000017500000000650214427463453015617 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamStd.Op module type ARG = sig type t val name: string end module Make (X: ARG): sig type t = X.t val save: OpamFilename.t -> t -> unit val load: OpamFilename.t -> t option val remove: OpamFilename.t -> unit end = struct let log fmt = OpamConsole.log (Printf.sprintf "CACHE(%s)" X.name) fmt let slog = OpamConsole.slog type t = X.t let check_marshaled_file fd = try let ic = Unix.in_channel_of_descr fd in let this_magic = OpamVersion.magic () in let magic_len = String.length this_magic in let file_magic = let b = Bytes.create magic_len in really_input ic b 0 magic_len; Bytes.to_string b in if not OpamCoreConfig.developer && file_magic <> this_magic then ( log "Bad %s cache: incompatible magic string %S (expected %S)." X.name file_magic this_magic; None ) else Some ic with e -> OpamStd.Exn.fatal e; log "Bad %s cache: %s" X.name (Printexc.to_string e); None let marshal_from_file file fd = let chrono = OpamConsole.timer () in let f ic = try let (cache: t) = Marshal.from_channel ic in log "Loaded %a in %.3fs" (slog OpamFilename.to_string) file (chrono ()); Some cache with End_of_file | Failure _ -> log "Bad %s cache: likely a truncated file, ignoring." X.name; None in OpamStd.Option.Op.(check_marshaled_file fd >>= f) let load cache_file = match OpamFilename.opt_file cache_file with | Some file -> let r = OpamFilename.with_flock `Lock_read file @@ fun fd -> marshal_from_file file fd in if r = None then begin log "Invalid %s cache, removing" X.name; OpamFilename.remove file end; r | None -> None let save cache_file t = if OpamCoreConfig.(!r.safe_mode) then log "Running in safe mode, not upgrading the %s cache" X.name else try let chrono = OpamConsole.timer () in OpamFilename.with_flock `Lock_write cache_file @@ fun fd -> log "Writing the %s cache to %s ..." X.name (OpamFilename.prettify cache_file); let oc = Unix.out_channel_of_descr fd in output_string oc (OpamVersion.magic ()); Marshal.to_channel oc t []; flush oc; log "%a written in %.3fs" (slog OpamFilename.prettify) cache_file (chrono ()) with Unix.Unix_error _ -> log "Could not acquire lock for writing %s, skipping %s cache update" (OpamFilename.prettify cache_file) X.name let remove cache_file = OpamFilename.remove cache_file end opam-2.1.5/src/core/opamStubs.ml.dummy0000644000175000017500000000333214427463453016700 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2018 MetaStack Solutions Ltd. *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) include OpamStubsTypes let that's_a_no_no _ = failwith "Windows only. This function isn't implemented." let getCurrentProcessID = that's_a_no_no let getpid = Unix.getpid let getStdHandle = that's_a_no_no let getConsoleScreenBufferInfo = that's_a_no_no let setConsoleTextAttribute _ = that's_a_no_no let fillConsoleOutputCharacter _ _ _ = that's_a_no_no let getConsoleMode = that's_a_no_no let setConsoleMode _ = that's_a_no_no let getWindowsVersion = that's_a_no_no let isWoW64 () = false let waitpids _ = that's_a_no_no let writeRegistry _ _ _ = that's_a_no_no let getConsoleOutputCP = that's_a_no_no let getCurrentConsoleFontEx _ = that's_a_no_no let create_glyph_checker = that's_a_no_no let delete_glyph_checker = that's_a_no_no let has_glyph _ = that's_a_no_no let isWoW64Process = that's_a_no_no let process_putenv _ = that's_a_no_no let shGetFolderPath _ = that's_a_no_no let sendMessageTimeout _ _ _ _ _ = that's_a_no_no let getParentProcessID = that's_a_no_no let getConsoleAlias _ = that's_a_no_no let win_create_process _ _ _ _ _ = that's_a_no_no opam-2.1.5/src/core/opamJson.ml0000644000175000017500000000602214427463453015356 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) type t = [ `Null | `Bool of bool | `Float of float| `String of string | `A of t list | `O of (string * t) list ] type 'a encoder = 'a -> t type 'a decoder = t -> 'a option let addc b c = Buffer.add_char b c let adds b s = Buffer.add_string b s let adds_esc b s = let len = String.length s in let max_idx = len - 1 in let flush b start i = if start < len then Buffer.add_substring b s start (i - start); in let rec loop start i = match i > max_idx with | true -> flush b start i | false -> let next = i + 1 in match String.get s i with | '"' -> flush b start i; adds b "\\\""; loop next next | '\\' -> flush b start i; adds b "\\\\"; loop next next | '\x00' .. '\x1F' | '\x7F' (* US-ASCII control chars *) as c -> flush b start i; adds b (Printf.sprintf "\\u%04X" (Char.code c)); loop next next | _ -> loop start next in loop 0 0 let enc_json_string b s = addc b '"'; adds_esc b s; addc b '"' let enc_vsep b = addc b ',' let enc_lexeme b = function | `Null -> adds b "null" | `Bool true -> adds b "true" | `Bool false -> adds b "false" | `Float f -> Printf.bprintf b "%.16g" f | `String s -> enc_json_string b s | `Name n -> enc_json_string b n; addc b ':' | `As -> addc b '[' | `Ae -> addc b ']' | `Os -> addc b '{' | `Oe -> addc b '}' let enc_json b (json:t) = let enc = enc_lexeme in let enc_sep seq enc_seq k b = match seq with | [] -> enc_seq seq k b | seq -> enc_vsep b; enc_seq seq k b in let rec value v k b = match v with | `A vs -> arr vs k b | `O ms -> obj ms k b | `Null | `Bool _ | `Float _ | `String _ as v -> enc b v; k b and arr vs k b = enc b `As; arr_vs vs k b and arr_vs vs k b = match vs with | v :: vs' -> value v (enc_sep vs' arr_vs k) b | [] -> enc b `Ae; k b and obj ms k b = enc b `Os; obj_ms ms k b and obj_ms ms k b = match ms with | (n, v) :: ms -> enc b (`Name n); value v (enc_sep ms obj_ms k) b | [] -> enc b `Oe; k b in value json (fun _ -> ()) b let to_string (json:t) = let b = Buffer.create 1024 in enc_json b json; Buffer.contents b let json_buffer = ref [] let append key json = json_buffer := (key,json) :: !json_buffer let flush oc = let b = Buffer.create 1024 in let json = (`O (List.rev !json_buffer)) in let json = enc_json b json; Buffer.contents b in output_string oc json; flush oc opam-2.1.5/src/core/opamCoreConfig.mli0000644000175000017500000001212314427463453016633 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2015-2018 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Configuration options for the core lib (record, global reference and setter) *) module E : sig type OpamStd.Config.E.t += | COLOR of OpamStd.Config.when_ option | CONFIRMLEVEL of OpamStd.Config.answer option | DEBUG of int option | DEBUGSECTIONS of OpamStd.Config.sections option | ERRLOGLEN of int option | KEEPLOGS of bool option | LOGS of string option | MERGEOUT of bool option | NO of bool option | PRECISETRACKING of bool option | SAFE of bool option | STATUSLINE of OpamStd.Config.when_ option | USEOPENSSL of bool option | UTF8 of OpamStd.Config.when_ext option | UTF8MSGS of bool option | VERBOSE of OpamStd.Config.level option | YES of bool option val confirmlevel: unit -> OpamStd.Config.answer option val debug: unit -> int option val logs: unit -> string option val yes: unit -> bool option end type t = private { debug_level : int; (** Controls debug messages, 0 to disable *) debug_sections : OpamStd.Config.sections; (** Controls which sections display debugging messages. If empty, all messages are displayed. *) verbose_level : OpamStd.Config.level; (** Controls printing of external commands and output, 0 to disable, more means print more low-level commands *) color : OpamStd.Config.when_; (** Console ANSI color control *) utf8 : OpamStd.Config.when_ext; (** Controls usage of UTF8 in OPAM-generated messages. Extended adds camel emojis *) disp_status_line: OpamStd.Config.when_; (** Controls on-line display of parallel commands being run, using ANSI escapes *) confirm_level : [ OpamStd.Config.answer | `undefined ]; yes: bool option; (** Affects interactive questions in OpamConsole: used to compute the automatic ansering level *) safe_mode : bool; (** Fail on writes or delays, don't ask questions (for quick queries, e.g. for shell completion) *) log_dir : string; (** Where to store log and temporary files (output from commands...) *) keep_log_dir : bool; (** Whether to cleanup temporary and log files on exit *) errlog_length : int; (** The number of log lines displayed on process error. 0 for all *) merged_output : bool; (** If set, stderr of commands is merged into their stdout *) use_openssl : bool; (** If false, will use built-in hash functions without checking for an openssl executable first *) precise_tracking : bool; (** If set, will take full md5 of all files when checking diffs (to track installations), rather than rely on just file size and mtime *) set : bool; (** Options have not yet been initialised (i.e. defaults are active) *) } type 'a options_fun = ?debug_level:int -> ?debug_sections:OpamStd.Config.sections -> ?verbose_level:OpamStd.Config.level -> ?color:OpamStd.Config.when_ -> ?utf8:OpamStd.Config.when_ext -> ?disp_status_line:OpamStd.Config.when_ -> ?confirm_level:OpamStd.Config.answer -> ?yes:bool option -> ?safe_mode:bool -> ?log_dir:string -> ?keep_log_dir:bool -> ?errlog_length:int -> ?merged_output:bool -> ?use_openssl:bool -> ?precise_tracking:bool -> 'a val default : t val set : t -> (unit -> t) options_fun val setk : (t -> 'a) -> t -> 'a options_fun val r : t ref val update : ?noop:_ -> (unit -> unit) options_fun (** Sets the OpamCoreConfig options, reading the environment to get default values when unspecified *) val init: ?noop:_ -> (unit -> unit) options_fun (** Like [init], but returns the given value. For optional argument stacking *) val initk: 'a -> 'a options_fun (** Automatic answering levels * [`ask]: prompt and ask user * [`no]: answer no to all opam questions * [`yes]: answer yes to all opam questions * [`unsafe_yes]: answer yes to all opam question and launch system package command wit non interactive options If confirm-level is set (from cli or environment variable), its value is returned. Otherwise, is takes last yes/no cli flag. For environment variables, if [OPAMYES] is set to true, it has priority over [OPAMNO]. As other environment variables, cli flags content is taken if given. [answer_is] and [answer_is_yes] computes the answer lazily, use [answer] in case of config update. *) val answer_is: OpamStd.Config.answer -> bool val answer_is_yes : unit -> bool val answer: unit -> OpamStd.Config.answer (** [true] if OPAM was compiled in developer mode *) val developer : bool opam-2.1.5/src/core/opamSystem.mli0000644000175000017500000003321714427463453016110 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Bindings of lots of filesystem and system operations *) (** Exception raised when subprocess fails *) exception Process_error of OpamProcess.result exception Command_not_found of string exception Permission_denied of string (** raise [Process_error] *) val process_error: OpamProcess.result -> 'a (** raise [Process_error] if the process didn't return 0 *) val raise_on_process_error: OpamProcess.result -> unit (** Exception raised when a computation in the current process fails. *) exception Internal_error of string (** Raise [Internal_error] *) val internal_error: ('a, unit, string, 'b) format4 -> 'a (** [with_tmp_dir fn] executes [fn] creates a temporary directory and passes its name to [fn]. The directory is alwasy removed on completion. *) val with_tmp_dir: (string -> 'a) -> 'a (** [in_tmp_dir fn] executes [fn] in a temporary directory. *) val in_tmp_dir: (unit -> 'a) -> 'a (** Runs a job with a temp dir that is cleaned up afterwards *) val with_tmp_dir_job: (string -> 'a OpamProcess.job) -> 'a OpamProcess.job (** Returns true if the default verbose level for base commands (cp, mv, etc.) is reached *) val verbose_for_base_commands: unit -> bool (** {2 Filesystem management} *) (** Returns a directory name, in the temporary directory, composed by {i opam} (if [prefix] is not set), pid, and random number. *) val mk_temp_dir: ?prefix:string -> unit -> string (** [copy_file src dst] copies [src] to [dst]. Remove [dst] before the copy if it is a link. *) val copy_file: string -> string -> unit (** [copy_dir src dst] copies the contents of directory [src] into directory [dst], creating it if necessary, merging directory contents and ovewriting files otherwise *) val copy_dir: string -> string -> unit val mv: string -> string -> unit type install_warning = [ `Add_exe (* [.exe] had to be added *) | `Install_dll (* Installation of [.dll] to bin/libexec *) | `Install_script (* Installation of script on Windows *) | `Install_unknown (* Installation of unknown file to bin/libexec *) | `Cygwin (* Installation of a Cygwin-linked executable *) | `Cygwin_libraries (* Installation of a binary linked to a Cygwin library *) ] (** Warnings which come from {!install} *) type install_warning_fn = string -> install_warning -> unit val default_install_warning : install_warning_fn (** The default warning function - displays a message on OpamConsole *) (** [install ?exec src dst] copies file [src] as file [dst] using [install]. If [exec], make the resulting file executable (otherwise, look at the permissions of the original file to decide). *) val install: ?warning:install_warning_fn -> ?exec:bool -> string -> string -> unit (** Checks if a file is an executable (regular file with execution permission) *) val is_exec: string -> bool val file_is_empty: string -> bool (** [link src dst] links [src] to [dst]. Remove [dst] if it is a file, not a directory. *) val link: string -> string -> unit (** [real_path p] returns the real path associated to [p]: [..] are expanded and relative paths become absolute. *) val real_path: string -> string (** Return the contents of a channel. *) val string_of_channel: in_channel -> string (** Raised when a file or directory can't be accessed (doesn't exist, bad permissions, etc.) *) exception File_not_found of string (** [read filename] returns the contents of [filename] (while taking an advisory read lock to prevent concurrent writes) *) val read: string -> string (** [write filename contents] write [contents] to [filename] (while taking an advisory write lock to prevent concurrent reads or writes) *) val write: string -> string -> unit (** [remove filename] removes [filename]. Works whether [filename] is a file or a directory *) val remove: string -> unit (** [remove_file filename] removes [filename]. Works only for normal files (or also at least for symlinks) *) val remove_file: string -> unit (** [remove_dir filename] removes [filename]. Works only for directory (not for symlinks or other files). *) val remove_dir: string -> unit (** Change the current working directory *) val chdir: string -> unit (** [in_dir dir fn] evaluates [fn] in the directory [dir] *) val in_dir: string -> (unit -> 'a) -> 'a (** Returns the list of files and directories in the given directory (full names) *) val ls: string -> string list (** [files_with_links dir] returns the files in the directory [dir]. Links simulating directory are ignored, others links are returned. *) val files_with_links: string -> string list (** [rec_files dir] returns the list of all files in [dir], recursively. Links behaving like directory are crossed. *) val rec_files: string -> string list (** Return the list of files in the current directory. *) val files: string -> string list (** Return the list of files in the current directory, inclduing any dangling symlinks. *) val files_all_not_dir: string -> string list (** [rec_dirs dir] return the list list of all directories recursively (going through symbolink links). *) val rec_dirs: string -> string list (** Return the list of directories in the current directory. *) val dirs: string -> string list val dir_is_empty: string -> bool (** [directories_with_links dir] returns the directories in the directory [dir]. Links pointing to directory are also returned. *) val directories_with_links: string -> string list (** Make a comman suitable for OpamProcess.Job. if [verbose], is set, command and output will be displayed (at command end for the latter, if concurrent commands are running). [name] is used for naming log files. [text] is what is displayed in the status line for this command. May raise Command_not_found, unless [resolve_path] is set to false (in which case you can end up with a process error instead) *) val make_command: ?verbose:bool -> ?env:string array -> ?name:string -> ?text:string -> ?metadata:(string * string) list -> ?allow_stdin:bool -> ?stdout:string -> ?dir:string -> ?resolve_path:bool -> string -> string list -> OpamProcess.command (** OLD COMMAND API, DEPRECATED *) (** a command is a list of words *) type command = string list (** Test whether a command exists in the environment, and returns it (resolved if found in PATH) *) val resolve_command: ?env:string array -> ?dir:string -> string -> string option (** Returns a function which should be applied to arguments for a given command by determining if the command is the Cygwin variant of the command. Returns the identity function otherwise. *) val get_cygpath_function: command:string -> (string -> string) lazy_t (** [command cmd] executes the command [cmd] in the correct OPAM environment. *) val command: ?verbose:bool -> ?env:string array -> ?name:string -> ?metadata:(string * string) list -> ?allow_stdin:bool -> command -> unit (** [commands cmds] executes the commands [cmds] in the correct OPAM environment. It stops whenever one command fails unless [keep_going] is set to [true]. In this case, the first error is re-raised at the end. *) val commands: ?verbose:bool -> ?env:string array -> ?name:string -> ?metadata:(string * string) list -> ?keep_going:bool -> command list -> unit (** [read_command_output cmd] executes the command [cmd] in the correct OPAM environment and return the lines from stdout if the command exists normally. If the command does not exist or if the command exited with a non-empty exit-code, throw an error. *) val read_command_output: ?verbose:bool -> ?env:string array -> ?metadata:(string * string) list -> ?allow_stdin:bool -> command -> string list (** END *) (** Test whether the file is an archive, by looking as its extension *) val is_archive: string -> bool (** [extract ~dir:dirname filename] extracts the archive [filename] into [dirname]. [dirname] should not exists and [filename] should contain only one top-level directory.*) val extract: dir:string -> string -> unit (** Same as [extract], but as an OpamProcess.job *) val extract_job: dir:string -> string -> exn option OpamProcess.job (** [extract_in ~dir:dirname filename] extracts the archive [filename] into [dirname]. *) val extract_in: dir:string -> string -> unit (** [extract_in_job] is similar to [extract_in], but as a job *) val extract_in_job: dir:string -> string -> exn option OpamProcess.job val make_tar_gz_job: dir:string -> string -> exn option OpamProcess.job (** Create a directory. Do not fail if the directory already exist. *) val mkdir: string -> unit (** Get the number of active processors on the system *) val cpu_count: unit -> int (** {2 File locking function} *) (** Unix file locks (mutable structure, to follow actual semantics) *) type lock (** The different kinds of unix advisory locks available (`Lock_none doesn't actually lock anything, or even create the lock file) *) type actual_lock_flag = [ `Lock_read | `Lock_write ] type lock_flag = [ `Lock_none | actual_lock_flag ] (** Dummy lock *) val lock_none: lock (** Raised when locks can't be acquired and [dontblock] was specified) *) exception Locked (** Force releases all open locks in the process. Required for Windows if an exception has been raised, since Windows doesn't permit unlinking while handles are open. *) val release_all_locks: unit -> unit (** Acquires a lock on the given file. Raises [Locked] if the lock can't be acquired and [dontblock] is set. Raises [OpamStd.Sys.Exit] if [safe_mode] is set and a write lock is required. Also raises Unix errors if the lock file can't be opened. *) val flock: [< lock_flag ] -> ?dontblock:bool -> string -> lock (** Updates an existing lock to the given level. Raises the same exceptions as [flock]. *) val flock_update: [< lock_flag ] -> ?dontblock:bool -> lock -> unit (** Releases an acquired lock (equivalent to [flock_update `Lock_none]) *) val funlock: lock -> unit (** Returns the highest of the two lock flags (with the order no lock < read lock < write lock) *) val lock_max: lock_flag -> lock_flag -> lock_flag (** Returns true if the lock already has the lock_flag rights or more *) val lock_isatleast: [< lock_flag ] -> lock -> bool (** Returns the current kind of the lock *) val get_lock_flag: lock -> lock_flag (** Returns the underlying fd for the lock or raises Not_found for `No_lock *) val get_lock_fd: lock -> Unix.file_descr (** {2 Misc} *) (** Apply a patch file in the current directory. If [preprocess] is set to false, there is no CRLF translation. Returns the error if the patch didn't apply. *) val patch: ?preprocess:bool -> dir:string -> string -> exn option OpamProcess.job (** Returns the end-of-line encoding style for the given file. [None] means that either the encoding of line endings is mixed, or the file contains no line endings at all (an empty file, or a file with one line and no EOL at EOF). Otherwise it returns [Some true] if all endings are encoded CRLF. *) val get_eol_encoding : string -> bool option (** [translate_patch ~dir input_patch output_patch] writes a copy of [input_patch] to [output_patch] as though [input_patch] had been applied in [dir]. The patch is rewritten such that if text files have different line endings then the patch is transformed to patch using the encoding on disk. In particular, this means that patches generated against Unix checkouts of Git sources will correctly apply to Windows checkouts of the same sources. *) val translate_patch: dir:string -> string -> string -> unit (** Create a temporary file in {i ~/.opam/logs/XXX}, if [dir] is not set. ?auto_clean controls whether the file is automatically deleted when opam terminates (default: [true]). *) val temp_file: ?auto_clean:bool -> ?dir:string -> string -> string (** Print stats *) val print_stats: unit -> unit (** Registers an exception printer that adds some OPAM version info, and details on process and Unix errors *) val register_printer: unit -> unit (** Initialises signal handlers, catch_break and some exception printers. The lib may not perform properly without this if [Sys.catch_break] isn't set and SIGPIPE isn't handled (with a no-op) *) val init: unit -> unit (** On Unix, a no-op. On Windows, convert / to \ *) val forward_to_back : string -> string (** On Unix, a no-op. On Windows, convert \ to / *) val back_to_forward : string -> string (** Identifies kinds of executable files. At present, only useful on Windows. Executable or DLLs are recognised based on their content, not on their filename. Any file beginning "#!" is assumed to be a shell script and all files are classified [`Unknown]. *) val classify_executable : string -> [ `Exe of [ `i386 | `x86 | `x86_64 ] | `Dll of [ `x86 | `x86_64 ] | `Script | `Unknown ] opam-2.1.5/src/core/opamSHA.ml0000644000175000017500000003311014427463453015056 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2016-2018 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) module type ConvSig = sig type t val bytes: int val toggle_big_endian: t -> t end module type BufSig = sig module Conv: ConvSig type t val unsafe_get: t -> int -> Conv.t val unsafe_set: t -> int -> Conv.t -> unit end module type InputSig = sig type src type t type chunk type elt val init: blocksize:int -> src -> t val close: t -> unit val byte_size: t -> int (** padded with 0, getting chunks after the end of input is allowed *) val get_chunk: t -> int -> chunk val get: chunk -> int -> elt (** only allowed after the end of input *) val set: chunk -> int -> elt -> unit (** only allowed after the end of input*) val set_byte: chunk -> int -> char -> unit end module Conv32 = struct type t = int32 let bytes = 4 external swap: t -> t = "%bswap_int32" let toggle_big_endian = if Sys.big_endian then fun x -> x else swap end module Conv64 = struct type t = int64 let bytes = 8 external swap: t -> t = "%bswap_int64" let toggle_big_endian = if Sys.big_endian then fun x -> x else swap end module B = Bigarray module A = B.Array1 type bigstring = (char, B.int8_unsigned_elt, B.c_layout) A.t module Buf_Bigstring32 = struct module Conv = Conv32 type t = bigstring external unsafe_get: t -> int -> Conv.t = "%caml_bigstring_get32u" external unsafe_set: t -> int -> Conv.t -> unit = "%caml_bigstring_set32u" end module Buf_Bigstring64 = struct module Conv = Conv64 type t = bigstring external unsafe_get: t -> int -> Conv.t = "%caml_bigstring_get64u" external unsafe_set: t -> int -> Conv.t -> unit = "%caml_bigstring_set64u" end module Buf_String32 = struct module Conv = Conv32 type t = Bytes.t external unsafe_get: t -> int -> Conv.t = "%caml_string_get32u" external unsafe_set: t -> int -> Conv.t -> unit = "%caml_string_set32u" end module Buf_String64 = struct module Conv = Conv64 type t = Bytes.t external unsafe_get: t -> int -> Conv.t = "%caml_string_get64u" external unsafe_set: t -> int -> Conv.t -> unit = "%caml_string_set64u" end module Input_file(Buf: BufSig with type t = bigstring) = struct type src = string (* filename *) type t = { fd: Unix.file_descr; blocksize: int; buf: Buf.t; } type chunk = Buf.t type elt = Buf.Conv.t let init ~blocksize src = let fd = Unix.openfile src [Unix.O_RDONLY] 0 in let buf = B.(array1_of_genarray (OpamCompat.Unix.map_file fd B.char c_layout false [|-1|])) in { fd; blocksize; buf } let close {fd; _} = Unix.close fd let byte_size {buf; _} = A.dim buf let get_chunk {blocksize; buf; _} i = let len = A.dim buf in let block_bytes = blocksize * Buf.Conv.bytes in if (i + 1) * block_bytes <= len then A.sub buf (i * block_bytes) (block_bytes) else let ba = A.create B.char B.c_layout (block_bytes) in A.fill ba '\x00'; if i * block_bytes < len then A.blit (A.sub buf (i * block_bytes) (len mod block_bytes)) (A.sub ba 0 (len mod block_bytes)); ba let get chunk i = Buf.Conv.toggle_big_endian (Buf.unsafe_get chunk (i * Buf.Conv.bytes)) let set chunk i x = Buf.unsafe_set chunk (i * Buf.Conv.bytes) (Buf.Conv.toggle_big_endian x) let set_byte chunk i c = A.unsafe_set chunk i c end module Input_string(Buf: BufSig with type t = Bytes.t) = struct type src = Bytes.t type t = { blocksize: int; buf: Bytes.t; } type chunk = { offset: int; b: Bytes.t; } type elt = Buf.Conv.t let init ~blocksize buf = { blocksize; buf } let close _ = () let byte_size {buf; _} = Bytes.length buf let get_chunk {blocksize; buf} i = let len = Bytes.length buf in let block_bytes = blocksize * Buf.Conv.bytes in if (i + 1) * block_bytes <= len then { offset = i * block_bytes; b = buf } else let b = Bytes.make block_bytes '\x00' in if i * block_bytes < len then Bytes.blit buf (i * block_bytes) b 0 (len mod block_bytes); { offset = 0; b } let get {offset; b} i = Buf.Conv.toggle_big_endian (Buf.unsafe_get b (offset + i * Buf.Conv.bytes)) let set {offset; b} i x = Buf.unsafe_set b (offset + i * Buf.Conv.bytes) (Buf.Conv.toggle_big_endian x) let set_byte {offset; b} i c = Bytes.unsafe_set b (offset + i) c end module Make_SHA256(I: InputSig with type elt = int32) = struct open Int32 let k = [| 0x428a2f98l; 0x71374491l; 0xb5c0fbcfl; 0xe9b5dba5l; 0x3956c25bl; 0x59f111f1l; 0x923f82a4l; 0xab1c5ed5l; 0xd807aa98l; 0x12835b01l; 0x243185bel; 0x550c7dc3l; 0x72be5d74l; 0x80deb1fel; 0x9bdc06a7l; 0xc19bf174l; 0xe49b69c1l; 0xefbe4786l; 0x0fc19dc6l; 0x240ca1ccl; 0x2de92c6fl; 0x4a7484aal; 0x5cb0a9dcl; 0x76f988dal; 0x983e5152l; 0xa831c66dl; 0xb00327c8l; 0xbf597fc7l; 0xc6e00bf3l; 0xd5a79147l; 0x06ca6351l; 0x14292967l; 0x27b70a85l; 0x2e1b2138l; 0x4d2c6dfcl; 0x53380d13l; 0x650a7354l; 0x766a0abbl; 0x81c2c92el; 0x92722c85l; 0xa2bfe8a1l; 0xa81a664bl; 0xc24b8b70l; 0xc76c51a3l; 0xd192e819l; 0xd6990624l; 0xf40e3585l; 0x106aa070l; 0x19a4c116l; 0x1e376c08l; 0x2748774cl; 0x34b0bcb5l; 0x391c0cb3l; 0x4ed8aa4al; 0x5b9cca4fl; 0x682e6ff3l; 0x748f82eel; 0x78a5636fl; 0x84c87814l; 0x8cc70208l; 0x90befffal; 0xa4506cebl; 0xbef9a3f7l; 0xc67178f2l; |] let ch x y z = logxor (logand x y) (logand (lognot x) z) let maj x y z = logxor (logand x y) (logxor (logand x z) (logand y z)) let sum0 x = logxor (logor (shift_right_logical x 2) (shift_left x (32 - 2))) (logxor (logor (shift_right_logical x 13) (shift_left x (32 - 13))) (logor (shift_right_logical x 22) (shift_left x (32 - 22)))) let sum1 x = logxor (logor (shift_right_logical x 6) (shift_left x (32 - 6))) (logxor (logor (shift_right_logical x 11) (shift_left x (32 - 11))) (logor (shift_right_logical x 25) (shift_left x (32 - 25)))) let lsig0 x = logxor (logor (shift_right_logical x 7) (shift_left x (32 - 7))) (logxor (logor (shift_right_logical x 18) (shift_left x (32 - 18))) (logor (shift_right_logical x 3) (shift_right_logical x 3))) let lsig1 x = logxor (logor (shift_right_logical x 17) (shift_left x (32 - 17))) (logxor (logor (shift_right_logical x 19) (shift_left x (32 - 19))) (logor (shift_right_logical x 10) (shift_right_logical x 10))) let sha_init = ( 0x6a09e667l, 0xbb67ae85l, 0x3c6ef372l, 0xa54ff53al, 0x510e527fl, 0x9b05688cl, 0x1f83d9abl, 0x5be0cd19l ) let hash_block = let warr = Array.make 64 0l in fun hh block -> for t = 0 to 15 do warr.(t) <- I.get block t done; for t = 16 to 63 do warr.(t) <- add (add (lsig1 warr.(t - 2)) warr.(t - 7)) (add (lsig0 warr.(t - 15)) warr.(t - 16)) done; let rec stir t (a, b, c, d, e, f, g, h) = if t >= 64 then let a', b', c', d', e', f', g', h' = hh in add a a', add b b', add c c', add d d', add e e', add f f', add g g', add h h' else let t1 = add (add h (sum1 e)) (add (add (ch e f g) k.(t)) warr.(t)) in let t2 = add (sum0 a) (maj a b c) in stir (t + 1) (add t1 t2, a, b, c, add d t1, e, f, g) in stir 0 hh let blocksize = 16 let hash src = let bs = I.init ~blocksize src in let nbytes = I.byte_size bs in let blocks = nbytes / (blocksize * 4) in let rem = nbytes mod (blocksize * 4) in let h = ref sha_init in for i = 0 to blocks - 1 do h := hash_block !h (I.get_chunk bs i) done; let lastblock = I.get_chunk bs blocks in I.set_byte lastblock rem '\x80'; let lastblock = if rem <= 55 then lastblock else (h := hash_block !h lastblock; I.get_chunk bs (blocks + 1)) in let bitsz = Int64.mul 8L (Int64.of_int nbytes) in I.set lastblock 14 Int64.(to_int32 (shift_right_logical bitsz 32)); I.set lastblock 15 Int64.(to_int32 (logand 0xffffffffL bitsz)); let (a, b, c, d, e, f, g, h) = hash_block !h lastblock in I.close bs; Printf.sprintf "%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx" a b c d e f g h end module Make_SHA512(I: InputSig with type elt = int64) = struct open Int64 let k = [| 0x428a2f98d728ae22L; 0x7137449123ef65cdL; 0xb5c0fbcfec4d3b2fL; 0xe9b5dba58189dbbcL; 0x3956c25bf348b538L; 0x59f111f1b605d019L; 0x923f82a4af194f9bL; 0xab1c5ed5da6d8118L; 0xd807aa98a3030242L; 0x12835b0145706fbeL; 0x243185be4ee4b28cL; 0x550c7dc3d5ffb4e2L; 0x72be5d74f27b896fL; 0x80deb1fe3b1696b1L; 0x9bdc06a725c71235L; 0xc19bf174cf692694L; 0xe49b69c19ef14ad2L; 0xefbe4786384f25e3L; 0x0fc19dc68b8cd5b5L; 0x240ca1cc77ac9c65L; 0x2de92c6f592b0275L; 0x4a7484aa6ea6e483L; 0x5cb0a9dcbd41fbd4L; 0x76f988da831153b5L; 0x983e5152ee66dfabL; 0xa831c66d2db43210L; 0xb00327c898fb213fL; 0xbf597fc7beef0ee4L; 0xc6e00bf33da88fc2L; 0xd5a79147930aa725L; 0x06ca6351e003826fL; 0x142929670a0e6e70L; 0x27b70a8546d22ffcL; 0x2e1b21385c26c926L; 0x4d2c6dfc5ac42aedL; 0x53380d139d95b3dfL; 0x650a73548baf63deL; 0x766a0abb3c77b2a8L; 0x81c2c92e47edaee6L; 0x92722c851482353bL; 0xa2bfe8a14cf10364L; 0xa81a664bbc423001L; 0xc24b8b70d0f89791L; 0xc76c51a30654be30L; 0xd192e819d6ef5218L; 0xd69906245565a910L; 0xf40e35855771202aL; 0x106aa07032bbd1b8L; 0x19a4c116b8d2d0c8L; 0x1e376c085141ab53L; 0x2748774cdf8eeb99L; 0x34b0bcb5e19b48a8L; 0x391c0cb3c5c95a63L; 0x4ed8aa4ae3418acbL; 0x5b9cca4f7763e373L; 0x682e6ff3d6b2b8a3L; 0x748f82ee5defb2fcL; 0x78a5636f43172f60L; 0x84c87814a1f0ab72L; 0x8cc702081a6439ecL; 0x90befffa23631e28L; 0xa4506cebde82bde9L; 0xbef9a3f7b2c67915L; 0xc67178f2e372532bL; 0xca273eceea26619cL; 0xd186b8c721c0c207L; 0xeada7dd6cde0eb1eL; 0xf57d4f7fee6ed178L; 0x06f067aa72176fbaL; 0x0a637dc5a2c898a6L; 0x113f9804bef90daeL; 0x1b710b35131c471bL; 0x28db77f523047d84L; 0x32caab7b40c72493L; 0x3c9ebe0a15c9bebcL; 0x431d67c49c100d4cL; 0x4cc5d4becb3e42b6L; 0x597f299cfc657e2aL; 0x5fcb6fab3ad6faecL; 0x6c44198c4a475817L; |] let rotate x n = logor (shift_right_logical x n) (shift_left x (64 - n)) let ch x y z = logxor (logand x y) (logand (lognot x) z) let maj x y z = logxor (logand x y) (logxor (logand x z) (logand y z)) let sum0 x = logxor (rotate x 28) (logxor (rotate x 34) (rotate x 39)) let sum1 x = logxor (rotate x 14) (logxor (rotate x 18) (rotate x 41)) let lsig0 x = logxor (rotate x 1) (logxor (rotate x 8) (shift_right_logical x 7)) let lsig1 x = logxor (rotate x 19) (logxor (rotate x 61) (shift_right_logical x 6)) let sha_init = ( 0x6a09e667f3bcc908L, 0xbb67ae8584caa73bL, 0x3c6ef372fe94f82bL, 0xa54ff53a5f1d36f1L, 0x510e527fade682d1L, 0x9b05688c2b3e6c1fL, 0x1f83d9abfb41bd6bL, 0x5be0cd19137e2179L ) let hash_block = let warr = Array.make 80 0L in fun hh block -> for t = 0 to 15 do warr.(t) <- I.get block t done; for t = 16 to 79 do warr.(t) <- add (add (lsig1 warr.(t - 2)) warr.(t - 7)) (add (lsig0 warr.(t - 15)) warr.(t - 16)) done; let rec stir t (a, b, c, d, e, f, g, h) = if t >= 80 then let a', b', c', d', e', f', g', h' = hh in add a a', add b b', add c c', add d d', add e e', add f f', add g g', add h h' else let t1 = add (add h (sum1 e)) (add (add (ch e f g) k.(t)) warr.(t)) in let t2 = add (sum0 a) (maj a b c) in stir (t + 1) (add t1 t2, a, b, c, add d t1, e, f, g) in stir 0 hh let blocksize = 16 let hash src = let bs = I.init ~blocksize src in let nbytes = I.byte_size bs in let blocks = nbytes / (blocksize * 8) in let rem = nbytes mod (blocksize * 8) in let h = ref sha_init in for i = 0 to blocks - 1 do h := hash_block !h (I.get_chunk bs i) done; let lastblock = I.get_chunk bs blocks in I.set_byte lastblock rem '\x80'; let lastblock = if rem <= 111 then lastblock else (h := hash_block !h lastblock; I.get_chunk bs (blocks+1)) in (* We assume sz fits in 61 bits... *) let bitsz = Int64.mul 8L (Int64.of_int nbytes) in I.set lastblock 15 bitsz; let (a, b, c, d, e, f, g, h) = hash_block !h lastblock in I.close bs; Printf.sprintf "%016Lx%016Lx%016Lx%016Lx%016Lx%016Lx%016Lx%016Lx" a b c d e f g h end module SHA256_file = Make_SHA256 (Input_file(Buf_Bigstring32)) module SHA512_file = Make_SHA512 (Input_file(Buf_Bigstring64)) module SHA256_string = Make_SHA256 (Input_string(Buf_String32)) module SHA512_string = Make_SHA512 (Input_string(Buf_String64)) let sha256_file = SHA256_file.hash let sha512_file = SHA512_file.hash let hash_file = function | `SHA256 -> sha256_file | `SHA512 -> sha512_file let sha256_bytes = SHA256_string.hash let sha512_bytes = SHA512_string.hash let hash_bytes = function | `SHA256 -> sha256_bytes | `SHA512 -> sha512_bytes let sha256 = sha256_file let sha512 = sha512_file let hash = hash_file opam-2.1.5/src/core/opamStd.mli0000644000175000017500000005043714427463453015361 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2020 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Generic stdlib functions (String, List, Option, Sys submodules...) *) (** {2 Signatures and functors} *) (** Sets with extended interface and infix operators *) module type SET = sig include Set.S val map: (elt -> elt) -> t -> t val is_singleton: t -> bool (** Returns one element, assuming the set is a singleton. Raises [Not_found] on an empty set, [Failure] on a non-singleton. *) val choose_one : t -> elt val choose_opt: t -> elt option val of_list: elt list -> t val to_string: t -> string val to_json: t -> OpamJson.t val of_json: OpamJson.t -> t option val find: (elt -> bool) -> t -> elt val find_opt: (elt -> bool) -> t -> elt option (** Raises Failure in case the element is already present *) val safe_add: elt -> t -> t (** Accumulates the resulting sets of a function of elements until a fixpoint is reached *) val fixpoint: (elt -> t) -> t -> t (** [map_reduce f op t] applies [f] to every element of [t] and combines the results using associative operator [op]. Raises [Invalid_argument] on an empty set, or returns [default] if it is defined. *) val map_reduce: ?default:'a -> (elt -> 'a) -> ('a -> 'a -> 'a) -> t -> 'a module Op : sig val (++): t -> t -> t (** Infix set union *) val (--): t -> t -> t (** Infix set difference *) val (%%): t -> t -> t (** Infix set intersection *) end end (** Maps with extended interface *) module type MAP = sig include Map.S val to_string: ('a -> string) -> 'a t -> string val to_json: ('a -> OpamJson.t) -> 'a t -> OpamJson.t val of_json: (OpamJson.t -> 'a option) -> OpamJson.t -> 'a t option val keys: 'a t -> key list val values: 'a t -> 'a list val find_opt: key -> 'a t -> 'a option val choose_opt: 'a t -> (key * 'a) option (** A key will be in the union of [m1] and [m2] if it is appears either [m1] or [m2], with the corresponding value. If a key appears in both [m1] and [m2], then the resulting value is built using the function given as argument. *) val union: ('a -> 'a -> 'a) -> 'a t -> 'a t -> 'a t val is_singleton: 'a t -> bool val of_list: (key * 'a) list -> 'a t (** Raises Failure in case the element is already present *) val safe_add: key -> 'a -> 'a t -> 'a t (** [update k f zero map] updates the binding of [k] in [map] using function [f], applied to the current value bound to [k] or [zero] if none *) val update: key -> ('a -> 'a) -> 'a -> 'a t -> 'a t (** [map_reduce f op t] applies [f] to every binding of [t] and combines the results using associative operator [op]. Raises [Invalid_argument] on an empty map, or returns [default] if it is defined. *) val map_reduce: ?default:'b -> (key -> 'a -> 'b) -> ('b -> 'b -> 'b) -> 'a t -> 'b end (** A signature for handling abstract keys and collections thereof *) module type ABSTRACT = sig type t val of_string: string -> t val to_string: t -> string val to_json: t -> OpamJson.t val of_json: OpamJson.t -> t option module Set: SET with type elt = t module Map: MAP with type key = t end (** A basic implementation of ABSTRACT using strings *) module AbstractString : ABSTRACT with type t = string (** {3 Generators for set and map modules with printers} *) module type OrderedType = sig include Set.OrderedType val to_string: t -> string val to_json: t -> OpamJson.t val of_json: OpamJson.t -> t option end module Set: sig module Make (S: OrderedType): SET with type elt = S.t end module Map: sig module Make (S: OrderedType): MAP with type key = S.t end (** {2 Integer collections} *) (** Map of ints *) module IntMap: MAP with type key = int (** Set of ints *) module IntSet: SET with type elt = int (** {2 Utility modules extending the standard library on base types} *) module Option: sig val map: ('a -> 'b) -> 'a option -> 'b option val iter: ('a -> unit) -> 'a option -> unit val default: 'a -> 'a option -> 'a val default_map: 'a option -> 'a option -> 'a option val replace : ('a -> 'b option) -> 'a option -> 'b option val map_default: ('a -> 'b) -> 'b -> 'a option -> 'b val compare: ('a -> 'a -> int) -> 'a option -> 'a option -> int val to_string: ?none:string -> ('a -> string) -> 'a option -> string val to_list: 'a option -> 'a list val some: 'a -> 'a option val none: 'a -> 'b option (** [of_Not_found f x] calls [f x], catches [Not_found] and returns [None] *) val of_Not_found: ('a -> 'b) -> 'a -> 'b option module Op: sig val (>>=): 'a option -> ('a -> 'b option) -> 'b option val (>>|): 'a option -> ('a -> 'b) -> 'b option val (>>+): 'a option -> (unit -> 'a option) -> 'a option val (+!): 'a option -> 'a -> 'a val (++): 'a option -> 'a option -> 'a option end end module List : sig val cons: 'a -> 'a list -> 'a list (** Convert list items to string and concat. [sconcat_map sep f x] is equivalent to String.concat sep (List.map f x) but tail-rec. *) val concat_map: ?left:string -> ?right:string -> ?nil:string -> ?last_sep:string -> string -> ('a -> string) -> 'a list -> string (** Like [List.find], but returning option instead of raising *) val find_opt: ('a -> bool) -> 'a list -> 'a option val to_string: ('a -> string) -> 'a list -> string (** Removes consecutive duplicates in a list *) val remove_duplicates: 'a list -> 'a list (** Sorts the list, removing duplicates *) val sort_nodup: ('a -> 'a -> int) -> 'a list -> 'a list (** Filter and map *) val filter_map: ('a -> 'b option) -> 'a list -> 'b list (** Retrieves [Some] values from a list *) val filter_some: 'a option list -> 'a list (** Returns the first non-[None] value returned by the passed function on the elements of the passed list. @raise Not_found if all of them yield [None] *) val find_map: ('a -> 'b option) -> 'a list -> 'b (** Insert a value in an ordered list *) val insert: ('a -> 'a -> int) -> 'a -> 'a list -> 'a list (** Inserts a value at the given index (starting from 0) in the list (start or end if index < 0 or > length respectively). Not tail-recursive *) val insert_at: int -> 'a -> 'a list -> 'a list (** Like [List.find], but returning option instead of raising *) val assoc_opt: 'a -> ('a * 'b) list -> 'b option (** Like [List.assoc], but as an option, and also returns the list with the binding removed, e.g. equivalent to [(List.assoc_opt x l, List.remove_assoc x l)] (but tail-recursive and more efficient) *) val pick_assoc: 'a -> ('a * 'b) list -> 'b option * ('a * 'b) list (** [update_assoc key value list] updates the first value bound to [key] in the associative list [list], or appends [(key, value)] if the key is not bound. *) val update_assoc: 'a -> 'b -> ('a * 'b) list -> ('a * 'b) list end module String : sig (** {3 Collections} *) module Map: MAP with type key = string module Set: SET with type elt = string (** Set of string sets *) module SetSet: SET with type elt = Set.t (** Map of string sets *) module SetMap: MAP with type key = Set.t (** {3 Checks} *) val starts_with: prefix:string -> string -> bool val ends_with: suffix:string -> string -> bool val contains_char: string -> char -> bool val contains: sub:string -> string -> bool val exact_match: Re.re -> string -> bool val find_from: (char -> bool) -> string -> int -> int (** Like [String.compare], but with lowercase/uppercase variants ordered next to each other (still considered not equal though) *) val compare_case: string -> string -> int (** {3 Manipulation} *) val map: (char -> char) -> string -> string val strip: string -> string val strip_right: string -> string val sub_at: int -> string -> string val remove_prefix: prefix:string -> string -> string val remove_suffix: suffix:string -> string -> string (** [is_prefix_of from full str] returns true if [str] if a prefix of [full], with at least [from] first characters *) val is_prefix_of: from:int -> full:string -> string -> bool (** {4 Transformations} *) (** Cut a string at the first occurrence of the given char *) val cut_at: string -> char -> (string * string) option (** Same as [cut_at], but starts from the right *) val rcut_at: string -> char -> (string * string) option (** Split a string at occurrences of a given characters. Empty strings are skipped. *) val split: string -> char -> string list (** The same as [split], but keep empty strings (leading, trailing or between contiguous delimiters) *) val split_delim: string -> char -> string list val fold_left: ('a -> char -> 'a) -> 'a -> string -> 'a end module Format : sig (** {4 Querying information} *) (** Returns the length of the string in terminal chars, ignoring ANSI color sequences from OpamConsole.colorise *) val visual_length: string -> int (** {4 Text formatting functions} *) (** Truncates the string to not visually get over [width] columns *) val cut_at_visual: string -> int -> string (** left indenting. [~visual] can be used to indent eg. ANSI colored strings and should correspond to the visible characters of s *) val indent_left: string -> ?visual:string -> int -> string val indent_right: string -> ?visual:string -> int -> string (** Pads fields in a table with spaces for alignment. *) val align_table: string list list -> string list list (** Cut long lines in string according to the terminal width *) val reformat: ?start_column:int -> ?indent:int -> ?width:int -> string -> string (** Convert a list of items to string as a dashed list (already reformats supposes no additional left margin: don't use within OpamConsole.error or similar) *) val itemize: ?bullet:string -> ('a -> string) -> 'a list -> string (** Display a pretty list: ["x";"y";"z"] -> "x, y and z". "and" can be changed by specifying [last] *) val pretty_list: ?last:string -> string list -> string (** Splits a list of strings so that it can be printed as a table that should fit on screen *) val as_aligned_table: ?width:int -> string list -> string list list end module Exn : sig (** To use when catching default exceptions: ensures we don't catch fatal errors like C-c. try-with should _always_ (by decreasing order of preference): - either catch specific exceptions - or re-raise the same exception (preferably with [Exn.finalise]) - or call this function on the caught exception *) val fatal: exn -> unit (** Register a backtrace for when you need to process a finalizer (that internally uses exceptions) and then re-raise the same exception. To be printed by pretty_backtrace. *) val register_backtrace: exn -> unit (** Return a pretty-printed backtrace *) val pretty_backtrace: exn -> string (** Runs the given finaliser, then reraises the given exception, while preserving backtraces (when the OCaml version permits, e.g. >= 4.05.0) *) val finalise: exn -> (unit -> unit) -> 'a (** Execute the given continuation, then run the finaliser before returning the result. If an exception is raised, call [finalise] with the given finaliser. *) val finally: (unit -> unit) -> (unit -> 'a) -> 'a end (** {2 Manipulation and query of environment variables} *) module Env : sig (** Remove from a c-separated list of string the ones with the given prefix *) val reset_value: prefix:string -> char -> string -> string list (** split a c-separated list of string in two according to the first occurrences of the string with the given [prefix]. The list of elements occurring before is returned in reverse order. If there are other elements with the same [prefix] they are kept in the second list. *) val cut_value: prefix:string -> char -> string -> string list * string list val get: string -> string val getopt: string -> string option val list: unit -> (string * string) list (** Utility function for shell single-quoted strings. In most shells, backslash escapes are not allowed and a single quote needs to be replaced by [quote double-quote quote double-quote quote] (close the single-quoted literal, put the single quote in a double-quoted literal, and reopen a single-quoted literal). fish is the exception and should set [using_backslashes] to escape both quotes and backslashes using backslashes *) val escape_single_quotes: ?using_backslashes:bool -> string -> string end (** {2 System query and exit handling} *) module Sys : sig (** {3 Querying} *) (** true if stdout is bound to a terminal *) val tty_out : bool (** true if stdin is bound to a terminal *) val tty_in : bool (** Queried lazily, but may change on SIGWINCH *) val terminal_columns : unit -> int (** The user's home directory. Queried lazily *) val home: unit -> string (** The /etc directory *) val etc: unit -> string (** The system directory (Windows only) *) val system: unit -> string type os = Darwin | Linux | FreeBSD | OpenBSD | NetBSD | DragonFly | Cygwin | Win32 | Unix | Other of string (** Queried lazily *) val os: unit -> os (** The output of the command "uname", with the given argument. Memoised. *) val uname: string -> string option (** Append .exe (only if missing) to executable filenames on Windows *) val executable_name : string -> string (** The different families of shells we know about *) type shell = SH_sh | SH_bash | SH_zsh | SH_csh | SH_fish (** Guess the shell compat-mode *) val guess_shell_compat: unit -> shell (** Guess the location of .profile *) val guess_dot_profile: shell -> string (** The separator character used in the PATH variable (varies depending on OS) *) val path_sep: char (** Splits a PATH-like variable separated with [path_sep]. More involved than it seems, because there may be quoting on Windows. By default, it returns the path cleaned (remove trailing, leading, contiguous delimiters). Optional argument [clean] permits to keep those empty strings. *) val split_path_variable: ?clean:bool -> string -> string list (** For native Windows builds, returns [`Cygwin] if the command is a Cygwin- compiled executable, [`CygLinked] if the command links to a library which is itself Cygwin-compiled or [`Native] otherwise. Note that this returns [`Native] on a Cygwin-build of opam! Both cygcheck and an unqualified command will be resolved using the current PATH. *) val is_cygwin_variant: string -> [ `Native | `Cygwin | `CygLinked ] (** {3 Exit handling} *) (** Like Stdlib.at_exit but with the possibility to call manually (eg. before exec()) *) val at_exit: (unit -> unit) -> unit (** Calls the functions registered in at_exit. Unneeded if exiting normally *) val exec_at_exit: unit -> unit (** Indicates intention to exit the program with given exit code *) exception Exit of int (** Indicates intention to exec() the given command (parameters as per [Unix.execvpe]), after proper finalisations. It's the responsibility of the main function to catch this, call [exec_at_exit], and [Unix.execvpe]. *) exception Exec of string * string array * string array (** Raises [Exit i] *) (* val exit: int -> 'a *) type exit_reason = [ `Success | `False | `Bad_arguments | `Not_found | `Aborted | `Locked | `No_solution | `File_error | `Package_operation_error | `Sync_error | `Configuration_error | `Solver_failure | `Internal_error | `User_interrupt ] val exit_codes : (exit_reason * int) list val get_exit_code : exit_reason -> int (** Raises [Exit], with the code associated to the exit reason *) val exit_because: exit_reason -> 'a (**/**) type warning_printer = {mutable warning : 'a . ('a, unit, string, unit) format4 -> 'a} val set_warning_printer : warning_printer -> unit end (** {2 Windows-specific functions} *) module Win32 : sig (** Win32 Registry Hives and Values *) module RegistryHive : sig val to_string : OpamStubs.registry_root -> string val of_string : string -> OpamStubs.registry_root end val set_parent_pid : int32 -> unit (** Change which the pid written to by {!parent_putenv}. This function cannot be called after [parent_putenv]. *) val parent_putenv : string -> string -> bool (** Update an environment variable in the parent (i.e. shell) process's environment. *) val persistHomeDirectory : string -> unit (** [persistHomeDirectory value] sets the HOME environment variable in this and the parent process and also persists the setting to the user's registry and broadcasts the change to other processes. *) end (** {2 General use infix function combinators} *) module Op: sig (** Function application (with lower priority) (predefined in OCaml 4.01+) *) val (@@): ('a -> 'b) -> 'a -> 'b (** Pipe operator -- reverse application (predefined in OCaml 4.01+) *) val (|>): 'a -> ('a -> 'b) -> 'b (** Function composition : (f @* g) x =~ f (g x) *) val (@*): ('b -> 'c) -> ('a -> 'b) -> 'a -> 'c (** Reverse function composition : (f @> g) x =~ g (f x) *) val (@>): ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c end (** {2 Helper functions to initialise configuration from the environment} *) module Config : sig type env_var = string type when_ = [ `Always | `Never | `Auto ] type when_ext = [ `Extended | when_ ] type answer = [ `unsafe_yes | `all_yes | `all_no | `ask ] (* Parse a envrionement variable boolean value *) val bool_of_string: string -> bool option val env: (string -> 'a) -> string -> 'a option val env_bool: env_var -> bool option val env_int: env_var -> int option type level = int (* Like [env_int], but accept boolean values for 0 and 1 *) val env_level: env_var -> level option type sections = int option String.Map.t val env_sections: env_var -> sections option val env_string: env_var -> string option val env_float: env_var -> float option val env_when: env_var -> when_ option val env_when_ext: env_var -> when_ext option val resolve_when: auto:(bool Lazy.t) -> when_ -> bool val env_answer: env_var -> answer option module type Sig = sig (** Read-only record type containing the lib's configuration options *) type t (** Type of functions with optional arguments for setting each of [t]'s fields, similarly named, and returning ['a] *) type 'a options_fun (** The default values of the options to use at startup *) val default: t (** Use to update any option in a [t], using the optional arguments of [options_fun]. E.g. [set opts ?option1:1 ?option4:"x" ()] *) val set: t -> (unit -> t) options_fun (** Same as [set], but passes the result to a continuation, allowing argument stacking *) val setk: (t -> 'a) -> t -> 'a options_fun (** The global reference containing the currently set library options. Access using [OpamXxxConfig.(!r.field)]. *) val r: t ref (** Updates the currently set options in [r] according to the optional arguments *) val update: ?noop:_ -> (unit -> unit) options_fun (** Sets the options, reading the environment to get default values when unspecified *) val init: ?noop:_ -> (unit -> unit) options_fun (** Sets the options like [init], but returns the given value (for arguments stacking) *) val initk: 'a -> 'a options_fun end (* Opam environment variables handling *) module E : sig type t = .. val find: (t -> 'a option) -> 'a val value: (t -> 'a option) -> (unit ->'a option) val update: t -> unit val updates: t list -> unit end end opam-2.1.5/src/core/opamACL.mli0000644000175000017500000000264614427463453015225 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2020 David Allsopp Ltd. *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** C auxiliary function used for POSIX 1003.1e DRAFT 17 permission checking. *) val get_acl_executable_info : string -> int -> int list option (** If compiled without libacl support, this function always returns None When opam is built with libacl support, [get_acl_executable_info file owner] takes a filename and the uid of the owner of that file (this is passed since the caller will have already called {!Unix.stat}). The function returns [Some []] if the process can execute [file] or [Some gids] if the process can execute [file] if one of its groups matches [gids]. If the process cannot under any circumstances execute [file] (or if an unexpected error occurred), then [None] is returned. *) opam-2.1.5/src/core/opamCompat.mli0000644000175000017500000000517714427463453016053 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2018-2020 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) module String #if OCAML_VERSION >= (4, 3, 0) = String #else : sig include module type of struct include String end val lowercase_ascii : string -> string val uppercase_ascii : string -> string val capitalize_ascii : string -> string end #endif module Char #if OCAML_VERSION >= (4, 3, 0) = Char #else : sig include module type of struct include Char end val lowercase_ascii: char -> char val uppercase_ascii: char -> char end #endif module Either #if OCAML_VERSION >= (4, 12, 0) = Either #else : sig type ('a, 'b) t = | Left of 'a | Right of 'b end #endif module Printexc #if OCAML_VERSION >= (4, 5, 0) = Printexc #else : sig include module type of struct include Printexc end val raise_with_backtrace: exn -> raw_backtrace -> 'a end #endif module Unix #if OCAML_VERSION >= (4, 6, 0) = Unix #else : sig include module type of struct include Unix end val map_file : Unix.file_descr -> ?pos:int64 -> ('a, 'b) Bigarray.kind -> 'c Bigarray.layout -> bool -> int array -> ('a, 'b, 'c) Bigarray.Genarray.t end #endif module Uchar #if OCAML_VERSION >= (4, 3, 0) = Uchar #else : sig type t val of_int : int -> t external to_int : t -> int = "%identity" end #endif module Buffer #if OCAML_VERSION >= (4, 6, 0) = Buffer #else : sig include module type of struct include Buffer end val add_utf_8_uchar : t -> Uchar.t -> unit end #endif module Filename #if OCAML_VERSION >= (4, 4, 0) = Filename #else : sig include module type of struct include Filename end val extension : string -> string end #endif module Result #if OCAML_VERSION >= (4, 8, 0) = Result #else : sig type ('a, 'e) t #if OCAML_VERSION >= (4, 3, 0) = ('a, 'e) result #endif = Ok of 'a | Error of 'e end #endif #if OCAML_VERSION < (4, 7, 0) module Stdlib = Pervasives #endif module Lazy #if OCAML_VERSION >= (4, 13, 0) = Lazy #else : sig include module type of struct include Lazy end val map : ('a -> 'b) -> 'a t -> 'b t end #endif opam-2.1.5/src/core/opamACL.ml.libacl0000644000175000017500000000131114427463453016265 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2020 David Allsopp Ltd. *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) include OpamlibACL opam-2.1.5/src/core/opamVersionCompare.mli0000644000175000017500000000415514427463453017557 0ustar stephsteph(******************************************************************************) (* This file is part of the Dose library http://www.irill.org/software/dose *) (* *) (* Copyright (C) 2009-2011 Pietro Abate *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (* Work developed with the support of the Mancoosi Project *) (* http://www.mancoosi.org *) (* *) (******************************************************************************) (** Version comparison function used throughout. From the Dose suite. *) (** Functions for manipulating and comparing Debian version strings. Compliant with Debian policy version 3.9.2. and Debian developers reference version 3.4.6 *) (** {2 Comparing debian version strings} *) (** The following functions compare any two strings, that is these functions do not check whether the arguments are really legal debian versions. If the arguments are debian version strings, then the result is as required by debian policy. Note that two strings may be equivalent, that is denote the same debian version, even when they differ in syntax, as for instance "0:1.2.00" and "1.02-0". *) (** @return [true] iff the two strings define the same version. Hence, the result may be true even when the two string differ syntactically. *) val equal : string -> string -> bool (** [compare x y] returns 0 if x is eqivalent to y, -1 if x is smaller than y, and 1 if x is greater than y. This is consistent with [Stdlib.compare]. *) val compare : string -> string -> int opam-2.1.5/src/core/opamUrl.ml0000644000175000017500000002054414427463453015214 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamStd.Op type version_control = [ `git | `darcs | `hg ] type backend = [ `http | `rsync | version_control ] type t = { transport: string; path: string; hash: string option; backend: backend; } let empty = { backend = `http; transport = "https"; path = ""; hash = None; } exception Parse_error of string let parse_error s = raise (Parse_error s) let split_url = let re = Re.(compile @@ whole_string @@ seq [ (* Parse the scheme, which is either backend+protocol or just a protocol *) opt @@ seq [ (* Backend *) opt @@ seq [ group @@ rep @@ diff any (set "+:"); alt [ char '+'; str "://"] ]; (* Protocol *) group @@ rep @@ diff any (char ':'); (* Separator *) str "://" ]; (* Parse the path, with is either path or path.suffix (suffix contains no .) *) group @@ seq [ non_greedy @@ rep @@ diff any (char '#'); (* If there's a .suffix, group it separately (used for backend guessing) *) opt @@ seq [ char '.'; group @@ rep1 @@ diff any (set "\\/.#")] ]; (* Parse the fragment (git branch, etc.) *) opt @@ seq [ char '#'; group @@ rep any ]; ]) in fun u -> match Re.Group.all (Re.exec re u) with | [| _; vc; transport; path; suffix; hash |] -> let opt = function "" -> None | s -> Some s in opt vc, opt transport, path, opt suffix, opt hash | _ -> assert false let vc_of_string = function | "git" -> `git | "hg" -> `hg | "darcs" -> `darcs | vc -> parse_error (Printf.sprintf "unsupported version control system %s" (OpamConsole.colorise `underline vc)) let string_of_vc = function | `git -> "git" | `darcs -> "darcs" | `hg -> "hg" let string_of_backend = function | `http -> "http" | `rsync -> "rsync" | #version_control as vc -> string_of_vc vc let backend_of_string = function | "http" | "https" | "ftp" | "wget" | "curl" -> `http | "file" -> `rsync | "git" -> `git | "darcs" -> `darcs | "hg" -> `hg | "path" | "local" | "rsync" | "ssh" | "scp" | "sftp" -> `rsync | p -> parse_error (Printf.sprintf "unsupported protocol %s" (OpamConsole.colorise `underline p)) let looks_like_ssh_path = (* ':' before any '/' : assume ssh, like git does. Exception for 'x:' with single char, because Windows *) let re = Re.(compile @@ seq [ group @@ repn (diff any (set "/:")) 2 None; char ':'; opt @@ char '/'; opt @@ group @@ seq [ alt [ diff any digit; seq [rep digit; compl [digit; char '/']] ]; rep any; ]; eos; ]) in fun path -> try let sub = Re.exec re path in Some (Re.Group.get sub 1 ^ try "/" ^ Re.Group.get sub 2 with Not_found -> "") with Not_found -> None let parse ?backend ?(handle_suffix=true) ?(from_file=true) s = let vc, transport, path, suffix, hash = split_url s in let backend = match backend with | Some b -> b | None -> match vc with | Some vc -> vc_of_string vc | None -> let of_suffix ~default = if not handle_suffix then default else match suffix with | Some sf -> (try vc_of_string sf with Parse_error _ -> default) | None -> match OpamStd.String.cut_at path '@' with | Some (user, _) -> (try vc_of_string user with Parse_error _ -> default) | None -> default in match transport with | None -> of_suffix ~default:`rsync | Some tr -> try vc_of_string tr with Parse_error _ -> of_suffix ~default:(backend_of_string tr) in let transport, path = match backend, transport, looks_like_ssh_path path with | `http, None, _ -> "http", path | _, (None | Some ("git"|"hg"|"darcs")), Some path -> "ssh", path | _, (None | Some ("hg"|"darcs")), None -> "file", OpamSystem.real_path path |> OpamSystem.back_to_forward | `rsync, Some "file", _ when not from_file -> "file", OpamSystem.real_path path |> OpamSystem.back_to_forward | _, Some tr, _ -> tr, path in { transport; path; hash; backend; } let parse_opt ?(quiet=false) ?backend ?handle_suffix ?from_file s = try Some (parse ?backend ?handle_suffix ?from_file s) with Parse_error pe -> if not quiet then OpamConsole.warning "URL parsing error on %s: %s" (OpamConsole.colorise `underline s) pe; None let of_string url = parse ~handle_suffix:false url let to_string url = let hash = match url.hash with Some h -> "#" ^ h | None -> "" in match url.backend with | #version_control as vc -> let vc = string_of_backend vc in if url.transport = vc then (* Don't be redundant on e.g git:// protocols *) Printf.sprintf "%s://%s%s" vc url.path hash else Printf.sprintf "%s+%s://%s%s" vc url.transport url.path hash | `rsync | `http -> Printf.sprintf "%s://%s%s" url.transport url.path hash let base_url url = match url.transport with | "" -> url.path | tr -> Printf.sprintf "%s://%s" tr url.path let local_path = function | { transport = ("file"|"path"|"local"|"rsync"); path; hash = _; backend = (#version_control | `rsync); } when looks_like_ssh_path path = None -> Some path | _ -> None let local_dir url = let open OpamStd.Option.Op in local_path url >>| OpamFilename.Dir.of_string >>= fun d -> if OpamFilename.exists_dir d then Some d else None let local_file url = let open OpamStd.Option.Op in local_path url >>| OpamFilename.of_string >>= fun f -> if OpamFilename.exists f then Some f else None let guess_version_control s = let vc,transport,path,_,_ = split_url s in if vc = None && transport = None && looks_like_ssh_path path = None then let open OpamFilename in let open Op in let dir = Dir.of_string path in if exists_dir (dir / ".git") || exists (dir // ".git") then Some`git else if exists_dir (dir / ".hg") then Some `hg else if exists_dir (dir / "_darcs") then Some `darcs else None else None let basename = let re = Re.(compile @@ seq [ opt @@ seq [rep any; char '/']; group @@ rep1 (diff any (char '/')); rep @@ char '/'; ]) in fun t -> try Re.Group.get (Re.exec re t.path) 1 with Not_found -> "" let root = let re = Re.(compile @@ seq [char '/'; rep any]) in fun t -> let path = (* The special-casing of "file" is needed for Windows *) if t.transport = "file" then "" else Re.replace_string re ~by:"" t.path in { t with path} let has_trailing_slash url = OpamStd.String.ends_with ~suffix:"/" url.path let to_json url = `String (to_string url) let of_json = function | `String s -> (try Some (of_string s) with _ -> None) | _ -> None type url = t let map_file_url f url = if url.transport = "file" then {url with path = f url.path} else url module O = struct type t = url let to_string = to_string let to_json = to_json let of_json = of_json let compare = compare end module Set = OpamStd.Set.Make(O) module Map = OpamStd.Map.Make(O) module Op = struct (** appending to an url path *) let ( / ) url dir = let url = if Filename.is_relative dir then url else root url in (* Even on Windows, a file:// _should_ use slash *) let dir = OpamSystem.back_to_forward dir in let path = if has_trailing_slash url || url.path = "" then url.path ^ dir else url.path ^ "/" ^ dir in {url with path } end opam-2.1.5/src/core/opamConsole.mli0000644000175000017500000001253314427463453016224 0ustar stephsteph(**************************************************************************) (* *) (* Copyright 2012-2019 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** Console output, ANSI color, logging and user querying *) (** Global configuration parameters (read from OpamGlobalConfig, and the environment when necessary) *) val debug: unit -> bool val verbose: unit -> bool val color: unit -> bool val utf8: unit -> bool val utf8_extended: unit -> bool val disp_status_line: unit -> bool (** General text formatting *) (** Settable attributes for ANSI terminal output. Nesting is generally not handled. *) type text_style = [ `black | `blue | `bold | `crossed | `cyan | `green | `magenta | `red | `underline | `white | `yellow ] (** Helper coloring functions. Returns the string unchanged if color is disabled *) val colorise : text_style -> string -> string val colorise' : text_style list -> string -> string val acolor : text_style -> unit -> string -> string val acolor_w : int -> text_style -> Format.formatter -> string -> unit module Symbols : sig val rightwards_arrow : OpamCompat.Uchar.t val box_drawings_light_down_and_right : OpamCompat.Uchar.t val box_drawings_light_horizontal : OpamCompat.Uchar.t val box_drawings_light_vertical : OpamCompat.Uchar.t val box_drawings_light_up_and_right : OpamCompat.Uchar.t val box_drawings_light_right : OpamCompat.Uchar.t val circled_division_slash : OpamCompat.Uchar.t val asterisk_operator : OpamCompat.Uchar.t val north_east_arrow : OpamCompat.Uchar.t val south_east_arrow : OpamCompat.Uchar.t val clockwise_open_circle_arrow : OpamCompat.Uchar.t val greek_small_letter_lambda : OpamCompat.Uchar.t val latin_capital_letter_o_with_stroke : OpamCompat.Uchar.t val six_pointed_black_star : OpamCompat.Uchar.t val upwards_arrow : OpamCompat.Uchar.t val downwards_arrow : OpamCompat.Uchar.t val up_down_arrow : OpamCompat.Uchar.t val downwards_double_arrow : OpamCompat.Uchar.t val downwards_black_arrow : OpamCompat.Uchar.t val black_down_pointing_triangle : OpamCompat.Uchar.t end val utf8_symbol: OpamCompat.Uchar.t -> ?alternates:OpamCompat.Uchar.t list -> string -> string (** Logging *) (** Timers, only active when debug is on. Returns the time between the application to each argument, in seconds *) val timer : unit -> unit -> float (** [log section ~level fmt args]. Used for debug messages, default level is 1 *) val log : string -> ?level:int -> ('a, Format.formatter, unit) format -> 'a (** Helper to pass stringifiers to log (use [log "%a" (slog to_string) x] rather than [log "%s" (to_string x)] to avoid costly unneeded stringifications *) val slog : ('a -> string) -> Format.formatter -> 'a -> unit val error : ('a, unit, string, unit) format4 -> 'a val warning : ('a, unit, string, unit) format4 -> 'a val note : ('a, unit, string, unit) format4 -> 'a (** Message without prefix, reformat or newline, to stderr (useful to continue error messages without repeating "[ERROR]") *) val errmsg : ('a, unit, string, unit) format4 -> 'a val error_and_exit : OpamStd.Sys.exit_reason -> ('a, unit, string, 'b) format4 -> 'a val msg : ('a, unit, string, unit) format4 -> 'a val formatted_msg : ?indent:int -> ('a, unit, string, unit) format4 -> 'a val header_msg : ('a, unit, string, unit) format4 -> 'a val header_error : ('a, unit, string, ('b, unit, string, unit) format4 -> 'b) format4 -> 'a (** Erase the current line on stdout (doesn't flush stdout) *) val carriage_delete: unit -> unit (** Display a dynamic status line to stdout, that will be erased on next call. The message should not be wider than screen nor contain newlines. Use {!clear_status} when the status line should be erased. *) val status_line : ('a, unit, string, unit) format4 -> 'a (** Erase the status line and restore the cursor to the start of the line *) val clear_status : unit -> unit (** Ask the user to press Y/y/N/n to continue (returns a boolean). Defaults to true (yes) if unspecified. If [require_unsafe_yes] is true, it automatically answer yes to the question if automatic answering is set to [`unsafe_yes] ; otherwise it will prompt and wait user input if it is set [`all_yes] (interactive). Its default is false. *) val confirm: ?require_unsafe_yes:bool -> ?default:bool -> ('a, unit, string, bool) format4 -> 'a (** Read some input from the user (returns a string option) *) val read: ('a, unit, string, string option) format4 -> 'a (** Prints a table; generally called on tables passed through [align_table]. The default [cut] is to wrap on stdout, stderr, keep as-is otherwise. [`Wrap sep] prepends [sep] on wrapped lines *) val print_table: ?cut:[`Wrap of string | `Truncate | `None] -> out_channel -> sep:string -> string list list -> unit opam-2.1.5/src/ocaml-flags-standard.sexp0000644000175000017500000000004314427463453017167 0ustar stephsteph(-w +a-4-40-42-44-48 -safe-string) opam-2.1.5/admin-scripts/0002755000175000017500000000000014427463453014276 5ustar stephstephopam-2.1.5/admin-scripts/to_1_1.ml0000755000175000017500000001033214427463453015712 0ustar stephsteph#!/usr/bin/env opam-admin.top #directory "+../opam-lib";; #directory "+../re";; (* Converts OPAM 1.2 packages for compat with OPAM 1.1 * merge 'install' with 'build' * remove the new fields: install, flags and dev-repo * remove dependency flags ('build', 'test', 'doc') * set file version * replace inequality constraints with '> & <' * remove new global variables from filters in commands, messages, 'patches', 'available' *) open OpamTypes open OpamStd.Option.Op ;; OpamFormatConfig.update ~all_parens:true;; let rewrite_constraint ~conj = (* Rewrites '!=' *) OpamFormula.map OpamFormula.(function | (`Neq,v) -> if conj then And (Atom (`Lt,v), Atom (`Gt,v)) else Or (Atom (`Lt,v), Atom (`Gt,v)) | atom -> Atom atom) ;; let vars_new_1_2 = [ "compiler"; "ocaml-native"; "ocaml-native-tools"; "ocaml-native-dynlink"; "arch" ] let filter_string = let rex = Re.(compile ( seq [ str "%{"; rep (seq [opt (char '%'); opt (char '}'); diff notnl (set "}%")]); str "}%"; ])) in Re_pcre.substitute ~rex ~subst:(fun s -> match String.sub s 2 (String.length s - 4) with | "compiler" -> "ocaml-version" | "ocaml-native" | "ocaml-native-tools" | "ocaml-native-dynlink" -> "true" | s when List.mem s vars_new_1_2 -> "" | s when String.contains s '?' -> (* new if/else printers: use default *) (try let i = String.rindex s ':' + 1 in String.sub s i (String.length s - i) with Not_found -> s) | _ -> s ) let rec filter_vars = function | FIdent ([],i,None) when List.mem (OpamVariable.to_string i) vars_new_1_2 -> None | FString s -> Some (FString (filter_string s)) | FBool _ | FIdent _ as f -> Some f | FOp (f1,op,f2) -> (match filter_vars f1, filter_vars f2 with | Some f1, Some f2 -> Some (FOp (f1, op, f2)) | _ -> Some (FBool false)) | FAnd (f1,f2) -> (match filter_vars f1, filter_vars f2 with | Some f1, Some f2 -> Some (FAnd (f1, f2)) | opt, None | None, opt -> Some (FBool false)) | FOr (f1,f2) -> (match filter_vars f1, filter_vars f2 with | Some f1, Some f2 -> Some (FOr (f1, f2)) | opt, None | None, opt -> opt) | FNot f -> (match filter_vars f with | Some f -> Some (FNot f) | None -> None) | FUndef -> None let filter_vars_optlist ol = List.map (fun (x, filter) -> x, filter >>= filter_vars) ol let filter_args sl = OpamStd.List.filter_map (fun (s, filter) -> match s with | CString s -> Some (CString (filter_string s),filter) | CIdent i when List.mem i vars_new_1_2 -> None | id -> Some (id,filter)) sl let filter_vars_commands ol = List.map (fun (args, filter) -> filter_args (filter_vars_optlist args), filter >>= filter_vars) ol let to_1_1 _ opam = let module OF = OpamFile.OPAM in if OpamVersion.compare (OF.opam_version opam) (OpamVersion.of_string "1.2") < 0 then opam else let opam = OF.with_build opam (filter_vars_commands (OF.build opam @ OF.install opam)) in let opam = OF.with_install opam [] in let opam = OF.with_flags opam [] in let opam = OF.with_dev_repo opam None in let opam = OF.with_features opam [] in let opam = OF.with_opam_version opam (OpamVersion.of_string "1.1") in let remove_ext = OpamFormula.map (fun (n, (_,cstr)) -> OpamFormula.Atom (n, ([], rewrite_constraint ~conj:false cstr))) in let opam = OF.with_depends opam (remove_ext (OF.depends opam)) in let opam = OF.with_depopts opam (remove_ext (OF.depopts opam)) in let opam = OF.with_conflicts opam (OpamFormula.map (fun (n, cstr) -> OpamFormula.Atom (n, rewrite_constraint ~conj:false cstr)) (OF.conflicts opam)) in let opam = OF.with_available opam (filter_vars (OF.available opam) +! FBool true) in let opam = OF.with_patches opam (filter_vars_optlist (OF.patches opam)) in let opam = OF.with_libraries opam [] in let opam = OF.with_syntax opam [] in let opam = OF.with_messages opam (filter_vars_optlist (OF.messages opam)) in let opam = OF.with_post_messages opam (filter_vars_optlist (OF.post_messages opam)) in opam ;; Opam_admin_top.iter_packages ~opam:to_1_1 () opam-2.1.5/admin-scripts/add-build-deps.ml0000755000175000017500000000147114427463453017412 0ustar stephsteph#!/usr/bin/env opam-admin.top #directory "+../opam-lib";; open Opam_admin_top;; (* Add the "build" dependency flag to all ocamlfind depends *) let to_build = List.map OpamPackage.Name.of_string ["ocamlfind"] let addbuild (pkg, (flags, cstr) as atom) = if List.mem pkg to_build && not (List.mem OpamTypes.Depflag_Build flags) then OpamFormula.Atom (pkg, (OpamTypes.Depflag_Build::flags, cstr)) else OpamFormula.Atom atom ;; iter_packages ~opam:(fun _ opam0 -> let open OpamFile.OPAM in let opam = opam0 in let opam = with_depends opam @@ OpamFormula.map addbuild @@ depends opam in let opam = with_depopts opam @@ OpamFormula.map addbuild @@ depopts opam in let opam = if opam <> opam0 then with_opam_version opam @@ OpamVersion.of_string "1.2" else opam in opam) () opam-2.1.5/admin-scripts/add-github-dev.ml0000755000175000017500000000164314427463453017421 0ustar stephsteph#!/usr/bin/env opam-admin.top #directory "+../opam-lib";; open Opam_admin_top;; #use "topfind";; #require "re";; let github_re = Re.compile (Re_perl.re "([^/]*github.com/.*)/archive/.*");; iter_packages_gen @@ fun nv ~prefix:_ ~opam ~descr:_ ~url ~dot_install:_ -> let opam = if OpamFile.OPAM.dev_repo opam <> None then opam else match url with | None -> opam | Some u -> let url = OpamFile.URL.url u in if url.OpamUrl.backend = `http && Re.execp github_re url.OpamUrl.path then let substrings = Re.exec github_re url.OpamUrl.path in let dev_url = { OpamUrl.transport = "git"; path = Re.get substrings 1; hash = None; backend = `git } in let opam = OpamFile.OPAM.with_dev_repo opam dev_url in OpamFile.OPAM.with_opam_version opam (OpamVersion.of_string "1.2") else opam in opam, `Keep, `Keep, `Keep opam-2.1.5/admin-scripts/depopts_to_conflicts.ml0000755000175000017500000000545214427463453021063 0ustar stephsteph#!/usr/bin/env opam-admin.top #directory "+../opam-lib";; open Opam_admin_top;; let contains_neq f = try OpamFormula.iter (function (_,cs) -> OpamFormula.iter (function (`Neq,_) -> raise Exit | _ -> ()) cs) f; false with Exit -> true ;; iter_packages ~opam:(fun _ opam -> let depopts = let formula = OpamFile.OPAM.depopts opam in let atoms = OpamFormula.fold_left (fun acc (n,(flags,_)) -> OpamFormula.Atom (n, (flags, OpamFormula.Empty)) :: acc) [] formula in OpamFormula.ors @@ OpamStd.List.remove_duplicates @@ List.rev atoms in let conflicts = (* add complement of the depopts as conflicts *) let module NM = OpamPackage.Name.Map in let depopts = (* get back a map (name => version_constraint) *) (* XXX this takes _all_ the atoms not considering con/disjunctions *) OpamFormula.fold_left (fun acc (name,(_,f)) -> try NM.add name ((OpamFormula.ors [f; NM.find name acc])) acc with Not_found -> NM.add name f acc) NM.empty (OpamFile.OPAM.depopts opam) in let neg_depopts = NM.fold (fun name f acc -> if f = OpamFormula.Empty then acc else let f = OpamFormula.(neg (fun (op,v) -> neg_relop op, v) f) in match OpamFormula.to_cnf (OpamFormula.Atom (name,f)) with | [] -> acc | [conj] -> conj @ acc | [x;y] when x = y -> x @ acc | cnf -> (* Formula is not a conjunction, we are left with no choice but to enumerate *) let f = OpamFormula.to_atom_formula @@ OpamFormula.ands @@ List.map OpamFormula.of_disjunction cnf in let conflict_packages = OpamPackage.Set.filter (fun pkg -> OpamFormula.eval (fun atom -> OpamFormula.check atom pkg) f) (OpamPackage.packages_of_name packages name) in OpamPackage.Set.fold (fun nv acc -> (OpamPackage.name nv, Some (`Eq, OpamPackage.version nv)) :: acc) conflict_packages acc) depopts [] in let conflicts = OpamFile.OPAM.conflicts opam in let add_conflicts = let c = OpamFormula.to_disjunction conflicts in List.filter (fun f -> not (List.mem f c)) neg_depopts in OpamFormula.ors (conflicts :: [OpamFormula.of_disjunction add_conflicts]) in let opam = OpamFile.OPAM.with_depopts opam depopts in let opam = OpamFile.OPAM.with_conflicts opam conflicts in let opam = if contains_neq conflicts then OpamFile.OPAM.with_opam_version opam (OpamVersion.of_string "1.2") else opam in opam) () ;; opam-2.1.5/admin-scripts/compilers-to-packages.ml0000755000175000017500000001354614427463453021033 0ustar stephsteph#!/usr/bin/env opam-admin.top #directory "+../opam-lib";; #directory "+../re";; (**************************************************************************) (* *) (* Copyright 2013-2016 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open OpamTypes open OpamProcess.Job.Op open Opam_admin_top open OpamStd.Option.Op ;; let () = let error_printer = function | OpamParallel.Errors (_, (_,exc)::_, _) -> Some (Printexc.to_string exc) | _ -> None in Printexc.register_printer error_printer ;; let compilers = let compilers_dir = OpamFilename.Op.(repo.repo_root / "compilers") in if OpamFilename.exists_dir compilers_dir then ( List.fold_left (fun map f -> if OpamFilename.check_suffix f ".comp" then let c = OpamFilename.(Base.to_string (basename (chop_extension f))) in OpamStd.String.Map.add c f map else map) OpamStd.String.Map.empty (OpamFilename.rec_files compilers_dir) ) else OpamStd.String.Map.empty ;; OpamStd.String.Map.iter (fun c comp_file -> let comp = OpamFile.Comp.read (OpamFile.make comp_file) in let descr_file = OpamFilename.(opt_file (add_extension (chop_extension comp_file) "descr")) in let descr = descr_file >>| fun f -> OpamFile.Descr.read (OpamFile.make f) in let comp = let drop_names = [ OpamPackage.Name.of_string "base-ocamlbuild" ] in (* ocamlbuild has requirements on variable ocaml-version: it can't be in the dependencies *) OpamFile.Comp.with_packages (OpamFormula.map (fun ((name, _) as atom) -> if List.mem name drop_names then OpamFormula.Empty else Atom atom) (OpamFile.Comp.packages comp)) comp in let opam = OpamFile.Comp.to_package (OpamPackage.Name.of_string "ocaml") comp descr in let nv = OpamFile.OPAM.package opam in let patches = OpamFile.Comp.patches comp in if patches <> [] then OpamConsole.msg "Fetching patches of %s to check their checksums...\n" (OpamPackage.to_string nv); let cache_file : string list list OpamFile.t = OpamFile.make @@ OpamFilename.of_string "~/.cache/opam-compilers-to-packages/url-hashes" in let url_md5 = (OpamFile.Lines.read_opt cache_file +! [] |> List.map @@ function | [url; md5] -> OpamUrl.of_string url, md5 | _ -> failwith "Bad cache") |> OpamUrl.Map.of_list in let extra_sources = (* Download them just to get their mandatory MD5 *) OpamParallel.map ~jobs:3 ~command:(fun url -> try Done (Some (url, OpamUrl.Map.find url url_md5, None)) with Not_found -> let err e = OpamConsole.error "Could not get patch file for %s from %s (%s), skipping" (OpamPackage.to_string nv) (OpamUrl.to_string url) (Printexc.to_string e); Done None in OpamFilename.with_tmp_dir_job @@ fun dir -> try (* Download to package.patch, rather than allowing the name to be guessed since, on Windows, some of the characters which are valid in URLs are not valid in filenames *) let f = let base = OpamFilename.Base.of_string "package.patch" in OpamFilename.create dir base in OpamProcess.Job.catch err (OpamDownload.download_as ~overwrite:false url f @@| fun () -> Some (url, OpamFilename.digest f, None)) with e -> err e) (OpamFile.Comp.patches comp) in List.fold_left (fun url_md5 -> function | Some (url,md5,_) -> OpamUrl.Map.add url md5 url_md5 | None -> url_md5) url_md5 extra_sources |> OpamUrl.Map.bindings |> List.map (fun (url,m) -> [OpamUrl.to_string url; m]) |> OpamFile.Lines.write cache_file; if List.mem None extra_sources then () else let opam = opam |> OpamFile.OPAM.with_extra_sources (OpamStd.List.filter_some extra_sources) |> OpamFile.OPAM.with_substs [OpamFilename.Base.of_string "ocaml.config"] in OpamFile.OPAM.write (OpamRepositoryPath.opam repo (Some "ocaml") nv) opam; let config = OpamFile.Dot_config.create @@ List.map (fun (v,c) -> OpamVariable.of_string v, c) @@ [ "ocaml-version", S (OpamFile.Comp.version comp); "compiler", S (OpamFile.Comp.name comp); "preinstalled", B false; (* fixme: generate those from build/config artifacts using a script ? Guess from os and arch vars and use static 'features' + variable expansion ? ... or just let them be fixed by hand ? *) "ocaml-native", B true; "ocaml-native-tools", B true; "ocaml-native-dynlink", B true; "ocaml-stubsdir", S "%{lib}%/stublibs"; ] in OpamFile.Dot_config.write (OpamFile.make OpamFilename.Op.(OpamRepositoryPath.files repo (Some "ocaml") nv // "ocaml.config.in")) config; OpamFilename.remove comp_file; OpamStd.Option.iter OpamFilename.remove descr_file; OpamFilename.rmdir_cleanup (OpamFilename.dirname comp_file); OpamConsole.msg "Compiler %s successfully converted to package %s\n" c (OpamPackage.to_string nv)) compilers ;; opam-2.1.5/admin-scripts/extract_mini_repository.sh0000755000175000017500000000561714427463453021631 0ustar stephsteph#! /bin/sh set -e if [ $# = 0 ]; then cat < /dev/null || true done ## Convert the required compilers as packages "${SOURCE_DIR}"/compilers-to-packages.ml ## Fetch the packages and compilers archives for version in ${COMPILERS}; do opam admin make --resolve --compiler ${version} ocaml.${version} ${PACKAGES} done ## Remove the unrequired package "versions unrequired_version() { case "$1" in base-*) return 1;; *) for version in archives/* do if [ "${version}" = "archives/$1+opam.tar.gz" ]; then return 1; fi done esac return 0 } for dir in packages/*/* do if unrequired_version "${dir##packages/*/}"; then rm -r "${dir}" fi done # Remove empty directories in "packages/" for dir in packages/* do rmdir "${dir}" 2> /dev/null || true done ## Remove unrequired files rm -f .gitignore .travis-ci-install.sh .travis-ci.sh .travis.yml README.md ## Build the archive cd "${WORK_DIR}" tar czf "${TARGET_DIR}/opam-mini-repository.tar.gz" ${REPO_DIR_NAME} opam-2.1.5/admin-scripts/split_install.ml0000755000175000017500000000311214427463453017507 0ustar stephsteph#!/usr/bin/env opam-admin.top #directory "+../opam-lib";; #directory "+../re";; open Opam_admin_top;; open OpamTypes;; iter_packages ~opam:(fun _ opam -> let module O = OpamFile.OPAM in if O.install opam <> [] then opam else let rec rev_split_while acc cond = function | [] -> acc, [] | x::r when cond x -> rev_split_while (x::acc) cond r | l -> acc, List.rev l in let condition = function | (CString "install",_)::_, _ -> true | (CString "cp",_)::r, _ -> (try let dest = match List.filter (function | CString s, _ -> not (OpamStd.String.starts_with ~prefix:"-" s) | CIdent _, _ -> true) (List.rev r) with | (d, _)::_ -> d | _ -> raise Not_found in let dests = ["prefix";"bin";"sbin";"lib";"man";"doc";"share";"etc"; "toplevel";"stublibs";"doc"] in match dest with | CIdent i -> List.mem i dests | CString s -> Re.(execp (compile (seq [alt (List.map str dests); str "}%"])) s) with Not_found -> false) | l, _ -> List.exists (function | (CString arg, _) -> OpamStd.String.contains ~sub:"install" arg | _ -> false) l in let install, build = rev_split_while [] condition (List.rev (O.build opam)) in opam |> OpamFile.OPAM.with_build build |> OpamFile.OPAM.with_install install) () ;; opam-2.1.5/admin-scripts/cudf-debug.ml0000755000175000017500000000344714427463453016646 0ustar stephsteph#!/usr/bin/env opam-admin.top #directory "+../cudf";; #directory "+../dose3";; #directory "+../opam-lib";; open Opam_admin_top;; let cudf2opam_name cpkg = OpamPackage.Name.of_string (try Cudf.lookup_package_property cpkg OpamCudf.s_source with Not_found -> Common.CudfAdd.decode cpkg.Cudf.package) let cudf2opam_version cpkg = OpamPackage.Version.of_string (try Cudf.lookup_package_property cpkg OpamCudf.s_source_number with Not_found -> Printf.sprintf "#cudf%d" cpkg.Cudf.version) let cudf_pp cpkg = OpamPackage.Name.to_string (cudf2opam_name cpkg), OpamPackage.Version.to_string (cudf2opam_version cpkg), [] let rebuild_version_map univ = Cudf.fold_packages (fun acc cpkg -> let nv = OpamPackage.create (cudf2opam_name cpkg) (cudf2opam_version cpkg) in OpamPackage.Map.add nv cpkg.Cudf.version acc ) OpamPackage.Map.empty univ let _ = match Cudf_parser.load_from_file Sys.argv.(1) with | Some preamble, univ, Some req -> begin match Dose_algo.Depsolver.check_request ~explain:true (preamble, univ, req) with | Dose_algo.Depsolver.Unsat (Some f) -> OpamConsole.msg "== DOSE MESSAGE ==\n"; flush stdout; Dose_algo.Diagnostic.fprintf_human ~pp:cudf_pp Format.err_formatter f; flush stderr; let version_map = rebuild_version_map univ in begin match OpamCudf.make_conflicts ~version_map univ f with | OpamTypes.Conflicts cs -> OpamConsole.msg "== OPAM MESSAGE ==\n%s\n" (OpamCudf.string_of_conflict (fun a -> Printf.sprintf "%s unavailable" (OpamFormula.string_of_atom a)) cs) | _ -> prerr_endline "unhandled case" end | _ -> () end | _ -> OpamConsole.error_and_exit `Solver_error "unsupported cudf file" opam-2.1.5/admin-scripts/couverture.ml0000755000175000017500000001216314427463453017037 0ustar stephsteph#!/usr/bin/env opam-admin.top #directory "+../opam-lib";; (**************************************************************************) (* *) (* Copyright 2015-2018 OCamlPro *) (* *) (* All rights reserved. This file is distributed under the terms of the *) (* GNU Lesser General Public License version 2.1, with the special *) (* exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) (** This script gives scenarios to install all named packages in a given set. This may require several steps, in case of conflicts. Consistent installation steps are printed one per line to stdout. Stderr gives more detail. Relies on the current opam root for the list of available packages, i.e. depends on configured remotes, OS and OCaml version, but not on the set of currently installed packages. *) open OpamTypes let max_install t inst_packages = let universe = OpamState.universe t Query in let wish_field = "wished" in let base = OpamState.base_packages t in let universe = { universe with u_installed = base; u_installed_roots = base; u_attrs = [wish_field, inst_packages]; } in if not (OpamCudf.external_solver_available ()) then failwith "No external solver found"; let preferences = let preferences = OpamSolverConfig.criteria `Default in Some (lazy (Printf.sprintf "+sum(solution,%s),%s" wish_field preferences)) in OpamSolverConfig.update ~solver_preferences_default:preferences (); let version_map = OpamSolver.cudf_versions_map universe universe.u_available in let request = { wish_install = []; wish_remove = []; wish_upgrade = []; extra_attributes = [wish_field]; criteria = `Default; } in let cudf_universe = OpamSolver.load_cudf_universe ~build:true universe ~version_map universe.u_available in match OpamCudf.resolve ~extern:true ~version_map cudf_universe request with | Conflicts _ -> failwith "Solver error (unexpected conflicts)" | Success u -> OpamPackage.Set.diff (OpamPackage.Set.of_list (List.map OpamCudf.cudf2opam (OpamCudf.packages u))) base module P = OpamPackage open P.Set.Op let rec couverture acc t pkgs = Printf.eprintf "# %d packages remaining...\n%!" (P.Name.Set.cardinal (P.names_of_packages pkgs)); let step = max_install t pkgs in let added = P.Name.Set.inter (P.names_of_packages step) (P.names_of_packages pkgs) in if P.Name.Set.is_empty added then let () = Printf.eprintf "# -> %d uninstallable packages remaining.\n%!" (P.Name.Set.cardinal (P.names_of_packages pkgs)) in List.rev acc, pkgs else let n = P.Name.Set.cardinal added in Printf.eprintf "# -> Step %d: covering %d/%d packages%s.\n%!" (List.length acc + 1) n (P.Name.Set.cardinal (P.names_of_packages pkgs)) (if n > 5 then "" else OpamStd.List.concat_map ~left:" (" ~right:")" " " P.Name.to_string (OpamPackage.Name.Set.elements added)); let pkgs = P.Set.filter (fun nv -> not (P.has_name step (P.name nv))) pkgs in couverture (step::acc) t pkgs let () = let root = OpamStateConfig.opamroot () in OpamFormatConfig.init (); if not (OpamStateConfig.load_defaults root) then failwith "Opam root not found"; OpamCoreConfig.init (); OpamSolverConfig.init (); OpamStateConfig.init (); let t = OpamState.load_state ~save_cache:false "couverture" (OpamStateConfig.get_switch_opt ()) in let avail = Lazy.force t.OpamState.Types.available_packages in let wanted = match Array.to_list Sys.argv with | [] | _::[] -> avail -- P.packages_of_names avail (OpamState.base_package_names t) | _::l -> List.fold_left (fun wanted name -> let nvs = if String.contains name '.' then P.Set.singleton (P.of_string name) else P.packages_of_name avail (P.Name.of_string name) in if P.Set.is_empty (nvs %% avail) then failwith (Printf.sprintf "Package %s not found" name) else wanted ++ nvs ) P.Set.empty l in let couv,remaining = couverture [] t wanted in let avail_names = P.names_of_packages avail in let remaining_names = P.names_of_packages remaining in Printf.eprintf "# Found a couverture for %d over %d packages in %d steps:\n%!" (P.Name.Set.cardinal (P.Name.Set.diff avail_names remaining_names)) (P.Name.Set.cardinal avail_names) (List.length couv); List.iter (fun s -> print_endline (OpamStd.List.concat_map " " OpamPackage.to_string (P.Set.elements s))) couv; Printf.eprintf "# %d uninstallable packages remain: %s\n%!" (P.Name.Set.cardinal remaining_names) (OpamStd.List.concat_map " " OpamPackage.Name.to_string (P.Name.Set.elements remaining_names)) opam-2.1.5/admin-scripts/Makefile0000644000175000017500000000106614427463453015737 0ustar stephstephDEPS = core format repository INCLUDE = $(patsubst %,-I ../src/%,$(DEPS)) -I ../src/tools LIBS = $(patsubst %,../src/opam-%.cma,$(DEPS)) %: %.ml sed 's/^#.*//' $< >$*-tmp.ml ocamlfind ocamlc -package unix,re.glob,ocamlgraph -linkpkg $(INCLUDE) $(LIBS) ../src/tools/opam_admin_top.ml $*-tmp.ml -o $@ rm $*-tmp.ml 1_2_to_2_0: compilers-to-packages cp $< $@ couverture: couverture.ml sed 's/^#.*//' $< >couverture-tmp.ml ocamlfind ocamlopt -package re.glob,opam-lib.state -linkpkg ../src/tools/opam_admin_top.ml couverture-tmp.ml -o $@ rm couverture-tmp.ml opam-2.1.5/admin-scripts/lint.ml0000755000175000017500000000354214427463453015603 0ustar stephsteph#!/usr/bin/env opam-admin.top #directory "+../opam-lib";; open Opam_admin_top;; let includes = ref [] let excludes = ref [] let short = ref false let list = ref false let usage = "Arguments:\n\ \ -s\tshort format, don't print explanations\n\ \ -l\tlist format, only print package names\n\ \ [N]\tshow only the listed warnings\n\ \ -[N]\tskip any packages that trigger any of these warnings\n\ " let () = let args = match Array.to_list Sys.argv with | _::args -> args | [] -> [] in List.iter (function | "-s" -> short := true | "-l" -> list := true | a -> try if String.length a > 0 && a.[0] = '-' then excludes := 0 - int_of_string a :: !excludes else includes := int_of_string a :: !includes with Failure _ -> OpamConsole.msg "%s" usage; OpamStd.Sys.exit_because `Bad_argument) args let () = OpamPackage.Map.iter (fun nv prefix -> let opam_file = OpamRepositoryPath.opam repo prefix nv in let w, _ = OpamFileTools.lint_file opam_file in if List.exists (fun (n,_,_) -> List.mem n !excludes) w then () else let w = if !includes = [] then w else List.filter (fun (n,_,_) -> List.mem n !includes) w in if w <> [] then if !list then print_endline (OpamPackage.to_string nv) else if !short then OpamConsole.msg "%s %s\n" (OpamPackage.to_string nv) (OpamStd.List.concat_map " " (fun (n,k,_) -> OpamConsole.colorise (match k with `Warning -> `yellow | `Error -> `red) (string_of_int n)) w) else OpamConsole.msg "\r\027[KIn %s:\n%s\n" (OpamPackage.to_string nv) (OpamFileTools.warns_to_string w)) (OpamRepository.packages_with_prefixes repo) opam-2.1.5/dune-project0000644000175000017500000000003514427463453014037 0ustar stephsteph(lang dune 1.11) (name opam) opam-2.1.5/opam-installer.opam0000644000175000017500000000241614427463453015327 0ustar stephstephopam-version: "2.0" version: "2.1.5" synopsis: "Installation of files to a prefix, following opam conventions" description: """ opam-installer is a small tool that can read *.install files, as defined by opam [1], and execute them to install or remove package files without going through opam. [1] http://opam.ocaml.org/doc/2.0/Manual.html#lt-pkgname-gt-install """ maintainer: "opam-devel@lists.ocaml.org" authors: [ "Vincent Bernardoff " "Raja Boujbel " "Roberto Di Cosmo " "Thomas Gazagnaire " "Louis Gesbert " "Fabrice Le Fessant " "Anil Madhavapeddy " "Guillem Rieu " "Ralf Treinen " "Frederic Tuong " ] homepage: "https://opam.ocaml.org" bug-reports: "https://github.com/ocaml/opam/issues" dev-repo: "git+https://github.com/ocaml/opam.git" license: "LGPL-2.1-only WITH OCaml-LGPL-linking-exception" build: [ ["./configure" "--disable-checks" "--prefix" prefix] ["dune" "build" "-p" name "-j" jobs] ] depends: [ "ocaml" {>= "4.02.3"} "opam-format" {= version} "cmdliner" {>= "0.9.8"} "dune" {>= "1.11.0"} ] opam-2.1.5/.gitignore0000644000175000017500000000251214427463453013507 0ustar stephsteph_build/ _obuild/ _opam/ _olint/ bootstrap/ tests/tmp/ tests/.merlin tests/reftests/.merlin .*.swp src_ext/lib src_ext/cudf/ src_ext/cppo/ src_ext/dose3/ src_ext/cmdliner/ src_ext/extlib/ src_ext/mccs/ src_ext/re/ src_ext/ocamlgraph/ src_ext/dune-local/ src_ext/result/ src_ext/stdlib-shims/ src_ext/opam-file-format/ src_ext/camlp4 src_ext/findlib src_ext/ocamlbuild src_ext/topkg src_ext/seq src_ext/secondary/ src_ext/*.*stamp src_ext/*.tbz src_ext/*.tar.gz src_ext/archives/* src_ext/*.*download src_ext/*.pkgbuild src_ext/dune Opam.Runtime.*/ *.tar.bz2 *.annot *.tar.gz *~ .#* \#*# opam opam-installer opam-admin.top opam.exe opam-installer.exe opam-admin.top.exe # debug files *.log *.cudf *.dot # Generated files: *.cmo *.cmx *.cmi *.cmt *.cmti *.cma *.cmxa *.cmxs *.a *.lib *.dll *.o *.obj *.install Makefile.config config.log config.status aclocal.m4 autom4te.cache src/ocaml-flags-configure.sexp src/**/.merlin src/client/linking.sexp src/client/no-git-version src/core/developer src/manifest/dune src/manifest/install.inc src/stubs/libacl/dune src/stubs/libacl/c-libraries.sexp src/stubs/win32/cc64 src/stubs/win32/dune src/stubs/c-flags.sexp # doc doc/dev-manual/*aux doc/dev-manual/*.html doc/dev-manual/*toc doc/html doc/man/.merlin doc/man-html doc/tutorials/opam.wiki doc/dev-manual/*.out doc/pages/*.html doc/*.build src/x_build_libs.ocp opam-2.1.5/Makefile.config.in0000644000175000017500000000203214427463453015025 0ustar stephstephdatarootdir = @datarootdir@ prefix = @prefix@ mandir = @mandir@ version = @PACKAGE_VERSION@ FETCH = @fetch@ PACKS = $(filter-out no,@OCAML_PKG_unix@ @OCAML_PKG_bigarray@ @OCAML_PKG_extlib@ @OCAML_PKG_re@ @OCAML_PKG_re_glob@ @OCAML_PKG_cmdliner@ @OCAML_PKG_ocamlgraph@ @OCAML_PKG_cudf@ @OCAML_PKG_dose3_common@ @OCAML_PKG_dose3_algo@ @OCAML_PKG_opam_file_format@ @OCAML_PKG_mccs@) CONF_OCAMLFLAGS = @CONF_OCAMLFLAGS@ MCCS_ENABLED = @MCCS_ENABLED@ OPAM_0INSTALL_SOLVER_ENABLED = @OPAM_0INSTALL_SOLVER_ENABLED@ OCAMLLIB = @OCAMLLIB@ OCAMLFIND = @OCAMLFIND@ OCAML = @OCAML@ OCAMLC = @OCAMLC@ OCAMLOPT = @OCAMLOPT@ DUNE = @DUNE@ DUNE_SECONDARY = @DUNE_SECONDARY@ LN_S = @LN_S@ EXE = @EXE@ WIN32 = @WIN32@ PATH:=@PATH_PREPEND@$(PATH) INCLUDE:=@INC_PREPEND@$(INCLUDE) LIB:=@LIB_PREPEND@$(LIB) LIB_PREFIX = @LIB_PREFIX@ CPATH = @CPATH@ LIBRARY_PATH = @LIBRARY_PATH@ MANIFEST_ARCH = @MANIFEST_ARCH@ RUNTIME_GCC_S = @RUNTIME_GCC_S@ PATCH = @PATCH@ export OCAMLVERSION OCAMLFIND OCAML OCAMLC OCAMLOPT EXE PATH INCLUDE LIB CPATH LIBRARY_PATH OCAMLLIB opam-2.1.5/opam-format.opam0000644000175000017500000000212514427463453014617 0ustar stephstephopam-version: "2.0" version: "2.1.5" synopsis: "Format library for opam 2.1" description: """ Definition of opam datastructures and its file interface. """ maintainer: "opam-devel@lists.ocaml.org" authors: [ "Vincent Bernardoff " "Raja Boujbel " "Roberto Di Cosmo " "Thomas Gazagnaire " "Louis Gesbert " "Fabrice Le Fessant " "Anil Madhavapeddy " "Guillem Rieu " "Ralf Treinen " "Frederic Tuong " ] homepage: "https://opam.ocaml.org" bug-reports: "https://github.com/ocaml/opam/issues" dev-repo: "git+https://github.com/ocaml/opam.git" license: "LGPL-2.1-only WITH OCaml-LGPL-linking-exception" build: [ ["./configure" "--disable-checks" "--prefix" prefix] ["dune" "build" "-p" name "-j" jobs] ] depends: [ "ocaml" {>= "4.02.3"} "opam-core" {= version} "opam-file-format" {>= "2.1.4"} "re" {>= "1.9.0"} "dune" {>= "1.11.0"} ] opam-2.1.5/m4/0002755000175000017500000000000014427463453012041 5ustar stephstephopam-2.1.5/m4/ocaml.m40000644000175000017500000001662014427463453013401 0ustar stephstephdnl autoconf macros for OCaml dnl dnl Copyright © 2009 Richard W.M. Jones dnl Copyright © 2009 Stefano Zacchiroli dnl Copyright © 2000-2005 Olivier Andrieu dnl Copyright © 2000-2005 Jean-Christophe Filliâtre dnl Copyright © 2000-2005 Georges Mariano dnl dnl For documentation, please read the ocaml.m4 man page. AC_DEFUN([AC_PROG_OCAML], [dnl # checking for ocamlc AC_CHECK_TOOL([OCAMLC],[ocamlc],[no]) if test "$OCAMLC" != "no"; then OCAMLVERSION=`$OCAMLC -v | tr -d '\015' | sed -n -e 's|.*version* *\(.*\)$|\1|p'` AC_MSG_RESULT([OCaml version is $OCAMLVERSION]) # If OCAMLLIB is set, use it if test "$OCAMLLIB" = ""; then OCAMLLIB=`$OCAMLC -where 2>/dev/null | tr -d '\015' || $OCAMLC -v|tail -1|cut -d ' ' -f 4` else AC_MSG_RESULT([OCAMLLIB previously set; preserving it.]) fi AC_MSG_RESULT([OCaml library path is $OCAMLLIB]) AC_SUBST([OCAMLVERSION]) AC_SUBST([OCAMLLIB]) # checking for ocamlopt AC_CHECK_TOOL([OCAMLOPT],[ocamlopt],[no]) OCAMLBEST=byte if test "$OCAMLOPT" = "no"; then AC_MSG_WARN([Cannot find ocamlopt; bytecode compilation only.]) else TMPVERSION=`$OCAMLOPT -v | tr -d '\015' | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` if test "$TMPVERSION" != "$OCAMLVERSION" ; then AC_MSG_RESULT([versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlopt discarded.]) OCAMLOPT=no else OCAMLBEST=opt fi fi AC_SUBST([OCAMLBEST]) # checking for ocamlc.opt AC_CHECK_TOOL([OCAMLCDOTOPT],[ocamlc.opt],[no]) if test "$OCAMLCDOTOPT" != "no"; then TMPVERSION=`$OCAMLCDOTOPT -v | tr -d '\015' | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` if test "$TMPVERSION" != "$OCAMLVERSION" ; then AC_MSG_RESULT([versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlc.opt discarded.]) else OCAMLC=$OCAMLCDOTOPT fi fi # checking for ocamlopt.opt if test "$OCAMLOPT" != "no" ; then AC_CHECK_TOOL([OCAMLOPTDOTOPT],[ocamlopt.opt],[no]) if test "$OCAMLOPTDOTOPT" != "no"; then TMPVERSION=`$OCAMLOPTDOTOPT -v | tr -d '\015' | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` if test "$TMPVERSION" != "$OCAMLVERSION" ; then AC_MSG_RESULT([versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlopt.opt discarded.]) else OCAMLOPT=$OCAMLOPTDOTOPT fi fi fi AC_SUBST([OCAMLOPT]) fi AC_SUBST([OCAMLC]) # checking for ocaml toplevel AC_CHECK_TOOL([OCAML],[ocaml],[no]) # checking for ocamldep AC_CHECK_TOOL([OCAMLDEP],[ocamldep],[no]) # checking for ocamldep.opt if test "$OCAMLDEP" != "no" ; then AC_CHECK_TOOL([OCAMLDEPDOTOPT],[ocamldep.opt],[no]) if test "$OCAMLDEPDOTOPT" != "no"; then TMPVERSION=`$OCAMLDEPDOTOPT -version | tr -d '\015' | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` if test "$TMPVERSION" != "$OCAMLVERSION" ; then AC_MSG_RESULT([version differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamldep.opt discarded.]) else OCAMLDEP=$OCAMLDEPDOTOPT fi fi fi # checking for ocamlmktop AC_CHECK_TOOL([OCAMLMKTOP],[ocamlmktop],[no]) # checking for ocamlmklib AC_CHECK_TOOL([OCAMLMKLIB],[ocamlmklib],[no]) # checking for ocamldoc AC_CHECK_TOOL([OCAMLDOC],[ocamldoc],[no]) # checking for ocamldoc.opt if test "$OCAMLDOC" != "no" ; then AC_CHECK_TOOL([OCAMLDOCDOTOPT],[ocamldoc.opt],[no]) if test "$OCAMLDOCDOTOPT" != "no"; then TMPVERSION=`$OCAMLDOCDOTOPT -version | tr -d '\015'` if test "$TMPVERSION" != "$OCAMLVERSION" ; then AC_MSG_RESULT([version differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamldoc.opt discarded.]) else OCAMLDOC=$OCAMLDOCDOTOPT fi fi fi # checking for ocamlbuild AC_CHECK_TOOL([OCAMLBUILD],[ocamlbuild],[no]) ]) AC_DEFUN([AC_PROG_OCAMLLEX], [dnl # checking for ocamllex AC_CHECK_TOOL([OCAMLLEX],[ocamllex],[no]) if test "$OCAMLLEX" != "no"; then AC_CHECK_TOOL([OCAMLLEXDOTOPT],[ocamllex.opt],[no]) if test "$OCAMLLEXDOTOPT" != "no"; then OCAMLLEX=$OCAMLLEXDOTOPT fi fi AC_SUBST([OCAMLLEX]) ]) AC_DEFUN([AC_PROG_OCAMLYACC], [dnl AC_CHECK_TOOL([OCAMLYACC],[ocamlyacc],[no]) AC_SUBST([OCAMLYACC]) ]) AC_DEFUN([AC_PROG_CAMLP4], [dnl AC_REQUIRE([AC_PROG_OCAML])dnl # checking for camlp4 AC_CHECK_TOOL([CAMLP4],[camlp4],[no]) if test "$CAMLP4" != "no"; then TMPVERSION=`$CAMLP4 -v 2>&1| tr -d '\015' | sed -n -e 's|.*version *\(.*\)$|\1|p'` if test "$TMPVERSION" != "$OCAMLVERSION" ; then AC_MSG_RESULT([versions differs from ocamlc $TMPVERSION != $OCAMLVERSION.]) CAMLP4=no fi fi AC_SUBST([CAMLP4]) # checking for companion tools AC_CHECK_TOOL([CAMLP4O],[camlp4o],[no]) AC_CHECK_TOOL([CAMLP4OF],[camlp4of],[no]) AC_CHECK_TOOL([CAMLP4OOF],[camlp4oof],[no]) AC_CHECK_TOOL([CAMLP4ORF],[camlp4orf],[no]) AC_CHECK_TOOL([CAMLP4PROF],[camlp4prof],[no]) AC_CHECK_TOOL([CAMLP4R],[camlp4r],[no]) AC_CHECK_TOOL([CAMLP4RF],[camlp4rf],[no]) AC_SUBST([CAMLP4O]) AC_SUBST([CAMLP4OF]) AC_SUBST([CAMLP4OOF]) AC_SUBST([CAMLP4ORF]) AC_SUBST([CAMLP4PROF]) AC_SUBST([CAMLP4R]) AC_SUBST([CAMLP4RF]) ]) AC_DEFUN([AC_PROG_OCAMLOBJINFO], [dnl AC_CHECK_TOOL([OCAMLOBJINFO],[ocamlobjinfo],[no]) AC_SUBST([OCAMLOBJINFO]) ]) AC_DEFUN([AC_PROG_FINDLIB], [dnl AC_REQUIRE([AC_PROG_OCAML])dnl AC_REQUIRE([AC_PROG_OCAMLOBJINFO])dnl # checking for ocamlfind AC_CHECK_TOOL([OCAMLFIND],[ocamlfind],[no]) AS_IF([test "$OCAMLFIND" != "no"],[ AS_IF([test "$OCAMLOBJINFO" = "no"],[AC_MSG_WARN([ocamlobjinfo not found; cannot verify ocamlfind])],[ AS_IF([! $OCAMLOBJINFO `$OCAMLFIND query -predicates byte -a-format findlib | tr -d '\015'` > /dev/null 2>&1],[ AC_MSG_RESULT([site-lib is for a different version of OCaml; ocamlfind discarded.]) OCAMLFIND=no ]) ]) ]) AC_SUBST([OCAMLFIND]) ]) dnl Thanks to Jim Meyering for working this next bit out for us. dnl XXX We should define AS_TR_SH if it's not defined already dnl (eg. for old autoconf). AC_DEFUN([AC_CHECK_OCAML_PKG], [dnl AC_REQUIRE([AC_PROG_FINDLIB])dnl AC_MSG_CHECKING([for OCaml findlib package $1]) unset found unset pkg found=no for pkg in $1 $2 ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then AC_MSG_RESULT([found]) AS_TR_SH([OCAML_PKG_$1])=$pkg found=yes break fi done if test "$found" = "no" ; then AC_MSG_RESULT([not found]) AS_TR_SH([OCAML_PKG_$1])=no fi AC_SUBST(AS_TR_SH([OCAML_PKG_$1])) ]) AC_DEFUN([AC_CHECK_OCAML_MODULE], [dnl AC_MSG_CHECKING([for OCaml module $2]) cat > conftest.ml <&5 2>&5 ; then found=yes break fi done if test "$found" ; then AC_MSG_RESULT([$$1]) else AC_MSG_RESULT([not found]) $1=no fi AC_SUBST([$1]) ]) dnl XXX Cross-compiling AC_DEFUN([AC_CHECK_OCAML_WORD_SIZE], [dnl AC_REQUIRE([AC_PROG_OCAML])dnl AC_MSG_CHECKING([for OCaml compiler word size]) cat > conftest.ml < conftest.ml <= B) # lt - less than (test A < B) # gt - greater than (test A > B) # # Additionally, the eq and ne operator can have a number after it to limit # the test to that number of minor versions. # # eq0 - equal up to the length of the shorter version # ne0 - not equal up to the length of the shorter version # eqN - equal up to N sub-version levels # neN - not equal up to N sub-version levels # # When the condition is true, shell commands ACTION-IF-TRUE are run, # otherwise shell commands ACTION-IF-FALSE are run. The environment # variable 'ax_compare_version' is always set to either 'true' or 'false' # as well. # # Examples: # # AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8]) # AX_COMPARE_VERSION([3.15],[lt],[3.15.8]) # # would both be true. # # AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8]) # AX_COMPARE_VERSION([3.15],[gt],[3.15.8]) # # would both be false. # # AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8]) # # would be true because it is only comparing two minor versions. # # AX_COMPARE_VERSION([3.15.7],[eq0],[3.15]) # # would be true because it is only comparing the lesser number of minor # versions of the two values. # # Note: The characters that separate the version numbers do not matter. An # empty string is the same as version 0. OP is evaluated by autoconf, not # configure, so must be a string, not a variable. # # The author would like to acknowledge Guido Draheim whose advice about # the m4_case and m4_ifvaln functions make this macro only include the # portions necessary to perform the specific comparison specified by the # OP argument in the final configure script. # # LICENSE # # Copyright (c) 2008 Tim Toolan # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 11 dnl ######################################################################### AC_DEFUN([AX_COMPARE_VERSION], [ AC_REQUIRE([AC_PROG_AWK]) # Used to indicate true or false condition ax_compare_version=false # Convert the two version strings to be compared into a format that # allows a simple string comparison. The end result is that a version # string of the form 1.12.5-r617 will be converted to the form # 0001001200050617. In other words, each number is zero padded to four # digits, and non digits are removed. AS_VAR_PUSHDEF([A],[ax_compare_version_A]) A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/[[^0-9]]//g'` AS_VAR_PUSHDEF([B],[ax_compare_version_B]) B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/[[^0-9]]//g'` dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary dnl # then the first line is used to determine if the condition is true. dnl # The sed right after the echo is to remove any indented white space. m4_case(m4_tolower($2), [lt],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"` ], [gt],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"` ], [le],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"` ], [ge],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` ],[ dnl Split the operator from the subversion count if present. m4_bmatch(m4_substr($2,2), [0],[ # A count of zero means use the length of the shorter version. # Determine the number of characters in A and B. ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'` ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'` # Set A to no more than B's length and B to no more than A's length. A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` ], [[0-9]+],[ # A count greater than zero means use only that many subversions A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` ], [.+],[ AC_WARNING( [illegal OP numeric parameter: $2]) ],[]) # Pad zeros at end of numbers to make same length. ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`" B="$B`echo $A | sed 's/./0/g'`" A="$ax_compare_version_tmp_A" # Check for equality or inequality as necessary. m4_case(m4_tolower(m4_substr($2,0,2)), [eq],[ test "x$A" = "x$B" && ax_compare_version=true ], [ne],[ test "x$A" != "x$B" && ax_compare_version=true ],[ AC_WARNING([illegal OP parameter: $2]) ]) ]) AS_VAR_POPDEF([A])dnl AS_VAR_POPDEF([B])dnl dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE. if test "$ax_compare_version" = "true" ; then m4_ifvaln([$4],[$4],[:])dnl m4_ifvaln([$5],[else $5])dnl fi ]) dnl AX_COMPARE_VERSION opam-2.1.5/opam-devel.opam0000644000175000017500000000327614427463453014436 0ustar stephstephopam-version: "2.0" version: "2.1.5" synopsis: "Bootstrapped development binary for opam 2.1" description: """ This package compiles (bootstraps) opam. For consistency and safety of the installation, the binaries are not installed into the PATH, but into lib/opam-devel, from where the user can manually install them system-wide. """ maintainer: "opam-devel@lists.ocaml.org" authors: [ "Vincent Bernardoff " "Raja Boujbel " "Roberto Di Cosmo " "Thomas Gazagnaire " "Louis Gesbert " "Fabrice Le Fessant " "Anil Madhavapeddy " "Guillem Rieu " "Ralf Treinen " "Frederic Tuong " ] homepage: "https://opam.ocaml.org" bug-reports: "https://github.com/ocaml/opam/issues" dev-repo: "git+https://github.com/ocaml/opam.git" license: "LGPL-2.1-only WITH OCaml-LGPL-linking-exception" build: [ ["./configure" "--disable-checks" "--prefix" prefix] [make "%{name}%.install"] ] depends: [ "ocaml" {>= "4.02.3"} "opam-client" {= version} "cmdliner" {>= "0.9.8"} "dune" {>= "1.11.0"} "conf-openssl" {with-test} "conf-diffutils" {with-test} ] post-messages: [ "The development version of opam has been successfully compiled into %{lib}%/%{name}%. You should not run it from there, please install the binaries to your PATH, e.g. with sudo cp %{lib}%/%{name}%/opam /usr/local/bin If you just want to give it a try without altering your current installation, you could use instead: alias opam2=\"OPAMROOT=~/.opam2 %{lib}%/%{name}%/opam\"" {success} ] opam-2.1.5/master_changes.md0000644000175000017500000000152114427463453015023 0ustar stephstephWorking version changelog, used as a base for the changelog and the release note. Possibly scripts breaking changes are prefixed with ✘. New option/command/subcommand are prefixed with ◈. ## Version * ## Global CLI * ## Plugins * ## Init ## Config report * ## Install * ## Remove * ## Switch ## Pin * ## List ## Show ## Var/Option ## Lint * ## Lock * ## Opamfile * ## External dependencies ## Sandbox ## Repository management * ## VCS * ## Build ## Infrastructure * ## Admin * ## Opam installer * ## State # Opam file format * ## Solver * ## Client ## Internal * ## Test * ## Reftests ### Tests ### Engine ## Github Actions ## Shell ## Doc ## Security fixes * # API updates ## opam-client ## opam-repository ## opam-state ## opam-solver ## opam-format ## opam-core opam-2.1.5/AUTHORS0000644000175000017500000000070114427463453012565 0ustar stephstephVincent Bernardoff Raja Boujbel Roberto Di Cosmo Thomas Gazagnaire Louis Gesbert Fabrice Le Fessant Anil Madhavapeddy Guillem Rieu Ralf Treinen Frederic Tuong opam-2.1.5/opam-core.opam0000644000175000017500000000223514427463453014261 0ustar stephstephopam-version: "2.0" version: "2.1.5" synopsis: "Core library for opam 2.1" description: """ Small standard library extensions, and generic system interaction modules used by opam. """ maintainer: "opam-devel@lists.ocaml.org" authors: [ "Vincent Bernardoff " "Raja Boujbel " "Roberto Di Cosmo " "Thomas Gazagnaire " "Louis Gesbert " "Fabrice Le Fessant " "Anil Madhavapeddy " "Guillem Rieu " "Ralf Treinen " "Frederic Tuong " ] homepage: "https://opam.ocaml.org" bug-reports: "https://github.com/ocaml/opam/issues" dev-repo: "git+https://github.com/ocaml/opam.git" license: "LGPL-2.1-only WITH OCaml-LGPL-linking-exception" build: [ ["./configure" "--disable-checks" "--prefix" prefix] ["dune" "build" "-p" name "-j" jobs] ] depends: [ "ocaml" {>= "4.02.3"} "base-unix" "base-bigarray" "ocamlgraph" "re" {>= "1.9.0"} "dune" {>= "1.11.0"} "cppo" {build & >= "1.1.0"} ] conflicts: "extlib-compat" opam-2.1.5/opam-solver.opam0000644000175000017500000000250714427463453014645 0ustar stephstephopam-version: "2.0" version: "2.1.5" synopsis: "Solver library for opam 2.1" description: """ Solver and Cudf interaction. This library is based on the Cudf and Dose libraries, and handles calls to the external solver from opam. """ maintainer: "opam-devel@lists.ocaml.org" authors: [ "Vincent Bernardoff " "Raja Boujbel " "Roberto Di Cosmo " "Thomas Gazagnaire " "Louis Gesbert " "Fabrice Le Fessant " "Anil Madhavapeddy " "Guillem Rieu " "Ralf Treinen " "Frederic Tuong " ] homepage: "https://opam.ocaml.org" bug-reports: "https://github.com/ocaml/opam/issues" dev-repo: "git+https://github.com/ocaml/opam.git" license: "LGPL-2.1-only WITH OCaml-LGPL-linking-exception" build: [ ["./configure" "--disable-checks" "--prefix" prefix] ["dune" "build" "-p" name "-j" jobs] ] depends: [ "ocaml" {>= "4.02.3"} "opam-format" {= version} "mccs" {>= "1.1+9"} ("dose3" {>= "6.1"} | "dose3" {>= "5"} & "ocaml" {= "4.02.3"}) "cudf" {>= "0.7"} "dune" {>= "1.11.0"} ] depopts: [ "z3" "opam-0install-cudf" ] conflicts: [ "z3" {< "4.8.4"} "opam-0install-cudf" {< "0.4"} ] opam-2.1.5/appveyor.yml0000644000175000017500000000300114427463453014101 0ustar stephstephplatform: - x64 image: Visual Studio 2019 environment: global: CYG_ROOT: cygwin64 CYG_ARCH: x86_64 CYGWIN: winsymlinks:native OCAML_PORT: CYG_CACHE: C:/cygwin/var/cache/setup CYG_MIRROR: http://mirrors.kernel.org/sourceware/cygwin/ DEP_MODE: lib-ext # This should be identical to the value in .travis.yml OPAM_REPO: https://github.com/ocaml/opam-repository.git OPAM_REPO_SHA: 3d6779beedc761067596bf5c3f5c25ab57a7e3e7 OPAM_TEST_REPO_SHA: 3d6779beedc761067596bf5c3f5c25ab57a7e3e7 matrix: - CYG_ROOT: cygwin64 CYG_ARCH: x86_64 DEP_MODE: lib-pkg - appveyor_build_worker_image: Visual Studio 2017 OCAML_PORT: msvc DEP_MODE: lib-pkg GIT_FOR_WINDOWS: 1 - appveyor_build_worker_image: Visual Studio 2017 OCAML_PORT: msvc64 - OCAML_PORT: mingw - OCAML_PORT: mingw64 DEP_MODE: lib-pkg GIT_FOR_WINDOWS: 1 cache: - C:\projects\opam\bootstrap - C:\projects\opam\src_ext\archives install: - call "%APPVEYOR_BUILD_FOLDER%\appveyor_build.cmd" install build_script: - call "%APPVEYOR_BUILD_FOLDER%\appveyor_build.cmd" build test_script: - call "%APPVEYOR_BUILD_FOLDER%\appveyor_build.cmd" test # Uncomment this to enable Remote Desktop on the build worker at the end of the # build. The worker is available for the remainder of the allocated hour. #on_finish: # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) opam-2.1.5/opam-repository.opam0000644000175000017500000000214514427463453015550 0ustar stephstephopam-version: "2.0" version: "2.1.5" synopsis: "Repository library for opam 2.1" description: """ This library includes repository and remote sources handling, including curl/wget, rsync, git, mercurial, darcs backends. """ maintainer: "opam-devel@lists.ocaml.org" authors: [ "Vincent Bernardoff " "Raja Boujbel " "Roberto Di Cosmo " "Thomas Gazagnaire " "Louis Gesbert " "Fabrice Le Fessant " "Anil Madhavapeddy " "Guillem Rieu " "Ralf Treinen " "Frederic Tuong " ] homepage: "https://opam.ocaml.org" bug-reports: "https://github.com/ocaml/opam/issues" dev-repo: "git+https://github.com/ocaml/opam.git" license: "LGPL-2.1-only WITH OCaml-LGPL-linking-exception" build: [ ["./configure" "--disable-checks" "--prefix" prefix] ["dune" "build" "-p" name "-j" jobs] ] depends: [ "ocaml" {>= "4.02.3"} "opam-format" {= version} "dune" {>= "1.11.0"} ] opam-2.1.5/doc/0002755000175000017500000000000014427463453012266 5ustar stephstephopam-2.1.5/doc/man/0002755000175000017500000000000014427463453013041 5ustar stephstephopam-2.1.5/doc/man/dune0000644000175000017500000000266514427463453013726 0ustar stephsteph; opam must always be invoked as %{bin:opam} to ensure that the manifested runtime on mingw is ; assembled, if it was selected at configure-time (%{exe:opamMain.exe} is not executable in this ; case. (rule (targets opam.1) (deps opam-topics.inc opam-admin-topics.inc) (action (with-stdout-to %{targets} (run %{bin:opam} --help=groff)))) (install (section man) (package opam) (files opam.1)) (rule (with-stdout-to opam-installer.1 (run %{bin:opam-installer} --help=groff))) (install (section man) (package opam-installer) (files opam-installer.1)) (executable (name dune_man) (libraries unix)) (rule (targets opam-topics.inc) (deps %{bin:opam} using-built-opam) (mode promote) (action (with-stdout-to %{targets} (run %{exe:dune_man.exe} opam)))) (rule (targets opam-admin-topics.inc) (deps %{bin:opam} using-built-opam) (mode promote) (action (with-stdout-to %{targets} (run %{exe:dune_man.exe} opam admin)))) (include opam-topics.inc) (include opam-admin-topics.inc) ; This ensures that no opam command run will block asking for input (env (_ (env-vars ("OPAMYES" "no")))) ; This ensure that %{bin:opam} really refers to the opam built in the tree (rule (with-stdout-to check_local_build.ml (echo "let s = Sys.argv.(1) in exit (if not (Filename.is_implicit s) && Filename.is_relative s then 0 else 1)"))) (rule (with-stdout-to using-built-opam (run ocaml %{dep:check_local_build.ml} %{bin:opam}))) opam-2.1.5/doc/man/opam-topics.inc0000644000175000017500000002207414427463453015772 0ustar stephsteph;; Generated by dune_man (rule (with-stdout-to opam-help.0 (echo ""))) (rule (targets opam-help.1 opam-help.err) (deps using-built-opam) (action (progn (with-stderr-to opam-help.err (with-stdout-to opam-help.1 (run %{bin:opam} help --help=groff))) (diff opam-help.err %{dep:opam-help.0})))) (rule (with-stdout-to opam-admin.0 (echo ""))) (rule (targets opam-admin.1 opam-admin.err) (deps using-built-opam) (action (progn (with-stderr-to opam-admin.err (with-stdout-to opam-admin.1 (run %{bin:opam} admin --help=groff))) (diff opam-admin.err %{dep:opam-admin.0})))) (rule (with-stdout-to opam-lock.0 (echo ""))) (rule (targets opam-lock.1 opam-lock.err) (deps using-built-opam) (action (progn (with-stderr-to opam-lock.err (with-stdout-to opam-lock.1 (run %{bin:opam} lock --help=groff))) (diff opam-lock.err %{dep:opam-lock.0})))) (rule (with-stdout-to opam-clean.0 (echo ""))) (rule (targets opam-clean.1 opam-clean.err) (deps using-built-opam) (action (progn (with-stderr-to opam-clean.err (with-stdout-to opam-clean.1 (run %{bin:opam} clean --help=groff))) (diff opam-clean.err %{dep:opam-clean.0})))) (rule (with-stdout-to opam-lint.0 (echo ""))) (rule (targets opam-lint.1 opam-lint.err) (deps using-built-opam) (action (progn (with-stderr-to opam-lint.err (with-stdout-to opam-lint.1 (run %{bin:opam} lint --help=groff))) (diff opam-lint.err %{dep:opam-lint.0})))) (rule (with-stdout-to opam-source.0 (echo ""))) (rule (targets opam-source.1 opam-source.err) (deps using-built-opam) (action (progn (with-stderr-to opam-source.err (with-stdout-to opam-source.1 (run %{bin:opam} source --help=groff))) (diff opam-source.err %{dep:opam-source.0})))) (rule (with-stdout-to opam-unpin.0 (echo ""))) (rule (targets opam-unpin.1 opam-unpin.err) (deps using-built-opam) (action (progn (with-stderr-to opam-unpin.err (with-stdout-to opam-unpin.1 (run %{bin:opam} unpin --help=groff))) (diff opam-unpin.err %{dep:opam-unpin.0})))) (rule (with-stdout-to opam-pin.0 (echo ""))) (rule (targets opam-pin.1 opam-pin.err) (deps using-built-opam) (action (progn (with-stderr-to opam-pin.err (with-stdout-to opam-pin.1 (run %{bin:opam} pin --help=groff))) (diff opam-pin.err %{dep:opam-pin.0})))) (rule (with-stdout-to opam-switch.0 (echo ""))) (rule (targets opam-switch.1 opam-switch.err) (deps using-built-opam) (action (progn (with-stderr-to opam-switch.err (with-stdout-to opam-switch.1 (run %{bin:opam} switch --help=groff))) (diff opam-switch.err %{dep:opam-switch.0})))) (rule (with-stdout-to opam-remote.0 (echo ""))) (rule (targets opam-remote.1 opam-remote.err) (deps using-built-opam) (action (progn (with-stderr-to opam-remote.err (with-stdout-to opam-remote.1 (run %{bin:opam} remote --help=groff))) (diff opam-remote.err %{dep:opam-remote.0})))) (rule (with-stdout-to opam-repository.0 (echo ""))) (rule (targets opam-repository.1 opam-repository.err) (deps using-built-opam) (action (progn (with-stderr-to opam-repository.err (with-stdout-to opam-repository.1 (run %{bin:opam} repository --help=groff))) (diff opam-repository.err %{dep:opam-repository.0})))) (rule (with-stdout-to opam-env.0 (echo ""))) (rule (targets opam-env.1 opam-env.err) (deps using-built-opam) (action (progn (with-stderr-to opam-env.err (with-stdout-to opam-env.1 (run %{bin:opam} env --help=groff))) (diff opam-env.err %{dep:opam-env.0})))) (rule (with-stdout-to opam-exec.0 (echo ""))) (rule (targets opam-exec.1 opam-exec.err) (deps using-built-opam) (action (progn (with-stderr-to opam-exec.err (with-stdout-to opam-exec.1 (run %{bin:opam} exec --help=groff))) (diff opam-exec.err %{dep:opam-exec.0})))) (rule (with-stdout-to opam-config.0 (echo ""))) (rule (targets opam-config.1 opam-config.err) (deps using-built-opam) (action (progn (with-stderr-to opam-config.err (with-stdout-to opam-config.1 (run %{bin:opam} config --help=groff))) (diff opam-config.err %{dep:opam-config.0})))) (rule (with-stdout-to opam-option.0 (echo ""))) (rule (targets opam-option.1 opam-option.err) (deps using-built-opam) (action (progn (with-stderr-to opam-option.err (with-stdout-to opam-option.1 (run %{bin:opam} option --help=groff))) (diff opam-option.err %{dep:opam-option.0})))) (rule (with-stdout-to opam-var.0 (echo ""))) (rule (targets opam-var.1 opam-var.err) (deps using-built-opam) (action (progn (with-stderr-to opam-var.err (with-stdout-to opam-var.1 (run %{bin:opam} var --help=groff))) (diff opam-var.err %{dep:opam-var.0})))) (rule (with-stdout-to opam-upgrade.0 (echo ""))) (rule (targets opam-upgrade.1 opam-upgrade.err) (deps using-built-opam) (action (progn (with-stderr-to opam-upgrade.err (with-stdout-to opam-upgrade.1 (run %{bin:opam} upgrade --help=groff))) (diff opam-upgrade.err %{dep:opam-upgrade.0})))) (rule (with-stdout-to opam-update.0 (echo ""))) (rule (targets opam-update.1 opam-update.err) (deps using-built-opam) (action (progn (with-stderr-to opam-update.err (with-stdout-to opam-update.1 (run %{bin:opam} update --help=groff))) (diff opam-update.err %{dep:opam-update.0})))) (rule (with-stdout-to opam-reinstall.0 (echo ""))) (rule (targets opam-reinstall.1 opam-reinstall.err) (deps using-built-opam) (action (progn (with-stderr-to opam-reinstall.err (with-stdout-to opam-reinstall.1 (run %{bin:opam} reinstall --help=groff))) (diff opam-reinstall.err %{dep:opam-reinstall.0})))) (rule (with-stdout-to opam-uninstall.0 (echo ""))) (rule (targets opam-uninstall.1 opam-uninstall.err) (deps using-built-opam) (action (progn (with-stderr-to opam-uninstall.err (with-stdout-to opam-uninstall.1 (run %{bin:opam} uninstall --help=groff))) (diff opam-uninstall.err %{dep:opam-uninstall.0})))) (rule (with-stdout-to opam-remove.0 (echo ""))) (rule (targets opam-remove.1 opam-remove.err) (deps using-built-opam) (action (progn (with-stderr-to opam-remove.err (with-stdout-to opam-remove.1 (run %{bin:opam} remove --help=groff))) (diff opam-remove.err %{dep:opam-remove.0})))) (rule (with-stdout-to opam-install.0 (echo ""))) (rule (targets opam-install.1 opam-install.err) (deps using-built-opam) (action (progn (with-stderr-to opam-install.err (with-stdout-to opam-install.1 (run %{bin:opam} install --help=groff))) (diff opam-install.err %{dep:opam-install.0})))) (rule (with-stdout-to opam-info.0 (echo ""))) (rule (targets opam-info.1 opam-info.err) (deps using-built-opam) (action (progn (with-stderr-to opam-info.err (with-stdout-to opam-info.1 (run %{bin:opam} info --help=groff))) (diff opam-info.err %{dep:opam-info.0})))) (rule (with-stdout-to opam-show.0 (echo ""))) (rule (targets opam-show.1 opam-show.err) (deps using-built-opam) (action (progn (with-stderr-to opam-show.err (with-stdout-to opam-show.1 (run %{bin:opam} show --help=groff))) (diff opam-show.err %{dep:opam-show.0})))) (rule (with-stdout-to opam-search.0 (echo ""))) (rule (targets opam-search.1 opam-search.err) (deps using-built-opam) (action (progn (with-stderr-to opam-search.err (with-stdout-to opam-search.1 (run %{bin:opam} search --help=groff))) (diff opam-search.err %{dep:opam-search.0})))) (rule (with-stdout-to opam-list.0 (echo ""))) (rule (targets opam-list.1 opam-list.err) (deps using-built-opam) (action (progn (with-stderr-to opam-list.err (with-stdout-to opam-list.1 (run %{bin:opam} list --help=groff))) (diff opam-list.err %{dep:opam-list.0})))) (rule (with-stdout-to opam-init.0 (echo ""))) (rule (targets opam-init.1 opam-init.err) (deps using-built-opam) (action (progn (with-stderr-to opam-init.err (with-stdout-to opam-init.1 (run %{bin:opam} init --help=groff))) (diff opam-init.err %{dep:opam-init.0})))) (install (section man) (package opam) (files opam-help.1 opam-admin.1 opam-lock.1 opam-clean.1 opam-lint.1 opam-source.1 opam-unpin.1 opam-pin.1 opam-switch.1 opam-remote.1 opam-repository.1 opam-env.1 opam-exec.1 opam-config.1 opam-option.1 opam-var.1 opam-upgrade.1 opam-update.1 opam-reinstall.1 opam-uninstall.1 opam-remove.1 opam-install.1 opam-info.1 opam-show.1 opam-search.1 opam-list.1 opam-init.1)) opam-2.1.5/doc/man/opam-admin-topics.inc0000644000175000017500000001062014427463453017052 0ustar stephsteph;; Generated by dune_man (rule (with-stdout-to opam-admin-help.0 (echo ""))) (rule (targets opam-admin-help.1 opam-admin-help.err) (deps using-built-opam) (action (progn (with-stderr-to opam-admin-help.err (with-stdout-to opam-admin-help.1 (run %{bin:opam} admin help --help=groff))) (diff opam-admin-help.err %{dep:opam-admin-help.0})))) (rule (with-stdout-to opam-admin-add-hashes.0 (echo ""))) (rule (targets opam-admin-add-hashes.1 opam-admin-add-hashes.err) (deps using-built-opam) (action (progn (with-stderr-to opam-admin-add-hashes.err (with-stdout-to opam-admin-add-hashes.1 (run %{bin:opam} admin add-hashes --help=groff))) (diff opam-admin-add-hashes.err %{dep:opam-admin-add-hashes.0})))) (rule (with-stdout-to opam-admin-add-constraint.0 (echo ""))) (rule (targets opam-admin-add-constraint.1 opam-admin-add-constraint.err) (deps using-built-opam) (action (progn (with-stderr-to opam-admin-add-constraint.err (with-stdout-to opam-admin-add-constraint.1 (run %{bin:opam} admin add-constraint --help=groff))) (diff opam-admin-add-constraint.err %{dep:opam-admin-add-constraint.0})))) (rule (with-stdout-to opam-admin-filter.0 (echo ""))) (rule (targets opam-admin-filter.1 opam-admin-filter.err) (deps using-built-opam) (action (progn (with-stderr-to opam-admin-filter.err (with-stdout-to opam-admin-filter.1 (run %{bin:opam} admin filter --help=groff))) (diff opam-admin-filter.err %{dep:opam-admin-filter.0})))) (rule (with-stdout-to opam-admin-list.0 (echo ""))) (rule (targets opam-admin-list.1 opam-admin-list.err) (deps using-built-opam) (action (progn (with-stderr-to opam-admin-list.err (with-stdout-to opam-admin-list.1 (run %{bin:opam} admin list --help=groff))) (diff opam-admin-list.err %{dep:opam-admin-list.0})))) (rule (with-stdout-to opam-admin-check.0 (echo ""))) (rule (targets opam-admin-check.1 opam-admin-check.err) (deps using-built-opam) (action (progn (with-stderr-to opam-admin-check.err (with-stdout-to opam-admin-check.1 (run %{bin:opam} admin check --help=groff))) (diff opam-admin-check.err %{dep:opam-admin-check.0})))) (rule (with-stdout-to opam-admin-lint.0 (echo ""))) (rule (targets opam-admin-lint.1 opam-admin-lint.err) (deps using-built-opam) (action (progn (with-stderr-to opam-admin-lint.err (with-stdout-to opam-admin-lint.1 (run %{bin:opam} admin lint --help=groff))) (diff opam-admin-lint.err %{dep:opam-admin-lint.0})))) (rule (with-stdout-to opam-admin-upgrade.0 (echo ""))) (rule (targets opam-admin-upgrade.1 opam-admin-upgrade.err) (deps using-built-opam) (action (progn (with-stderr-to opam-admin-upgrade.err (with-stdout-to opam-admin-upgrade.1 (run %{bin:opam} admin upgrade --help=groff))) (diff opam-admin-upgrade.err %{dep:opam-admin-upgrade.0})))) (rule (with-stdout-to opam-admin-cache.0 (echo ""))) (rule (targets opam-admin-cache.1 opam-admin-cache.err) (deps using-built-opam) (action (progn (with-stderr-to opam-admin-cache.err (with-stdout-to opam-admin-cache.1 (run %{bin:opam} admin cache --help=groff))) (diff opam-admin-cache.err %{dep:opam-admin-cache.0})))) (rule (with-stdout-to opam-admin-make.0 (echo ""))) (rule (targets opam-admin-make.1 opam-admin-make.err) (deps using-built-opam) (action (progn (with-stderr-to opam-admin-make.err (with-stdout-to opam-admin-make.1 (run %{bin:opam} admin make --help=groff))) (diff opam-admin-make.err %{dep:opam-admin-make.0})))) (rule (with-stdout-to opam-admin-index.0 (echo ""))) (rule (targets opam-admin-index.1 opam-admin-index.err) (deps using-built-opam) (action (progn (with-stderr-to opam-admin-index.err (with-stdout-to opam-admin-index.1 (run %{bin:opam} admin index --help=groff))) (diff opam-admin-index.err %{dep:opam-admin-index.0})))) (install (section man) (package opam) (files opam-admin-help.1 opam-admin-add-hashes.1 opam-admin-add-constraint.1 opam-admin-filter.1 opam-admin-list.1 opam-admin-check.1 opam-admin-lint.1 opam-admin-upgrade.1 opam-admin-cache.1 opam-admin-make.1 opam-admin-index.1)) opam-2.1.5/doc/man/dune_man.ml0000644000175000017500000000307614427463453015165 0ustar stephstephlet gen_topic target_basename dline t = Printf.printf "\n\ (rule\n\ \ (with-stdout-to %s-%s.0 (echo \"\")))\n\ (rule\n\ \ (targets %s-%s.1 %s-%s.err)\n\ \ (deps using-built-opam)\n\ \ (action (progn (with-stderr-to %s-%s.err\n\ \ (with-stdout-to %s-%s.1 (run %s %s --help=groff)))\n\ \ (diff %s-%s.err %%{dep:%s-%s.0}))))\n\ " target_basename t target_basename t target_basename t target_basename t target_basename t dline t target_basename t target_basename t let () = let cmd,args = match Array.to_list Sys.argv with | _::cmd::args -> cmd, args | [] | [_] -> invalid_arg "Missing command argument" in let cline = String.concat " " (cmd :: args) ^ " help topics" in let topics = let ic = Unix.open_process_in cline in set_binary_mode_in ic false; let rec aux () = match input_line ic with | "" -> aux () | s -> s :: aux () | exception _ -> close_in ic; [] in aux () in let target_basename = String.concat "-" ("opam" :: args) in let dline = String.concat " " ("%{bin:opam}" :: args) in print_string ";; Generated by dune_man\n"; List.iter (gen_topic target_basename dline) topics; Printf.printf "\n\ (install\n\ \ (section man)\n\ \ (package opam)\n\ \ (files%s))\n" (String.concat " " (List.map (Printf.sprintf "\n %s-%s.1" target_basename) topics)) opam-2.1.5/doc/modules0000644000175000017500000002362614427463453013670 0ustar stephstephWarning: this file may not contain the most up-to-date information. You should refer to index.html instead. src │ ├── core Generic standard and system library │   │   [ opam-core lib ] │   ├── opamVersion.ml (generated) Current OPAM version │   ├── opamCoreConfig.ml Configuration options for this lib (record, global reference and setter) │   ├── opamVersionCompare.ml Version comparison function used throughout. From the Dose suite. │   ├── opamJson.ml Wrapper on Jsonm; only needed for some debug options │   ├── opamStd.ml Generic stdlib functions (String, List, Option, Sys submodules...) │   ├── opamConsole.ml Console output, ANSI color, logging and user querying │   ├── opamCompat.ml.4.01/4.02 Compatibility layer (Bytes, etc.) for different OCaml versions │   │   # system handling │   ├── opamProcess.ml Process and job handling, with logs, termination status, etc. │   ├── opamSystem.ml Bindings of lots of filesystem and system operations │   ├── opamFilename.ml Higher level file and directory name manipulation AND file operations, wrappers on OpamSystem using the filename type │   ├── opamParallel.ml Parallel execution of jobs following a directed graph │   ├── opamUrl.ml URL parsing and printing, with support for our different backends | | # Windows support │   ├── opamStubsTypes.ml Types in the stubs definitions (shared between both implementations) │   └── opamStubs.ml C stubs for Windows. A "dummy" alternate is provided for Unix, which doesn't require any C code │ ├── format Definition of OPAM datastructures and its file interface │   │   [ opam-format lib ] │   ├── opamFormatConfig.ml Configuration options for this lib (record, global reference and setter) │   ├── opamTypes.mli Definitions of many types used throughout │   ├── opamTypesBase.ml Helper functions on the base types. Often opened │   │   # basic types, used as keys │   ├── opamCompiler.ml The compiler type (string, version pairs) │   ├── opamPackage.ml The package type, and package name type (name+version, values often called "nv" in the code) │   ├── opamRepositoryName.ml The repository type │   ├── opamSwitch.ml The switch type │   ├── opamVariable.ml OPAM variables with scope (global or module) │   │   # more advanced types │   ├── opamFilter.ml Formulas on variables, as used in opam files build scripts │   ├── opamFormula.ml Formulas on packages, opt. with sub-formulas on versions, and conversion functions │   │   # file format │   ├── opamLineLexer.mll A simple lexer to list of lines, which are lists of words │   ├── opamLexer.mll OPAM config file lexer │   ├── opamParser.mly OPAM config file generic type parser │   ├── opamFormat.ml OPAM config files syntax and conversion tools, printing │   └── opamFile.ml Handles all OPAM file formats as record types and submodules, conversion to and from syntax │ ├── repository Handling of remote sources │   │   [ opam-repository lib ] │   ├── opamRepositoryConfig.ml Configuration options for this lib (record, global reference, setter, initialisation) │   ├── opamRepositoryBackend.ml Signature for repository handlers and some helpers for the repository type │   ├── opamRepositoryPath.ml Defines the file hierarchy in repositories │   ├── opamDownload.ml Configuration init and handling of downloading commands │   ├── opamHTTP.ml Main HTTP backend │   ├── opamLocal.ml Rsync backend, for local or ssh sources │   ├── opamVCS.ml Layer for handling version control sources │   ├── opamDarcs.ml Darcs support (through OpamVCS) │   ├── opamGit.ml Git support (through OpamVCS) │   ├── opamHg.ml Mercurial support (through OpamVCS) │   └── opamRepository.ml Operations on repositories (update, fetch...) based on the above backends │ ├── solver Solver and Cudf interaction │   │   [ opam-solver lib ] │   ├── opamSolverConfig.ml Configuration options for this lib (record, global reference, setter, initialisation) │   ├── opamActionGraph.ml Handles graphs of actions (package changes), based on ocamlgraph │   ├── opamCudfSolver.ml Bindings to CUDF solvers │   ├── opamCudf.ml Solver interaction, conversion of answer to solution │   └── opamSolver.ml Entry point, conversion of universe to cudf, dependencies computation │ ├── state Handling of the ~/.opam hierarchy and actions on it │   │   [ opam-state lib ] │   ├── opamStateConfig.ml Configuration options for this lib (record, global reference, setter, initialisation) │   ├── opamPath.ml Defines the file hierarchy in ~/.opam │   ├── opamScript.ml (generated) Shell config scripts as OCaml strings │   ├── opamStateTypes.mli Defines the types holding global, repository and switch states │   ├── opamGlobalState.ml Loading and handling of the global state of an opam root │   ├── opamRepositoryState.ml loading and handling of the repository state of an opam root (i.e. what is in ~/.opam/repo) │   ├── opamSwitchState.ml Loading and querying a switch state │   ├── opamPackageVar.ml Resolution and handling of opam variables + filters │   ├── opamFileTools.ml Generic tools for handling package metadata │   ├── opamSwitchAction.ml Switch-related actions and changes │   ├── opamEnv.ml Process environment setup and handling, shell configuration │   ├── opamPinned.ml Specific query and handling of pinned packages │   ├── opamUpdate.ml Synchronisation and downloading of repositories and package sources │   ├── opamSolution.ml Interface with the solver, processing of full solutions through actions │   └── opamAction.ml Handles concrete actions on packages, like installations and removals │ ├── stubs C stubs. This library is built on Windows-only and automatically pulled into opam-core if needed │   ├── opamInject.c Code for process injection shared between opamWindows.c and opam-putenv.c │   ├── opamWindows.c C stubs themselves │   └── opamWin32Stubs.ml OCaml external declarations for the stubs │ ├── client Everything related to the OPAM state, installation and front-end │   │   [ opam-client lib ] │   ├── opamClientConfig.ml Configuration options for this lib (record, global reference, setter, initialisation), plus helper for global setup │   ├── opamConfigCommand.ml Functions for the "opam config" subcommand │   ├── opamPinCommand.ml Functions for the "opam pin" subcommand │   ├── opamRepositoryCommand.ml Functions for the "opam repository" subcommand │   ├── opamSwitchCommand.ml Functions for the "opam switch" subcommand │   ├── opamListCommand.ml Functions for the "opam list" subcommand │   ├── opamClient.ml High-level execution of user-facing functions like "upgrade", and wrappers around the *Command modules │   ├── opamGitVersion.mli (generated) Current git version of OPAM │   ├── opamArg.ml Command-line argument parsers and helpers │   │   [ opam exe ] │   └── opamMain.ml Main, including cmdliner command handling │ └── tools │   [ opam-admin tool ] ├── opam_mk_repo.ml Repo index and archives generation ├── opam_depexts_change.ml Operation on external dependencies in a repo ├── opam_findlib.ml Automatically add some findlib information to a repo ├── opam_rename.ml Package renaming ├── opam_stats.ml Repo stats & graphs generation ├── opam_repo_check.ml Check the repo for errors ├── opam_admin.ml Source of the opam-admin tool, main │   [ other stand-alone tools ] ├── opam_admin_top.ml Tiny library for admin-scripts, included in opam-admin.top ├── opam-putenv.c Tiny C tool used on Windows for cross-architecture process injection ├── opam_check.ml Tiny tool used in internal checks ("make tests") ├── opam_installer.ml Handles OPAM's ".install" files └── opamlfind.ml Experimental ocamlfind wrapper tool opam-2.1.5/doc/pages/0002755000175000017500000000000014427463453013365 5ustar stephstephopam-2.1.5/doc/pages/Packaging.md0000644000175000017500000002147214427463453015577 0ustar stephsteph# Creating and publishing opam packages An opam package is defined by a `.opam`, or simply `opam` file, containing its metadata. This short guide will get you through writing this definition, testing it, and publishing to the [opam-repository](https://github.com/ocaml/opam-repository). ## Creating a package definition file For complete documentation of the format, see [the manual](Manual.html#Package-definitions). If your project does not yet have a package definition, get to the root of its source, and then either - run `opam pin .` to create and edit a template, and test your definition right away, - or create a `.opam` file and edit it by hand. The file follows a simple `field: ` format: ``` opam-version: "2.0" name: "project" version: "0.1" synopsis: "One-line description" description: """ Longer description """ maintainer: "Name " authors: "Name " license: "" homepage: "" bug-reports: "" dev-repo: "" depends: [ "ocaml" "ocamlfind" ] build: [ ["./configure" "--prefix=%{prefix}%"] [make] ] install: [make "install"] ``` The `depends:`, `build:` and `install:` are the most important fields here. If your project uses [`dune`](https://github.com/ocaml/dune), skip `install:` and use: ``` build: ["dune" "build" "-p" name "-j" jobs] ``` See [below](#The-file-format-in-more-detail) for more on the format. It is recommended to use [`opam lint`](man/opam-lint.html) to check the validity of your opam file. ## Testing Make sure you have committed everything if using a version-control system (_e.g._ `git add *.opam && git commit`), and just run ``` opam install . ``` from the root of your project. This will attempt to install the newly-defined package so you can check it goes as expected. ## Publishing Publishing is done using Github's pull-request mechanism, which allows automated checks to be run, and discussion to happen with the maintainers before your contribution is merged. You will need a [Github](https://github.com/) account. Submitting is most easily done using the `opam-publish` plugin. Run `opam publish --help` for more options. ### If the project is hosted on Github First tag the project. Assuming this is version 0.1: ``` git tag -a 0.1 git push origin 0.1 ``` Alternatively, you can create a release using the web UI (https://github.com/USER/REPO/releases/new). Then just run `opam publish` from your source directory and follow the steps. ### If not Assuming your release is available as an archive at `https://foo.bar/project-0.1.tar.gz`, run: ``` opam publish https://foo.bar/project-0.1.tar.gz . ``` from your source directory. The final `.` argument indicates to search for package definitions in the current directory rather than in the archive. > `opam publish` can be re-run any number of times to update an existing > submission, or propose changes to an already released package. > To fill the pull request, `opam publish` clones _opam repository_ over ssh, > you need to have your *ssh keys* registered in your [Github > account](https://help.github.com/en/articles/connecting-to-github-with-ssh). ### Without opam-publish First, you will need to add a section in the following format to the package definition, to specify where to retrieve the source of the package: ``` url { src: "https://address/of/project.1.0.tar.gz" checksum: "md5=3ffed1987a040024076c08f4a7af9b21" } ``` Then get to https://github.com/ocaml/opam-repository and select `Fork` on the top-right. Clone the resulting repository, add your package definition, and push back, as such: ``` git clone git@github.com:USER/opam-repository cd opam-repository cp OPAM_FILE packages/NAME/NAME.VERSION/opam git add packages git commit git push origin HEAD:add-pkg-NAME ``` Then, back to the web UI, Github should propose to file a pull-request for your newly pushed branch. If not, select the `new pull request` button on the left. ## The file format in more detail ### The basics The `opam-version` and `maintainer` fields are mandatory; you should remove the others rather than leave them empty. * `synopsis` should be a one-line description of what your package does, used in listings. It is recommended to also add a `description` field for a longer explanation (hint: you may delimit long strings with triple-quotation mark delimiters `"""` to avoid escaping issues). Since opam 2.0.1, linting requires to have at least synopsis or description filled. * You'll probably be the `maintainer` for now, so give a way to contact you in case your package needs maintenance. * Most interesting is the `build` field, that tells opam how to compile the project. Each element of the list is a single command in square brackets, containing arguments either as a string (`"./configure"`) or a variable name (`make`, defined by default to point at the chosen "make" command -- think `$(MAKE)` in Makefiles). `%{prefix}%` is another syntax to replace variables within strings. `opam config list` (or `opam var` with opam 2.1.0) will give you a list of available variables. `build` instructions shouldn't need to write outside of the package's source directory. * `install` is similar to `build`, but tells opam how to install. The example above should indeed be `install: [ [make "install"] ]`, but the extra square brackets are optional when there is a single element. This field can be skipped if your package generates a [`.install`](Manual.html#lt-pkgname-gt-install) file, like is the case when using `dune`. * `depends` should be a list of existing opam package names that your package relies on to build and run. You'll be guaranteed those are there when you execute the `build` instructions, and won't be changed or removed while your package is installed. If contributing to the default repository at https://opam.ocaml.org, it is quite unlikely that you don't need at least `"ocaml"` there. > Note: when running local shell scripts during _e.g._ `build:`, it is > preferable to use `build: ["sh" "-exc" "./SCRIPT"]` than call the script > directly. A few other fields are available, but that should be enough to get started. Like `install`, most fields may contain lists in square brackets rather than a single element: `maintainer`, `author`, `homepage`, `bug-reports`, `license` and `depends`. You may add a `remove` field, but since opam 2.0, removal of installed files is done automatically, so that should only be needed if your `install` modified existing files. ### Advanced usage This is just a very short introduction, don't be afraid to consult [the reference](Manual.html#opam) for details and more: * [**Version constraints**](Manual.html#Package-Formulas): an optional version constraint can be added after any package name in `depends`: simply write `"package" {>= "3.2"}`. Warning, versions are strings too, don't forget the quotes. * [**Formulas**](Manual.html#Package-Formulas): depends are by default a conjunction (all of them are required), but you can use the logical "and" `&` and "or" `|` operators, and even group with parentheses. The same is true for version constraints: `("pkg1" & "pkg2") | "pkg3" {>= "3.2" & != "3.7"}`. * [**Build depends**](Manual.html#Filtered-package-formulas): you may add, among others, the key `build` in the version constraints, _e.g._ `"package" {build & >= "3.2"}`, to indicate that there is no run-time dependency to this package: it is required but won't trigger rebuilds of your package when changed. * [**OS constraints**](Manual.html#opamfield-available): The `available` field is a formula that determines your package's availability based on the operating system or other [global opam variables](Manual.html#Global-variables). For example: ``` available: [ os != "macos" ] ``` * [**Conflicts**](Manual.html#opamfield-conflicts): some packages just can't coexist. The `conflicts` field is a list of packages, with optional version constraints. See also [`conflict-class`](Manual.html#opamfield-conflict-class) for _families_ of incompatible packages. * [**Optional dependencies**](Manual.html#opamfield-depopts): they change the way your package builds, but are not mandatory. The `depopts` field is a package formula like `depends`. simple list of package names. If you require specific versions, add a `conflicts` field with the ones that won't work. * [**Variables**](Manual.html#Variables): you can get a list of predefined variables that you can use in your opam rules with `opam config list` (or `opam var` with opam 2.1.0). * [**Filters**](Manual.html#Filters): dependencies, commands and single command arguments may need to be omitted depending on the environment. This uses the same optional argument syntax as above, postfix curly braces, with boolean conditions: ``` ["./configure" "--with-foo" {ocaml-version > "3.12"} "--prefix=%{prefix}%"] [make "byte"] { !ocaml:native } [make "native"] { ocaml:native } ``` opam-2.1.5/doc/pages/index.menu0000644000175000017500000000056614427463453015367 0ustar stephsteph# Contains the documentation menu with the following syntax: # without extension -> A menu title # .md -> A markdown page # empty -> A menu divider #source: https://github.com/ocaml/opam/tree/master/doc/pages opam 2.0 documentation Install.md Upgrade_guide.md Usage.md FAQ.md Tricks.md Packaging.md Distribution.md External_solvers.md Manual.md opam-2.1.5/doc/pages/Distribution.md0000644000175000017500000001660314427463453016372 0ustar stephsteph# opam and other package managers: distributions list This page tracks the state of binary packaging of opam on upstream distributions. If you do package up opam for your various OS, please feel free to add it below, update [this file](https://github.com/ocaml/opam/tree/master/doc/pages/Distribution.md) and open a [pull request](https://github.com/ocaml/opam/compare). Opam is in [![Packaging status](https://repology.org/badge/tiny-repos/opam.svg?header=)](https://repology.org/project/opam/versions) repository families. The pages/files linked are the ones that give the best overview of the available versions. Those [_pkgs_](http://pkgs.org/search/opam) and [_repology_]() pages may be used to get an up-to-date overview of official packages on most Linux distributions. ## _Official_ packages OS/distrubtion, their latest opam version and their maintainers: * Arch Linux [![Arch package](https://repology.org/badge/version-for-repo/arch/opam.svg?header=)](https://www.archlinux.org/packages/?q=opam) * [Package search](https://www.archlinux.org/packages/community/x86_64/opam/) * Alexander F. Rødseth [@xyproto](https://github.com/xyproto) * Debian Linux (9, oldstable, Stretch) [![Debian Oldstable package](https://repology.org/badge/version-for-repo/debian_oldstable/opam.svg?header=)](https://packages.debian.org/oldstable/source/opam) * [Package search](https://packages.debian.org/search?keywords=opam&searchon=names&suite=all§ion=all) * Mehdi Dogguy [@mehdid](https://github.com/mehdid), nicoo [@nbraud](https://www.github.com/nbraud) * Debian Linux (10, stable, Buster) [![Debian Stable package](https://repology.org/badge/version-for-repo/debian_stable/opam.svg?header=)](https://packages.debian.org/stable/source/opam) * [Package search](https://packages.debian.org/search?keywords=opam&searchon=names&suite=all§ion=all) * Mehdi Dogguy [@mehdid](https://github.com/mehdid), nicoo [@nbraud](https://www.github.com/nbraud) * Debian Linux (11, testing, Bullseye) [![Debian Testing package](https://repology.org/badge/version-for-repo/debian_testing/opam.svg?header=)](https://packages.debian.org/testing/source/opam) * [Package search](https://packages.debian.org/search?keywords=opam&searchon=names&suite=all§ion=all) * Mehdi Dogguy [@mehdid](https://github.com/mehdid), nicoo [@nbraud](https://www.github.com/nbraud) * Debian Linux (unstable, sid) [![Debian Unstable package](https://repology.org/badge/version-for-repo/debian_unstable/opam.svg?header=)](https://packages.debian.org/unstable/source/opam) * [Package search](https://packages.debian.org/search?keywords=opam&searchon=names&suite=all§ion=all) * Mehdi Dogguy [@mehdid](https://github.com/mehdid), nicoo [@nbraud](https://www.github.com/nbraud) * Fedora 32 [![Fedora 32 package](https://repology.org/badge/version-for-repo/fedora_32/opam.svg?header=)](https://src.fedoraproject.org/rpms/opam) * [Package page](https://apps.fedoraproject.org/packages/opam) * Ben Rosser [@TC01](https://www.github.com/TC01) * FreeBSD [![FreeBSD port](https://repology.org/badge/version-for-repo/freebsd/opam.svg?header=)](https://www.freshports.org/devel/ocaml-opam) * [Package search](http://www.freebsd.org/cgi/ports.cgi?query=opam&stype=all) * Hannes Mehnert [@hannesm](https://www.github.com/hannesm) * Gnu Guix [![GNU Guix package](https://repology.org/badge/version-for-repo/gnuguix/opam.svg?header=)](https://guix.gnu.org/packages/opam-2.0.6/) * [Package definition](https://git.savannah.gnu.org/cgit/guix.git/tree/gnu/packages/ocaml.scm#n428) * Julien Lepiller [@roptat](https://github.com/roptat) * Homebrew (MacOS X) [![Homebrew package](https://repology.org/badge/version-for-repo/homebrew/opam.svg?header=)](https://formulae.brew.sh/formula/opam) * Macports (MacOS X) [![MacPorts package](https://repology.org/badge/version-for-repo/macports/opam.svg?header=)](https://ports.macports.org/port/opam/summary) * [Package definition](https://github.com/macports/macports-ports/blob/master/sysutils/opam/Portfile) * Perry E. Metzger [@pmetzger](https://www.github.com/pmetzger) * Mageia Linux (Cauldron) [![Mageia Cauldron package](https://repology.org/badge/version-for-repo/mageia_cauldron/opam.svg?header=)](https://madb.mageia.org/package/show/source/1/application/0/release/cauldron/name/opam) * [Package definition](http://svnweb.mageia.org/packages/cauldron/opam/current/SPECS/opam.spec?view=markup) * David Geiger [@david-geiger](https://www.github.com/david-geiger) * NixOS [![nixpkgs stable package](https://repology.org/badge/version-for-repo/nix_stable/opam.svg?header=)](https://github.com/NixOS/nixpkgs/blob/release-20.03/pkgs/development/tools/ocaml/opam/default.nix#L114) * [Package definitions](https://github.com/NixOS/nixpkgs/tree/master/pkgs/development/tools/ocaml/opam) * Henry Till * OpenBSD [![OpenBSD port](https://repology.org/badge/version-for-repo/openbsd/opam.svg?header=)](http://openports.se/sysutils/opam) * [Package page](http://ports.su/sysutils/opam,-main) * Christopher Zimmerman [@madroach](https://github.com/madroach) * OpenSuse (Tumbleweed) [![openSUSE Tumbleweed package](https://repology.org/badge/version-for-repo/opensuse_tumbleweed/opam.svg?header=)](https://build.opensuse.org/package/show/openSUSE:Factory/opam) * Anil Madhavapeddy [@avsm](https://www.github.com/avsm) * Ubuntu Linux (16.04, LTS, xenial) [![Ubuntu 16.04 package](https://repology.org/badge/version-for-repo/ubuntu_16_04/opam.svg?header=)](https://packages.ubuntu.com/source/xenial/opam) * [Package search](http://packages.ubuntu.com/search?keywords=opam&searchon=names&suite=all§ion=all) - bwrap unavailable * Ubuntu Linux (18.04, LTS, bionic) [![Ubuntu 18.04 package](https://repology.org/badge/version-for-repo/ubuntu_18_04/opam.svg?header=)](https://packages.ubuntu.com/source/bionic/opam) * [Package search](http://packages.ubuntu.com/search?keywords=opam&searchon=names&suite=all§ion=all) * Ubuntu Linux (19.10, LTS, eoan) [![Ubuntu 20.10 package](https://repology.org/badge/version-for-repo/ubuntu_20_10/opam.svg?header=)](https://packages.ubuntu.com/source/eoan/opam) * [Package search](http://packages.ubuntu.com/search?keywords=opam&searchon=names&suite=all§ion=all) * Ubuntu Linux (20.10, groovy) [![Ubuntu 20.10 package](https://repology.org/badge/version-for-repo/ubuntu_20_10/opam.svg?header=)](https://packages.ubuntu.com/source/groovy/opam) * [Package search](http://packages.ubuntu.com/search?keywords=opam&searchon=names&suite=all§ion=all) ## Third party packages * CentOS (6,7) * Anil Madhavapeddy [@avsm](https://www.github.com/avsm) * Exherbo Linux * 1.1.1 [Package page](http://git.exherbo.org/summer/packages/dev-ocaml/opam/index.html) (_ocaml-unofficial_) * nicoo [@nbraud](https://www.github.com/nbraud) * Ubuntu Linux PPA * 2.0.4 [Anil's official opam PPA](https://launchpad.net/~avsm) and [ppa post](https://discuss.ocaml.org/t/opam-2-0-experimental-ppas/2446) * Anil Madhavapeddy [@avsm](https://www.github.com/avsm) * Windows * [MinGW repo](https://github.com/fdopen/opam-repository-mingw) - Andreas Hauptmann [@fdopen](https://www.github.com/fdopen) * David Allsopp [@dra27](https://www.github.com/dra27) If you can't find latest version packages for your distribution here, see [the opam installation page](Install.html) for binaries or building from source. [Docker containers](http://hub.docker.com/r/ocaml/opam) for severals distributions and OCaml compiler versions are also available. opam-2.1.5/doc/pages/Tricks.md0000644000175000017500000001306414427463453015150 0ustar stephsteph> The following are beyond the scope of the [FAQ](FAQ.html), but have been found > useful for specific use-cases or for advanced users. #### Simulate actions from the current switch state (for debugging) - `opam upgrade --show-actions` (stop at the action summary dialog) - `opam upgrade --dry-run` (display only) - if you really want to try out the results: * `opam switch export testing-state.export` * `opam switch create tmp-testing --empty` * `opam switch import testing-state.export --fake` * try actions with `--fake` (registers them in opam, but doesn't actually run the build/install commands) * revert to normal: `opam switch ; opam switch remove tmp-testing` - Experiment with the solver: * `opam --cudf=cudf-file` * or `opam config cudf-universe >cudf-file-1.cudf` * run e.g. aspcud with `aspcud cudf-file-1.cudf /dev/stdout CRITERIA` --- #### Install in all switches Not supported natively at the moment, but it's being considered. Quick hack: ``` for switch in $(opam switch list -s); do opam install --switch $switch PACKAGE done ``` You may want to add `--yes` if you're confident. --- #### Update opam environment within emacs The best way is to use `opam-user-setup` (just run `opam user-setup install`), and that will make the `opam-update-env` interactive function available in emacs. You could also define the function by hand: ```lisp (defun opam-env () (interactive nil) (dolist (var (car (read-from-string (shell-command-to-string "opam config env --sexp")))) (setenv (car var) (cadr var)))) ``` You may want to run this at emacs startup if it doesn't inherit the proper shell environment. Be also careful that `tuareg-mode` has its own bindings that override the environment when using the `compile` command, so that may get in the way (see Tuareg [issue #94](https://github.com/ocaml/tuareg/issues/94)). --- #### Provide a set of packages for a group of users to install The easiest way is to create a package with your prerequisites as `depends` and have them pin that. A quick way to host the file is to use a [Gist](https://gist.github.com). Create one with minimal contents and listing your packages as dependencies -- the file name **has** to be `opam`: ``` opam-version: "2.0" name: "ocaml101" version: "0.1" maintainer: "Louis Gesbert " depends: [ "menhir" { = "20140422" } "merlin" { >= "2" } "ocp-indent" "ocp-index" ] ``` Save that and get the `HTTPS clone URL`. All that is needed then is to run: ```shell $ opam pin ``` Furthermore, `opam update` will then pick up any modification you made to the gist. These other options may offer more control, with a little more work, depending on the scale you work at: - distribute an "export" file, as generated by `opam switch export ` - define and host your own repository, and use a specific [`opamrc`](Manual.html#opamrc) file on the user's systems, to automatically select your repository and defaults on `opam init`. --- #### Alternate implementations for a package opam currently doesn't support a `provides:` field that would allow packages to replace others. If you have two packages `a` and `b` providing `foo`, you need to: - Define a (virtual) package `foo`, with `depends: ["a" | "b"]`, for any version you want available: so if the versions of `a`, `b` and `foo` match you would have _e.g._ `foo.1` with `depends: ["a" {= "1"} | "b" {= "1"}]`. Or, better, using opam 2.0 variables: `depends: ["a" {= _:version} | "b" {= _:version}]`, duplicated for any version desired. - Make sure `a` and `b` conflict with each other. The scalable solution for this is to use the `conflict-class:` field: add _e.g._ `conflict-class: "foo-implementation"` to all versions of both `a` and `b`. The need to define the virtual package explicitly also ensures that a third package can't inject a new implementation without that being visible in `foo`: it would otherwise be a security hole when we deploy end-to-end signing of packages. --- #### How to rename a package Opam doesn't technically allow packages to be renamed, but you can create a package with the new name, and a upgrade path between the two. Assuming you want to rename `foo` to `bar`: 1. Create a new version of `foo`, e.g. `foo.transition`, depending on `bar`, and with a description mentioning it is a virtual package that can be safely removed. The package shouldn't have a source URL or build, install, etc. instructions. 2. Create `bar` as a new package. 3. Add `conflicts: "foo" {!= "transition"}`. Remember to keep that field on any new version of `bar`. This ensures at the same time that users upgrading will get the new package `bar`, and that the package can't be installed twice under the two names. --- #### Display the current "opam switch" in the prompt ? This can get quite handy if you have many switches you use in parallel. You can use e.g. the command `opam switch show --safe 2>/dev/null | sed 's|.*/|*|'` to return a (shortened) switch name. For `bash`, just include `$(COMMAND)` in your definition of `PS1` (making sure the `$` is escaped). For `zsh`, use `setopt prompt_subst`, and include `$(COMMAND)` in the definition of `prompt`. --- #### How to install a maximum number of packages ? The following sequence of commands tries to install as much packages as possible in a local switch with OCaml `$(VERSION)`. ```shell opam update opam switch create . ocaml-base-compiler.$(VERSION) export OPAMSOLVERTIMEOUT=3600 opam list --available -s | xargs opam install --best-effort --yes # Be patient ``` opam-2.1.5/doc/pages/Specifying_Solver_Preferences.md0000644000175000017500000001657214427463453021673 0ustar stephsteph# Specifying user Preferences for the External Solvers A fundamental distinguishing feature of the `opam` package manager is the fact that it is designed to reuse state-of-the-art dependency solving technology that gives the users the possibility to express their preferences regarding the operations to be performed during an installation, instead of being bound to an hard-coded strategy. This section provides basic documentation on this feature, and its usage. ## What are user preferences for installations, and why are them important? When you request the installation of some packages, say p1...pn, `opam` has a lot to do: it needs to look at all the packages already installed on your machine, find all packages available from the repositories, consider your request, and then come up with a set of actions to be performed to satisfy your request. Unfortunately, there are a lot of assumptions hidden in your mind when you tell `opam` that you want p1...pn installed: should it choose the latest version of the p1...pn? That seems a sensible thing to do, but sometimes installing a recent version of a package p may lead to downgrading or removing another package q, which is something you might not want. What should `opam` do in this case? Remove q to get the latest p, or keep q and get the most recent p that is compatible with it? Well, the answer is: it depends! It depends on what _you_ really want, and different users may have different points of view. User preferences, supported by `CUDF`-compatible solvers, are the means you can use to make the assumptions in your mind explicit and known to the solver used by `opam`, so that the actions performed on your machine correspond to your personalised needs. ## How do I express my preferences? Preferences are expressed using a simple language built by prefixing a little set of combinators with the `-` (minus) or `+` (plus) operators. The most useful combinators are the following ones: * `new` : the number of new packages * `changed` : the number of packages modified * `removed` : the number of packages removed * `notuptodate` : the number of packages that are not at their latest version For example, the preference `-removed` tells the solver that among all possible ways of satisfying your request, it should choose one that minimises the number of packages removed. These combinators can be combined in a comma separated sequence, that is treated in lexicographic order by the solver. ### Default preferences for an upgrade For example, the preference `-removed,-notuptodate,-changed` tells the solver that after ensuring that removals are minimised, it should look for a solution that minimises also the number of packages which are not at their latest version, and then reduce the changes to a minimum. This is the default preference setting used by `opam` when you perform an update or an upgrade, and in practice it tries to bring _all_ your packages to the latest version available, as far as this does not implies removing too many packages. It can be set using the environment variable `OPAMUPGRADECRITERIA` ### Default preferences for an install When you request to install a (set of) package(s), in general you do not expect to see all your existing packages updated, and this is why in this case `opam` uses a different default value `-removed,-changed,-notuptodate` that tries to minimise changes to the system. It can be set using the environment variable `OPAMCRITERIA` ### Specifying preferences for opam Recent versions of `opam` allow one to specify criteria on the command line, using the `--criteria` option, that will apply only to the current command. For example, if you are a very conservative user, you might try issuing the following command: ``` opam install --criteria="-removed,-changed" ... ``` This can also be used for some tricks: if for example you want to repair your set of installed packages, you can use the `opam upgrade` command without specifying a preference for newer versions in the criteria: ``` opam upgrade --criteria="-changed" ``` You can also use the `OPAMCRITERIA` and `OPAMUPGRADECRITERIA` environment variables to specify your preferences (for example, adding your preferred settings to a shell profile). If both variables are set, upgrades are controlled by `OPAMUPGRADECRITERIA`, while `OPAMCRITERIA` applies to all other commands. If only `OPAMCRITERIA` is set, it applies to all commands. If only `OPAMUPGRADECRITERIA` is set, it applies to upgrade commands only, while all other commands are controlled by the `opam` internal default preferences. ## Yes, there are different versions of the user preference language The `opam` package manager is an instance of the approach described in the article "[A modular package manager architecture](http://dl.acm.org/citation.cfm?id=2401012)", which was one of the outcomes of the [Mancoosi](http://www.mancoosi.org) research project. This architecture relies on external dependency solvers for package managers, that communicate with the package manager front-end via the [CUDF format](http://www.mancoosi.org/cudf/). We have now several CUDF-compatible solvers, developed by a variety of research teams during the [MISC competitions](http://www.mancoosi.org/misc/) run yearly from 2010 to 2012: * [aspcud](http://www.cs.uni-potsdam.de/wv/aspcud/) * [Mccs](http://www.i3s.unice.fr/~cpjm/misc/mccs.html) * [Packup](http://sat.inesc-id.pt/~mikolas/sw/packup/) * [P2Cudf](https://wiki.eclipse.org/Equinox/p2/CUDFResolver) Each of these competitions led to improving the preferences language, by allowing the user progressively more flexibility. As of today, the preferences language described in the previous section, which corresponds to the one used in the 2010 competition, should be supported by all external solvers, but if you happen to use as external solver one of the entrants of the 2012 competition, like recent versions of `aspcud`, then you have access to a more sophisticated set of preferences, described in [the 2012 MISC competition rules](http://www.mancoosi.org/misc-2012/criteria/). For example, you could use `-count(removed), -count(down),-sum(solution,installedsize),-notuptodate(solution),-count(changed)` to instruct a solver to minimise downgrades, and mininise the installed size, among other criteria. ### News in aspcud 1.9.x Starting from version 1.9.0, `aspcud` adds support for three extra selectors, that are particularly useful to perform local upgrades. Here they are: * `installrequest` is the set of packages in the solution that satisfy the requirements mentioned in the install: part of a CUDF request * `upgraderequest` is the set of packages in the solution that satisfy the requirements mentioned in the upgrade: part of a CUDF request * `request` is the union of the above two Using this extended set of package selector, it is now finally possible to specify user preferences that describe optimisations to be applied only to the packages explicitly mentioned in the request. For example, `-notuptodate(request),-count(changed)` would find a solution that tries to bring all packages mentioned in the request to their latest version, while leaving all the rest as untouched as possible. And if we have added to each package a `priority` value, we could also play with preferences like `+sum(upgraderequest,priority),-count(changed)` to get the packages mentioned in the upgrade request to the version with the highest possible priority, while leaving all the rest as untouched as possible. opam-2.1.5/doc/pages/Upgrade_guide.md0000644000175000017500000002424114427463453016454 0ustar stephsteph# Quick upgrade guide from opam 1.2 to opam 2.0 This guide is not a complete list of changes, but it highlights changes that users of opam 1.2 should know about, as well as some important new features. ## Command-line ### What you need to be aware of Some commands have changed syntax: - [`opam switch`](man/opam-switch.html): `create` must be specified to create a new switch. You should then specify either `--empty` or a base compiler package, _e.g._ use `opam switch create 4.06 ocaml-base-compiler.4.06.0` to create a new switch named `4.06`. Just `opam switch create 4.06.0` also still works in most cases. - [`opam repository`](man/opam-repository.html) (or `opam remote`): repositories are still configured globally, but are now selected for each switch. So by default `opam repository add` will only affect the current switch. You can change the defaults with `--set-defaults`, and choose the repositories at switch creation time with `opam switch create --repositories REPOS` - [`opam list`](man/opam-list.html) and [`opam show`](man/opam-show.html) have been largely reworked to offer more options - options to build tests and documentation are now respectively `--with-test` and `--with-doc`. They only apply to packages listed on the command-line The `opam-admin` tool, for repository operations, is now built into opam, use the [`opam admin`](man/opam-admin.html) command instead. Opam now comes with [a solver built-in](https://github.com/AltGr/ocaml-mccs), which means that installing `aspcud` alongside opam is no longer required. Pinning to a version-controlled directory will now only use what is committed by default (opam 1.2 had a "mixed mode" where it would use the current versions of files, but only the version-controlled ones. This was good most of the time, but could become puzzling _e.g._ when opam didn't see an added source file). The option [`--working-dir`](man/opam-install.html#lbAH) can be used to temporarily make opam fetch uncommitted changes (see also [`--inplace-build`](man/opam-install.html#lbAG)), and [`--assume-built`](man/opam-install.html#lbAG) to run only installation instructions, assuming that build has been done locally. Upon pinning, opam 2.0 will also select the current branch by default if unspecified, so that later running `git checkout BRANCH` in the source tree doesn't affect the pinned package. ### New features - __new command aliases__: [`opam var`](man/opam-var.html), [`opam exec`](man/opam-exec.html), [`opam env`](man/opam-env.html) can be used in place of the corresponding [`opam config`](man/opam-config.html) subcommands - __new command__: [`opam clean`](man/opam-clean.html) to clear caches, logs, etc. - __local switches__: use _e.g._ [`opam switch create .`](man/opam-switch.html#lbAE) to create a switch in the current directory. The switch contents will be in a `_opam` directory, which can be safely removed once done. The switch path can then be used as a handle to refer to the switch. Additionally, the above command will install any packages which definitions are found in the selected directory into the local switch. - __automatic pinning__: use _e.g._ [`opam install .`](man/opam-install.html#lbAD) to pin and install any packages found in the current directory. `opam install . --deps-only` can also be used to prepare a switch for working with a source tree. This extension also concerns the `remove`, `upgrade`, `reinstall` and `show` commands, and specifying the path to a specific `opam` file is also supported. - __archive caching__: opam now uses a much better caching mechanism, both locally and on the opam-repository. In particular, upstream repositories being down should no longer prevent package installation (even for older or removed packages). Git repositories are also cached. - __better error mitigation__, messages and recovery. [`opam install --restore`](man/opam-install.html#lbAF) can be used to retry after a failed operation. - a plugin, _e.g._ [`opam-depext`](https://github.com/ocaml/opam-depext/tree/2.0), will now be available from all switches once installed in one. - [`opam install --destdir`](man/opam-install.html#lbAF) can be used to copy build artefacts of given packages to an external prefix - __sandboxing__: on Linux and MacOS, all package commands will now be sandboxed by default. The [`bubblewrap`](https://github.com/projectatomic/bubblewrap) tool is now required to this end on Linux, and the `sandbox_exec` command is used on MacOS. See [`faq entry`](FAQ.html#Why-does-opam-require-bwrap) for more details. ## File formats ### What you need to be aware of > #### Repositories and migration > > **Repositories for 1.2 and 2.0 have a different format**, but everything > should be transparent unless you publish packages: > > - [**The main repository**](https://github.com/ocaml/opam-repository/tree/master) > is now in format **2.0**. This means the `master` branch, and the > contents of `https://opam.ocaml.org/packages`. > - [**There is a 1.2 branch**](https://github.com/ocaml/opam-repository/tree/1.2) > that is served at `opam.ocaml.org/1.2.2`. > > When publishing packages, remember that: > > - packages in **2.0 format** must be published to the `2.0.0` branch — e.g. > using the new > [opam-publish.2.0](https://github.com/ocaml/opam-publish/tree/2.0). They > will **only** be available to opam 2.0 users. > - packages in **1.2 format** are no more accepted, expect for relevant fixes. > In that case they must be published to `1.2` branch. > > - [`opam-publish.2.0.0`](https://github.com/ocaml/opam-publish/tree/2.0) has > a fully revamped interface, and many new features, like filing a single PR > for multiple packages. It files pull-request in 2.0 format only to master > branch of the repository. The new version of > [`dune-release.1.0.1`](https://github.com/samoht/dune-release/tree/master) > handles the new format. > > - It is also advised to keep in-source opam files in 1.2 format until that > date, so as not to break uses of `opam pin add --dev-repo` by opam 1.2 users. > > - The small `opam-package-upgrade` plugin can be used to upgrade single 1.2 > opam files to 2.0 format. You can also use API to upgrade you opam files, > using > [`OpamFormatUpgrade.opam_file`](https://opam.ocaml.org/doc/api/opam-state/OpamFormatUpgrade/#val-opam_file), > available in package `opam-state`. > > - More advice for package maintainers and custom repositories in this [blog > post](https://opam.ocaml.org/blog/opam-2-0-0-repo-upgrade-roadmap/#Advice-for-package-maintainers). - compiler definition files: these no longer exist, as compilers have been replaced by normal package definitions (that should have [`flags: compiler`](Manual.html#opamflag-compiler)) - the base syntax of `opam` files didn't change, but: - compilers now being packages, _e.g._ the field `available: [ ocaml-version >= "4.00.1" ]` is now encoded as a dependency towards the `ocaml` package with `depends: [ "ocaml" {>= "4.00.1"} ]`. The `ocaml-version` variable is no longer defined. - extra dependencies needed for test and documentation must now be flagged with resp. [`with-test`](Manual.html#opamfield-depends) and [`with-doc`](Manual.html#opamfield-depends). Fields `build-test:` and `build-doc:` are deprecated in favour of filters on [`build:`](Manual.html#opamfield-build) instructions, and there is a new [`run-test:`](Manual.html#opamfield-run-test) field - the format of the [`depexts:`](Manual.html#opamfield-depexts) field is changed - the host system is now polled through the `arch`, `os`, `os-distribution` and `os-version` variables. `os` may now take the value `macos` instead of `darwin`. - [`depopts: [ "foo" >= "v0" ]`](Manual.html#opamfield-depopts) now means that the optional dependency is only active for the corresponding versions, there is no implicit conflict with `"foo" < "v0"` - URLs must now be non-ambiguous in files, _e.g._ you must use `git+https://github.com/owner/pkg.git` rather than `https://github.com/owner/pkg.git`. The latter will still be understood as `git` and rewritten to the former if used from the command-line. - Any specified [`patches:`](Manual.html#opamfield-patches) must now apply with `patch -p1` and use unified, rather than context, diffs. - `opam switch export/import` format has been changed (but files in the 1.2 format can still be read). - __the conversion from the 1.2 format is done internally and automatic, both for repositories and when pinning.__ Be careful, however, not to submit 2.0 format files if they are to be used by opam 1.2. ### New features `opam` files have been extended in a lot of ways: - more expressive [dependencies](/blog/opam-extended-dependencies/) - new fields: - [`pin-depends:`](Manual.html#opamfield-depexts) - [`run-test:`](Manual.html#opamfield-run-test) - [`setenv:`](Manual.html#opamfield-setenv) - [`conflict-class`](Manual.html#opamfield-conflict-class) - [`extra-source:`](Manual.html#opamsection-extra-sources) - [`extra-files:`](Manual.html#opamfield-extra-files) - opam now tracks installed files, so the `remove:` field can now in general be omitted. Specify [`flags: light-uninstall`](Manual.html#opamflag-light-uninstall) if you do need `remove:` instructions, but these are not required to be run from the source tree of the package. - the `descr` file is now preferably replaced by [`synopsis:`](Manual.html#opamfield-synopsis) and [`description:`](Manual.html#opamfield-description) fields in the `opam` file (and strings can be put between `"""` to avoid escaping issues) - the `url` file can be replaced by a section of the form [`url { src: "URL" checksum: "CKSUM" }`](Manual.html#opamsection-url). With the above, this allows single-file package definitions - [checksums](Manual.html#Checksums) now accept SHA256 and SHA512 besides MD5. Use the strings `"md5=HEX"`, `"sha256=HEX"`, `"sha512=HEX"`. For more details on the new opam, see: - [the manual](Manual.html) - `opam COMMAND --help` - [the changelog](https://github.com/ocaml/opam/blob/master/CHANGES) - [the blog](/blog/opam-2-0-0-rc/) for announcements of some of the new features - [the tracker](https://github.com/ocaml/opam/issues) opam-2.1.5/doc/pages/About.md0000644000175000017500000001145414427463453014764 0ustar stephsteph# opam ## A little bit of History ### opam The [first specification draft of OPAM](https://github.com/ocaml/opam/blob/30598a59c98554057ce2beda80f0d31474b94150/specs/roadmap.pdf?raw=true) was written at the end of Jan 2012 by Thomas Gazagnaire from OCamlPro. The specification was reviewed by Fabrice Le Fessant (OCamlPro/INRIA), Yaron Minsky (Jane Street) -- who funded the project, and Anil Madhavapeddy (University of Cambridge) -- who needed a source-based package manager to manage libraries emerging from the Mirage OS project. At about the same time, Frederic Tuong, an intern from Inria, funded by the DORM research grant in collaboration with OCamlPro and IRILL, started to implement [the first version of OPAM](https://github.com/ocaml/opam/commits/master?page=112) (called `ocp-get` at the time) at the end of Feb 2012. He also started to create the [first OPAM packages](https://github.com/ocaml/opam-repository/commits/master?page=200) one month later. Frederic and Thomas worked closely together in the following months to [demonstrate OPAM](https://www.youtube.com/watch?v=ivLqeRZJTGs) at the [OCaml Workshop 2012](http://oud.ocaml.org/2012/) where (almost) everyone was already using it! Frederic started a PhD in Oct 2012 and left the OPAM team to focus on his studies. Roberto Di Cosmo and Pietro Abate, from IRILL, began helping Thomas at the end of 2012 to properly integrate their [Mancoosi](http://www.mancoosi.org/) tools (such as [CUDF](http://www.mancoosi.org/cudf/) and `dose`) so that OPAM could benefit from modern constraint solving tools and be able to automatically use the `aspcud` external solver if is available. At the end of 2012, Vincent Bernardoff and Guillem Rieu (from OCamlPro) worked for a few months on improving the documentation and ease of use of OPAM for newcomers. They created [opam2web](https://github.com/ocaml/opam2web), the tool used to generate https://opam.ocaml.org. The [first public beta of OPAM](http://www.ocamlpro.com/blog/2013/01/17/opam-beta.html) was released in Jan 2013 and few months later (in March 2013) [the first official release landed](http://www.ocamlpro.com/blog/2013/03/14/opam-1.0.0.html). A few days later, Louis Gesbert -- who joined OCamlPro in Dec 2012, pushed [his first commit](https://github.com/ocaml/opam/commit/c56cf5e1e244cee9f707da8b682996bbc5dd31ff) to the codebase. In Nov 2013, [OPAM 1.1.0](https://opam.ocaml.org/blog/opam-1-1-0-released/) was released and Louis became the technical lead. A months later, [opam 1.1.1](https://opam.ocaml.org/blog/opam-1-1-1-released/) with numerous bug fixes. ### opam-repository Meanwhile, in June 2012 Mirage started to use opam (as it was using a custom 3.12.1 compiler). Very quickly, starting off Frederic's work, Anil and Thomas shared the task of adding new packages and monitor the pull-requests on opam-repository. The initial policy was to accept as many packages as possible, which means that things were often broken. So they started to use background [bulks builds](https://github.com/avsm/opam-bulk-logs) to improve the overall repository quality. In July 2012, Jane-Street's Core libraries made [its apparition](https://github.com/ocaml/opam-repository/commit/bad688d0f49f6c750525b0047b336eb8606e419d) in the repository. To improve the quality of new packages, Travis CI was [integrated](https://github.com/ocaml/opam-repository/commit/2671cb1e968e084c13989762ea43fc1a5b4703d7) in Sept 2013 to the pull-request process. From Aug to Nov 2013, all the contributors of opam-repository were contacted to re-license their contribution to CC0, which enable the [move of the repository](https://github.com/ocaml/opam-repository/issues/955) to the `ocaml` organisation. The [opam weather service](http://ows.irill.org/), created by Iril and OCamlPro, was announced in Apr 2014 and expose quality metrics to the repository quality. *Notes*: Some significant bumps in opam-repository were adoption by projects: start of the bi-weekly pulls from Jane Street on Core (the biggest one), the Ocsigen and XAPI remotes, and Mirage releases. ## Getting Support Opam has been created and is maintained by [OCamlPro](http://www.ocamlpro.com/). Bug reports and feature requests for the opam tool should be reported on [opam's issue-tracker](https://github.com/ocaml/opam/issues). Packaging issues or requests for a new package can be reported on the [official repository's issue-tracker](https://github.com/ocaml/opam-repository/issues). General queries for both the tool and the packages could be addressed on the [OCaml-platform mailing-list](http://lists.ocaml.org/listinfo/platform) and insights and evolution of opam internals can discussed on the [opam-devel mailing-list](http://lists.ocaml.org/listinfo/opam-devel). Standard commercial terms and support on opam, as well as training and consulting services, are provided by [OCamlPro](http://www.ocamlpro.com/). opam-2.1.5/doc/pages/FAQ.md0000644000175000017500000004272014427463453014321 0ustar stephsteph# opam FAQ > This FAQ is for general questions about opam and its usage. You may also be > interested in the more advanced [Tricks](Tricks.html) for specific use-cases > or advanced users. #### 🐫 What is opam for? Easily installing, upgrading and managing your OCaml compiler(s), tools and libraries. It's made of a tool, the [opam package manager](https://github.com/ocaml/opam), and a community-maintained [package repository](https://github.com/ocaml/opam-repository). Note that the tool itself is not specific to OCaml at its core, and could be used for different systems using specific repositories (e.g. for the [Coq theorem prover](http://coq.io/opam/)) --- #### 🐫 How to get, install and upgrade opam? See the [install guide](Install.html). If upgrading, you can bootstrap using `opam install opam-devel`, and follow the instructions. --- #### 🐫 Where is the manual? opam has git-like, hierarchical [manpages](https://opam.ocaml.org/doc/2.0/man/opam.html). Try `opam --help` for a starting point. Or get started from the [Usage](Usage.html) guide. If you want to know more about opam packages, see the [Packaging Howto](Packaging.html). The full reference on the internals and file formats is in the [Manual](Manual.html). You may also want to browse the [library APIs](api/). --- #### 🐫 What changes does opam do to my filesystem? opam is designed to be run strictly as user (non-root), and except for the explicit options provided during `opam init`, opam only writes within `~/.opam` (and `/tmp`). This directory — the default "opam root" — contains configuration, various internal data, a cache of downloaded archives, and your OCaml installations. If you choose to create "local switches", the installation prefix will be put in the specified directory with `/_opam/` appended. Nothing else will be changed. Please note, however, that programs you install using opam won't themselves be bound by any restrictions. On Linux, and since opam 2.0.0~rc2, package instructions (build, install, remove) are also run in a sandbox and guaranteed not to affect your system. --- #### 🐫 Why does opam require ``bwrap``? Since opam 2.0.0~rc2, opam uses `bwrap` on Linux to run package instructions in a sandbox. This restricts their access to parts of the system (e.g., forbid access to operating system, user data, or network). See the [bubblewrap page](https://github.com/projectatomic/bubblewrap) for details. A similar mechanism is used on macOS, using the `sandbox-exec` command. We use `bwrap` to prevent packages from writing outside their allotted filesystem space or use the network. For example, build commands have restricted write access, restrained to their dedicated build directory and `/tmp`. These sandboxing instructions are specified in the built-in configuration, that you can display with `opam init --show-default-opamrc`: ``` init-scripts: ["sandbox.sh" """ [...] """] {os = "linux"} wrap-build-commands: ["%{hooks}%/sandbox.sh" "build"] {os = "linux"} wrap-install-commands: ["%{hooks}%/sandbox.sh" "install"] {os = "linux"} wrap-remove-commands: ["%{hooks}%/sandbox.sh" "remove"] {os = "linux"} ``` Sandboxing provides an important level of security, and should always be kept enabled. Note, however, that: - Only the _package_ build/install/remove commands are protected: if you install a program using opam and execute it, it will run with your standard user rights. - If your installation uses unusual paths (opam root outside `HOME`, system folder, etc.), since `2.0.1` you can use the environment variable `OPAM_USER_PATH_RO` to have them handled by then sandbox script, e.g. This variable format is the same as `PATH`, you can add it in your shell configuration file, e.g `export OPAM_USER_PATH_RO=/rw/usrlocal:/media`. Contained paths are added as read-only. - If needed, for special cases like unprivileged containers, sandboxing can be disabled on `opam init` with the `--disable-sandboxing` flag (only for non-initialised opam). Or by using a [custom `opamrc`](Manual.html#configfield-wrap-build-commands). Use wisely, broken Makefiles that run `rm -rf /` [__do__ happen](https://github.com/ocaml/opam/issues/3231). --- #### 🐫 Why does ``opam init`` need to add stuff to my init scripts / why is ``eval $(opam env)`` needed? This is not strictly needed, but by updating your `PATH` and a few specific environment variables, one can: 1. Automatically find executables installed in opam (current switch) 2. Ensure the OCaml tools are going to look at the right places for installed libraries (e.g. when running `make`) If you don't want to update your startup scripts or change your environment, you can also: - Remember to use `opam exec -- COMMAND` whenever you want to run `COMMAND` while being aware of the opam installation, or - Run `eval $(opam env)` in the shell specifically when you are going to work on a project that uses your opam installation. Just be careful, in this case, that running e.g. `make` while forgetting to do this may lead to use a system-wide installation of OCaml, that may be in conflict (and typically trigger "Inconsistent assumptions" errors in OCaml). --- #### 🐫 What is a "switch"? An OCaml installation and a set of installed packages within an opam installation. This can be used to keep different OCaml versions side-by-side, or different sets of packages. See the [related section](Usage.html#opamswitch) in the usage manual and `opam switch --help`. The "prefix" for a given installation is simply `~/.opam/`. A switch is either based on a system-wide OCaml installation, or on a local installation. In the former case, opam will need to recompile all packages when your system compiler changes. In the latter case, OCaml will be downloaded and compiled on creation of the switch. Standard switches are held within `~/.opam`, but by using a directory as switch handle (instead of a plain name), you may create switches that have their contents in any local repository. They are put in a `_opam/` subdirectory in this case, and it is safe to just remove that subdirectory to clear the switch. --- #### 🐫 Can I work on different switches at the same time in different shells? Yes. Use one of: ``` eval $(opam env --switch --set-switch) # for the current shell opam exec --switch -- # for one command ``` This only affects the environment. --- #### 🐫 Can I get a new switch with the same packages installed? Yes. Use: ``` opam switch export --switch opam switch import --switch ``` The file format is human-readable, so you are free to edit the file before doing the `import` if you need to customise the installation. ### 🐫 How to share my working switch setup for a specific package ? When working on a project, it is sometimes needed to share a set of dependencies that you know (locally) the project is working with. You can share this set by generating a _locked_ opam file. Ths is easily done using the [`lock` command](man/opam-lock.html): it creates an opam file with a `depends:` field populated with all dependencies, at their exact version in the current (working) switch. You can then share this `opam.locked` file, or check it in your version-control system. ```shell $ opam lock # generate a .opam.lock file $ opam install --locked # use locked file, if present ``` --- #### 🐫 I installed a package by hand / used ``ocamlfind remove`` / fiddled with the installed packages and opam is out of sync. Help! Don't panic. opam assumes it's controlling what's below `~/.opam/`, but there are several ways you can recover: * `opam remove --force` will run the uninstall instructions even if the package is not registered as installed. Then retry `opam install`. * `opam reinstall` will try to remove an installed package, but go on to re-installing even if that fails. * If all else fails, you can re-install your current set of packages from scratch using `opam switch reinstall`. * You can force opam to register an installation or removal _without actually performing anything_ using `opam install|remove --fake`. This is not recommended though, as your manual install may not be exactly equivalent to the one expected by other opam packages, and opam may later on trigger reinstallations or upgrades of the package. Don't complain if you mess up your installation using this! If you want to control how a package is installed or modify it, the right way is `opam pin`. * You shouldn't have to, but if you want to restart from scratch, just delete `~/.opam` and get back to `opam init` --- #### 🐫 What are the minimum requirements? 1GB of memory should be all you need. It was reported that you may run into problems with 512MB of RAM and no swap. Of course, compiling the packages may need more. --- #### 🐫 Some packages fail during compilation, complaining about missing dependencies ("m4", "libgtk", etc.) > NOTE: since opam 2.1.0, the following is directly handled by opam, without > relying on a plugin. They probably depend on system, non-OCaml libraries: they need to be installed using your system package manager (apt-get, yum, pacman, homebrew, etc.) since they are outside the scope of opam. opam metadata includes documentation about these external dependencies, on a variety of systems/distributions, in the form of a [`depexts:`](https://opam.ocaml.org/doc/2.0/Manual.html#opamfield-depexts) field. Opam should print the required system dependencies, as documented for your OS, upon failure, and the `depext` opam plugin can take care of installing them for you: ``` opam depext ``` This should install `opam-depext` if needed and prompt to install the system packages required by your opam packages or their dependencies, through your OS's packaging system. If that doesn't work... * Check for hints printed by the failing package * Lookup the development packages corresponding to the error in your system's package repositories. * Dependencies for your specific system may not be known, but check the output of `opam list --rec --resolve ,... --columns name,depexts:`: it will list dependencies on all known systems and may get you in the right direction. In any of these cases, that's useful information that was missing from the opam repository: we would really appreciate that you take a minute to save others the trouble of looking by filling an issue in [the opam-repository tracker](https://github.com/ocaml/opam-repository/issues), with your system details, the output of `opam config report`, and the solution, if you found it. Thanks! --- #### 🐫 I have weird checksum errors: where do they come from? First of all, you should make sure your repositories are up-to-date: ``` opam update ``` If this isn't enough, or if you get the checksum errors while running `opam init`, this could be caused by a badly configured proxy cache that is serving stale files. To clear your proxy cache, you can use `wget --no-cache ` and retry. As a last resort, you can bypass the checksum checks using `--no-checksums`. --- #### 🐫 opam is prompting me to install or upgrade packages that I am not interested in, or doesn't install the latest version by default. Why? What can I do? * You can be more explicit in your request (`opam upgrade PACKAGES`, `opam install 'PACKAGE>=VERSION' PACKAGE...`, etc.). The latest version may not be available on your system, in this case this will tell you why. * See how to set [solver preferences](External_solvers.html) that could match your intentions better than the defaults * Check for pending reinstallations `opam reinstall --list-pending` --- #### 🐫 When trying to install a new package, opam wants to remove or downgrade packages that I have installed. How to know why? There is likely a conflict between them or their dependencies and what you are requesting, here is how to find out. We'll suppose you were trying to install `foo` and `bar` got removed: * `opam install foo bar`, if not possible, will tell you why. * The above may find a solution by using older version of the packages, in that case try and force the latest versions thusly: `opam install foo.2.0 bar.1.1` (you can also use constraints like `'foo>=2.0'`). --- #### 🐫 Where do I report Bugs, Issues and Feature Requests? - Bug reports and feature requests for the opam **tool** should be reported on [opam's issue-tracker](https://github.com/ocaml/opam/issues). Please include the output of `opam config report` whenever applicable. - Packaging issues or requests for a new package can be reported on the [official repository's issue-tracker](https://github.com/ocaml/opam-repository/issues). - General queries for both the tool and the packages can be addressed on the [OCaml-platform mailing-list](http://lists.ocaml.org/listinfo/platform) and insights and evolution of opam internals can discussed on the [opam-devel mailing-list](http://lists.ocaml.org/listinfo/opam-devel). - https://discuss.ocaml.org is a good place for community assistance. - You may also try IRC channel `#ocaml` on Freenode. --- #### 🐫 How to link to libraries installed with opam? The standard way of doing this is to use [ocamlfind](https://opam.ocaml.org/packages/ocamlfind), which is orthogonal to opam: `ocamlfind query `. If you use [dune](https://github.com/ocaml/dune), this should be completely transparent. Your libraries are installed to the directory returned by ``opam var lib``, which is by default `~/.opam//lib`. Note that using `ocamlc`'s option `-I +dir` will make `dir` relative to `lib/ocaml`, and will only work for the libraries that ship with the compiler. Also, remember to add the dependency when you package your project! --- #### 🐫 How does opam tell which version of a package is newer? We use the basics of the [version ordering](https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version) from Debian: - version strings are sliced into alternate, possibly empty non-digit / digit sequences, always starting with a non-digit sequence. - those are sorted lexicographically, using resp. ASCII (with symbol > letter) and number order. For example `a` gives `["a"]`, and `1` gives `["";1]`, so `a` is latest (`"" < "a"`). - the `~` character is special as it sorts even before the end of sequence. It's most convenient for pre-releases, allowing `1.0~beta` to be before `1.0`. Here is an example of an ordered sequence: `~~`, `~`, `~beta2`, `~beta10`, `0.1`, `1.0~beta`, `1.0`, `1.0-test`, `1.0.1`, `1.0.10`, `dev`, `trunk` --- #### 🐫 What does the `--jobs` option do? It doesn't seem to enable parallel builds. It does, but at the _package_ granularity: it will only be noticeable if you build independent packages in the same command. Each package has its own build commands, and it's up to them to enable parallelism. If you are a packager, you may use the `jobs` opam variable, e.g. `make "-j%{jobs}%"`. --- #### 🐫 opam wants to do reinstallations after update. Can I skip them? When opam detects meaningful changes in upstream packages, it marks them for reinstallation, to be sure you get the latest fixes — repository managers generally don't abuse modifying existing packages. You can check this with: ``` opam reinstall --list-pending ``` And, in case you want to skip them: ``` opam reinstall --forget-pending ``` You should only do this if you know the changes you are skipping, though. --- #### 🐫 Some package installation fails with "ocamlfind: already installed" Probably the package was either installed from outside of opam, or uncleanly removed. You should try: ``` opam remove --force opam install ``` This will process the uninstall instructions, even if opam has no knowledge of the package being installed. You may also try to uninstall directly with ocamlfind, or just remove the problematic files. --- #### 🐫 opam is slow on top of NFS. How can I make it faster? opam root is usually located in the `home` directory, which, on top of NFS, slows down opam operations. Locating opam root in `/tmp` is not a solution: you could lose your opam configuration at each reboot. You can use the [`nfsopam`](https://github.com/UnixJunkie/nfsopam) script to have the best of both worlds: persistence of NFS directories and fast operations of local directories. --- #### 🐫 What does the `--cli` option do? Should I be using it everywhere? `--cli` was introduced in opam 2.1 to deal with changes in the command line interface between releases. It tells opam to interpret the command line as a specific version, in particular it means that new options or options which have had their meaning altered will not be available, or will be behave as they did in that version. It only affects the command-line - it does not, for example, stop a root from being upgraded from an older version to the current version. We recommend using it in scripts (and programs which call opam) since they can then expect to work seamlessly with future versions of the opam client. It's also a good idea to use it in blog posts, or other documentation you may share, since it allows copy-and-paste to work reliably (a user with a newer version of opam should have no issues and a user with an older opam gets a clearer error message). We don't recommend using it in day-to-day use of opam in the shell, because you'll be typing more and you won't get to notice exciting new features! If the behaviour of a command or option is altered, and you write something which in no longer valid, opam will try to tell you what the new command should look like. opam-2.1.5/doc/pages/Usage.md0000644000175000017500000001527414427463453014762 0ustar stephsteph# Using opam This document starts with a quick introduction, then covers most commonly-used opam features. If you are a developer and want to get a project packaged or change an existing package, see the step-by-step [packaging guide](Packaging.html). The full documentation is available inline, using ``` opam --help opam --help ``` This document is intended as a quicker overview, use the above to dig into the details. ## Basics ``` # ** Get started ** opam init # Initialize ~/.opam # ** Lookup ** opam list -a # List all available packages opam search QUERY # List packages with QUERY in their name or description opam show PACKAGE # Display information about PACKAGE # ** Install ** opam install PACKAGE # Download, build and install the latest version of PACKAGE # and all its dependencies opam remove PACKAGE # Uninstall the given package # ** Upgrade ** opam update # Update the packages database opam upgrade # Bring everything to the latest version possible # ** More ** opam CMD --help # Command-specific manpage ``` You may prefer to [browse packages online](https://opam.ocaml.org/packages). If you find a package there but not on your computer, either it has been recently added and you should simply run `opam update`, or it's not available on your system or OCaml version — `opam install PACKAGE` will give you the reason. ## `--cli` option Since opam 2.1, opam is able to be invoked using a previous version of its command line. It's recommended that all opam commands in scripts use it, and also blog posts and other sources of information, so you may come across examples which include it. We don't recommend using it in the shell because it's more to type! ## Details on commands ### opam init opam needs to initialize its internal state in a `~/.opam` directory to work. This command will also automatically pick a compiler to install, unless `--bare` has been specified. To make your shell aware of what has been installed in opam, some variables need to be set in your environment. You will be prompted to update your configuration, and given instructions on how to proceed manually if you decline. ### opam update This command synchronizes opam's database with the package repositories. The lists of available packages and their details are stored into `~/.opam/repo/`. Remember to run this regularly if you want to keep up-to-date, or if you are having trouble with a package. It will also update any packages that are bound to version-controlled sources. ### Looking up packages There are three commands for that: * `opam list` List installed packages, or packages matching various selection criteria. * `opam search` Search in package descriptions. * `opam show` Print details on a given package. ### opam install This command downloads, builds and installs packages along with all their dependencies. You can specify one or several packages, along with version constraints. E.g: ``` opam install lwt opam install ocp-indent ocp-index.1.0.2 opam install "ocamlfind>=1.4.0" ``` ### opam upgrade Will attempt to upgrade the installed packages to their newest versions. You should run it after `opam update`, and may use `opam pin` to prevent specific packages from being upgraded. ### opam switch This command enables the user to have several installations on disk, each with their own prefix, set of installed packages, compiler version, etc. Use cases include having to work or test with different OCaml versions, keeping separate development environments for specific projects, etc. Use `opam switch create [name] ` to _switch_ to a different compiler. Don't forget to run the advertised `eval $(opam env)` to update your PATH accordingly. Replace `[name]` with a directory name to have the switch created in that directory, and automatically selected when opam is run from there: this is typically done within projects that require a specific compiler or set of opam packages. Creating a new switch requires re-compiling OCaml, unless you use the `ocaml-system` package, that relies on the global OCaml installation. ### opam pin This command allows one to pin a package to a specific version, but has been extended to allow much more than that. The syntax is ``` opam pin add ``` Where `` may be a version, but also an [URL](Manual.html#URLs) of a local path, an archive, or even a git, mercurial or darcs repository. The package will be kept up-to-date with its origin on `opam update` and when explicitly mentioned in a command, so that you can simply run `opam upgrade ` to re-compile it from its upstream. If the upstream includes opam metadata, that will be used as well. ``` opam pin add camlpdf 1.7 # version pin opam pin add camlpdf ~/src/camlpdf # path opam pin add opam-lib https://github.com/ocaml/opam.git#1.2 # specific branch or commit opam pin add opam-lib --dev-repo # upstream repository ``` This is actually a powerful mechanism to divert any package definition, and can even be used to locally create packages that don't have entries in the repositories. This can be used in conjunction with `opam source` to patch an existing package in a breeze: ``` opam source --dev-repo --pin cd ; hack hack hack; opam upgrade . ``` ### opam repo opam is configured by default to use the community's software repository at [opam.ocaml.org](https://opam.ocaml.org), but third-party repositories can easily be used in addition, or in replacement. ``` opam repo add
``` defines the alias `` to refer to the package repository found at `
`. Without further options, that repository will be set to lookup for package definitions over what was already defined **in the current switch only**. See options `--all` and `--set-default` to affect other and newly created switches, respectively. The `
` may point to an HTTP, local or version-controlled repository. To create a new switch bound to specific repositories, it's easier to use instead: ``` opam switch create --repos =
,default ``` Defining your own repository, either locally or online, is quite easy: you can start off by cloning [the official repository](https://github.com/ocaml/opam-repository) if you intend it as a replacement, or just create a new directory with a `packages` sub-directory, and a [`repo` file](Manual.html#repo) containing at least an `opam-version` field. See the [packaging guide](Packaging.html) if you need help on the package format. If your repository is going to be served over HTTP, you should generate an index using the `opam admin index` command. opam-2.1.5/doc/pages/Manual.md0000644000175000017500000023664714427463453015144 0ustar stephsteph # The opam manual This manual gathers reference information on opam and its file formats. It is primarily of use for packagers, package maintainers and repository maintainers. * For simple usage of opam, see the [Usage](Usage.html) page, and the comprehensive built-in documentation [`opam [command] --help`](man/index.html). * For a gentler introduction to packaging, see the [Packaging guide](Packaging.html) * If you want to hack on opam or build related tools, the API documentation can be browsed [here](api/index.html) ## File hierarchies ### opam root opam holds its configuration, metadata, logs, temporary directories and caches within a directory that we will call _opam root_. By default, this is `~/.opam`, and we may refer to it by this name in this manual for the sake of simplicity, but this can be changed using the `OPAMROOT` environment variable or the `--root` command-line argument. An existing opam root is required for opam to operate normally, and one is created upon running `opam init`. The initial configuration can be defined through a configuration file at `~/.opamrc`, `/etc/opamrc` or at a location specified through the `--config` command-line option. If none is present, opam defaults to its built-in configuration that binds to the OCaml repository at `https://opam.ocaml.org`. Except in explicit cases, opam only alters files within its opam root. It is organised as follows: - [`~/.opam/config`](#config): the global opam configuration file - `~/.opam/repo/`: contains the mirrors of the configured package repositories - [`~/.opam/repo/repos-config`](#repos-config): lists the configured package repositories and their URLs - `~/.opam/repo/`: mirror of the given repository - `~/.opam/opam-init/`: contains opam configuration scripts for the outside world, e.g. shell environment initialisation - `~/.opam/download-cache/`: caches of downloaded files - `~/.opam/plugins/`: reserved for plugins - `~/.opam/`: prefixes of named [switches](#Switches) ### Repositories Repositories are collection of opam package definitions. They respect the following hierarchy: - [`/repo`](#repo): repository configuration file - [`/packages//./opam`](#opam): holds the metadata for the given package. `url` and `descr` may also be present, in which case they override what may already be present in the `opam` file - [`/packages//./files/`](#files): contains files that are copied over the root of the source tree of the given package before it gets used. - `/cache/`: cached package files, by checksum. Note that the cache location is configured in the [repo](#repofield-archive-mirrors) file, this name is only where `opam admin cache` puts it by default. - `/archives/`: this is no longer used by opam automatically, but is the canonical place where you should place your package archives if you want to serve them from the repository server directly. The URLs of the packages will have to be set accordingly. - `/index.tar.gz`: archive containing the whole repository contents (except the cache), needed when serving over HTTP. It can be generated using `opam admin index`. opam repositories can be accessed using local or remote (ssh) paths, HTTP URLs, or one of the supported version control systems (git, Mercurial, Darcs). A repository is set up using ``` opam repository add [--this-switch|--all-switches|--set-default] ``` The last flag sets what switches are affected by the new repository: - `--this-switch` (**default**) selects only the current switch - `--all-switches` affects all the currently existing switches - `--set-default` affects all switches created in the future Creating a new switch using e.g. a custom repository overlay on the default repository can be done in a single call using: ``` opam switch create --repos==,default ``` which will define the new repository `` at `` if needed. Use `opam repository list --all` for an overview of configured repositories. Repository selection is always ordered, with the definition of a given version of a package being taken from the repository with the lowest index where it is found. Data from the configured repositories is updated from the upstreams manually using the `opam update` command. This only updates repositories in use by the currently selected switches, unless `--all` is specified. ### Switches opam is designed to hold any number of concurrent installation prefixes, called _switches_. Switches are isolated from each other and have their own set of installed packages, selection of repositories, and configuration options. All package-related commands operate on a single switch, and require one to be selected. The current switch can be selected in the following ways: - globally, using `opam switch `. opam will use that switch for all further commands, except when overridden in one of the following ways. - for local switches, which are external to the opam root, when in the directory where the switch resides or a descendant. - by setting the `OPAMSWITCH=` environment variable, to set it within a single shell session. This can be done by running `eval $(opam env --switch )` to set the shell environment at once, see below. - through the `--switch ` command-line flag, for a single command. Switches have their own prefix, normally `~/.opam/`, where packages get installed ; to use what is installed in a switch, some environment variables need to be set, _e.g._ to make executables installed into `~/.opam//bin` visible, that directory needs to be added to `PATH`, but individual packages can define their own settings as well. Command `opam env` returns the environment updates corresponding to the current switch, in a format readable by your shell, and when needed opam will prompt you to run: ``` eval $(opam env) ``` A switch is created using `opam switch create (|--empty)`. - `` can be either a plain name, or a directory name (if containing `/` or starting with `.`). In the latter case the switch is _local_ and instead of being held at `~/.opam/`, it will be created in the given directory, as a `_opam` subdirectory. Local switches are automatically selected depending on the current directory, see above. - If a `` is selected, opam will install the corresponding packages and their dependencies in the new switch. These packages will be marked as _base_, protected against removal and unaffected by upgrade commands. `` can be selected among packages which have the `compiler` flag set, or their versions. Use `opam switch list-available` to list them. #### Structure If we define `` as: - `~/.opam/` for plain switches - `/_opam` for local switches, when `` is a path Switches are laid out thusly: - `/`: prefix of the switch, holding the installation hierarchy in the UNIX `/usr` standard (with subdirectories `bin`, `lib`, `share`, `man`, `doc`, `etc`...) - `/.opam-switch/`: holds all opam data regarding this switch - [`/.opam-switch/switch-config`: switch-specific configuration](#switch-config) - [`/.opam-switch/switch-state`: stores the sets of installed, base, pinned packages](#switch-state) - `/.opam-switch/environment`: contains the environment variable settings for this switch - `/.opam-switch/reinstall`: list of packages marked for reinstallation (development packages where changes have been detected) - [`/.opam-switch/config/.config`](#lt-pkgname-gt-config): installed package's, opam specific configuration - [`/.opam-switch/install/.install`](#lt-pkgname-gt-install): `.install` files used to install the given package - `/.opam-switch/install/.changes`: file system changes done by the installation of the given package, as tracked by opam - `/.opam-switch/packages/./`: metadata of the given package as it has been used for its installation - `/.opam-switch/sources/./` or `/`: unpacked sources of packages. The version is omitted from the directory name for pinned packages, which are typically synchronised to a version-control system rather than unpacked from an archive. - `/.opam-switch/overlay//`: custom definition for the given pinned packages - `/.opam-switch/build/./`: temporary directories where the packages are compiled - `/.opam-switch/remove/./`: temporary directories used for calling the packages' `remove` commands, when those need the source. - `/.opam-switch/backup`: snapshots of previous states of the switch, and other backup files. #### Pinning Pinning is an operation by which a package definition can be created or altered locally in a switch. In its most simple form, `opam pin `, `` is bound to the specified version and won't be changed on `opam upgrade` (assuming it is an existing package). `opam pin edit ` provides a way to directly pin and edit the metadata of the given package, locally to the current switch, for example to tweak a dependency. `opam pin [package] ` can further be used to divert the source of a package, or even create a new package ; this is very useful to point to a local path containing a development or patched version of the package source. When pinning a package, the source is searched for metadata in an `opam` or `.opam` file, either at the root of the source tree or in an `opam` directory. You can also replace that file by a directory containing an `opam` file and optionally other metadata, like a `files/` subdirectory. As the `package` argument is optional, `opam` guesses package name from the `` or the `opam` file found. Note that for local VCS pinning, when given without package name, `opam` retrieves the locally found `opam` file, even if not versioned. If this file is versioned, `opam` relies on the versioned version. Whenever an install, reinstall or upgrade command-line refers to a pinned package, opam first fetches its latest source. `opam update [--development]` is otherwise the standard way to update the sources of all the packages pinned in the current switch. `opam install ` is an automatic way to handle pinning packages whose definitions are found in ``, synchronise and install them. The `upgrade`, `reinstall` and `remove` commands can likewise be used with a directory argument to refer to pinned packages. ## Common file format ### Conventions Syntax is given in a BNF-like notation. Non-terminals are written ``, terminals are either plain text or written in double-quotes (`"terminal"`), curly brackets denote zero or more repetitions when suffixed with `*`, or one or more when suffixed with `+`, and square brackets denote zero or one occurrence. Parentheses are for grouping. `(")` and `(""")` respectively mean one and three quotation mark characters. As a special case, and for readability, we add simplified notations for _lists_ and _options_: - `[ ... ]` means `"[" { }* "]" | `. It corresponds to a case of the `` non-terminal and is a list of `` repeated any number of times. The square brackets can be omitted when `` occurs just once. - ` { ... }` means ` "{" { }* "}"`, and is a shortcut for the `