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

Implement :env_vars option for %Mix.Dep{} #6933

Merged
merged 7 commits into from
Oct 19, 2017

Conversation

zorbash
Copy link
Contributor

@zorbash zorbash commented Oct 15, 2017

This PR is the implementation of this proposal, which allows defining per dependency env variables to be used when loading or compiling it.

Example:

def deps do
  {:exometer, "~> 1.2.1", env_vars: [{"EXOMETER_PACKAGES", "(amqp)"}]}
end

Will set the EXOMETER_PACKAGES env variable to "(amqp)" which will include the amqp dependencies in the mix.lock (see: exometer-dependency-management). This is a Rebar specific example, but the PR sets the env vars to all types of supported packages.

All the files have been formatted using the new mix format task.
I'll be really happy to get feedback to improve this PR and make all the required changes to have it merged.

@@ -36,6 +36,15 @@ defmodule Mix.Dep.Loader do
only != nil and env not in List.wrap(only)
end

def with_env_vars(%Mix.Dep{env_vars: env_vars}, callback) do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's have a fast path clause that checks if env_vars is an empty list and then we just invoke the callback.

@@ -36,6 +36,15 @@ defmodule Mix.Dep.Loader do
only != nil and env not in List.wrap(only)
end

def with_env_vars(%Mix.Dep{env_vars: env_vars}, callback) do
env = System.get_env()
System.put_env(env_vars)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use try/after here.

@@ -261,9 +261,15 @@ defmodule Mix.Tasks.Deps.Compile do
end
end

defp do_command(%Mix.Dep{app: app, opts: opts}, config, command, print_app?, env \\ []) do
defp do_command(
%Mix.Dep{app: app, env_vars: env_vars, opts: opts},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move %Mix.Dep{app: app, opts: opts} out of the function head and into the function body.


with_deps(
[
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please look at the other tests. You should define the deps as a variable before calling with_deps.

@josevalim
Copy link
Member

/cc @mobileoverlord could this be useful to you?

@josevalim
Copy link
Member

My only concern is regarding the name since "env" is a bit overloaded. I wonder if system_vars would or system_env would be a better name?

@zorbash
Copy link
Contributor Author

zorbash commented Oct 15, 2017

If I had to choose between system_vars and system_env, I'd go with system_env as it's closer sounding to the System.*_env family of functions and might be more memorable.

@@ -31,6 +31,8 @@ defmodule Mix.Dep do
the information on this field is private to the manager and should not be
relied on

* `env_vars` - an enumerable of tuples containing environment key-value as binary
Copy link
Member

@ericmj ericmj Oct 15, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be elaborated on. It doesn't say what the option does and when it's used. For example it is only used during loading and not during compilation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied the text of the :env option of System.cmd/3 which is of the same type. You're absolutely right that it needs better doc there, I'll update it.

Should I also add an entry in the changelog about this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We try to avoid updating the changelog in PRs because it easily leads to conflicts. An entry will be added before we do a new release of course.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworded it to:

an enumerable of key-value tuples of binaries to be set as environment variables when loading or compiling the dependency

I tried to keep keep it short to match the terseness of the rest of the options. Let me know what you think.

@ericmj
Copy link
Member

ericmj commented Oct 15, 2017

Keep in mind that this option won't be honored for hex package dependencies so we will have to reject publishing to hex when the option is used.

@josevalim
Copy link
Member

@ericmj do you have any preference regarding the name?

@ericmj
Copy link
Member

ericmj commented Oct 16, 2017

I prefer system_env.

@josevalim
Copy link
Member

@zorbash let's go with :system_env and please address the remaining comments. :)

@zorbash
Copy link
Contributor Author

zorbash commented Oct 16, 2017

I've made changes reflecting suggestions in the comments and renamed :env_vars to :system_env.

@ericmj about #6933 (comment) Would it be desirable to submit a PR to hex to not publish when system_env is used?

@ericmj
Copy link
Member

ericmj commented Oct 18, 2017

about #6933 (comment) Would it be desirable to submit a PR to hex to not publish when system_env is used?

Please do.

@@ -161,7 +174,8 @@ defmodule Mix.Dep.Loader do
app: app,
requirement: req,
status: scm_status(scm, opts),
opts: Keyword.put_new(opts, :env, :prod)
opts: Keyword.put_new(opts, :env, :prod),
system_env: Keyword.get(opts, :system_env, [])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we have to separate this from opts.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes it easier to pattern match on it later and I don't think this needs to be available to the SCM, does it?

In any case, if we have a dedicated field for it, we should probably pop it from opts by calling Keyword.pop(opts, :system_env, []).

Copy link
Contributor Author

@zorbash zorbash Oct 18, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With system_env as a dedicated field, we can pattern match to reject a package from being published by adding:

%Mix.Dep{app: app, system_env: _} ->
  Mix.raise "Can't build package when :system_env is set for dependency #{app}, remove `system_env: ...`"

to https://github.com/hexpm/hex/blob/v0.17.1/lib/mix/tasks/hex.build.ex#L157

But I don't see how hex, containing such a change would keep being compatible with all the Elixir versions (other than master) defined in its .travis.yml, unless if we pattern match on it as a Map.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hex wouldn't be able to pattern match on it, we would have to pull it out with Map.get/3. We don't seem to use it for pattern matching in this PR either.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ericmj we pattern match on it both times we use it. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ericmj if you're OK with something like:

Enum.each(include, fn %Mix.Dep{app: app, opts: opts} = dep ->
  if Map.get(dep, :system_env) do
    Mix.raise "Can't build package when :system_env is set for dependency #{app}, remove `system_env: ...`"
  end
end)

we can keep the dedicated field and also use keyword.pop/3 as @josevalim suggested, so not to have it in the opts as it's not an SCM option.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@josevalim I meant pattern match in a conditional way, right now the pattern matches could be replaced with dep.system_env or opts[:system_env]. But it’s not a strong opinion so let’s go ahead with th dedicated field.

@zorbash yeah, something like that would work.

@ericmj ericmj merged commit 055cff4 into elixir-lang:master Oct 19, 2017
@ericmj
Copy link
Member

ericmj commented Oct 19, 2017

Thank you!

@zorbash zorbash deleted the env-for-mix-deps-compile branch October 19, 2017 22:10
ericmj pushed a commit to hexpm/hex that referenced this pull request Oct 19, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants