From 49f87e49f4917ef48c648a3d985aa77e68af2ca7 Mon Sep 17 00:00:00 2001 From: Raja Boujbel Date: Thu, 28 Nov 2024 18:31:39 +0100 Subject: [PATCH] env: add '--bindings' flag to output as environment variable bindings --- master_changes.md | 1 + src/client/opamCommands.ml | 29 +++++++++++++--------- src/client/opamConfigCommand.ml | 42 +++++++++++++++++++++----------- src/client/opamConfigCommand.mli | 19 +++++++++------ tests/reftests/env.test | 26 ++++++++++++++++++++ 5 files changed, 85 insertions(+), 32 deletions(-) diff --git a/master_changes.md b/master_changes.md index 64d2b77cc2e..1d7c5fc8daa 100644 --- a/master_changes.md +++ b/master_changes.md @@ -69,6 +69,7 @@ users) ## Clean ## Env + * [NEW] Add `--bindings` option to output env as environment variable binding, useful for CI environment populating [#6316 @rjbou - fix #5791] ## Opamfile diff --git a/src/client/opamCommands.ml b/src/client/opamCommands.ml index 1d1266926fe..db269800ccc 100644 --- a/src/client/opamCommands.ml +++ b/src/client/opamCommands.ml @@ -1302,9 +1302,15 @@ let option cli = $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 env_format cli = + mk_vflag ~cli None [ + cli_original, Some `sexp, ["sexp"], + "Print environment as an s-expression rather than in shell format"; + cli_from cli2_4, Some `bindingss, ["bindingss"], + "Print environment as variable bindings rather than in shell format.\ + Useful to populate CI environment." + ] + let inplace_path cli = mk_flag ~cli cli_original ["inplace-path"] @@ -1402,7 +1408,7 @@ let config cli = let open Common_config_flags in let config global_options - command shell sexp inplace_path + command shell env_format inplace_path set_opamroot set_opamswitch params () = apply_global_options cli global_options; let shell = match shell with @@ -1418,7 +1424,7 @@ let config cli = | Some sw -> `Ok (OpamConfigCommand.env gt sw ~set_opamroot ~set_opamswitch - ~csh:(shell=SH_csh) ~sexp ~fish:(shell=SH_fish) + ~csh:(shell=SH_csh) ~env_format ~fish:(shell=SH_fish) ~pwsh ~cmd:(shell=SH_cmd) ~inplace_path)) | Some `revert_env, [] -> @@ -1428,7 +1434,7 @@ let config cli = | Some sw -> `Ok (OpamConfigCommand.ensure_env gt sw; OpamConfigCommand.print_eval_env - ~csh:(shell=SH_csh) ~sexp ~fish:(shell=SH_fish) + ~csh:(shell=SH_csh) ~env_format ~fish:(shell=SH_fish) ~pwsh ~cmd:(shell=SH_cmd) (OpamEnv.add [] []))) | Some `list, [] -> @@ -1640,7 +1646,8 @@ let config cli = mk_command_ret ~cli cli_original "config" ~doc ~man Term.(const config - $global_options cli $command $shell_opt cli cli_original $sexp cli + $global_options cli $command $shell_opt cli cli_original + $env_format cli $inplace_path cli $set_opamroot cli $set_opamswitch cli $params) @@ -1711,7 +1718,7 @@ let env cli = after printing the list of not up-to-date variables." in let env - global_options shell sexp inplace_path set_opamroot set_opamswitch + global_options shell env_format inplace_path set_opamroot set_opamswitch revert check () = apply_global_options cli global_options; if check then @@ -1733,19 +1740,19 @@ let env cli = | Some sw -> OpamConfigCommand.env gt sw ~set_opamroot ~set_opamswitch - ~csh:(shell=SH_csh) ~sexp ~fish:(shell=SH_fish) + ~csh:(shell=SH_csh) ~env_format ~fish:(shell=SH_fish) ~pwsh ~cmd:(shell=SH_cmd) ~inplace_path); | true -> OpamConfigCommand.print_eval_env - ~csh:(shell=SH_csh) ~sexp ~fish:(shell=SH_fish) + ~csh:(shell=SH_csh) ~env_format ~fish:(shell=SH_fish) ~pwsh ~cmd:(shell=SH_cmd) (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 + $global_options cli $shell_opt cli cli_original $env_format cli $inplace_path cli $set_opamroot cli $set_opamswitch cli $revert $check) diff --git a/src/client/opamConfigCommand.ml b/src/client/opamConfigCommand.ml index 314264de2d1..47c426f3b53 100644 --- a/src/client/opamConfigCommand.ml +++ b/src/client/opamConfigCommand.ml @@ -131,6 +131,16 @@ let print_sexp_env output env = aux env; output ")\n" +let print_bindingss_env output env = + let rec aux = function + | [] -> () + | (k, v, _) :: r -> + if not (List.exists (fun (k1, _, _) -> k = k1) r) then + Printf.ksprintf output "%s=%s\n" k v; + aux r + in + aux env + let rec print_fish_env output env = let set_arr_cmd ?(modf=fun x -> x) k v = let v = modf @@ OpamStd.String.split v ':' in @@ -183,7 +193,7 @@ let print_without_cr s = output_string stdout s; flush stdout -let print_eval_env ~csh ~sexp ~fish ~pwsh ~cmd env = +let print_eval_env ~csh ~env_format ~fish ~pwsh ~cmd env = let env = (env : OpamTypes.env :> (string * string * string option) list) in let output_normally = OpamConsole.msg "%s" in let never_with_cr = @@ -192,18 +202,22 @@ let print_eval_env ~csh ~sexp ~fish ~pwsh ~cmd env = else output_normally in - if sexp then + match env_format with + | Some `sexp -> print_sexp_env output_normally env - else if csh then - print_csh_env never_with_cr env - else if fish then - print_fish_env never_with_cr env - else if pwsh then - print_pwsh_env output_normally env - else if cmd then - print_cmd_env output_normally env - else - print_env never_with_cr env + | Some `bindingss -> + print_bindingss_env output_normally env + | None -> + if csh then + print_csh_env never_with_cr env + else if fish then + print_fish_env never_with_cr env + else if pwsh then + print_pwsh_env output_normally env + else if cmd then + print_cmd_env output_normally env + else + print_env never_with_cr env let check_writeable l = let map_writeable ({OpamTypes.envu_op; _} as update) = @@ -331,7 +345,7 @@ let ensure_env gt switch = ignore (ensure_env_aux gt switch) let env gt switch ?(set_opamroot=false) ?(set_opamswitch=false) - ~csh ~sexp ~fish ~pwsh ~cmd ~inplace_path = + ~csh ~env_format ~fish ~pwsh ~cmd ~inplace_path = log "config-env"; let opamroot_not_current = let current = gt.root in @@ -371,7 +385,7 @@ let env gt switch ?(set_opamroot=false) ?(set_opamswitch=false) let env = ensure_env_aux ~set_opamroot ~set_opamswitch ~force_path gt switch in - print_eval_env ~csh ~sexp ~fish ~pwsh ~cmd env + print_eval_env ~csh ~env_format ~fish ~pwsh ~cmd env [@@ocaml.warning "-16"] let subst gt fs = diff --git a/src/client/opamConfigCommand.mli b/src/client/opamConfigCommand.mli index a205bd376a5..3756cc76f9f 100644 --- a/src/client/opamConfigCommand.mli +++ b/src/client/opamConfigCommand.mli @@ -16,15 +16,17 @@ 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. *) +(** Display the current environment. Booleans [csh], [env_format] 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 -> pwsh:bool -> cmd:bool -> - inplace_path:bool -> unit + csh:bool -> env_format:[< `sexp | `bindingss ] option -> fish:bool -> + pwsh:bool -> cmd:bool -> inplace_path:bool -> + unit (** Ensures that the environment file exists in the given switch, regenerating it, if necessary. *) @@ -32,7 +34,10 @@ 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 -> pwsh:bool -> cmd:bool -> env -> unit +val print_eval_env: + csh:bool -> env_format:[< `sexp | `bindingss ] option -> fish:bool -> pwsh:bool -> + cmd:bool -> env + -> unit (** Display the content of all available packages variables *) val list: 'a switch_state -> name list -> unit diff --git a/tests/reftests/env.test b/tests/reftests/env.test index 981afd3fe34..165102fde48 100644 --- a/tests/reftests/env.test +++ b/tests/reftests/env.test @@ -651,3 +651,29 @@ OPAM_PACKAGE_NAME=another-package OPAM_PACKAGE_VERSION=another-version OPAM_SWITCH_PREFIX=${BASEDIR}/OPAM/bd PATH=${BASEDIR}/OPAM/bd/bin:another-path +### : opam env outputs : +### opam switch create outputs --empty +### +opam-version: "2.0" +setenv: [ PKGVAR = "piou"] +### opam install op -y +The following actions will be performed: +=== install 1 package + - install op 1 + +<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> +-> installed op.1 +Done. +### opam exec -- opam env --sexp | grep -v "OPAM_LAST_ENV|MANPATH|PATH" +( + ("OPAM_SWITCH_PREFIX" "${BASEDIR}/OPAM/outputs") + ("PKGVAR" "piou") +) +### opam exec -- opam env --bindingss | grep -v "OPAM_LAST_ENV|MANPATH|PATH" +OPAM_SWITCH_PREFIX=${BASEDIR}/OPAM/outputs +PKGVAR=piou +### opam exec -- opam env --bindingss --sexp +opam: options '--sexp' and '--bindingss' cannot be present at the same time +Usage: opam env [OPTION]… +Try 'opam env --help' or 'opam --help' for more information. +# Return code 2 #