Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file cmdliner_runner.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376moduleArg=Cmdliner.ArgmoduleCmd=Cmdliner.CmdmoduleTerm=Cmdliner.Termlethelpman_formatcmdstopic=matchtopicwith|None->`Help(`Pager,None)(* help about the program. *)|Sometopic->(lettopics="topics"::cmdsinletconv,_=Cmdliner.Arg.enum(List.rev_map(funs->(s,s))topics)inmatchconvtopicwith|`Errore->`Error(false,e)|`Oktwhent="topics"->List.iterprint_endlinetopics;`Ok()|`OktwhenList.memtcmds->`Help(man_format,Somet)|`Ok_t->(* should never get here if all `topics` are handled *)`Help(`Pager,None))(* Help sections common to all commands *)lethelp_secs=[`SCmdliner.Manpage.s_common_options;`P"These options are common to all commands.";`S"MORE HELP";`P"Use $(mname) $(i,COMMAND) --help for help on a single command.";](* Options common to all commands *)letsetup_logstyle_rendererlevel=Fmt_tty.setup_std_outputs?style_renderer();Logs.set_levellevel;Logs.set_reporter(Logs.format_reporter());Dkml_install_api.Log_config.create?log_config_style_renderer:style_renderer?log_config_level:level()letsetup_log_t=Term.(constsetup_log$Fmt_cli.style_renderer()$Logs_cli.level())(* Define a context that includes all component-based fields *)letcreate_context~install_direction~staging_default~target_abiself_component_namereglog_configprefix_dirarchive_dirstaging_files_optopam_context_opt=letopenPath_evalinletopenError_handling.Monad_syntaxinlet*staging_files_source,_fl=Path_location.staging_files_source~staging_default~opam_context_opt~staging_files_optinlet*global_context,_fl=Global_context.createreginstall_directioninlet*interpreter,_fl=Interpreter.createglobal_context~install_direction~self_component_name~abi:target_abi~staging_files_source~prefix_dir~archive_dirinreturn{Dkml_install_api.Context.eval=Interpreter.evalinterpreter;path_eval=Interpreter.path_evalinterpreter;target_abi_v2=target_abi;log_config;}(* Cmdliner, at least in 1.0.4, has the pp_str treated as an escaped OCaml
string. Not sure why, but backslashes on Windows path are interpreted
to be escape sequences. So create raw_* to add escaping to the raw
strings. *)letquotes=Fmt.str"`%s'"sleterr_nokinds=Fmt.str"no %s %s"(quotes)kindleterr_not_dirs=Fmt.str"%s is not a directory"(quotes)letraw_pp_strfmts=Fmt.stringfmt(String.escapeds)letraw_dir=letparses=matchSys.file_existsswith|true->ifSys.is_directorysthen`Okselse`Error(err_not_dirs)|false->`Error(err_no"directory"s)in(parse,raw_pp_str)(* Options for installation commands *)letprefix_dir_t=letdoc="$(docv) is the installation directory"inlett=Arg.(required&opt(somestring)None&info[Cmdliner_common.prefix_arg]~docv:"PREFIX"~doc)inletto_abs_dirprefix=letfp=Fpath.vprefixinmatchFpath.is_relfpwith|true->Fpath.(v(Sys.getcwd())//fp)|false->fpinTerm.(constto_abs_dir$t)(** Directory containing dkml-package.bc or whatever executable
(perhaps a renamed setup.exe in a non-bin folder) is currently running. *)letexec_dir=Fpath.(parent(vBos.OS.Arg.exec))(** The root directory that was uncompressed at end-user install time *)letenduser_archive_dir()=(* get path to .archivetree *)letopenError_handling.Monad_syntaxinletarchivetree()=Diskuvbox.find_up~from_dir:exec_dir~basenames:[Fpath.v".archivetree"]~max_ascent:3()inlet*archivetree_opt,fl=Dkml_install_api.Forward_progress.lift_result__POS__Fmt.linesError_handling.runner_fatal_log(archivetree())inmatcharchivetree_optwith|Somearchivetree->(* the archive directory is the directory containing .archivetree *)return(fst(Fpath.split_basearchivetree))|None->fl~id:"855c1e64"(Fmt.str"The archive directory containing .archivetree could not be located \
in %a or an ancestor"Fpath.ppexec_dir);Dkml_install_api.Forward_progress.Halted_progressExit_transient_failure(** [staging_default_dir_for_package ~archive_dir].
For the benefit of Windows and macOS we keep the directory name ("sg") small. *)letstaging_default_dir_for_package~archive_dir=Fpath.(archive_dir/"sg")(** [static_default_dir_for_package ~archive_dir].
For the benefit of Windows and macOS we keep the directory name ("st") small. *)letstatic_default_dir_for_package~archive_dir=Fpath.(archive_dir/"st")letstaging_files_opt_t=letdoc="$(docv) is the staging files directory for the installation"inArg.(value&opt(someraw_dir)None&info[Cmdliner_common.staging_files_arg]~docv:"DIR"~doc)letstatic_files_opt_t=letdoc="$(docv) is the static files directory of the installation"inArg.(value&opt(someraw_dir)None&info[Cmdliner_common.static_files_arg]~docv:"DIR"~doc)letopam_context_opt_t=letdoc=Fmt.str"Obtain staging and static files from an Opam switch. The Opam switch \
will not be used for staging files if $(b,--%s) specified, and the Opam \
switch will not be used for static files if $(b,--%s) specified. A \
switch prefix is either the $(b,_opam) subdirectory of a local Opam \
switch or $(b,%s/<switchname>) for a global Opam switch. The typical \
use of $(b,--%s) is to set it to the OPAM_SWITCH_PREFIX environment \
variable; the OPAM_SWITCH_PREFIX environment variable is set \
automatically by commands like `%s`."Cmdliner_common.staging_files_argCmdliner_common.static_files_arg(Cmdliner.Manpage.escape"$OPAMROOT")Cmdliner_common.opam_context_args(ifSys.win32thenCmdliner.Manpage.escape"(& opam env) -split '\\r?\\n' | ForEach-Object { Invoke-Expression \
$_ }` for Windows PowerShell or `eval $(opam env)"else"eval $(opam env)")in(* IMPORTANT: Do not get cute and try to default this to the environment
variable OPAM_SWITCH_PREFIX. That would make self-contained installers
be dependent on prior environment variables, which is very bad. *)Arg.(value&opt(somedir)None&info[Cmdliner_common.opam_context_args]~docv:"OPAM_SWITCH_PREFIX"~doc)(** [staging_files_source_for_package_t] is the
setup.exe/uninstall.exe {!Term.t} for the staging files directory. It
defaults to the sibling directory "staging". *)letstaging_files_source_for_package_t=letstaging_files_source'opam_context_optstaging_files_opt=letstaging_default=Path_location.Staging_default_dir(fun()->staging_default_dir_for_package~archive_dir:(Error_handling.continue_or_exit@@enduser_archive_dir()))inPath_location.staging_files_source~staging_default~opam_context_opt~staging_files_optinTerm.(conststaging_files_source'$opam_context_opt_t$staging_files_opt_t)(** [static_files_source_for_package_t] is the
setup.exe/uninstall.exe {!Term.t} for the static files directory. It
defaults to the sibling directory "static". *)letstatic_files_source_for_package_t=letstatic_files_source'opam_context_optstatic_files_opt=letstatic_default=Path_location.Static_default_dir(fun()->static_default_dir_for_package~archive_dir:(Error_handling.continue_or_exit@@enduser_archive_dir()))inPath_location.static_files_source~static_default~opam_context_opt~static_files_optinTerm.(conststatic_files_source'$opam_context_opt_t$static_files_opt_t)letunwrap_progress_t~defaultt=letunwrap=function|Dkml_install_api.Forward_progress.Completed->default|Dkml_install_api.Forward_progress.Continue_progress(a,_fl)->a|Dkml_install_api.Forward_progress.Halted_progressexitcode->exit(Dkml_install_api.Forward_progress.Exit_code.to_int_exitcodeexitcode)inTerm.(constunwrap$t)letunwrap_progress_nodefault_tt=letunwrap=function|Dkml_install_api.Forward_progress.Completed->raise(Invalid_argument"Completed forward progress was not expected")|Dkml_install_api.Forward_progress.Continue_progress(a,_fl)->a|Dkml_install_api.Forward_progress.Halted_progressexitcode->exit(Dkml_install_api.Forward_progress.Exit_code.to_int_exitcodeexitcode)inTerm.(constunwrap$t)(** [ctx_for_runner_t component_name reg] creates a user.exe/admin.exe [Term]
for component [component_name]
that sets up logging and any other global state, and defines the context
record.
The package (setup.exe/uninstall.exe) will typically use sudo on Unix
or gsudo on Windows to elevate the privileges of `admin.exe`. However
it is very unlikely that the environment variables are propagated from
the user (setup.exe) to the elevated process (admin.exe). So the
staging directory must be specified (`No_staging_default`) when the runner
user.exe/admin.exe is launched.
That is, the user process setup.exe can pass its
environment variable OPAM_SWITCH_PREFIX (if specified with the no argument
`--opam-context` option of setup.exe) into the staging directory argument
for admin.exe. *)letctx_for_runner_t~install_direction~target_abicomponent_namereg=letarchive_dir=Error_handling.continue_or_exit@@enduser_archive_dir()inlett=Term.(const(create_context~install_direction~target_abi~staging_default:No_staging_default)$constcomponent_name$constreg$setup_log_t$prefix_dir_t$constarchive_dir$staging_files_opt_t$opam_context_opt_t)inunwrap_progress_nodefault_tt(** [ctx_for_package_t component_name reg] creates a setup.exe/uninstall.exe [Term]
for component [component_name] that sets up logging and any other global
state, and defines the context record.
Unlike {!ctx_for_runner_t} the expectation is that setup.exe/uninstall.exe
will be directly launched by the user and have access to the user's
environment variables, especially OPAM_SWITCH_PREFIX. So the no argument
--opam-context option of setup.exe can default to OPAM_SWITCH_PREFIX.
Unlike {!ctx_for_runner_t} the staging directory has a default
(`Staging_default_dir`) based on relative paths from setup.exe. *)letctx_for_package_t~install_direction~target_abicomponent_namereg=letarchive_dir=Error_handling.continue_or_exit@@enduser_archive_dir()inletstaging_default=Path_location.Staging_default_dir(fun()->staging_default_dir_for_package~archive_dir)inlett=Term.(const(create_context~install_direction~target_abi~staging_default)$constcomponent_name$constreg$setup_log_t$prefix_dir_t$constarchive_dir$staging_files_opt_t$opam_context_opt_t)inunwrap_progress_nodefault_ttletto_selectorcomponent_selector=ifcomponent_selector=[]thenDkml_install_register.Component_registry.All_componentselseJust_named_components_plus_their_dependenciescomponent_selectorletcomponent_selector_t~(install_direction:Dkml_install_register.install_direction)=letdoc=matchinstall_directionwith|Install->"A component to install; all the components it depends on are \
implicitly added. May be repeated. If no components are specified, \
then all components are installed."|Uninstall->"A component to uninstall; all the components it depends on are \
implicitly added. May be repeated. If no components are specified, \
then all components are uninstalled."inArg.(value&opt_allstring[]&info["component"]~doc)(* Misc *)letcommon_runner_args~log_config~prefix_dir~staging_files_source=letzs="--"^sinletargs=Array.concat[Dkml_install_api.Log_config.to_argslog_config;[|zCmdliner_common.prefix_arg;Fpath.to_stringprefix_dir|];]inletargs=matchstaging_files_sourcewith|Path_location.Opam_staging_switch_prefixswitch_prefix->Array.concat[args;[|zCmdliner_common.opam_context_args;Fpath.to_stringswitch_prefix;|];]|Staging_files_dirstaging_files->Array.concat[args;[|zCmdliner_common.staging_files_arg;Fpath.to_stringstaging_files;|];]inargs(* Commands *)lethelp_cmd=lettopic=letdoc="The topic to get help on. `topics' lists the topics."inArg.(value&pos0(somestring)None&info[]~docv:"TOPIC"~doc)inletdoc="display help about $(mname) and $(mname) commands"inletman=[`SCmdliner.Manpage.s_description;`P"Prints help about $(mname) commands and other subjects...";`Blockshelp_secs;]inletinfo=Cmd.info"help"~doc~maninCmd.vinfoTerm.(ret(consthelp$Arg.man_format$Term.choice_names$topic))(* Term evaluation *)leteval_progresscmd=letopenDkml_install_api.Forward_progressinmatchCmd.eval_valuecmdwith|Ok`Version->Cmd.Exit.ok|Ok`Help->Cmd.Exit.ok|Ok(`Okv)->(matchvwith|Completed->Cmd.Exit.ok|Continue_progress((),_)->Cmd.Exit.ok|Halted_progressexitcode->Exit_code.to_int_exitcodeexitcode)|Error`Parse->Exit_code.to_int_exitcodeExit_code.Exit_unrecoverable_failure|Error`Term|Error`Exn->Exit_code.to_int_exitcodeExit_code.Exit_transient_failure