Compare commits

...
34 Commits
Author SHA1 Message Date
José Valim e02d7bf913 Release v1.0.4 2015-04-07 23:35:13 +02:00
José Valim fe5ff41514 Tag async tests as such 2015-04-07 11:35:31 +02:00
José Valim e9887a760e Wait until test process is down in ExUnit runner
This should fix a race condition where the next test would
start before all linked processes in the previous test were
killed, often leading to already registered errors.
2015-04-06 19:13:09 +02:00
Eric Meadows-Jönsson 0559fe5927 Fix doc formatting in ExUnit.Formatter
Signed-off-by: Eric Meadows-Jönsson <eric.meadows.jonsson@gmail.com>
2015-04-05 19:27:01 -05:00
José Valim 1a05bff45d Update CHANGELOG 2015-04-05 19:28:53 +02:00
José Valim 4d6670342b Fixes for Erlang 18.0-rc1 2015-04-05 18:28:13 +02:00
Eric Meadows-Jönsson 193e85882e Add compatibilty with OTP 18 typespec changes
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2015-04-05 17:59:29 +02:00
José Valim a58c007e0c Avoid missing behaviour warnings when compiling erlang files 2015-04-04 18:34:58 +02:00
José Valim ce6f4e6d15 Clean up ExUnit.Assertions docs 2015-04-03 17:08:03 +02:00
José Valim 321096665a Do not propagate protocol consolidation to children 2015-04-02 21:39:33 +02:00
José Valim b93aae9f86 Ensure we quote proper file on exceptions
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>

Conflicts:
	lib/elixir/test/elixir/exception_test.exs
2015-04-02 18:40:24 +02:00
José Valim a503069479 Ensure we consolidate only when there was a change 2015-04-02 15:42:56 +02:00
José Valim 120ea0fc8a Start v1.0.4-dev 2015-04-02 15:15:27 +02:00
José Valim d725c66d93 Update CHANGELOG 2015-04-02 15:04:00 +02:00
José Valim fab917dba3 Do not print app name as a filename 2015-04-02 15:00:52 +02:00
José Valim 23fb92f444 Improve error message for IEx.pry/1 2015-04-02 14:57:00 +02:00
José Valim db61109495 Generate build_embedded and start_permanent in new apps 2015-04-02 14:41:58 +02:00
José Valim c4e8ad0d65 Support start_permanent 2015-04-02 14:41:47 +02:00
José Valim ce77fa54b9 Support build_embedded and consolidate_protocols 2015-04-02 14:39:08 +02:00
Paulo Almeida eee921bf7b Support mix help --search PATTERN
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2015-04-02 09:47:07 +02:00
José Valim 73c6a0be8b Update CHANGELOG 2015-04-02 09:39:05 +02:00
José Valim 7644bd87a5 Merge pull request #3198 from eksperimental/pattern_operator
fix Kernel.=~/2 for "" =~ ""

Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2015-04-02 09:37:05 +02:00
José Valim 9e2c5a29a4 Speed up decode_www_form
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2015-03-17 19:02:12 +01:00
José Valim 09498422d0 Speed up URI.decode_query/1
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2015-03-17 18:17:29 +01:00
Eric Meadows-Jönsson a697bab7f2 Store relative paths in erlang manifest
Signed-off-by: Eric Meadows-Jönsson <eric.meadows.jonsson@gmail.com>
2015-03-13 13:44:16 +01:00
José Valim 36e81d587e Increase elixir_counter timeout
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2015-03-12 19:00:56 +01:00
Booker C. Bense 17a0abd57a Added test for markup ending in . and code to pass the test
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2015-03-07 00:19:39 +01:00
Or Neeman e6cfc20556 Produce clearer messages for syntax errors before a sigil
Closes #3130

Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2015-03-07 00:19:20 +01:00
Or Neeman 906f03102b Return value when matching with _ on last line of block
Closes #3125

Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2015-03-02 14:27:47 +01:00
José Valim 6a594e2bba Ensure changes in child deps forces the parent to recompile
This test fell through the cracks when we changed mix
to no longer compile dependencies on get but during
project compilation.

Therefore, this patch fixes the bug and ensures the test
is up to date to check the original scenario it was supposed
to.

Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2015-03-01 11:03:03 +01:00
José Valim 10dd8f843b Fallback to undocumented API only if necessary
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>

Conflicts:
	lib/elixir/src/elixir.erl
2015-03-01 11:02:51 +01:00
José Valim 53ecea8b03 Do not erase stacktrace on bad configs
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2015-03-01 11:02:05 +01:00
Eric Meadows-Jönsson efba8d8bfa Fix httpc proxy option profile
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2015-03-01 11:00:43 +01:00
José Valim 5a201065dc Update new major.minor instructions
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2015-02-12 11:17:22 +01:00
62 changed files with 667 additions and 351 deletions
+19
View File
@@ -1,5 +1,24 @@
# Changelog
## v1.0.4
* Enhancements
* [Elixir] Support Erlang 17.5 and 18.0
* [Mix] Support "--search PATTERN" in "mix help"
* [Mix] Support `:start_permanent` that starts the application as permanent
* [Mix] Support `:build_embedded` that compile protocols, avoid symlinks and ensure protocols are loaded on boot
* [Mix] Make "mix app.start" public and support "--permanent" and "--temporary" options
* [URI] Speed decoding operations
* Bug fixes
* [Elixir] Produce clearer error messages for syntax errors before a sigil
* [Elixir] Return value when matching on `_` in the last line of a block
* [Elixir] Ensure changes in child deps forces the parent to recompile
* [Kernel] Fix a bug where `=~/2` returned false when matching on an empty string. The current behaviour was changed to match the behaviour of `String.contains?/2`
* [Mix] Store relative paths in erlang manifests
* [Mix] Fix httpc proxy option profile for downloading hex and other safe packges
* [Mix] Fix missing behaviour warning when compiling Erlang modules
## v1.0.3 (2015-02-12)
* Enhancements
+4 -4
View File
@@ -28,13 +28,13 @@ This document simply outlines the release process:
## New vMAJOR.MINOR releases
11. Create a new branch "vMAJOR.MINOR"
12. Create a new branch "vMAJOR.MINOR"
12. Move docs generation to `docs/vOLD-MAJOR.OLD-MINOR` and copy them to `docs/stable`
13. Move docs generation to `docs/vMAJOR.MINOR` and copy them from `docs/stable`
13. Bump versions, start new CHANGELOG, add `-dev` back and commit "Start vVERSION+1"
14. In master, bump versions, start new CHANGELOG, add `-dev` back and commit "Start vVERSION+1"
14. `make release_docs` and push it to `elixir-lang/docs`
15. `make release_docs` and push it to `elixir-lang/docs`
## Places where version is mentioned
+1 -1
View File
@@ -1 +1 @@
1.0.3
1.0.4
+1 -10
View File
@@ -51,16 +51,7 @@ defmodule Code do
:code.del_path(to_char_list(Path.expand path))
end
@doc """
Re-add paths given to the command line to keep their position
on the overall code path.
Some tools may change the code path by prepending new items but
still want the paths given by the user to have higher priority.
Calling this function guarantees the paths are re-added on
top of the user given ones.
"""
@spec readd_paths() :: :ok
@doc false
def readd_paths() do
{pa, pz} = :elixir_code_server.call(:paths)
:code.add_pathsa(pa)
+1 -1
View File
@@ -408,7 +408,7 @@ defmodule IO.ANSI.Docs do
# Characters that can mark the beginning or the end of a word.
# Only support the most common ones at this moment.
@delimiters [?\s, ?', ?", ?!, ?@, ?#, ?$, ?%, ?^, ?&, ?-, ?+, ?(, ?), ?[, ?], ?{, ?}, ?<, ?>]
@delimiters [?\s, ?', ?", ?!, ?@, ?#, ?$, ?%, ?^, ?&, ?-, ?+, ?(, ?), ?[, ?], ?{, ?}, ?<, ?>, ?.]
# Inline start
+7
View File
@@ -1386,7 +1386,14 @@ defmodule Kernel do
iex> "abcd" =~ "ad"
false
iex> "abcd" =~ ""
true
"""
@spec (String.t =~ (String.t | Regex.t)) :: boolean
def left =~ "" when is_binary(left), do: true
def left =~ right when is_binary(left) and is_binary(right) do
:binary.match(left, right) != :nomatch
end
+37 -7
View File
@@ -644,6 +644,10 @@ defmodule Kernel.Typespec do
[]
end
defp typespec_to_ast({:user_type, line, name, args}) do
typespec_to_ast({:type, line, name, args})
end
defp typespec_to_ast({:type, line, :tuple, :any}) do
{:tuple, [line: line], []}
end
@@ -677,8 +681,13 @@ defmodule Kernel.Typespec do
end
defp typespec_to_ast({:type, line, :map, fields}) do
fields = Enum.map fields, fn {:type, _, :map_field_assoc, k, v} ->
{typespec_to_ast(k), typespec_to_ast(v)}
fields = Enum.map fields, fn
# OTP 18
{:type, _, :map_field_assoc, [k, v]} ->
{typespec_to_ast(k), typespec_to_ast(v)}
# OTP 17
{:type, _, :map_field_assoc, k, v} ->
{typespec_to_ast(k), typespec_to_ast(v)}
end
{struct, fields} = Keyword.pop(fields, :__struct__)
@@ -821,9 +830,17 @@ defmodule Kernel.Typespec do
## Handle maps and structs
defp typespec({:%{}, meta, fields}, vars, caller) do
fields = :lists.map(fn {k, v} ->
{:type, line(meta), :map_field_assoc, typespec(k, vars, caller), typespec(v, vars, caller)}
end, fields)
fields =
if :erlang.system_info(:otp_release) >= '18' do
:lists.map(fn {k, v} ->
{:type, line(meta), :map_field_assoc, [typespec(k, vars, caller), typespec(v, vars, caller)]}
end, fields)
else
:lists.map(fn {k, v} ->
{:type, line(meta), :map_field_assoc, typespec(k, vars, caller), typespec(v, vars, caller)}
end, fields)
end
{:type, line(meta), :map, fields}
end
@@ -884,7 +901,8 @@ defmodule Kernel.Typespec do
# Handle ranges
defp typespec({:.., meta, args}, vars, caller) do
typespec({:range, meta, args}, vars, caller)
args = for arg <- args, do: typespec(arg, vars, caller)
{:type, line(meta), :range, args}
end
# Handle special forms
@@ -968,9 +986,21 @@ defmodule Kernel.Typespec do
typespec((quote do: :elixir.as_boolean(unquote(arg))), vars, caller)
end
defp typespec({:fun, meta, args}, vars, caller) do
args = for arg <- args, do: typespec(arg, vars, caller)
{:type, line(meta), :fun, args}
end
defp typespec({name, meta, arguments}, vars, caller) do
arguments = for arg <- arguments, do: typespec(arg, vars, caller)
{:type, line(meta), name, arguments}
if :erlang.system_info(:otp_release) >= '18' do
arity = length(arguments)
type = if :erl_internal.is_type(name, arity), do: :type, else: :user_type
{type, line(meta), name, arguments}
else
{:type, line(meta), name, arguments}
end
end
# Handle literals
+21 -16
View File
@@ -95,7 +95,10 @@ defmodule URI do
"""
def decode_query(q, dict \\ %{}) when is_binary(q) do
Enum.reduce query_decoder(q), dict, fn({k, v}, acc) -> Dict.put(acc, k, v) end
case do_decode_query(q) do
nil -> dict
{{k, v}, q} -> decode_query(q, Dict.put(dict, k, v))
end
end
@doc """
@@ -104,19 +107,19 @@ defmodule URI do
## Examples
iex> URI.query_decoder("foo=1&bar=2") |> Enum.map &(&1)
iex> URI.query_decoder("foo=1&bar=2") |> Enum.map(&(&1))
[{"foo", "1"}, {"bar", "2"}]
"""
def query_decoder(q) when is_binary(q) do
Stream.unfold(q, &do_decoder/1)
Stream.unfold(q, &do_decode_query/1)
end
defp do_decoder("") do
defp do_decode_query("") do
nil
end
defp do_decoder(q) do
defp do_decode_query(q) do
{first, next} =
case :binary.split(q, "&") do
[first, rest] -> {first, rest}
@@ -231,7 +234,7 @@ defmodule URI do
"""
def decode(uri) do
unpercent(uri)
unpercent(uri, "", false)
catch
:malformed_uri ->
raise ArgumentError, "malformed URI #{inspect uri}"
@@ -247,23 +250,25 @@ defmodule URI do
"""
def decode_www_form(str) do
String.split(str, "+") |> Enum.map_join(" ", &unpercent/1)
unpercent(str, "", true)
catch
:malformed_uri ->
raise ArgumentError, "malformed URI #{inspect str}"
end
defp unpercent(<<?%, hex_1, hex_2, tail :: binary>>) do
<<bsl(hex_to_dec(hex_1), 4) + hex_to_dec(hex_2)>> <> unpercent(tail)
end
defp unpercent(<<?%, _>>), do: throw(:malformed_uri)
defp unpercent(<<?%>>), do: throw(:malformed_uri)
defp unpercent(<<head, tail :: binary>>) do
<<head>> <> unpercent(tail)
defp unpercent(<<?+, tail::binary>>, acc, spaces = true) do
unpercent(tail, <<acc::binary, ?\s>>, spaces)
end
defp unpercent(<<>>), do: <<>>
defp unpercent(<<?%, hex_1, hex_2, tail::binary>>, acc, spaces) do
unpercent(tail, <<acc::binary, bsl(hex_to_dec(hex_1), 4) + hex_to_dec(hex_2)>>, spaces)
end
defp unpercent(<<?%, _::binary>>, _acc, _spaces), do: throw(:malformed_uri)
defp unpercent(<<head, tail::binary>>, acc, spaces) do
unpercent(tail, <<acc::binary, head>>, spaces)
end
defp unpercent(<<>>, acc, _spaces), do: acc
defp hex_to_dec(n) when n in ?A..?F, do: n - ?A + 10
defp hex_to_dec(n) when n in ?a..?f, do: n - ?a + 10
+6 -3
View File
@@ -29,9 +29,12 @@ start(_Type, _Args) ->
end,
ok = io:setopts(standard_io, Opts),
%% Must use undocument {unicode, true} to set unicode on standard_error, more
%% info: http://erlang.org/pipermail/erlang-bugs/2014-April/004310.html
ok = io:setopts(standard_error, [{unicode,true}]),
ok = case io:setopts(standard_error, [{encoding,utf8}]) of
ok -> ok;
{error, _} -> io:setopts(standard_error, [{unicode,true}]) %% R17.3 and earlier
end,
case file:native_name_encoding() of
latin1 ->
io:format(standard_error,
+2 -2
View File
@@ -3,8 +3,8 @@
handle_info/2, terminate/2, code_change/3, next/0]).
-behaviour(gen_server).
-define(timeout, 1000). %% 1 second
-define(limit, 4294967296). %% 2^32
-define(timeout, 30000). %% 30 seconds
-define(limit, 4294967295). %% 2^32 - 1
next() ->
gen_server:call(?MODULE, next, ?timeout).
+1 -1
View File
@@ -215,7 +215,7 @@ expand_quoted(Meta, Receiver, Name, Arity, Quoted, E) ->
end.
caller(Line, #{module := nil} = E) ->
{elixir_compiler, '__FILE__', 2, location(Line, E)};
{elixir_compiler_0, '__FILE__', 1, location(Line, E)};
caller(Line, #{module := Module, function := nil} = E) ->
{Module, '__MODULE__', 0, location(Line, E)};
caller(Line, #{module := Module, function := {Name, Arity}} = E) ->
+7
View File
@@ -55,6 +55,13 @@ parse_error(Line, File, Error, <<>>) ->
parse_error(Line, File, <<"syntax error before: ">>, <<"'end'">>) ->
do_raise(Line, File, 'Elixir.SyntaxError', <<"unexpected token: end">>);
%% Produce a human-readable message for errors before a sigil
parse_error(Line, File, <<"syntax error before: ">>, <<"{sigil,", _Rest/binary>> = Full) ->
{ok, Tokens, _} = erl_scan:string(binary_to_list(Full)),
{ok, {sigil, _, Sigil, [Content], _}} = erl_parse:parse_term(Tokens ++ [{dot, 1}]),
Message = <<"syntax error before: sigil ~", Sigil," with content '", Content/binary, "'">>,
do_raise(Line, File, 'Elixir.SyntaxError', Message);
%% Aliases are wrapped in ['']
parse_error(Line, File, Error, <<"['", Token/binary>>) when is_binary(Error) ->
Rest =
+1 -1
View File
@@ -10,7 +10,7 @@
translate({'=', Meta, [Left, Right]}, S) ->
Return = case Left of
{'_', _, Atom} when is_atom(Atom) -> false;
{'_', _, Atom} when is_atom(Atom) -> S#elixir_scope.return;
_ -> true
end,
+16
View File
@@ -327,4 +327,20 @@ defmodule Kernel.ExceptionTest do
assert %ErlangError{original: :sample} |> message ==
"erlang error: :sample"
end
test "format_stacktrace from file" do
assert_raise ArgumentError, fn ->
Code.eval_string("def foo do end", [], file: "myfile")
end
assert Exception.format_stacktrace(System.stacktrace) =~ "myfile:1: (file)"
end
test "format_stacktrace from module" do
assert_raise ArgumentError, fn ->
Code.eval_string("defmodule Foo do raise ArgumentError, ~s(oops) end", [], file: "myfile")
end
assert Exception.format_stacktrace(System.stacktrace) =~ "myfile:1: (module)"
end
end
@@ -103,6 +103,9 @@ defmodule IO.ANSI.DocsTest do
result = format("*world*")
assert result == "\e[1mworld\e[0m\n\e[0m"
result = format("*world*.")
assert result == "\e[1mworld\e[0m.\n\e[0m"
result = format("**world**")
assert result == "\e[1mworld\e[0m\n\e[0m"
@@ -151,6 +151,12 @@ defmodule Kernel.ComprehensionTest do
assert for({_,x} <- [1, 2, a: 3, b: 4, c: 5], do: x * 2) == [6, 8, 10]
end
test "list for comprehension matched to '_' on last line of block" do
assert (if true do
_ = for x <- [1, 2, 3], do: x * 2
end) == [2, 4, 6]
end
test "list for comprehensions with filters" do
assert for(x <- [1, 2, 3], x > 1, x < 3, do: x * 2) == [4]
end
+13 -2
View File
@@ -89,6 +89,12 @@ defmodule Kernel.ErrorsTest do
'+.foo'
end
test :syntax_error_before_sigil do
assert_compile_fail SyntaxError,
"nofile:1: syntax error before: sigil ~s with content 'bar baz'",
'~s(foo) ~s(bar baz)'
end
test :compile_error_on_op_ambiguity do
msg = "nofile:1: \"a -1\" looks like a function call but there is a variable named \"a\", " <>
"please use explicit parenthesis or even spaces"
@@ -750,8 +756,13 @@ defmodule Kernel.ErrorsTest do
end
'''
assert_compile_fail CompileError,
"nofile:2: spec for undefined function ErrorsTest.omg/0",
if :erlang.system_info(:otp_release) >= '18' do
message = "nofile:2: spec for undefined function omg/0"
else
message = "nofile:2: spec for undefined function ErrorsTest.omg/0"
end
assert_compile_fail CompileError, message,
'''
defmodule ErrorsTest do
@spec omg :: atom
+30 -21
View File
@@ -154,15 +154,6 @@ defmodule Kernel.TypespecTest do
types(module)
end
test "@type with a range" do
module = test_module do
@type mytype :: range(1, 10)
end
assert [type: {:mytype, {:type, _, :range, [{:integer, _, 1}, {:integer, _, 10}]}, []}] =
types(module)
end
test "@type with a range op" do
module = test_module do
@type mytype :: 1..10
@@ -177,11 +168,19 @@ defmodule Kernel.TypespecTest do
@type mytype :: %{hello: :world}
end
assert [type: {:mytype,
{:type, _, :map, [
{:type, _, :map_field_assoc, {:atom, _, :hello}, {:atom, _, :world}}
]},
[]}] = types(module)
if :erlang.system_info(:otp_release) >= '18' do
assert [type: {:mytype,
{:type, _, :map, [
{:type, _, :map_field_assoc, [{:atom, _, :hello}, {:atom, _, :world}]}
]},
[]}] = types(module)
else
assert [type: {:mytype,
{:type, _, :map, [
{:type, _, :map_field_assoc, {:atom, _, :hello}, {:atom, _, :world}}
]},
[]}] = types(module)
end
end
test "@type with a struct" do
@@ -190,13 +189,23 @@ defmodule Kernel.TypespecTest do
@type mytype :: %TestTypespec{hello: :world}
end
assert [type: {:mytype,
{:type, _, :map, [
{:type, _, :map_field_assoc, {:atom, _, :__struct__}, {:atom, _, TestTypespec}},
{:type, _, :map_field_assoc, {:atom, _, :hello}, {:atom, _, :world}},
{:type, _, :map_field_assoc, {:atom, _, :other}, {:type, _, :term, []}}
]},
[]}] = types(module)
if :erlang.system_info(:otp_release) >= '18' do
assert [type: {:mytype,
{:type, _, :map, [
{:type, _, :map_field_assoc, [{:atom, _, :__struct__}, {:atom, _, TestTypespec}]},
{:type, _, :map_field_assoc, [{:atom, _, :hello}, {:atom, _, :world}]},
{:type, _, :map_field_assoc, [{:atom, _, :other}, {:type, _, :term, []}]}
]},
[]}] = types(module)
else
assert [type: {:mytype,
{:type, _, :map, [
{:type, _, :map_field_assoc, {:atom, _, :__struct__}, {:atom, _, TestTypespec}},
{:type, _, :map_field_assoc, {:atom, _, :hello}, {:atom, _, :world}},
{:type, _, :map_field_assoc, {:atom, _, :other}, {:type, _, :term, []}}
]},
[]}] = types(module)
end
end
test "@type with undefined struct" do
+42
View File
@@ -6,11 +6,25 @@ defmodule KernelTest do
test "=~/2" do
assert ("abcd" =~ ~r/c(d)/) == true
assert ("abcd" =~ ~r/e/) == false
assert ("abcd" =~ ~R/c(d)/) == true
assert ("abcd" =~ ~R/e/) == false
string = "^ab+cd*$"
assert (string =~ "ab+") == true
assert (string =~ "bb") == false
assert ("abcd" =~ ~r//) == true
assert ("abcd" =~ ~R//) == true
assert ("abcd" =~ "") == true
assert ("" =~ ~r//) == true
assert ("" =~ ~R//) == true
assert ("" =~ "") == true
assert ("" =~ "abcd") == false
assert ("" =~ ~r/abcd/) == false
assert ("" =~ ~R/abcd/) == false
assert_raise FunctionClauseError, "no function clause matching in Kernel.=~/2", fn ->
1234 =~ "hello"
end
@@ -18,6 +32,34 @@ defmodule KernelTest do
assert_raise FunctionClauseError, "no function clause matching in Kernel.=~/2", fn ->
1234 =~ ~r"hello"
end
assert_raise FunctionClauseError, "no function clause matching in Kernel.=~/2", fn ->
1234 =~ ~R"hello"
end
assert_raise FunctionClauseError, "no function clause matching in Kernel.=~/2", fn ->
~r"hello" =~ "hello"
end
assert_raise FunctionClauseError, "no function clause matching in Kernel.=~/2", fn ->
~r"hello" =~ ~r"hello"
end
assert_raise FunctionClauseError, "no function clause matching in Kernel.=~/2", fn ->
:abcd =~ ~r//
end
assert_raise FunctionClauseError, "no function clause matching in Kernel.=~/2", fn ->
:abcd =~ ""
end
assert_raise FunctionClauseError, "no function clause matching in Regex.match?/2", fn ->
"abcd" =~ nil
end
assert_raise FunctionClauseError, "no function clause matching in Regex.match?/2", fn ->
"abcd" =~ :abcd
end
end
test "^" do
+12 -4
View File
@@ -121,11 +121,19 @@ defmodule ProtocolTest do
end
test "protocol defines callbacks" do
assert get_callbacks(Sample, :ok, 1) ==
[{:type, 9, :fun, [{:type, 9, :product, [{:type, 9, :t, []}]}, {:type, 9, :boolean, []}]}]
if :erlang.system_info(:otp_release) >= '18' do
assert get_callbacks(Sample, :ok, 1) ==
[{:type, 9, :fun, [{:type, 9, :product, [{:user_type, 9, :t, []}]}, {:type, 9, :boolean, []}]}]
assert get_callbacks(WithAny, :ok, 1) ==
[{:type, 16, :fun, [{:type, 16, :product, [{:type, 16, :t, []}]}, {:type, 16, :term, []}]}]
assert get_callbacks(WithAny, :ok, 1) ==
[{:type, 16, :fun, [{:type, 16, :product, [{:user_type, 16, :t, []}]}, {:type, 16, :term, []}]}]
else
assert get_callbacks(Sample, :ok, 1) ==
[{:type, 9, :fun, [{:type, 9, :product, [{:type, 9, :t, []}]}, {:type, 9, :boolean, []}]}]
assert get_callbacks(WithAny, :ok, 1) ==
[{:type, 16, :fun, [{:type, 16, :product, [{:type, 16, :t, []}]}, {:type, 16, :term, []}]}]
end
end
test "protocol defines attributes" do
+5 -17
View File
@@ -207,26 +207,16 @@ defmodule ExUnit.Assertions do
true
end
@doc """
Asserts `value` is true.
If it fails, it raises an expectation error
using the given `left` and `right` values.
You probably don't need to use this—the regular `assert` function
handles this for you.
## Examples
assert this > that, this, that, "more than"
"""
@doc false
def assert(value, left, right, message) when is_binary(message) do
assert(value, left: left, right: right, message: message)
end
@doc """
Asserts a message was or is going to be received. Unlike
`assert_received`, it has a default timeout of 100 milliseconds.
Asserts a message was or is going to be received.
Unlike `assert_received`, it has a default timeout
of 100 milliseconds.
The `expected` argument is a pattern.
@@ -460,8 +450,6 @@ defmodule ExUnit.Assertions do
end
@doc """
refute_receive message, timeout \\ 100, message \\ nil
Asserts `message` was not received (and won't be received) within
the `timeout` period.
+8 -6
View File
@@ -162,15 +162,17 @@ defmodule ExUnit.Case do
quote do
unless Module.get_attribute(__MODULE__, :ex_unit_tests) do
if unquote(async) do
ExUnit.Server.add_async_case(__MODULE__)
else
ExUnit.Server.add_sync_case(__MODULE__)
end
Enum.each [:ex_unit_tests, :tag, :moduletag],
&Module.register_attribute(__MODULE__, &1, accumulate: true)
if unquote(async) do
@moduletag async: true
ExUnit.Server.add_async_case(__MODULE__)
else
@moduletag async: false
ExUnit.Server.add_sync_case(__MODULE__)
end
@before_compile ExUnit.Case
use ExUnit.Callbacks
end
+7 -7
View File
@@ -9,23 +9,23 @@ defmodule ExUnit.Formatter do
The following events are possible:
* `{:suite_started, opts}` -
the suite has started with the specified options to the runner.
the suite has started with the specified options to the runner.
* `{:suite_finished, run_us, load_us}` -
the suite has finished. `run_us` and `load_us` are the run and load
times in microseconds respectively.
the suite has finished. `run_us` and `load_us` are the run and load
times in microseconds respectively.
* `{:case_started, test_case}` -
a test case has started. See `ExUnit.TestCase` for details.
a test case has started. See `ExUnit.TestCase` for details.
* `{:case_finished, test_case}` -
a test case has finished. See `ExUnit.TestCase` for details.
a test case has finished. See `ExUnit.TestCase` for details.
* `{:test_started, test_case}` -
a test case has started. See `ExUnit.Test` for details.
a test case has started. See `ExUnit.Test` for details.
* `{:test_finished, test_case}` -
a test case has finished. See `ExUnit.Test` for details.
a test case has finished. See `ExUnit.Test` for details.
"""
+7 -3
View File
@@ -47,7 +47,7 @@ defmodule ExUnit.Runner do
|> Keyword.put(:exclude, exclude)
|> Keyword.put(:include, include)
|> Keyword.put_new(:max_cases, :erlang.system_info(:schedulers_online))
|> Keyword.put_new(:seed, :erlang.now |> elem(2))
|> Keyword.put_new(:seed, :os.timestamp |> elem(2))
end
defp loop(config) do
@@ -159,7 +159,9 @@ defmodule ExUnit.Runner do
{test_case, pending} =
receive do
{^case_pid, :case_finished, test_case, tests} ->
Process.demonitor(case_ref, [:flush])
receive do
{:DOWN, ^case_ref, :process, ^case_pid, _} -> :ok
end
{test_case, tests}
{:DOWN, ^case_ref, :process, ^case_pid, error} ->
test_case = %{test_case | state: {:failed, {{:EXIT, case_pid}, error, []}}}
@@ -214,7 +216,9 @@ defmodule ExUnit.Runner do
test =
receive do
{^test_pid, :test_finished, test} ->
Process.demonitor(test_ref, [:flush])
receive do
{:DOWN, ^test_ref, :process, ^test_pid, _} -> :ok
end
test
{:DOWN, ^test_ref, :process, ^test_pid, error} ->
%{test | state: {:failed, {{:EXIT, test_pid}, error, []}}}
+1
View File
@@ -19,6 +19,7 @@ defmodule ExUnit.CaseTest do
assert context[:case] == __MODULE__
assert context[:test] == __ENV__.function |> elem(0)
assert context[:line] == line
assert context[:async] == true
assert context[:hello] == true
assert context[:world] == :good
end
+33 -17
View File
@@ -391,27 +391,43 @@ defmodule IEx do
Setting variables or importing modules in IEx does not
affect the caller the environment (hence it is called `pry`).
"""
defmacro pry(timeout \\ 1000) do
defmacro pry(timeout \\ 5000) do
quote do
env = __ENV__
meta = "#{inspect self} at #{Path.relative_to_cwd(env.file)}:#{env.line}"
opts = [binding: binding, dot_iex_path: "", env: env, prefix: "pry"]
res = IEx.Server.take_over("Request to pry #{meta}", opts, unquote(timeout))
# We cannot use colors because IEx may be off.
case res do
{:error, :self} = err ->
IO.puts :stdio, "IEx cannot pry itself."
{:error, :no_iex} = err ->
IO.puts :stdio, "Cannot pry #{meta}. Is an IEx shell running?"
_ ->
:ok
end
res
IEx.pry(binding, __ENV__, unquote(timeout))
end
end
@doc """
Callback for `IEx.pry/1`.
You can invoke this function directly when you are not able to invoke
`IEx.pry/1` as a macro. This function expects the binding (from
`Kernel.binding/0`), the environment (from `__ENV__`) and the timeout
(a sensible default is 5000).
"""
def pry(binding, env, timeout) do
meta = "#{inspect self} at #{Path.relative_to_cwd(env.file)}:#{env.line}"
opts = [binding: binding, dot_iex_path: "", env: env, prefix: "pry"]
res = IEx.Server.take_over("Request to pry #{meta}", opts, timeout)
# We cannot use colors because IEx may be off.
case res do
{:error, :self} ->
IO.puts :stdio, "IEx cannot pry the shell itself."
{:error, :no_iex} ->
extra =
case :os.type do
{:win32, _} -> " If you are Windows, you may need to start IEx with the --werl flag."
_ -> ""
end
IO.puts :stdio, "Cannot pry #{meta}. Is an IEx shell running?" <> extra
_ ->
:ok
end
res
end
## Callbacks
# This is a callback invoked by Erlang shell utilities
+5 -5
View File
@@ -82,8 +82,8 @@ defmodule Logger.Translator do
defp translate_supervisor(min_level,
[supervisor: sup, errorContext: context,
reason: reason,
offender: [{:pid, pid}, {:name, name} | offender]])
when is_pid(pid) and context !== :shutdown do
offender: [{:pid, pid}, {name_or_id, name} | offender]])
when is_pid(pid) and context !== :shutdown and name_or_id in [:name, :id] do
{:ok, ["Child ", inspect(name), " of Supervisor ",
sup_name(sup), ?\s, sup_context(context), ?\n,
"Pid: ", inspect(pid), ?\n,
@@ -95,7 +95,7 @@ defmodule Logger.Translator do
[supervisor: sup, errorContext: context,
reason: reason,
offender: [{:pid, _pid},
{:name, name} | offender]]) do
{name_or_id, name} | offender]]) when name_or_id in [:name, :id] do
{:ok, ["Child ", inspect(name), " of Supervisor ",
sup_name(sup), ?\s, sup_context(context), ?\n,
child_info(min_level, offender), ?\n,
@@ -117,7 +117,7 @@ defmodule Logger.Translator do
[supervisor: sup, errorContext: context,
reason: reason,
offender: [{:nb_children, n},
{:name, name} | offender]]) do
{name_or_id, name} | offender]]) when name_or_id in [:name, :id] do
{:ok, ["Children ", inspect(name), " of Supervisor ",
sup_name(sup), ?\s, sup_context(context), ?\n,
"Number: ", inspect(n), ?\n,
@@ -134,7 +134,7 @@ defmodule Logger.Translator do
defp translate_progress(min_level,
[supervisor: sup,
started: [{:pid, pid}, {:name, name} | started]]) do
started: [{:pid, pid}, {name_or_id, name} | started]]) when name_or_id in [:name, :id] do
{:ok, ["Child ", inspect(name), " of Supervisor ",
sup_name(sup), " started\n",
"Pid: ", inspect(pid), ?\n |
+2
View File
@@ -99,6 +99,8 @@ defmodule Mix.Compilers.Elixir do
defp compile_manifest(manifest, entries, stale, dest, on_start) do
Mix.Project.build_structure
true = Code.prepend_path(dest)
on_start.()
cwd = File.cwd!
+5
View File
@@ -72,6 +72,11 @@ defmodule Mix.Compilers.Erlang do
# Build the project structure so we can write down compiled files.
Mix.Project.build_structure
# Let's prepend the newly created path so compiled files
# can be accessed still during compilation (for behaviours
# and what not).
Code.prepend_path(Mix.Project.compile_path)
# Remove manifest entries with no source
Enum.each(removed, &File.rm/1)
+1 -1
View File
@@ -138,7 +138,7 @@ defmodule Mix.Config do
config
rescue
e in [LoadError] -> reraise(e, System.stacktrace)
e -> raise LoadError, file: file, error: e
e -> reraise(LoadError, [file: file, error: e], System.stacktrace)
end
end
+1 -1
View File
@@ -133,7 +133,7 @@ defmodule Mix.Dep.Fetcher do
dep_names = Enum.map(deps, fn dep -> dep.app end)
parents = Enum.filter all_deps, fn dep ->
Enum.any?(dep.deps, &(&1 in dep_names))
Enum.any?(dep.deps, &(&1.app in dep_names))
end
do_with_depending(parents, all_deps) ++ parents
+20 -5
View File
@@ -80,8 +80,10 @@ defmodule Mix.Project do
# The configuration that is pushed down to dependencies.
@doc false
def deps_config(config \\ config()) do
[build_path: build_path(config),
[build_embedded: config[:build_embedded],
build_path: build_path(config),
build_per_environment: config[:build_per_environment],
consolidate_protocols: false,
deps_path: deps_path(config)]
end
@@ -320,7 +322,7 @@ defmodule Mix.Project do
_ = cond do
opts[:symlink_ebin] ->
_ = Mix.Utils.symlink_or_copy(source, target)
_ = symlink_or_copy(config, source, target)
match?({:ok, _}, :file.read_link(target)) ->
_ = File.rm_rf!(target)
File.mkdir_p!(target)
@@ -328,11 +330,22 @@ defmodule Mix.Project do
File.mkdir_p!(target)
end
_ = Mix.Utils.symlink_or_copy(Path.expand("include"), Path.join(app, "include"))
_ = Mix.Utils.symlink_or_copy(Path.expand("priv"), Path.join(app, "priv"))
_ = symlink_or_copy(config, Path.expand("include"), Path.join(app, "include"))
_ = symlink_or_copy(config, Path.expand("priv"), Path.join(app, "priv"))
:ok
end
defp symlink_or_copy(config, source, target) do
if config[:build_embedded] do
if File.exists?(source) do
File.rm_rf!(target)
File.cp_r!(source, target)
end
else
Mix.Utils.symlink_or_copy(source, target)
end
end
@doc """
Returns all load paths for this project.
"""
@@ -378,6 +391,7 @@ defmodule Mix.Project do
defp default_config do
[aliases: [],
build_per_environment: true,
build_embedded: false,
default_task: "run",
deps: [],
deps_path: "deps",
@@ -386,7 +400,8 @@ defmodule Mix.Project do
erlc_include_path: "include",
erlc_options: [:debug_info],
lockfile: "mix.lock",
preferred_cli_env: []]
preferred_cli_env: [],
start_permanent: false]
end
defp get_project_config(nil), do: []
+48 -16
View File
@@ -1,29 +1,53 @@
defmodule Mix.Tasks.App.Start do
use Mix.Task
@shortdoc "Start all registered apps"
@recursive true
@moduledoc """
Starts all registered apps. If no apps key exists,
it starts the current application.
Starts all registered apps.
The application is started by default as temporary. In case
`:start_permanent` is set to true in your prject configuration
or the `--permanent` flag is given, it is started as permanent,
which guarantee the node will shutdown in case the application
crashes permanently.
## Command line options
* `--force` - force compilation regardless of compilation times
* `--no-compile` - do not compile even if files require compilation
* `--force` - force compilation regardless of compilation times
* `--temporary` - start the application as temporary
* `--permanent` - start the application as permanent
* `--no-compile` - do not compile even if files require compilation
* `--no-protocols` - do not load consolidated protocols
* `--no-deps-check` - do not check dependencies
* `--no-elixir-version-check`
- do not check elixir version
* `--no-start` - do not start applications after compilation
* `--no-elixir-version-check` - do not check elixir version
* `--no-start` - do not start applications after compilation
"""
@spec run(OptionParser.argv) :: :ok
def run(args) do
Mix.Project.get!
Mix.Task.run "loadpaths", ["--no-readd"|args]
{opts, _, _} = OptionParser.parse args, switches: [permanent: :boolean, temporary: :boolean]
Mix.Task.run "loadpaths", args
unless "--no-compile" in args do
Mix.Task.run "compile", ["--no-readd"|args]
Mix.Task.run "compile", args
end
unless "--no-protocols" in args do
path = Path.join(Mix.Project.build_path, "consolidated")
if File.dir?(path) do
Code.prepend_path(path)
Enum.each(File.ls!(path), fn file ->
module = file |> Path.rootname() |> String.to_atom()
:code.purge(module)
:code.delete(module)
end)
end
end
unless "--no-start" in args do
@@ -32,17 +56,15 @@ defmodule Mix.Tasks.App.Start do
# or not.
#
# Mix should not depend directly on Logger so check that it's loaded.
if Code.ensure_loaded?(Logger), do: Logger.App.stop()
start(Mix.Project.config[:app])
if Process.whereis(Logger), do: Logger.App.stop()
start(Mix.Project.config, opts)
end
Code.readd_paths()
end
@doc false
def start(app) do
if app do
case Application.ensure_all_started(app) do
def start(config, opts) do
if app = config[:app] do
case Application.ensure_all_started(app, type(config, opts)) do
{:ok, _} -> :ok
{:error, {app, reason}} ->
Mix.raise "Could not start application #{app}: " <>
@@ -52,4 +74,14 @@ defmodule Mix.Tasks.App.Start do
:error
end
end
@doc false
def type(config, opts) do
cond do
opts[:temporary] -> :temporary
opts[:permanent] -> :permanent
config[:start_permanent] -> :permanent
true -> :temporary
end
end
end
+22
View File
@@ -0,0 +1,22 @@
defmodule Mix.Tasks.Compile.All do
use Mix.Task
@moduledoc false
@recursive true
# This is an internal task used by mix compile which
# is meant to be recursive and be invoked for each child
# project.
def run(args) do
Mix.Project.get!
res =
Enum.map(Mix.Tasks.Compile.compilers(), fn(compiler) ->
Mix.Task.run("compile.#{compiler}", args)
end)
true = Code.prepend_path(Mix.Project.compile_path)
if :ok in res, do: :ok, else: :noop
end
end
+1 -1
View File
@@ -104,7 +104,7 @@ defmodule Mix.Tasks.Compile.App do
if mods == [], do: Mix.Project.build_structure(config)
File.write!(target, :io_lib.format("~p.", [contents]))
Mix.shell.info "Generated #{app}.app"
Mix.shell.info "Generated #{app} app"
:ok
else
:noop
-1
View File
@@ -65,7 +65,6 @@ defmodule Mix.Tasks.Compile.Elixir do
|| Mix.Utils.stale?(configs, [manifest])
Mix.Compilers.Elixir.compile(manifest, srcs, skip, [:ex], dest, force, fn ->
true = Code.prepend_path(dest)
set_compiler_opts(project, opts, [])
end)
end
+3 -1
View File
@@ -65,6 +65,8 @@ defmodule Mix.Tasks.Compile.Erlang do
opt
end
compile_path = Path.relative_to(compile_path, File.cwd!)
tuples = files
|> scan_sources(include_path, source_paths)
|> sort_dependencies
@@ -165,6 +167,6 @@ defmodule Mix.Tasks.Compile.Erlang do
end
defp module_from_artifact(artifact) do
artifact |> Path.basename |> Path.rootname
artifact |> Path.basename |> Path.rootname |> String.to_atom
end
end
+21 -9
View File
@@ -15,6 +15,12 @@ defmodule Mix.Tasks.Compile do
* `:compilers` - compilers to run, defaults to:
`[:leex, :yeec, :erlang, :elixir, :app]`
* `:consolidate_protocols` - when true, runs protocol
consolidation via the `compile.protocols` task
* `:build_embedded` - when true, activates protocol
consolidation and does not generate symlinks in builds
## Command line options
* `--list` - list all enabled compilers
@@ -47,21 +53,22 @@ defmodule Mix.Tasks.Compile do
shell.info format('mix ~-#{max}s # ~ts', [task, doc])
end
shell.info "\nEnabled compilers: #{Enum.join compilers(), ", "}"
compilers = compilers() ++ if(consolidate_protocols?(), do: [:protocols], else: [])
shell.info "\nEnabled compilers: #{Enum.join compilers, ", "}"
end
def run(args) do
Mix.Project.get!
Mix.Task.run "loadpaths", ["--no-readd"|args]
Mix.Task.run "loadpaths", args
res =
Enum.map(compilers(), fn(compiler) ->
List.wrap Mix.Task.run("compile.#{compiler}", args)
end)
res = Mix.Task.run "compile.all", args
res = if :ok in List.wrap(res), do: :ok, else: :noop
true = Code.prepend_path(Mix.Project.compile_path)
unless "--no-readd" in args, do: Code.readd_paths()
if Enum.any?(res, &(:ok in &1)), do: :ok, else: :noop
if res == :ok && consolidate_protocols?() do
Mix.Task.run "compile.protocols", args
end
res
end
# Loadpaths without checks because compilers may be defined in deps.
@@ -70,6 +77,11 @@ defmodule Mix.Tasks.Compile do
Mix.Task.reenable "loadpaths"
end
defp consolidate_protocols? do
config = Mix.Project.config
Keyword.get(config, :consolidate_protocols, config[:build_embedded])
end
@doc """
Returns all compilers.
"""
+16 -11
View File
@@ -1,21 +1,26 @@
defmodule Mix.Tasks.Compile.Protocols do
use Mix.Task
@recursive true
@shortdoc "Consolidates all protocols in all paths"
@moduledoc ~S"""
Consolidates all protocols in all paths.
This module consolidates all protocols in the code path
and output the new binary files to the given directory
(defaults to "consolidated").
This task is automatically invoked whenever the project
enables `:consolidate_protocols` or `:build_embedded` in
its configuration.
A new directory will be created with the consolidated
protocol versions in the build directory for the given
environment. Simply add it to your loadpath to make use
of it according to your MIX_ENV:
## Consolidation
Protocol consolidation is useful in production when no
dynamic code loading will happen, effectively optimizing
protocol dispatches by not accounting for code loading.
This task consolidates all protocols in the code path
and output the new binary files to the given directory
(defaults to "_build/MIX_ENV/consolidated").
In case you are manually compiling protocols or building
releases, you need to take the generated protocols into
account. This can be done with:
$ elixir -pa _build/MIX_ENV/consolidated -S mix run
+1 -1
View File
@@ -84,7 +84,7 @@ defmodule Mix.Tasks.Deps.Check do
to_prune = Enum.reduce(all, paths, &(&2 -- Mix.Dep.load_paths(&1)))
Enum.map(to_prune, fn path ->
# Path may not be in code path
# Path cannot be in code path when deleting
_ = Code.delete_path(path)
File.rm_rf!(path |> Path.dirname)
end)
+1 -1
View File
@@ -102,7 +102,7 @@ defmodule Mix.Tasks.Deps.Compile do
end
try do
res = Mix.Task.run("compile", ["--no-deps", "--no-elixir-version-check", "--no-readd"])
res = Mix.Task.run("compile", ["--no-deps", "--no-elixir-version-check"])
:ok in List.wrap(res)
catch
kind, reason ->
+4 -15
View File
@@ -48,11 +48,6 @@ defmodule Mix.Tasks.Escript.Build do
Defaults to `true` for Elixir projects.
* `:consolidate_protocols` - if `true`, all protocols will be consolidated
before being embedded into the escript.
Defaults to `true` for Elixir projects.
* `:shebang` - shebang interpreter directive used to execute the escript.
Defaults to `"#! /usr/bin/env escript\n"`.
@@ -93,19 +88,13 @@ defmodule Mix.Tasks.Escript.Build do
Mix.Task.run :compile, args
end
project = Mix.Project.config
project = Mix.Project.config
language = Keyword.get(project, :language, :elixir)
should_consolidate =
Keyword.get(project, :consolidate_protocols, language == :elixir)
if should_consolidate do
Mix.Task.run "compile.protocols", []
end
escriptize(project, language, opts[:force], should_consolidate)
escriptize(project, language, opts[:force])
end
defp escriptize(project, language, force, should_consolidate) do
defp escriptize(project, language, force) do
escript_opts = project[:escript] || []
script_name = to_string(escript_opts[:name] || project[:app])
@@ -131,7 +120,7 @@ defmodule Mix.Tasks.Escript.Build do
|> Stream.concat
|> prepare_beam_paths
if should_consolidate do
if Keyword.get(project, :consolidate_protocols, project[:build_embedded]) do
beam_paths =
Path.wildcard(consolidated_path <> "/*")
|> prepare_beam_paths(beam_paths)
+41 -18
View File
@@ -8,10 +8,11 @@ defmodule Mix.Tasks.Help do
## Arguments
mix help - prints all tasks and their shortdoc
mix help TASK - prints full docs for the given task
mix help --names - prints all task names and aliases
(useful for autocompleting)
mix help - prints all tasks and their shortdoc
mix help TASK - prints full docs for the given task
mix help --search PATTERN - prints all tasks that contain PATTERN in the name
mix help --names - prints all task names and aliases
(useful for autocompleting)
## Colors
@@ -40,24 +41,12 @@ defmodule Mix.Tasks.Help do
def run([]) do
loadpaths!
shell = Mix.shell
modules = Mix.Task.load_all()
docs = for module <- modules,
doc = Mix.Task.shortdoc(module) do
{"mix " <> Mix.Task.task_name(module), doc}
end
max = Enum.reduce docs, 0, fn({task, _}, acc) ->
max(byte_size(task), acc)
end
{docs, max} = build_task_doc_list(modules)
display_default_task_doc(max)
Enum.each Enum.sort(docs), fn({task, doc}) ->
shell.info format_task(task, max, doc)
end
display_task_doc_list(docs, max)
display_iex_task_doc(max)
end
@@ -78,6 +67,22 @@ defmodule Mix.Tasks.Help do
end
end
def run(["--search", pattern]) do
loadpaths!
modules =
Mix.Task.load_all()
|> Enum.filter(&(String.contains?(Mix.Task.task_name(&1), pattern)))
{docs, max} = build_task_doc_list(modules)
display_task_doc_list(docs, max)
end
def run(["--search"]) do
Mix.raise "Unexpected arguments, expected `mix help --search PATTERN`"
end
def run([task]) do
loadpaths!
@@ -147,4 +152,22 @@ defmodule Mix.Tasks.Help do
Mix.shell.info format_task("iex -S mix", max,
"Start IEx and run the default task")
end
defp display_task_doc_list(docs, max) do
Enum.each Enum.sort(docs), fn({task, doc}) ->
Mix.shell.info format_task(task, max, doc)
end
end
defp build_task_doc_list(modules) do
Enum.reduce modules, {[], 0}, fn module, {docs, max} ->
doc = Mix.Task.shortdoc(module)
if doc do
task = "mix " <> Mix.Task.task_name(module)
docs = [{task, doc} | docs]
max = max(byte_size(task), max)
end
{docs, max}
end
end
end
-4
View File
@@ -29,10 +29,6 @@ defmodule Mix.Tasks.Loadpaths do
load_project(config, args)
end
unless "--no-readd" in args do
Code.readd_paths()
end
:ok
end
+6
View File
@@ -207,6 +207,8 @@ defmodule Mix.Tasks.New do
[app: :<%= @app %>,
version: "0.0.1",
elixir: "~> <%= @version %>",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
deps: deps]
end
@@ -242,6 +244,8 @@ defmodule Mix.Tasks.New do
deps_path: "../../deps",
lockfile: "../../mix.lock",
elixir: "~> <%= @version %>",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
deps: deps]
end
@@ -277,6 +281,8 @@ defmodule Mix.Tasks.New do
def project do
[apps_path: "apps",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
deps: deps]
end
+2 -2
View File
@@ -434,7 +434,7 @@ defmodule Mix.Utils do
# Starting a http client profile allows us to scope
# the effects of using a http proxy to this function
{:ok, pid} = :inets.start(:httpc, [{:profile, :mix}])
{:ok, _pid} = :inets.start(:httpc, [{:profile, :mix}])
headers = [{'user-agent', 'Mix/#{System.version}'}]
request = {:binary.bin_to_list(path), headers}
@@ -476,7 +476,7 @@ defmodule Mix.Utils do
if uri.host && uri.port do
host = String.to_char_list(uri.host)
:httpc.set_options([{proxy_scheme(uri.scheme), {{host, uri.port}, []}}], :hex)
:httpc.set_options([{proxy_scheme(uri.scheme), {{host, uri.port}, []}}], :mix)
end
end
+2 -1
View File
@@ -1,6 +1,7 @@
-module(b).
-compile(export_all).
-callback c() -> term().
-record(br, {cell=undefined}).
b() -> #br{cell=specified}.
b() -> #br{cell=specified}.
+1
View File
@@ -2,5 +2,6 @@
-compile(export_all).
-include("r.hrl").
-behaviour(b).
c() -> #r{cell=specified}.
-3
View File
@@ -1,3 +0,0 @@
defprotocol DepProto do
def hello(x)
end
-9
View File
@@ -1,9 +0,0 @@
defmodule DepProto.Mixfile do
use Mix.Project
def project do
[ app: :depproto,
version: "0.1.0" ]
end
end
+23 -46
View File
@@ -3,38 +3,6 @@ Code.require_file "../test_helper.exs", __DIR__
defmodule Mix.CLITest do
use MixTest.Case
test "env and path configs" do
in_fixture "no_mixfile", fn ->
File.write! "custom.exs", """
defmodule P do
use Mix.Project
def project, do: [app: :p, version: "0.1.0"]
end
"""
System.put_env("MIX_ENV", "prod")
System.put_env("MIX_EXS", "custom.exs")
# Emulate protocol consolidation
File.mkdir_p!("_build/prod/consolidated")
{output, _status} =
System.cmd elixir_executable,
["-pa", "_build/prod/consolidated",
mix_executable, "run",
"-e", "IO.inspect {Mix.env, System.argv}",
"-e", "IO.inspect hd(:code.get_path)",
"--", "1", "2", "3"]
System.delete_env("MIX_ENV")
System.delete_env("MIX_EXS")
assert output =~ "Compiled lib/a.ex"
assert output =~ ~s({:prod, ["1", "2", "3"]})
assert output =~ ~s('#{Path.expand("_build/prod/consolidated")}')
end
end
test "default task" do
in_fixture "no_mixfile", fn ->
File.write! "mix.exs", """
@@ -49,20 +17,6 @@ defmodule Mix.CLITest do
end
end
test "custom mix.exs" do
in_fixture "no_mixfile", fn ->
File.write! "mix.exs", """
defmodule P do
use Mix.Project
def project, do: [app: :p]
end
"""
output = mix ~w[]
assert File.regular?("_build/dev/lib/p/ebin/Elixir.A.beam")
assert output =~ "Compiled lib/a.ex"
end
end
test "compiles and invokes simple task from CLI" do
in_fixture "no_mixfile", fn ->
File.mkdir_p!("lib")
@@ -121,6 +75,29 @@ defmodule Mix.CLITest do
end
end
test "env config" do
in_fixture "no_mixfile", fn ->
File.write! "custom.exs", """
defmodule P do
use Mix.Project
def project, do: [app: :p, version: "0.1.0"]
end
"""
System.put_env("MIX_ENV", "prod")
System.put_env("MIX_EXS", "custom.exs")
output = mix ["run", "-e", "IO.inspect {Mix.env, System.argv}",
"--", "1", "2", "3"]
assert output =~ "Compiled lib/a.ex"
assert output =~ ~s({:prod, ["1", "2", "3"]})
end
after
System.delete_env("MIX_ENV")
System.delete_env("MIX_EXS")
end
test "new with tests" do
in_tmp "new_with_tests", fn ->
output = mix ~w[new .]
+10 -1
View File
@@ -63,7 +63,16 @@ defmodule Mix.ProjectTest do
end
end
test "builds the project structure with ebin symlink" do
test "builds the project structure without symlinks" do
in_fixture "archive", fn ->
config = [app_path: Path.expand("_build/archive"), build_embedded: true]
assert Mix.Project.build_structure(config) == :ok
assert File.dir?("_build/archive/ebin")
assert {:error, _} = :file.read_link("_build/archive/ebin")
end
end
test "builds the project structure with symlinks" do
in_fixture "archive", fn ->
config = [app_path: Path.expand("_build/archive")]
File.mkdir_p!("include")
+41 -20
View File
@@ -5,7 +5,7 @@ defmodule Mix.Tasks.App.StartTest do
defmodule AppStartSample do
def project do
[app: :app_start_sample, version: "0.1.0"]
[app: :app_start_sample, version: "0.1.0", start_permanent: true]
end
def application do
@@ -89,7 +89,14 @@ defmodule Mix.Tasks.App.StartTest do
end
test "start does nothing if app is nil" do
assert Mix.Tasks.App.Start.start(nil) == :error
assert Mix.Tasks.App.Start.start([app: nil], []) == :error
end
test "allows type to be configured" do
assert Mix.Tasks.App.Start.type([], [permanent: true]) == :permanent
assert Mix.Tasks.App.Start.type([], [temporary: true]) == :temporary
assert Mix.Tasks.App.Start.type([start_permanent: true], []) == :permanent
assert Mix.Tasks.App.Start.type([], []) == :temporary
end
defmodule ReturnSample do
@@ -115,9 +122,12 @@ defmodule Mix.Tasks.App.StartTest do
Process.put(:application_definition, mod: {ReturnApp, {:error, :bye}})
Mix.Tasks.Compile.run []
assert_raise Mix.Error, "Could not start application return_sample: Mix.Tasks.App.StartTest.ReturnApp.start(:normal, {:error, :bye}) returned an error: :bye",
fn ->
Mix.Tasks.App.Start.start(:return_sample)
message = "Could not start application return_sample: " <>
"Mix.Tasks.App.StartTest.ReturnApp.start(:normal, {:error, :bye}) " <>
"returned an error: :bye"
assert_raise Mix.Error, message, fn ->
Mix.Tasks.App.Start.start([app: :return_sample], [])
end
end
end
@@ -130,10 +140,14 @@ defmodule Mix.Tasks.App.StartTest do
{:badarg, [{ReturnApp, :start, 2, []}] }}})
Mix.Tasks.Compile.run []
assert_raise Mix.Error, "Could not start application return_sample: Mix.Tasks.App.StartTest.ReturnApp.start(:normal, {:error, {:badarg, [{Mix.Tasks.App.StartTest.ReturnApp, :start, 2, []}]}}) returned an error: an exception was raised:\n" <>
" ** (ArgumentError) argument error\n" <>
" Mix.Tasks.App.StartTest.ReturnApp.start/2", fn ->
Mix.Tasks.App.Start.start(:return_sample)
message = "Could not start application return_sample: " <>
"Mix.Tasks.App.StartTest.ReturnApp.start(:normal, {:error, {:badarg, [{Mix.Tasks.App.StartTest.ReturnApp, :start, 2, []}]}}) " <>
"returned an error: an exception was raised:\n" <>
" ** (ArgumentError) argument error\n" <>
" Mix.Tasks.App.StartTest.ReturnApp.start/2"
assert_raise Mix.Error, message, fn ->
Mix.Tasks.App.Start.start([app: :return_sample], [])
end
end
end
@@ -145,9 +159,12 @@ defmodule Mix.Tasks.App.StartTest do
Process.put(:application_definition, mod: {ReturnApp, :bad})
Mix.Tasks.Compile.run []
assert_raise Mix.Error, "Could not start application return_sample: Mix.Tasks.App.StartTest.ReturnApp.start(:normal, :bad) returned a bad value: :bad",
fn ->
Mix.Tasks.App.Start.start(:return_sample)
message = "Could not start application return_sample: " <>
"Mix.Tasks.App.StartTest.ReturnApp.start(:normal, :bad) " <>
"returned a bad value: :bad"
assert_raise Mix.Error, message, fn ->
Mix.Tasks.App.Start.start([app: :return_sample], [])
end
end
end
@@ -175,10 +192,12 @@ defmodule Mix.Tasks.App.StartTest do
Process.put(:application_definition, mod: {ExitApp, :bye})
Mix.Tasks.Compile.run []
assert_raise Mix.Error, "Could not start application exit_sample: exited in: Mix.Tasks.App.StartTest.ExitApp.start(:normal, :bye)\n" <>
" ** (EXIT) :bye",
fn ->
Mix.Tasks.App.Start.start(:exit_sample)
message = "Could not start application exit_sample: exited in: " <>
"Mix.Tasks.App.StartTest.ExitApp.start(:normal, :bye)\n" <>
" ** (EXIT) :bye"
assert_raise Mix.Error, message, fn ->
Mix.Tasks.App.Start.start([app: :exit_sample], [])
end
end
end
@@ -190,10 +209,12 @@ defmodule Mix.Tasks.App.StartTest do
Process.put(:application_definition, mod: {ExitApp, :normal})
Mix.Tasks.Compile.run []
assert_raise Mix.Error, "Could not start application exit_sample: exited in: Mix.Tasks.App.StartTest.ExitApp.start(:normal, :normal)\n" <>
" ** (EXIT) normal",
fn ->
Mix.Tasks.App.Start.start(:exit_sample)
message = "Could not start application exit_sample: exited in: " <>
"Mix.Tasks.App.StartTest.ExitApp.start(:normal, :normal)\n" <>
" ** (EXIT) normal"
assert_raise Mix.Error, message, fn ->
Mix.Tasks.App.Start.start([app: :exit_sample], [])
end
end
end
+19 -1
View File
@@ -8,7 +8,7 @@ defmodule Mix.Tasks.Compile.ElixirTest do
:ok
end
test "compiles a project" do
test "compiles a project without per environment build" do
Mix.Project.pop
Mix.ProjectStack.post_config [build_per_environment: false]
Mix.Project.push MixTest.Case.Sample
@@ -40,6 +40,24 @@ defmodule Mix.Tasks.Compile.ElixirTest do
end
end
test "recompiles project if elixir version changed" do
in_fixture "no_mixfile", fn ->
Mix.Tasks.Compile.run []
purge [A, B, C]
assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
assert System.version == Mix.Dep.Lock.elixir_vsn
Mix.Task.clear
File.write!("_build/dev/lib/sample/.compile.lock", "the_past")
File.touch!("_build/dev/lib/sample/.compile.lock", {{2010, 1, 1}, {0, 0, 0}})
Mix.Tasks.Compile.run []
assert System.version == Mix.Dep.Lock.elixir_vsn
assert File.stat!("_build/dev/lib/sample/.compile.lock").mtime > {{2010, 1, 1}, {0, 0, 0}}
end
end
test "does not write beam down on failures" do
import ExUnit.CaptureIO
@@ -36,6 +36,10 @@ defmodule Mix.Tasks.Compile.ErlangTest do
assert File.regular?("_build/dev/lib/sample/ebin/b.beam")
assert File.regular?("_build/dev/lib/sample/ebin/c.beam")
assert File.read!("_build/dev/lib/sample/.compile.erlang") ==
"_build/dev/lib/sample/ebin/b.beam\n" <>
"_build/dev/lib/sample/ebin/c.beam"
assert Mix.Tasks.Compile.Erlang.run([]) == :noop
refute_received {:mix_shell, :info, ["Compiled src/b.erl"]}
+30 -22
View File
@@ -9,18 +9,26 @@ defmodule Mix.Tasks.CompileTest do
end
end
defmodule Consolidation do
def project do
[app: :consolidation,
version: "0.1.0",
consolidate_protocols: true]
end
end
setup do
Mix.Project.push MixTest.Case.Sample
:ok
end
test "mix compile --list with mixfile" do
test "compile --list with mixfile" do
Mix.Tasks.Compile.run ["--list"]
assert_received {:mix_shell, :info, ["\nEnabled compilers: yecc, leex, erlang, elixir, app"]}
assert_received {:mix_shell, :info, ["mix compile.elixir # " <> _]}
end
test "mix compile --list with custom mixfile" do
test "compile --list with custom mixfile" do
Mix.Project.push CustomCompilers
Mix.Tasks.Compile.run ["--list"]
assert_received {:mix_shell, :info, ["\nEnabled compilers: elixir, app, custom"]}
@@ -28,14 +36,32 @@ defmodule Mix.Tasks.CompileTest do
test "compile a project with mixfile" do
in_fixture "no_mixfile", fn ->
Mix.Tasks.Compile.run []
assert Mix.Tasks.Compile.run([]) == :ok
assert File.regular?("_build/dev/lib/sample/ebin/Elixir.A.beam")
assert File.regular?("_build/dev/lib/sample/ebin/sample.app")
assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
assert_received {:mix_shell, :info, ["Generated sample.app"]}
assert_received {:mix_shell, :info, ["Generated sample app"]}
end
end
test "compile a project with protocol consolidation" do
Mix.Project.push Consolidation
in_fixture "no_mixfile", fn ->
assert Mix.Tasks.Compile.run([]) == :ok
assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
assert_received {:mix_shell, :info, ["Consolidated Enumerable"]}
assert File.regular? "_build/dev/consolidated/Elixir.Enumerable.beam"
assert Mix.Tasks.Compile.run([]) == :noop
refute_received {:mix_shell, :info, ["Consolidated Enumerable"]}
assert Mix.Tasks.App.Start.run([]) == :ok
assert Protocol.consolidated?(Enumerable)
end
after
purge [Enumerable]
end
test "compile a project with multiple compilers and a syntax error in an erlang file" do
in_fixture "no_mixfile", fn ->
import ExUnit.CaptureIO
@@ -56,22 +82,4 @@ defmodule Mix.Tasks.CompileTest do
refute File.regular?("ebin/Elixir.C.beam")
end
end
test "recompiles project if elixir version changed" do
in_fixture "no_mixfile", fn ->
Mix.Tasks.Compile.run []
purge [A, B, C]
assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
assert System.version == Mix.Dep.Lock.elixir_vsn
Mix.Task.clear
File.write!("_build/dev/lib/sample/.compile.lock", "the_past")
File.touch!("_build/dev/lib/sample/.compile.lock", {{2010, 1, 1}, {0, 0, 0}})
Mix.Tasks.Compile.run []
assert System.version == Mix.Dep.Lock.elixir_vsn
assert File.stat!("_build/dev/lib/sample/.compile.lock").mtime > {{2010, 1, 1}, {0, 0, 0}}
end
end
end
+6 -2
View File
@@ -100,7 +100,11 @@ defmodule Mix.Tasks.DepsGitTest do
assert File.exists?("deps/git_repo/mix.exs")
assert File.rm("deps/git_repo/.fetch") == :ok
Mix.Tasks.Deps.Update.run ["deps_on_git_repo"]
# Compile the dependencies
Mix.Tasks.Deps.Compile.run []
# Now update children and make sure it propagates
Mix.Tasks.Deps.Update.run ["git_repo"]
assert File.exists?("deps/deps_on_git_repo/.fetch")
assert File.exists?("deps/git_repo/.fetch")
@@ -109,7 +113,7 @@ defmodule Mix.Tasks.DepsGitTest do
assert File.exists?("_build/dev/lib/git_repo/ebin")
Code.delete_path("_build/dev/lib/git_repo/ebin")
# Deps on git repo loads it automatically on compile.
# Deps on git repo loads it automatically on compile
Mix.Task.reenable "deps.loadpaths"
Mix.Tasks.Deps.Compile.run ["deps_on_git_repo"]
assert File.exists?("_build/dev/lib/deps_on_git_repo/ebin")
+11 -23
View File
@@ -34,10 +34,7 @@ defmodule Mix.Tasks.EscriptTest do
def project do
[ app: :escripttestwithdeps,
version: "0.0.1",
escript: [
main_module: Escripttest,
path: Path.join("ebin", "escripttestwithdeps"),
],
escript: [main_module: Escripttest],
deps: [{:ok, path: fixture_path("deps_status/deps/ok")}] ]
end
end
@@ -47,10 +44,7 @@ defmodule Mix.Tasks.EscriptTest do
[ app: :escripttesterlangwithdeps,
version: "0.0.1",
language: :erlang,
escript: [
main_module: :escripttest,
path: Path.join("ebin", "escripttesterlangwithdeps"),
],
escript: [main_module: :escripttest],
deps: [{:ok, path: fixture_path("deps_status/deps/ok")}] ]
end
end
@@ -58,12 +52,9 @@ defmodule Mix.Tasks.EscriptTest do
defmodule EscriptConsolidated do
def project do
[ app: :escripttestconsolidated,
build_embedded: true,
version: "0.0.1",
escript: [
main_module: Escripttest,
path: Path.join("ebin", "escripttestconsolidated"),
],
deps: [{:depproto, path: fixture_path("dep_with_protocol")}] ]
escript: [main_module: Escripttest] ]
end
end
@@ -109,20 +100,20 @@ defmodule Mix.Tasks.EscriptTest do
in_fixture "escripttest", fn ->
Mix.Tasks.Escript.Build.run []
assert_received {:mix_shell, :info, ["Generated escript ebin/escripttestwithdeps with MIX_ENV=dev"]}
assert System.cmd("escript", ["ebin/escripttestwithdeps"]) == {"TEST\n", 0}
assert_received {:mix_shell, :info, ["Generated escript escripttestwithdeps with MIX_ENV=dev"]}
assert System.cmd("escript", ["escripttestwithdeps"]) == {"TEST\n", 0}
end
after
purge [Ok.Mixfile]
end
test "generate Erlang escript with config and deps" do
test "generate escript with erlang and deps" do
Mix.Project.push EscriptErlangWithDeps
in_fixture "escripttest", fn ->
Mix.Tasks.Escript.Build.run []
assert_received {:mix_shell, :info, ["Generated escript ebin/escripttesterlangwithdeps with MIX_ENV=dev"]}
assert System.cmd("escript", ["ebin/escripttesterlangwithdeps"]) == {"Erlang value", 0}
assert_received {:mix_shell, :info, ["Generated escript escripttesterlangwithdeps with MIX_ENV=dev"]}
assert System.cmd("escript", ["escripttesterlangwithdeps"]) == {"Erlang value", 0}
end
after
purge [Ok.Mixfile]
@@ -133,11 +124,8 @@ defmodule Mix.Tasks.EscriptTest do
in_fixture "escripttest_protocols", fn ->
Mix.Tasks.Escript.Build.run []
assert_received {:mix_shell, :info, ["Generated escript ebin/escripttestconsolidated with MIX_ENV=dev"]}
assert System.cmd("escript", ["ebin/escripttestconsolidated", "Enumerable"]) == {"true\n", 0}
assert System.cmd("escript", ["ebin/escripttestconsolidated", "DepProto"]) == {"true\n", 0}
assert_received {:mix_shell, :info, ["Generated escript escripttestconsolidated with MIX_ENV=dev"]}
assert System.cmd("escript", ["escripttestconsolidated", "Enumerable"]) == {"true\n", 0}
end
after
purge [DepProto.Mixfile]
end
end
+25
View File
@@ -56,6 +56,31 @@ defmodule Mix.Tasks.HelpTest do
end
end
test "help --search PATTERN" do
in_fixture "no_mixfile", fn ->
Mix.Tasks.Help.run ["--search", "deps"]
assert_received {:mix_shell, :info, ["mix deps" <> _]}
assert_received {:mix_shell, :info, ["mix deps.clean" <> _]}
end
end
test "help --search without pattern" do
assert_raise Mix.Error, "Unexpected arguments, expected `mix help --search PATTERN`", fn ->
Mix.Tasks.Help.run ["--search"]
end
end
test "help --search without results" do
in_fixture "no_mixfile", fn ->
output =
capture_io fn ->
Mix.Tasks.Help.run ["--search", "foo"]
end
assert output == ""
end
end
test "bad arguments" do
assert_raise Mix.Error, "Unexpected arguments, expected `mix help` or `mix help TASK`", fn ->
Mix.Tasks.Help.run ["foo", "bar"]
-2
View File
@@ -46,8 +46,6 @@ defmodule Mix.Tasks.RunTest do
end
test "run errors on missing files" do
git_repo = fixture_path("git_repo/lib/git_repo.ex")
in_fixture "no_mixfile", fn ->
assert_raise Mix.Error, "No files matched pattern \"non-existent\" given to --require", fn ->
Mix.Tasks.Run.run ["-r", "non-existent"]
+2 -2
View File
@@ -17,10 +17,10 @@ defmodule Mix.UmbrellaTest do
assert_received {:mix_shell, :info, ["==> bar"]}
assert_received {:mix_shell, :info, ["Compiled lib/bar.ex"]}
assert_received {:mix_shell, :info, ["Generated bar.app"]}
assert_received {:mix_shell, :info, ["Generated bar app"]}
assert_received {:mix_shell, :info, ["==> foo"]}
assert_received {:mix_shell, :info, ["Compiled lib/foo.ex"]}
assert_received {:mix_shell, :info, ["Generated foo.app"]}
assert_received {:mix_shell, :info, ["Generated foo app"]}
# Ensure foo was loaded and in the same env as Mix.env
assert_received {:mix_shell, :info, [":foo env is dev"]}
+2 -4
View File
@@ -1,9 +1,7 @@
{application, elixir,
[{description, "elixir"},
{vsn, "1.0.3"},
{modules, [
elixir
]},
{vsn, "1.0.4"},
{modules, [elixir]},
{registered, [elixir_config, elixir_code_server]},
{applications, [kernel,stdlib,crypto,compiler,syntax_tools]},
{mod, {elixir,[]}},