Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file dkml_install_api_intf.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368(* Cmdliner 1.0 -> 1.1 deprecated a lot of things. But until Cmdliner 1.1
is in common use in Opam packages we should provide backwards compatibility.
In fact, Diskuv OCaml is not even using Cmdliner 1.1. *)[@@@alert"-deprecated"]moduletypeComponent_config_defaultable=sigvalinstall_depends_on:stringlist(** [install_depends_on] are the components, if any, that this component depends on
during installation.
Dependencies will be installed in topological order. *)valuninstall_depends_on:stringlist(** [uninstall_depends_on] are the components, if any, that this component depends on
during uninstallation.
Dependencies will be uninstalled in reverse topological order. *)valinstall_user_subcommand:component_name:string->subcommand_name:string->fl:Forward_progress.fatal_logger->ctx_t:Types.Context.tCmdliner.Term.t->(unitCmdliner.Term.t*Cmdliner.Term.info)Forward_progress.t(** [install_user_subcommand ~component_name ~subcommand_name ~ctx_t] defines a
subcommand that should be added to {b dkml-install-runner.exe}
that, when invoked, will install the component with non-privileged
user permissions.
[~component_name]: This will correspond to the component name defined
in the full [Component_config] module type.
[~subcommand_name]: Typically but not always the subcommand name is
["install-user-" ^ component_name].
[~fl]: A fatal logger used whenver there is an error requiring the
process to exit.
[~ctx_t]: A Cmdliner term that sets up common options and delivers a
context record. The common options include options for logging. The
context record is described at {!Dkml_install_api}.
You must include the [ctx_t] term in your returned [Term.t * Term.info],
as in:
{[
let execute_install ctx =
Format.printf
"We can run bytecode using: %s@\n"
(ctx.Dkml_install_api.Context.path_eval "%{ocamlrun:share-abi}/bin/ocamlrun")
let install_user_subcommand ~component_name ~subcommand_name ~fl ~ctx_t =
let doc = "Install the pieces that don't require Administrative rights" in
Dkml_install_api.Forward_progress.Continue_progress (Cmdliner.Term.(const execute_install $ ctx_t, info subcommand_name ~doc), fl)
]}
Your [Term.t] function ([install_user_subcommand ctx]) should raise
{!Installation_error} for any unrecoverable failures. *)valuninstall_user_subcommand:component_name:string->subcommand_name:string->fl:Forward_progress.fatal_logger->ctx_t:Types.Context.tCmdliner.Term.t->(unitCmdliner.Term.t*Cmdliner.Term.info)Forward_progress.t(** [uninstall_user_subcommand ~component_name ~ctx_t] defines a
subcommand that should be added to {b dkml-install-runner.exe}
that, when invoked, will uninstall the component with non-privileged
user permissions.
[~component_name]: This will correspond to the component name defined
in the full [Component_config] module type.
[~subcommand_name]: Typically but not always the subcommand name is
["uninstall-user-" ^ component_name].
[~fl]: A fatal logger used whenver there is an error requiring the
process to exit.
[~ctx_t]: A Cmdliner term that sets up common options and delivers a
context record. The common options include options for logging. The
context record is described at {!Dkml_install_api}.
You must include the [ctx_t] term in your returned [Term.t * Term.info],
as in:
{[
let execute_uninstall ctx =
Format.printf
"We can run bytecode using: %s@\n"
(ctx.Dkml_install_api.Context.path_eval "%{ocamlrun:share-abi}/bin/ocamlrun")
let uninstall_user_subcommand ~component_name ~subcommand_name ~fl ~ctx_t =
let doc = "Uninstall the pieces that don't require Administrative rights" in
Dkml_install_api.Forward_progress.Continue_progress (Cmdliner.Term.(const execute_uninstall $ ctx_t, info subcommand_name ~doc), fl)
]}
Your [Term.t] function ([uninstall_user_subcommand ctx]) should raise
{!Installation_error} for any unrecoverable failures. *)valneeds_install_admin:ctx:Types.Context.t->bool(** [needs_install_admin ~ctx] should inspect the environment and say [true]
if and only if the [install_admin_subcommand] is necessary.
[ctx] will be a minimal context that does not have access to other
components. *)valneeds_uninstall_admin:ctx:Types.Context.t->bool(** [needs_uninstall_admin] should inspect the environment and say [true]
if and only if the [install_admin_subcommand] is necessary.
[ctx] will be a minimal context that does not have access to other
components. *)valinstall_admin_subcommand:component_name:string->subcommand_name:string->fl:Forward_progress.fatal_logger->ctx_t:Types.Context.tCmdliner.Term.t->(unitCmdliner.Term.t*Cmdliner.Term.info)Forward_progress.t(** [install_admin_subcommand ~component_name ~subcommand_name ~fl ~ctx_t] defines a
subcommand that should be added to {b dkml-install-runner.exe}
that, when invoked, will install the component with privileged
administrator (`root` or `sudo` on Unix) permissions.
[~component_name]: This will correspond to the component name defined
in the full [Component_config] module type.
[~subcommand_name]: Typically but not always the subcommand name is
["install-admin-" ^ component_name].
[~fl]: A fatal logger used whenver there is an error requiring the
process to exit.
[~ctx_t]: A Cmdliner term that sets up common options and delivers a
context record. The common options include options for logging. The
context record is described at {!Dkml_install_api}.
You must include the [ctx_t] term in your returned [Term.t * Term.info],
as in:
{[
let execute_install_admin ctx =
Format.printf
"We can run bytecode using: %s@\n"
(ctx.Dkml_install_api.Context.path_eval "%{ocamlrun:share-abi}/bin/ocamlrun")
let install_admin_subcommand ~component_name ~subcommand_name ~ctx_t =
let doc = "Install the pieces requiring Administrative rights" in
Dkml_install_api.Forward_progress.Continue_progress (Cmdliner.Term.(const execute_install_admin $ ctx_t, info subcommand_name ~doc), fl)
]}
Your [Term.t] function ([execute_install_admin ctx]) should raise
{!Installation_error} for any unrecoverable failures. *)valuninstall_admin_subcommand:component_name:string->subcommand_name:string->fl:Forward_progress.fatal_logger->ctx_t:Types.Context.tCmdliner.Term.t->(unitCmdliner.Term.t*Cmdliner.Term.info)Forward_progress.t(** [uninstall_admin_subcommand ~component_name ~ctx_t] defines a
subcommand that should be added to {b dkml-install-runner.exe}
that, when invoked, will uninstall the component with privileged
administrator (`root` or `sudo` on Unix) permissions.
[~component_name]: This will correspond to the component name defined
in the full [Component_config] module type.
[~subcommand_name]: Typically but not always the subcommand name is
["uninstall-" ^ component_name].
[~fl]: A fatal logger used whenver there is an error requiring the
process to exit.
[~ctx_t]: A Cmdliner term that sets up common options and delivers a
context record. The common options include options for logging. The
context record is described at {!Dkml_install_api}.
You must include the [ctx_t] term in your returned [Term.t * Term.info],
as in:
{[
let execute_uninstall_admin ctx =
Format.printf
"We can run bytecode using: %s@\n"
(ctx.Dkml_install_api.Context.path_eval "%{ocamlrun:share-abi}/bin/ocamlrun")
let uninstall_admin_subcommand ~component_name ~subcommand_name ~fl ~ctx_t =
let doc = "Install the pieces requiring Administrative rights" in
Dkml_install_api.Forward_progress.Continue_progress (Cmdliner.Term.(const execute_uninstall_admin $ ctx_t, info subcommand_name ~doc), fl)
]}
Your [Term.t] function ([execute_uninstall_admin ctx]) should raise
{!Installation_error} for any unrecoverable failures. *)valtest:unit->unit(** [test ()] is reserved for unit testing; it should do nothing in
real code *)endmoduletypeComponent_config=sigincludeComponent_config_defaultablevalcomponent_name:string(** [component_name] is the name of the component. It must be lowercase
alphanumeric; dashes (-) are allowed. *)endmoduletypeIntf=sig(** {2 Configuration} *)moduletypeComponent_config_defaultable=Component_config_defaultable[@@inline](** Component configuration values that can be supplied with defaults. *)moduletypeComponent_config=Component_config[@@inline](** Each component must define a configuration module *)(**
You {e should} [include Default_component_config] in any of your
components so that your component can be future-proof against
changes in the {!Component_config} signature.
*)(** Default values for a subset of the module type {!Component_config}. *)moduleDefault_component_config:sigincludeComponent_config_defaultable(** @inline *)end(** {2 Process execution} *)vallog_spawn_onerror_exit:id:string->?conformant_subprocess_exitcodes:bool->Bos.Cmd.t->unit(** [log_spawn_onerror_exit ~id ?conformant_subprocess_exitcodes cmd] logs the command [cmd] and runs it
synchronously, and prints an error on the fatal logger [fl ~id]
and then exits with a non-zero exit code if the command exits with a non-zero
error code.
The environment variable ["OCAMLRUNPARAM"] will be set to ["b"] so that
any OCaml bytecode launched by [log_spawn_onerror_exit] will have
backtraces. Any exiting environment variable ["OCAMLRUNPARAM"] will
be kept, however.
{3 Exit Codes}
The exit code used to leave this process depends on [conformant_subprocess_exitcodes].
When [conformant_subprocess_exitcodes = true] or [conformant_subprocess_exitcodes] is not
specified, the exit code will be the same as the
spawned process exit code if and only if the exit code belongs to one of
{!Forward_progress.Exit_code}; if the spawned exit code does not belong then
the exit code will be {!Forward_progress.Exit_code.Exit_transient_failure}.
When [conformant_subprocess_exitcodes = false] the exit code will always be
{!Forward_progress.Exit_code.Exit_transient_failure} if the spawned process
ends in error.
*)(** {2 Uninstallation} *)valuninstall_directory_onerror_exit:id:string->dir:Fpath.t->wait_seconds_if_stuck:float->unit(** [uninstall_directory ~id ~dir ~wait_seconds_if_stuck] removes the directory [dir] and, if any process
is using the files in [dir], will give the [wait_seconds_if_stuck] seconds to stop using the
program. If the directory cannot be removed then prints an error on the
fatal logger [fl ~id] and exists with a transient error code.
For Windows machines a file cannot be removed if it is in use. For most *nix
machines the file can be removed since the inode lives on. Consequently
only on Windows machines will trigger the logic to check if a process
is using a file or directory. This behavior may change in the future. *)(**
{2 Logging}
Logging follows the Cmdliner standards.
All dkml_install generated executables can be supplied with the following
options:
{v
--color=WHEN (absent=auto)
Colorize the output. WHEN must be one of `auto', `always' or
`never'.
-q, --quiet
Be quiet. Takes over -v and --verbosity.
-v, --verbose
Increase verbosity. Repeatable, but more than twice does not bring
more.
--verbosity=LEVEL (absent=warning)
Be more or less verbose. LEVEL must be one of `quiet', `error',
`warning', `info' or `debug'. Takes over -v.
v}
You can use {!Log_config} to pass the color and verbosity options into
your own bytecode executables.
Start by initializing the logger in your own executables with the
following [setup_log_t] Cmdliner Term:
{[
let setup_log style_renderer level =
Fmt_tty.setup_std_outputs ?style_renderer ();
Logs.set_level level;
Logs.set_reporter (Logs_fmt.reporter ());
Dkml_install_api.Log_config.create ?log_config_style_renderer:style_renderer
?log_config_level:level ()
let setup_log_t =
Term.(const setup_log $ Fmt_cli.style_renderer () $ Logs_cli.level ())
]}
Finally, with a {!Log_config.t} you can use {!Log_config.to_args} to pass the
correct command line options into your own executables.
For components that are configured to spawn bytecode programs
you can locate the {!Log_config.t} in the
{!Dkml_install_api.Context.log_config}
([ctx.Dkml_install_api.Context.log_config])
context field. That could look like:
{[
let execute ctx =
let ocamlrun =
ctx.Context.path_eval "%{staging-ocamlrun:share-abi}/bin/ocamlrun"
in
log_spawn_onerror_exit
(* Always use your own unique id; create it with PowerShell on Windows:
[guid]::NewGuid().Guid.Substring(0,8)
or on macOS/Unix:
uuidgen | tr A-Z a-z | cut -c1-8
*)
~id:"9b7e32e0"
Cmd.(
v (Fpath.to_string
(ctx.Context.path_eval "%{staging-ocamlrun:share-abi}/bin/ocamlrun"))
% Fpath.to_string
(ctx.Context.path_eval "%{_:share}%/generic/your_bytecode.bc")
(* Pass --verbosity and --color to your bytecode *)
%% Log_config.to_args ctx.Context.log_config)
let () =
let reg = Component_registry.get () in
Component_registry.add_component reg
(module struct
include Default_component_config
let component_name = "enduser-yourcomponent"
let install_depends_on = [ "staging-ocamlrun" ]
let install_user_subcommand ~component_name:_ ~subcommand_name ~fl ~ctx_t =
let doc = "Install your component" in
Dkml_install_api.Forward_progress.Continue_progress (Cmdliner.Term.(const execute $ ctx_t, info subcommand_name ~doc), fl)
end)
]}
Others can use the {!Log_config.t} return value from [setup_log] when
calling {!Log_config.to_args}.
*)moduleLog_config:moduletypeofLog_configend