Skip to content

Commit 2854fec

Browse files
author
José Valim
committed
Move mix dependencies to _build
1 parent 14a562f commit 2854fec

26 files changed

+186
-98
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ $(1): lib/$(1)/ebin/Elixir.$(2).beam lib/$(1)/ebin/$(1).app
2121

2222
lib/$(1)/ebin/$(1).app: lib/$(1)/mix.exs
2323
$(Q) cd lib/$(1) && ../../bin/elixir -e "Mix.Sup.start_link()" -r mix.exs -e "Mix.Task.run('compile.app')"
24+
$(Q) cp lib/$(1)/_build/lib/$(1)/ebin/$(1).app lib/$(1)/ebin/$(1).app
25+
$(Q) rm -rf lib/$(1)/_build
2426

2527
lib/$(1)/ebin/Elixir.$(2).beam: $(wildcard lib/$(1)/lib/*.ex) $(wildcard lib/$(1)/lib/*/*.ex) $(wildcard lib/$(1)/lib/*/*/*.ex)
2628
@ echo "==> $(1) (compile)"

lib/mix/lib/mix/cli.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ defmodule Mix.CLI do
5050
defp run_task(name, args) do
5151
try do
5252
# We need to skip loading the paths for the project and
53-
# its dependencies because the dependencies may be setting
54-
# up or getting updated and we don't want to load their
55-
# config until the process is done.
53+
# its dependencies on deps.get and deps.update to avoid
54+
# having two versions of the same dep after get or update
55+
# is done.
5656
if not deps_task?(name) && Mix.Project.get do
5757
Mix.Task.run "loadpaths", ["--no-deps-check", "--no-elixir-version-check"]
5858
Mix.Task.reenable "loadpaths"

lib/mix/lib/mix/deps.ex

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ defmodule Mix.Deps do
252252
do: "the dependency requires Elixir #{req} but you are running on v#{System.version}"
253253
254254
defp dep_status(Mix.Dep[app: app, requirement: req, opts: opts, from: from]) do
255-
info = { app, req, Dict.drop(opts, [:dest, :lock, :env, :drop]) }
255+
info = { app, req, Dict.drop(opts, [:dest, :lock, :env, :build]) }
256256
"\n > In #{Path.relative_to_cwd(from)}:\n #{inspect info}\n"
257257
end
258258

@@ -341,10 +341,8 @@ defmodule Mix.Deps do
341341
Returns all load paths for the dependency.
342342
Expects a fetched dependency.
343343
"""
344-
def load_paths(Mix.Dep[manager: :mix, app: app, opts: opts]) do
345-
Mix.Project.in_project(app, opts[:dest], fn _ ->
346-
Mix.Project.load_paths
347-
end) |> Enum.uniq
344+
def load_paths(Mix.Dep[manager: :mix, opts: opts]) do
345+
[Path.join(opts[:build], "ebin")]
348346
end
349347
350348
def load_paths(Mix.Dep[manager: :rebar, opts: opts, extra: extra]) do

lib/mix/lib/mix/deps/converger.ex

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,10 @@ defmodule Mix.Deps.Converger do
4040
an updated depedency in case some processing is done.
4141
"""
4242
def all(rest, callback) do
43-
config = [ deps_path: Path.expand(Mix.project[:deps_path]),
44-
root_lockfile: Path.expand(Mix.project[:lockfile]) ]
43+
conf = Mix.Project.deps_config
4544
main = Mix.Deps.Retriever.children
4645
apps = Enum.map(main, &(&1.app))
47-
all(main, [], [], apps, config, callback, rest)
46+
all(main, [], [], apps, conf, callback, rest)
4847
end
4948

5049
# We traverse the tree of dependencies in a breadth-

lib/mix/lib/mix/deps/lock.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ defmodule Mix.Deps.Lock do
4040
parent project lockfile.
4141
"""
4242
def lockfile do
43-
Mix.project[:root_lockfile] || Mix.project[:lockfile]
43+
Mix.project[:lockfile]
4444
end
4545

4646
@doc """

lib/mix/lib/mix/deps/retriever.ex

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,11 @@ defmodule Mix.Deps.Retriever do
7979
defp with_scm_and_app({ app, req, opts }, scms) when is_atom(app) and
8080
(is_binary(req) or is_regex(req) or req == nil) and is_list(opts) do
8181

82-
path = Path.join(Mix.project[:deps_path], app)
83-
opts = Keyword.put(opts, :dest, path)
82+
dest = Path.join(Mix.Project.deps_path, app)
83+
build = Path.join([Mix.Project.build_path, "lib", app])
84+
opts = opts
85+
|> Keyword.put(:dest, dest)
86+
|> Keyword.put(:build, build)
8487

8588
{ scm, opts } = Enum.find_value scms, { nil, [] }, fn(scm) ->
8689
(new = scm.accepts_options(app, opts)) && { scm, new }

lib/mix/lib/mix/project.ex

Lines changed: 96 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ defmodule Mix.Project do
3636
end
3737
end
3838

39+
@private_config [:build_path, :app_path]
40+
3941
# Invoked after each Mix.Project is compiled.
4042
@doc false
4143
def __after_compile__(env, _binary) do
@@ -46,7 +48,10 @@ defmodule Mix.Project do
4648
# the top of the stack can be accessed.
4749
@doc false
4850
def push(atom, file // "nofile") when is_atom(atom) do
49-
config = Keyword.merge default_config, get_project_config(atom)
51+
config = default_config
52+
|> Keyword.merge(get_project_config(atom))
53+
|> Keyword.drop(@private_config)
54+
5055
case Mix.ProjectStack.push(atom, config, file) do
5156
:ok ->
5257
:ok
@@ -62,6 +67,14 @@ defmodule Mix.Project do
6267
Mix.ProjectStack.pop
6368
end
6469

70+
# The configuration that is pushed down to dependencies.
71+
@doc false
72+
def deps_config(config // config()) do
73+
[ build_path: build_path(config),
74+
deps_path: deps_path(config),
75+
lockfile: Path.expand(config[:lockfile]) ]
76+
end
77+
6578
@doc """
6679
Retrieves the current project, `nil` if there is no
6780
current project (i.e. there is no mixfile in the current
@@ -93,6 +106,7 @@ defmodule Mix.Project do
93106

94107
@doc """
95108
Returns the project configuration for the current environment.
109+
This configuration is cached once the project is pushed into the stack.
96110
"""
97111
def config do
98112
case Mix.ProjectStack.peek do
@@ -102,14 +116,16 @@ defmodule Mix.Project do
102116
end
103117

104118
@doc """
105-
Returns a list of project configuration files, for example,
106-
`mix.exs` and `mix.lock`. This function is usually used
107-
in compilation tasks to trigger a full recompilation
108-
whenever such configuration files change.
119+
Returns a list of project configuration files as known by
120+
this project. This function is usually used in compilation
121+
tasks to trigger a full recompilation whenever such
122+
configuration files change.
123+
124+
By default it includes the mix.exs file and the lock manifest.
109125
"""
110126
def config_files do
111-
project = get
112-
opts = [Mix.Deps.Lock.manifest]
127+
project = get
128+
opts = [Mix.Deps.Lock.manifest]
113129

114130
if project && (source = project.__info__(:compile)[:source]) do
115131
opts = [String.from_char_list!(source)|opts]
@@ -149,16 +165,82 @@ defmodule Mix.Project do
149165
end
150166

151167
@doc """
152-
Returns the paths this project compiles to,
153-
collecting all `:compile_path` in case of umbrella apps.
168+
Returns the path to store dependencies for this project.
169+
The returned path will be expanded.
170+
171+
## Examples
172+
173+
Mix.Project.deps_path
174+
#=> "/path/to/project/deps"
175+
176+
"""
177+
def deps_path(config // config()) do
178+
Path.expand config[:deps_path]
179+
end
180+
181+
@doc """
182+
Returns the build path for this project.
183+
The returned path will be expanded.
184+
185+
## Examples
186+
187+
Mix.Project.build_path
188+
#=> "/path/to/project/_build"
189+
190+
"""
191+
def build_path(config // config()) do
192+
config[:build_path] || Path.expand("_build")
193+
end
194+
195+
@doc """
196+
Returns the library path inside the build.
197+
The returned path will be expanded.
198+
199+
## Examples
200+
201+
Mix.Project.app_path
202+
#=> "/path/to/project/_build/lib/app"
203+
204+
"""
205+
def app_path(config // config()) do
206+
config[:app_path] || if app = config[:app] do
207+
Path.join([build_path(config), "lib", app])
208+
else
209+
raise Mix.Error, message: "Cannot access build without an application name, " <>
210+
"please ensure you are in a directory with a mix.exs file and it defines " <>
211+
"an :app name under the project configuration"
212+
end
213+
end
214+
215+
@doc """
216+
Returns the paths this project compiles to.
217+
The returned path will be expanded.
218+
219+
## Examples
220+
221+
Mix.Project.compile_path
222+
#=> "/path/to/project/_build/lib/app/priv"
223+
154224
"""
155225
def compile_path(config // config()) do
156-
unless config[:app] do
157-
raise Mix.Error, message: "Cannot access compilation path without an application name, " <>
158-
"please ensure you are in a directory with a mix.exs file and it defines an :app " <>
159-
"name under the project configuration"
226+
Path.join(app_path(config), "ebin")
227+
end
228+
229+
@doc """
230+
Builds the project structure for the current application.
231+
"""
232+
def build_structure(config // config()) do
233+
ebin = compile_path(config)
234+
File.mkdir_p!(ebin)
235+
236+
lib = Path.dirname(ebin)
237+
old = Path.expand("priv")
238+
239+
case :file.make_symlink(old, Path.join(lib, "priv")) do
240+
:ok -> :ok
241+
{ :error, :eexist } -> :ok
242+
{ :error, _ } -> File.cp_r!(old, lib) |> IO.inspect
160243
end
161-
Path.expand "ebin"
162244
end
163245

164246
@doc """

lib/mix/lib/mix/tasks/compile.app.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ defmodule Mix.Tasks.Compile.App do
6363
properties = ensure_correct_properties(app, properties)
6464
contents = { :application, app, properties }
6565

66-
File.mkdir_p!(Path.dirname(target))
66+
Mix.Project.build_structure(config)
6767
File.open!(target, [:write], &:io.fwrite(&1, "~p.", [contents]))
6868

6969
Mix.shell.info "Generated #{app}.app"

lib/mix/lib/mix/tasks/compile.elixir.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ defmodule Mix.Tasks.Compile.Elixir do
245245
end
246246

247247
result = files_to_path(manifest, stale, to_compile, compile_path, fn ->
248-
File.mkdir_p!(compile_path)
248+
Mix.Project.build_structure(project)
249249
Code.prepend_path(compile_path)
250250
set_compiler_opts(project, opts, [])
251251
end)

lib/mix/lib/mix/tasks/compile.erlang.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,8 @@ defmodule Mix.Tasks.Compile.Erlang do
258258
if stale == [] && removed == [] do
259259
:noop
260260
else
261-
File.mkdir_p!(Path.dirname(manifest))
261+
# Build the project structure so we can write down compiled files.
262+
Mix.Project.build_structure
262263

263264
# Remove manifest entries with no source
264265
Enum.each(removed, &File.rm/1)

0 commit comments

Comments
 (0)