diff --git a/src/client/opamArg.ml b/src/client/opamArg.ml index c43ff1f6382..81d1c10e482 100644 --- a/src/client/opamArg.ml +++ b/src/client/opamArg.ml @@ -458,6 +458,8 @@ type global_options = { no_auto_upgrade : bool; working_dir : bool; ignore_pin_depends : bool; + no_checksums: bool; + req_checksums : bool; cli : OpamCLIVersion.t; } @@ -469,6 +471,7 @@ let create_global_options opt_root external_solver use_internal_solver cudf_file solver_preferences best_effort safe_mode json no_auto_upgrade working_dir ignore_pin_depends + no_checksums req_checksums d_no_aspcud _ = if d_no_aspcud then OpamConsole.warning @@ -485,7 +488,9 @@ let create_global_options { 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 } + no_auto_upgrade; working_dir; ignore_pin_depends; + no_checksums; req_checksums; + cli } let apply_global_options cli o = if o.git_version then ( @@ -532,7 +537,10 @@ let apply_global_options cli o = (* - repository options - *) (* ?download_tool:(OpamTypes.arg list * dl_tool_kind) Lazy.t *) (* ?retries:int *) - (* ?force_checksums:bool option *) + ?force_checksums:(if o.req_checksums then Some (Some true) + else if o.no_checksums then Some (Some false) + else None) + (* ?repo_tarring: bool *) (* - solver options *) ?cudf_file:(some o.cudf_file) ?solver @@ -630,8 +638,6 @@ type build_options = { reuse_build_dir: bool; inplace_build : bool; make : string option; - no_checksums : bool; - req_checksums : bool; build_test : bool; build_doc : bool; dev_setup : bool; @@ -649,14 +655,14 @@ type build_options = { } let create_build_options - keep_build_dir reuse_build_dir inplace_build make no_checksums - req_checksums build_test build_doc dev_setup show dryrun skip_update + keep_build_dir reuse_build_dir inplace_build make + build_test build_doc dev_setup 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; dev_setup; show; dryrun; skip_update; + keep_build_dir; reuse_build_dir; inplace_build; make; + build_test; build_doc; dev_setup; show; dryrun; skip_update; fake; jobs; ignore_constraints_on; unlock_base; locked; lock_suffix; assume_depexts; no_depexts; } @@ -664,13 +670,14 @@ let create_build_options 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) + (* ?force_checksums:bool option *) + (* ?repo_tarring: bool *) (); +*) OpamStateConfig.update (* ?root: -- handled globally *) ?jobs:(b.jobs >>| fun j -> lazy j) @@ -1378,6 +1385,17 @@ let global_options cli = through $(i,opam pin) or through $(i,opam install DIR). This is \ equivalent to setting $(b,IGNOREPINDEPENDS=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 Term.(const create_global_options $git_version $debug $debug_level $verbose $quiet $color $switch $yes $confirm_level @@ -1385,6 +1403,7 @@ let global_options cli = $use_internal_solver $cudf_file $solver_preferences $best_effort $safe_mode $json_flag $no_auto_upgrade $working_dir $ignore_pin_depends + $no_checksums $req_checksums $d_no_aspcud $cli_arg) (* lock options *) @@ -1432,14 +1451,6 @@ let build_options cli = 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"]; @@ -1526,7 +1537,7 @@ let build_options cli = in Term.(const create_build_options $keep_build_dir $reuse_build_dir $inplace_build $make - $no_checksums $req_checksums $build_test $build_doc $dev_setup $show + $build_test $build_doc $dev_setup $show $dryrun $skip_update $fake $jobs_flag ~section cli cli_original $ignore_constraints_on $unlock_base $locked $lock_suffix $assume_depexts $no_depexts) diff --git a/src/client/opamArg.mli b/src/client/opamArg.mli index b652b36d921..5f7bfd88201 100644 --- a/src/client/opamArg.mli +++ b/src/client/opamArg.mli @@ -170,6 +170,8 @@ type global_options = { no_auto_upgrade : bool; working_dir : bool; ignore_pin_depends : bool; + no_checksums: bool; + req_checksums : bool; cli : OpamCLIVersion.t; } diff --git a/src/client/opamCommands.ml b/src/client/opamCommands.ml index 618b5a78a0f..0fc9556e223 100644 --- a/src/client/opamCommands.ml +++ b/src/client/opamCommands.ml @@ -3775,9 +3775,10 @@ let source cli = OpamSwitchState.drop (OpamClient.PIN.pin t nv.name ~version:nv.version target) in - mk_command ~cli cli_original "source" ~doc ~man + mk_command ~cli cli_original "source" ~doc ~man Term.(const source - $global_options cli $atom $dev_repo $pin $no_switch $dir) + $global_options cli + $atom $dev_repo $pin $no_switch $dir) (* LINT *) let lint_doc = "Checks and validate package description ('opam') files." diff --git a/tests/reftests/archive.test b/tests/reftests/archive.test index 69c2eaac0e3..6f27b3db421 100644 --- a/tests/reftests/archive.test +++ b/tests/reftests/archive.test @@ -285,6 +285,10 @@ Done. ### opam source good-md5 Successfully extracted to ${BASEDIR}/good-md5.1 ### test -f good-md5.1/hello +### rm -r good-md5.1 +### opam source good-md5 --require-checksums +Successfully extracted to ${BASEDIR}/good-md5.1 +### test -f good-md5.1/hello ### opam clean --download-cache Clearing cache of downloaded files ### :I:2: good sha256 @@ -321,6 +325,10 @@ Done. ### opam source good-sha256 Successfully extracted to ${BASEDIR}/good-sha256.1 ### test -f good-sha256.1/hello +### rm -r good-sha256.1 +### opam source good-sha256 --require-checksums +Successfully extracted to ${BASEDIR}/good-sha256.1 +### test -f good-sha256.1/hello ### opam clean --download-cache Clearing cache of downloaded files ### :I:3: good md5 & sha256 @@ -375,6 +383,10 @@ Done. ### opam source good-md5-good-sha256 Successfully extracted to ${BASEDIR}/good-md5-good-sha256.1 ### test -f good-md5-good-sha256.1/hello +### rm -r good-md5-good-sha256.1 +### opam source good-md5-good-sha256 --require-checksums +Successfully extracted to ${BASEDIR}/good-md5-good-sha256.1 +### test -f good-md5-good-sha256.1/hello ### opam clean --download-cache Clearing cache of downloaded files ### :I:4: good sha256 & good md5 @@ -426,6 +438,10 @@ Done. ### opam source good-sha256-good-md5 Successfully extracted to ${BASEDIR}/good-sha256-good-md5.1 ### test -f good-sha256-good-md5.1/hello +### rm -r good-sha256-good-md5.1 +### opam source good-sha256-good-md5 --require-checksums +Successfully extracted to ${BASEDIR}/good-sha256-good-md5.1 +### test -f good-sha256-good-md5.1/hello ### opam clean --download-cache Clearing cache of downloaded files ### :I:5: no checksum @@ -471,6 +487,12 @@ OpamSolution.Fetch_fail("no-checksum.1: Missing checksum, and `--require-checksu ### opam source no-checksum Successfully extracted to ${BASEDIR}/no-checksum.1 ### test -f no-checksum.1/hello +### rm -r no-checksum.1 +### opam source no-checksum --require-checksums +[ERROR] Download failed: no-checksum.1: Missing checksum, and `--require-checksums` was set. +# Return code 40 # +### test -f no-checksum.1/hello +# Return code 1 # ### opam clean --download-cache Clearing cache of downloaded files ### :I:6: multiple md5 @@ -530,6 +552,15 @@ OpamSolution.Fetch_fail("Checksum mismatch") # Return code 40 # ### test -f multiple-md5.1/hello # Return code 1 # +### rm -r multiple-md5.1 +### opam source multiple-md5 --require-checksums | '[0-9a-z]{32}' -> 'hash' +[ERROR] multiple-md5.1: Checksum mismatch for file://${BASEDIR}/archive.tgz: + expected md5=hash + got md5=hash +[ERROR] Download failed: Checksum mismatch +# Return code 40 # +### test -f multiple-md5.1/hello +# Return code 1 # ### opam clean --download-cache Clearing cache of downloaded files ### :I:7: bad md5 @@ -589,6 +620,15 @@ OpamSolution.Fetch_fail("Checksum mismatch") # Return code 40 # ### test -f bad-md5.1/hello # Return code 1 # +### rm -r bad-md5.1 +### opam source bad-md5 --require-checksums | '[0-9a-z]{32}' -> 'hash' +[ERROR] bad-md5.1: Checksum mismatch for file://${BASEDIR}/archive.tgz: + expected md5=hash + got md5=hash +[ERROR] Download failed: Checksum mismatch +# Return code 40 # +### test -f bad-md5.1/hello +# Return code 1 # ### opam clean --download-cache Clearing cache of downloaded files ### :I:8: good md5 & bad sha256 @@ -718,6 +758,15 @@ OpamSolution.Fetch_fail("Checksum mismatch") # Return code 40 # ### test -f good-md5-bad-sha256.1/hello # Return code 1 # +### rm -r good-md5-bad-sha256.1 +### opam source good-md5-bad-sha256 --require-checksums | '[0-9a-z]{64}' -> 'md5' +[ERROR] good-md5-bad-sha256.1: Checksum mismatch for file://${BASEDIR}/archive.tgz: + expected sha256=md5 + got sha256=md5 +[ERROR] Download failed: Checksum mismatch +# Return code 40 # +### test -f good-md5-bad-sha256.1/hello +# Return code 1 # ### opam clean --download-cache Clearing cache of downloaded files ### :I:9: good sha256 & bad md5 @@ -777,6 +826,15 @@ OpamSolution.Fetch_fail("Checksum mismatch") # Return code 40 # ### test -f good-sha256-bad-md5.1/hello # Return code 1 # +### rm -r good-sha256-bad-md5.1 +### opam source good-sha256-bad-md5 --require-checksums | '[0-9a-z]{32}' -> 'hash' +[ERROR] good-sha256-bad-md5.1: Checksum mismatch for file://${BASEDIR}/archive.tgz: + expected md5=hash + got md5=hash +[ERROR] Download failed: Checksum mismatch +# Return code 40 # +### test -f good-sha256-bad-md5.1/hello +# Return code 1 # ### opam clean --download-cache Clearing cache of downloaded files ### :I:10: clash with all md5 @@ -921,6 +979,15 @@ OpamSolution.Fetch_fail("Checksum mismatch") # Return code 40 # ### test -f clash-with-all-md5s.666/hello # Return code 1 # +### rm -r clash-with-all-md5s.666 +### opam source clash-with-all-md5s --require-checksums | '[0-9a-z]{32}' -> 'hash' +[ERROR] clash-with-all-md5s.666: Checksum mismatch for file://${BASEDIR}/archive.tgz: + expected md5=hash + got md5=hash +[ERROR] Download failed: Checksum mismatch +# Return code 40 # +### test -f clash-with-all-md5s.666/hello +# Return code 1 # ### opam clean --download-cache Clearing cache of downloaded files ### ::::::::::::::::: diff --git a/tests/reftests/extrafile.test b/tests/reftests/extrafile.test index bb30f20a6a4..01150c3315f 100644 --- a/tests/reftests/extrafile.test +++ b/tests/reftests/extrafile.test @@ -196,6 +196,10 @@ Done. ### opam source good-md5 Successfully extracted to ${BASEDIR}/good-md5.1 ### test -f good-md5.1/p.patch +### rm -r good-md5.1 +### opam source good-md5 --require-checksums +Successfully extracted to ${BASEDIR}/good-md5.1 +### test -f good-md5.1/p.patch ### opam clean --download-cache Clearing cache of downloaded files ### :I:2: good md5 & sha256 @@ -230,6 +234,10 @@ Done. ### opam source good-md5-good-sha256 Successfully extracted to ${BASEDIR}/good-md5-good-sha256.1 ### test -f good-md5-good-sha256.1/p.patch +### rm -r good-md5-good-sha256.1 +### opam source good-md5-good-sha256 --require-checksums +Successfully extracted to ${BASEDIR}/good-md5-good-sha256.1 +### test -f good-md5-good-sha256.1/p.patch ### opam clean --download-cache Clearing cache of downloaded files ### :I:3: bad md5 @@ -278,6 +286,12 @@ Bad hash for - ${BASEDIR}/OPAM/repo/default/packages/bad-md5/bad-md5.1/files/p ### opam source bad-md5 | '.n"' -> '"' [WARNING] Some errors extracting to ${BASEDIR}/bad-md5.1: Failure("Bad hash for - ${BASEDIR}/OPAM/repo/default/packages/bad-md5/bad-md5.1/files/p.patch") +### test -f bad-md5.1/p.patch +# Return code 1 # +### rm -r bad-md5.1 +### opam source bad-md5 --require-checksums | '.n"' -> '"' +[WARNING] Some errors extracting to ${BASEDIR}/bad-md5.1: Failure("Bad hash for - ${BASEDIR}/OPAM/repo/default/packages/bad-md5/bad-md5.1/files/p.patch") + ### test -f bad-md5.1/p.patch # Return code 1 # ### opam clean --download-cache @@ -324,6 +338,11 @@ Bad hash for - ${BASEDIR}/OPAM/repo/default/packages/good-md5-bad-sha256/good- ### opam source good-md5-bad-sha256 | '.n"' -> '"' [WARNING] Some errors extracting to ${BASEDIR}/good-md5-bad-sha256.1: Failure("Bad hash for - ${BASEDIR}/OPAM/repo/default/packages/good-md5-bad-sha256/good-md5-bad-sha256.1/files/p.patch") +### test -f good-md5-bad-sha256.1/p.patch +### rm -r good-md5-bad-sha256.1 +### opam source good-md5-bad-sha256 --require-checksums | '.n"' -> '"' +[WARNING] Some errors extracting to ${BASEDIR}/good-md5-bad-sha256.1: Failure("Bad hash for - ${BASEDIR}/OPAM/repo/default/packages/good-md5-bad-sha256/good-md5-bad-sha256.1/files/p.patch") + ### test -f good-md5-bad-sha256.1/p.patch ### opam clean --download-cache Clearing cache of downloaded files @@ -376,6 +395,10 @@ Done. ### opam source no-checksum Successfully extracted to ${BASEDIR}/no-checksum.1 ### test -f no-checksum.1/p.patch +### rm -r no-checksum.1 +### opam source no-checksum --require-checksums +Successfully extracted to ${BASEDIR}/no-checksum.1 +### test -f no-checksum.1/p.patch ### opam clean --download-cache Clearing cache of downloaded files ### ::::::::::::::::: @@ -413,6 +436,10 @@ Done. ### opam source not-mentioned Successfully extracted to ${BASEDIR}/not-mentioned.1 ### test -f not-mentioned.1/p.patch +### rm -r not-mentioned.1 +### opam source not-mentioned --require-checksums +Successfully extracted to ${BASEDIR}/not-mentioned.1 +### test -f not-mentioned.1/p.patch ### opam clean --download-cache Clearing cache of downloaded files ### :II:2: not present diff --git a/tests/reftests/extrasource.test b/tests/reftests/extrasource.test index f46207d1e0c..02aad4aa77f 100644 --- a/tests/reftests/extrasource.test +++ b/tests/reftests/extrasource.test @@ -398,6 +398,10 @@ Done. ### opam source good-sha256 Successfully extracted to ${BASEDIR}/good-sha256.1 ### test -f good-sha256.1/i-am-a-patch +### rm -r good-sha256.1 +### opam source good-sha256 --require-checksums +Successfully extracted to ${BASEDIR}/good-sha256.1 +### test -f good-sha256.1/i-am-a-patch ### opam clean --download-cache Clearing cache of downloaded files ### :I:3: good md5 & sha256 @@ -450,6 +454,10 @@ Done. ### opam source good-md5-good-sha256 Successfully extracted to ${BASEDIR}/good-md5-good-sha256.1 ### test -f good-md5-good-sha256.1/i-am-a-patch +### rm -r good-md5-good-sha256.1 +### opam source good-md5-good-sha256 --require-checksums +Successfully extracted to ${BASEDIR}/good-md5-good-sha256.1 +### test -f good-md5-good-sha256.1/i-am-a-patch ### opam clean --download-cache Clearing cache of downloaded files ### :I:4: good sha256 & good md5 @@ -501,6 +509,10 @@ Done. ### opam source good-sha256-good-md5 Successfully extracted to ${BASEDIR}/good-sha256-good-md5.1 ### test -f good-sha256-good-md5.1/i-am-a-patch +### rm -r good-sha256-good-md5.1 +### opam source good-sha256-good-md5 --require-checksums +Successfully extracted to ${BASEDIR}/good-sha256-good-md5.1 +### test -f good-sha256-good-md5.1/i-am-a-patch ### opam clean --download-cache Clearing cache of downloaded files ### :I:5: no checksum @@ -545,6 +557,12 @@ no-checksum.1/i-am-a-patch: Missing checksum, and `--require-checksums` was set. ### opam source no-checksum Successfully extracted to ${BASEDIR}/no-checksum.1 ### test -f no-checksum.1/i-am-a-patch +### rm -r no-checksum.1 +### opam source no-checksum --require-checksums +[WARNING] Some errors extracting to ${BASEDIR}/no-checksum.1: Failure("no-checksum.1/i-am-a-patch: Missing checksum, and `--require-checksums` was set.") + +### test -f no-checksum.1/i-am-a-patch +# Return code 1 # ### opam clean --download-cache Clearing cache of downloaded files ### :I:6: multiple md5 @@ -600,6 +618,14 @@ OpamSolution.Fetch_fail("Checksum mismatch") # Return code 40 # ### test -f multiple-md5.1/i-am-a-patch # Return code 1 # +### opam source multiple-md5 --require-checksums | '[0-9a-z]{32}' -> 'hash' +[ERROR] multiple-md5.1/i-am-a-patch: Checksum mismatch for file://${BASEDIR}/p.patch: + expected md5=hash + got md5=hash +[ERROR] Download failed: Checksum mismatch +# Return code 40 # +### test -f multiple-md5.1/i-am-a-patch +# Return code 1 # ### opam clean --download-cache Clearing cache of downloaded files ### :I:7: bad md5 @@ -655,6 +681,14 @@ OpamSolution.Fetch_fail("Checksum mismatch") # Return code 40 # ### test -f bad-md5.1/i-am-a-patch # Return code 1 # +### opam source bad-md5 --require-checksums | '[0-9a-z]{32}' -> 'hash' +[ERROR] bad-md5.1/i-am-a-patch: Checksum mismatch for file://${BASEDIR}/p.patch: + expected md5=hash + got md5=hash +[ERROR] Download failed: Checksum mismatch +# Return code 40 # +### test -f bad-md5.1/i-am-a-patch +# Return code 1 # ### opam clean --download-cache Clearing cache of downloaded files ### :I:8: good md5 & bad sha256 @@ -780,6 +814,14 @@ OpamSolution.Fetch_fail("Checksum mismatch") # Return code 40 # ### test -f good-md5-bad-sha256.1/i-am-a-patch # Return code 1 # +### opam source good-md5-bad-sha256 --require-checksums | '[0-9a-z]{64}' -> 'md5' +[ERROR] good-md5-bad-sha256.1/i-am-a-patch: Checksum mismatch for file://${BASEDIR}/p.patch: + expected sha256=md5 + got sha256=md5 +[ERROR] Download failed: Checksum mismatch +# Return code 40 # +### test -f good-md5-bad-sha256.1/i-am-a-patch +# Return code 1 # ### opam clean --download-cache Clearing cache of downloaded files ### :I:9: good sha256 & bad md5 @@ -835,6 +877,14 @@ OpamSolution.Fetch_fail("Checksum mismatch") # Return code 40 # ### test -f good-sha256-bad-md5.1/i-am-a-patch # Return code 1 # +### opam source good-sha256-bad-md5 --require-checksums | '[0-9a-z]{32}' -> 'hash' +[ERROR] good-sha256-bad-md5.1/i-am-a-patch: Checksum mismatch for file://${BASEDIR}/p.patch: + expected md5=hash + got md5=hash +[ERROR] Download failed: Checksum mismatch +# Return code 40 # +### test -f good-sha256-bad-md5.1/i-am-a-patch +# Return code 1 # ### opam clean --download-cache Clearing cache of downloaded files ### :I:10: clash with all md5 @@ -959,6 +1009,14 @@ OpamSolution.Fetch_fail("Checksum mismatch") # Return code 40 # ### test -f clash-with-all-md5s.666/i-am-a-patch # Return code 1 # +### opam source clash-with-all-md5s --require-checksums | '[0-9a-z]{32}' -> 'hash' +[ERROR] clash-with-all-md5s.666/i-am-a-patch: Checksum mismatch for file://${BASEDIR}/p.patch: + expected md5=hash + got md5=hash +[ERROR] Download failed: Checksum mismatch +# Return code 40 # +### test -f clash-with-all-md5s.666/i-am-a-patch +# Return code 1 # ### opam clean --download-cache Clearing cache of downloaded files ### ::::::::::::::::: @@ -1011,6 +1069,11 @@ The following actions will be performed: Successfully extracted to ${BASEDIR}/not-mentioned.1 ### test -f not-mentioned.1/i-am-a-patch # Return code 1 # +### rm -r not-mentioned.1 +### opam source not-mentioned --require-checksums +Successfully extracted to ${BASEDIR}/not-mentioned.1 +### test -f not-mentioned.1/i-am-a-patch +# Return code 1 # ### :II:2: Double extra-source ### opam lint --package multiple /multiple.1: Errors. @@ -1061,6 +1124,10 @@ Done. ### opam source multiple Successfully extracted to ${BASEDIR}/multiple.1 ### test -f multiple.1/i-am-a-patch +### rm -r multiple.1 +### opam source multiple --require-checksums +Successfully extracted to ${BASEDIR}/multiple.1 +### test -f multiple.1/i-am-a-patch ### ::::::::::::::::: ### :III: Cache manipulation ### ::::::::::::::::: @@ -1242,6 +1309,10 @@ Done. ### opam source escape-absolute Successfully extracted to ${BASEDIR}/escape-absolute.1 ### test -f escape-absolute.1/etc/passwd +### rm -r escape-absolute.1 +### opam source escape-absolute --require-checksums +Successfully extracted to ${BASEDIR}/escape-absolute.1 +### test -f escape-absolute.1/etc/passwd ### :IV:2: good md5 ### # /!\ all escape!!! ### opam lint --package escape-build-good-md5 @@ -1281,3 +1352,7 @@ Done. ### opam source escape-source-good-md5 Successfully extracted to ${BASEDIR}/escape-source-good-md5.1 ### test -f shouldnt-exist +### rm -r escape-source-good-md5.1 +### opam source escape-source-good-md5 --require-checksums +Successfully extracted to ${BASEDIR}/escape-source-good-md5.1 +### test -f shouldnt-exist