rebar/rebar — pull request #98 by jcomellas (2013-06-13 19:37:08+00:00)
Title: Repetition of environment variable definitions in child processes (ports)

I noticed this problem while working on a project that needs to run some pre compile hook scripts during the build process. During the build process, we also need to have a code base that is external to our project in the code path, and we cannot include this external project as a rebar dependency for the time being.

Basically, what I noticed was that while running the following command from the command line worked:
```bash
ERL_LIBS=/usr/local/lib/cloudi-1.2.3/lib rebar compile
```
Running the same thing from a Makefile target like this one didn't:
```make
compile:
ERL_LIBS=/usr/local/lib/cloudi-1.2.3/lib rebar compile
```
The issue was that when running from the command line the script's child process saw the `ERL_LIBS` environment variable as:
```
/home/jcomellas/devel/myproject/deps:/usr/local/lib/cloudi-1.2.3/lib
```
And when running rebar from a make invocation it saw it as just:
```
/usr/local/lib/cloudi-1.2.3/lib
```
The missing path in this last case is the one automatically added by rebar for the subdirectory where the dependencies reside.

What I've been able to assess is that the issue is caused by the interaction between `rebar_deps:setup_env/1` and `rebar_port_compiler:setup_env/1`. The first of these functions to be called is `rebar_deps:setup_env/1` and it generates the following output:
```erlang
[{"REBAR_DEPS_DIR", "/home/jcomellas/devel/myproject/deps"},
{"ERL_LIBS", "/home/jcomellas/devel/myproject/deps:/usr/local/lib/cloudi-1.2.3/lib"}]
```
Then `rebar_port_compiler:setup_env/1` is called and it generates another environment based on the one inherited from the parent process (*make*) which, among other things, contains the following entry:
```erlang
{"ERL_LIBS", "/usr/local/lib/cloudi-1.2.3/lib"},
```
These lists are then concatenated, leaving two repetitions of `ERL_LIBS` in the resulting environment. This happens in `rebar_core:setup_envs/2` in the line where the tuple `{C1, E++Env}` is returned:
```erlang
setup_envs(Config, Modules) ->
lists:foldl(fun(M, {C,E}=T) ->
case erlang:function_exported(M, setup_env, 1) of
true ->
Env = M:setup_env(C),
C1 = rebar_config:save_env(C, M, Env),
{C1, E++Env};
false ->
T
end
end, {Config, []}, Modules).
```
I haven't created a pull request because I'm not sure what the correct solution is:

1. I could use `lists:keystore/4` to store the values from one plugin's environment into the other one to avoid the repetitions, but how can I determine which plugin has precedence.

2. I could make sure that no plugin other than `rebar_deps` emits the `ERL_LIBS` and `REBAR_DEPS_DIR` variables in their environment. This would fix my problem and most common occurrences, but other plugins might share other environment variables in the future.

What do you think is the correct solution?