dbuenzli / bos

Basic OS interaction for OCaml
http://erratique.ch/software/bos
ISC License
65 stars 16 forks source link

Use ENV vars in commands #82

Closed EnriqueVidal closed 5 years ago

EnriqueVidal commented 5 years ago

Hi,

This is probably not an issue but I can't figure out how to work around, this, I want to run commands that rely on using env vars as an argument but whenever I run them $VARNAME has it's $ escaped (or that's what I think it's happening), here's an example:

Open Bos;

let env = Astring.String.Map.of_list([("FOO", "BAR")]);
let echo = Cmd.v("echo");
let print = Cmd.(echo % "$FOO");

OS.Cmd.run(~env, print);

It prints "$FOO" instead of "BAR", I have been looking at the docs but can't seem to figure this one out.

I hope someone can point me in the right direction.

hcarty commented 5 years ago

If you want $FOO from the calling program's environment, you probably want to capture that and pass it in explicitly. See, for example, Bos.OS.Env.opt_var: https://erratique.ch/software/bos/doc/Bos.OS.Env.html#VALopt_var

Then you could use something like:

let foo = OS.Env.opt_var("FOO", ~absent="placeholder");
let print = Cmd.(echo % foo);
EnriqueVidal commented 5 years ago

Nice, just tried this and it worked:

open Bos;

let foo = OS.Env.opt_var("FOO", ~absent="BAR");
let print = Cmd.echo(echo % foo);

OS.Cmd.(run_out(print) |> to_lines); // Result.Ok(["BAR"]);

Is there a way to set the env in advnaced and picked from that map? I'd like to not have to re-defined variables in every function for commands that will share these.

EnriqueVidal commented 5 years ago

I think I've found a less elegant way to do this:

/* Env.re */
open Bos;
open Astring;

let envDefaults = [
  ("FOO", "BAR"),
  ("BAZ", "CHAZ"),
  ("GITPATH", "/some/path"),
];

let make = () => 
  List.map(
    ((eVar, fallback) => (
      eVar,
      OS.Env.(value(eVar, string, ~absent=fallback)),
    ),
    envWithDefaults,
  )
  |> String.Map.of_list;

let getVar = (var, map) => 
  String.Map.get(var, map);
/* Deps.re */
open Bos;

let env = Env.make();
let git = Cmd.v("git");

let installFoo = () => {
  let path = Env.getVar("GITPATH",  env);
  let clone = Cmd.(git % "clone" % path);

  Cmd.run(clone);
};

Is there a more elegant way to handle this for an installation script that relies on some vars across many different functions? what I mean is multiple functions could be using more than a single var.

dbuenzli commented 5 years ago

@EnriqueVidal questions are welcome but I prefer if these discussions happen on the OCaml forum where there is more people willing to help answering them and results of the discussions may benefit more people.

So I'm closing this. But feel free to finish the discussion here. Thanks @hcarty for your answer.

EnriqueVidal commented 5 years ago

Understood, thanks for your patience.