Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

env: add a flag to output as environment variable bindings #6316

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions master_changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ users)
## Clean

## Env
* [NEW] Add `--raw` option to output env as environment variable binding, useful for CI environment populating [#6316 @rjbou - fix #5791]

## Opamfile

Expand Down
29 changes: 18 additions & 11 deletions src/client/opamCommands.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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 `raw, ["raw"],
"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"]
Expand Down Expand Up @@ -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
Expand All @@ -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, [] ->
Expand All @@ -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, [] ->
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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)

Expand Down
61 changes: 37 additions & 24 deletions src/client/opamConfigCommand.ml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ let list t ns =
OpamStd.Format.align_table |>
OpamConsole.print_table stdout ~sep:" "

let name_not_in_env n env =
not (List.exists (fun (n', _, _) -> String.equal n n') env)

let possibly_unix_path_env_value k v =
if k = "PATH" then
(Lazy.force OpamSystem.get_cygpath_path_transform) ~pathlist:true v
Expand All @@ -72,8 +75,7 @@ let rec print_env output = function
| (k, v, comment) :: r ->
if OpamConsole.verbose () then
OpamStd.Option.iter (Printf.ksprintf output ": %s;\n") comment;
if not (List.exists (fun (k1, _, _) -> k = k1) r) || OpamConsole.verbose ()
then (
if name_not_in_env k r || OpamConsole.verbose () then (
let v' = possibly_unix_path_env_value k v in
Printf.ksprintf output "%s='%s'; export %s;\n"
k (OpamStd.Env.escape_single_quotes v') k);
Expand All @@ -84,8 +86,7 @@ let rec print_csh_env output = function
| (k, v, comment) :: r ->
if OpamConsole.verbose () then
OpamStd.Option.iter (Printf.ksprintf output ": %s;\n") comment;
if not (List.exists (fun (k1, _, _) -> k = k1) r) || OpamConsole.verbose ()
then (
if name_not_in_env k r || OpamConsole.verbose () then (
let v' = possibly_unix_path_env_value k v in
Printf.ksprintf output "setenv %s '%s';\n"
k (OpamStd.Env.escape_single_quotes v'));
Expand All @@ -94,8 +95,7 @@ let rec print_csh_env output = function
let rec print_pwsh_env output = function
| [] -> ()
| (k, v, _) :: r ->
if not (List.exists (fun (k1, _, _) -> k = k1) r) || OpamConsole.verbose ()
then
if name_not_in_env k r || OpamConsole.verbose () then
Printf.ksprintf output "$env:%s = '%s'\n"
k (OpamStd.Env.escape_powershell v);
print_pwsh_env output r
Expand All @@ -104,8 +104,7 @@ let print_cmd_env output env =
let rec aux = function
| [] -> ()
| (k, v, _) :: r ->
if not (List.exists (fun (k1, _, _) -> k = k1) r) || OpamConsole.verbose ()
then begin
if name_not_in_env k r || OpamConsole.verbose () then begin
let is_special = function
| '(' | ')' | '!' | '^' | '%' | '"' | '<' | '>' | '|' -> true
| _ -> false
Expand All @@ -123,14 +122,24 @@ let print_sexp_env output env =
let rec aux = function
| [] -> ()
| (k, v, _) :: r ->
if not (List.exists (fun (k1, _, _) -> k = k1) r) then
if name_not_in_env k r then
Printf.ksprintf output " (%S %S)\n" k v;
aux r
in
output "(\n";
aux env;
output ")\n"

let print_raw_env output env =
let rec aux = function
| [] -> ()
| (k, v, _) :: r ->
if name_not_in_env k 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
Expand All @@ -156,7 +165,7 @@ let rec print_fish_env output env =
match env with
| [] -> ()
| (k, v, _) :: r ->
if not (List.exists (fun (k1, _, _) -> k = k1) r) then
if name_not_in_env k r then
(match k with
| "PATH" | "CDPATH" ->
(* This function assumes that `v` does not include any variable
Expand All @@ -183,7 +192,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 =
Expand All @@ -192,18 +201,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 `raw ->
print_raw_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) =
Expand Down Expand Up @@ -331,7 +344,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
Expand Down Expand Up @@ -371,7 +384,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 =
Expand Down
19 changes: 12 additions & 7 deletions src/client/opamConfigCommand.mli
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,28 @@ 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 | `raw ] 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. *)
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 | `raw ] 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
Expand Down
26 changes: 26 additions & 0 deletions tests/reftests/env.test
Original file line number Diff line number Diff line change
Expand Up @@ -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
### <pkg:op.1>
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 --raw | grep -v "OPAM_LAST_ENV|MANPATH|PATH"
OPAM_SWITCH_PREFIX=${BASEDIR}/OPAM/outputs
PKGVAR=piou
### opam exec -- opam env --raw --sexp
opam: options '--sexp' and '--raw' cannot be present at the same time
Usage: opam env [OPTION]…
Try 'opam env --help' or 'opam --help' for more information.
# Return code 2 #
Loading