Packages
espec
1.10.0
1.10.0
1.9.2
1.9.1
1.9.0
1.8.3
1.8.2
1.8.1
1.8.0
1.7.0
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.2
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.0.1
1.0.0
0.8.28
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.1
0.5.0
0.4.2
0.4.1
0.4.0
0.3.7
0.3.5
0.3.0
0.2.0
0.1.0
BDD testing framework for Elixir inspired by RSpec.
Current section
Files
Jump to
Current section
Files
lib/mix/utils/stale_compatible.ex
defmodule Mix.Utils.StaleCompatible do
@moduledoc false
# This module was written to deal with the incompatibilies between Elixir <= 1.9
# and the release of Elixir 1.10. It is expected to eventually go away if certain
# private APIs in Elixir become public or we shift away from reliance on
# the private APIs.
require Mix.Compilers.Elixir, as: CE
import Record
alias Mix.Utils.Stale
defrecordp :source,
source: nil,
compile_references: [],
runtime_references: [],
external: []
def parallel_require_callbacks(pid, cwd),
do:
parse_version()
|> parallel_require_callbacks(pid, cwd)
def tests_with_changed_references(test_sources),
do:
parse_version()
|> tests_with_changed_references(test_sources)
## Test changed dependency resolution
cond do
Version.match?(System.version(), "< 1.16.0") ->
def tests_with_changed_references(%Version{major: 1, minor: minor} = version, test_sources)
when minor >= 10 and minor < 16 do
test_manifest = Stale.manifest()
[elixir_manifest] = Mix.Tasks.Compile.Elixir.manifests()
if Mix.Utils.stale?([elixir_manifest], [test_manifest]) do
compile_path = Mix.Project.compile_path()
{elixir_modules, elixir_sources} = apply(CE, :read_manifest, [elixir_manifest])
stale_modules =
for CE.module(module: module) <- elixir_modules,
beam = Path.join(compile_path, Atom.to_string(module) <> ".beam"),
Mix.Utils.stale?([beam], [test_manifest]),
do: module,
into: MapSet.new()
stale_modules =
find_all_dependent_on(version, stale_modules, elixir_sources, elixir_modules)
for module <- stale_modules,
source(source: source, runtime_references: r, compile_references: c) <-
test_sources,
module in r or module in c,
do: source,
into: MapSet.new()
else
MapSet.new()
end
end
true ->
def tests_with_changed_references(%Version{major: 1} = version, test_sources) do
test_manifest = Stale.manifest()
[elixir_manifest] = Mix.Tasks.Compile.Elixir.manifests()
if Mix.Utils.stale?([elixir_manifest], [test_manifest]) do
compile_path = Mix.Project.compile_path()
{elixir_modules, elixir_sources} = apply(CE, :read_manifest, [elixir_manifest])
stale_modules =
for {module, _} <- elixir_modules,
beam = Path.join(compile_path, Atom.to_string(module) <> ".beam"),
Mix.Utils.stale?([beam], [test_manifest]),
do: module,
into: MapSet.new()
stale_modules =
find_all_dependent_on(version, stale_modules, elixir_sources, elixir_modules)
for module <- stale_modules,
source(source: source, runtime_references: r, compile_references: c) <-
test_sources,
module in r or module in c,
do: source,
into: MapSet.new()
else
MapSet.new()
end
end
end
## ParallelRequire callback: Handled differently depending on Elixir version
def parallel_require_callbacks(%Version{major: 1, minor: minor} = version, pid, cwd)
when minor >= 9,
do: [
each_module: &each_module(version, pid, cwd, &1, &2, &3),
each_file: &each_file(version, pid, cwd, &1, &2)
]
def parallel_require_callbacks(%Version{major: 1, minor: minor} = version, pid, cwd)
when minor >= 6 and minor < 9 do
[each_module: &each_module(version, pid, cwd, &1, &2, &3)]
end
def parallel_require_callbacks(_, _, _),
do: {:error, "Your version of Elixir #{System.version()} cannot support the stale feature"}
defp each_module(%Version{major: 1, minor: minor}, pid, cwd, file, module, _binary)
when minor >= 9 do
external = get_external_resources(module, cwd)
if external != [] do
Agent.update(pid, fn sources ->
file = Path.relative_to(file, cwd)
{source, sources} = List.keytake(sources, file, source(:source))
[source(source, external: external ++ source(source, :external)) | sources]
end)
end
:ok
end
defp each_module(%Version{major: 1, minor: minor}, pid, cwd, source, module, _binary)
when minor >= 6 and minor < 9 do
{compile_references, struct_references, runtime_references} =
apply(Kernel.LexicalTracker, :remote_references, [module])
external = get_external_resources(module, cwd)
source = Path.relative_to(source, cwd)
Agent.cast(pid, fn sources ->
external =
case List.keyfind(sources, source, source(:source)) do
source(external: old_external) -> external ++ old_external
nil -> external
end
new_source =
source(
source: source,
compile_references: compile_references ++ struct_references,
runtime_references: runtime_references,
external: external
)
List.keystore(sources, source, source(:source), new_source)
end)
end
defp each_file(%Version{major: 1, minor: minor}, pid, _cwd, file, lexical) when minor >= 10 do
Agent.update(pid, fn sources ->
case List.keytake(sources, file, source(:source)) do
{source, sources} ->
{compile_references, struct_references, runtime_references, _compile_env} =
apply(Kernel.LexicalTracker, :references, [lexical])
source =
source(
source,
compile_references: compile_references ++ struct_references,
runtime_references: runtime_references
)
[source | sources]
nil ->
sources
end
end)
end
defp each_file(%Version{major: 1, minor: 9}, pid, _cwd, file, lexical) do
Agent.update(pid, fn sources ->
case List.keytake(sources, file, source(:source)) do
{source, sources} ->
{compile_references, struct_references, runtime_references} =
apply(Kernel.LexicalTracker, :remote_references, [lexical])
source =
source(
source,
compile_references: compile_references ++ struct_references,
runtime_references: runtime_references
)
[source | sources]
nil ->
sources
end
end)
end
defp get_external_resources(module, cwd) do
for file <- Module.get_attribute(module, :external_resource),
do: Path.relative_to(file, cwd)
end
defp find_all_dependent_on(
version,
modules,
sources,
all_modules,
resolved \\ MapSet.new()
) do
new_modules =
for module <- modules,
module not in resolved,
dependent_module <- dependent_modules(version, module, all_modules, sources),
do: dependent_module,
into: modules
if MapSet.size(new_modules) == MapSet.size(modules) do
new_modules
else
find_all_dependent_on(version, new_modules, sources, all_modules, modules)
end
end
cond do
Version.match?(System.version(), "< 1.16.0") ->
defp dependent_modules(%Version{major: 1, minor: minor}, module, modules, sources)
when minor >= 11 do
for CE.source(
source: source,
runtime_references: r,
compile_references: c,
export_references: s
) <- sources,
module in r or module in c or module in s,
CE.module(sources: sources, module: dependent_module) <- modules,
source in sources,
do: dependent_module
end
true ->
defp dependent_modules(%Version{}, module, modules, sources) do
for {source,
CE.source(
runtime_references: r,
compile_references: c,
export_references: e
)} <- sources,
module in r or module in c or module in e,
{dependent_module, CE.module(sources: sources)} <- modules,
source in sources,
do: dependent_module
end
end
defp parse_version do
System.version()
|> Version.parse()
|> case do
{:ok, version} -> version
:error -> :error
end
end
end