Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e6d67c169 | ||
|
|
614ae049e6 | ||
|
|
b1492cb0cf | ||
|
|
237a71311c | ||
|
|
e40b280fd8 | ||
|
|
308255bda8 | ||
|
|
1e81a5b9a5 | ||
|
|
0627d7b0d4 | ||
|
|
99ec7522d3 |
@@ -0,0 +1,87 @@
|
||||
name: builds.hex.pm
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- v*.*
|
||||
tags:
|
||||
- v*
|
||||
|
||||
env:
|
||||
ELIXIR_OPTS: "--warnings-as-errors"
|
||||
ERLC_OPTS: "warnings_as_errors"
|
||||
LANG: C.UTF-8
|
||||
|
||||
concurrency: builds_txt
|
||||
|
||||
jobs:
|
||||
release_pre_built:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
include:
|
||||
- otp: 23
|
||||
otp_version: '23.3'
|
||||
build_docs: build_docs
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 50
|
||||
- name: Get tags
|
||||
run: git fetch --tags origin
|
||||
- uses: ./.github/workflows/release_pre_built
|
||||
with:
|
||||
otp_version: ${{ matrix.otp_version }}
|
||||
otp: ${{ matrix.otp }}
|
||||
build_docs: ${{ matrix.build_docs }}
|
||||
- name: Utils.sh
|
||||
run: |
|
||||
cat << 'EOF' > utils.sh
|
||||
function purge_key() {
|
||||
curl \
|
||||
-X POST \
|
||||
-H "Fastly-Key: ${FASTLY_KEY}" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Content-Length: 0" \
|
||||
"https://api.fastly.com/service/$1/purge/$2"
|
||||
}
|
||||
function purge() {
|
||||
purge_key ${FASTLY_REPO_SERVICE_ID} $1
|
||||
purge_key ${FASTLY_BUILDS_SERVICE_ID} $1
|
||||
sleep 2
|
||||
purge_key ${FASTLY_REPO_SERVICE_ID} $1
|
||||
purge_key ${FASTLY_BUILDS_SERVICE_ID} $1
|
||||
sleep 2
|
||||
purge_key ${FASTLY_REPO_SERVICE_ID} $1
|
||||
purge_key ${FASTLY_BUILDS_SERVICE_ID} $1
|
||||
}
|
||||
EOF
|
||||
chmod +x utils.sh
|
||||
- name: Upload Docs to S3
|
||||
if: ${{ matrix.build_docs }}
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.HEX_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.HEX_AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_REGION: ${{ secrets.HEX_AWS_REGION }}
|
||||
AWS_S3_BUCKET: ${{ secrets.HEX_AWS_S3_BUCKET }}
|
||||
FASTLY_REPO_SERVICE_ID: ${{ secrets.HEX_FASTLY_REPO_SERVICE_ID }}
|
||||
FASTLY_BUILDS_SERVICE_ID: ${{ secrets.HEX_FASTLY_BUILDS_SERVICE_ID }}
|
||||
FASTLY_KEY: ${{ secrets.HEX_FASTLY_KEY }}
|
||||
run: |
|
||||
source utils.sh
|
||||
version=$(echo ${{ github.ref_name }} | sed -e 's/^v//g')
|
||||
for f in doc/*; do
|
||||
if [ -d "$f" ]; then
|
||||
app=`echo $f | sed s/"doc\/"//`
|
||||
tarball="${app}-${version}.tar.gz"
|
||||
surrogate_key="docs/${app}-${version}"
|
||||
tar -czf "${tarball}" -C "doc/${app}" .
|
||||
aws s3 cp "${tarball}" "s3://${{ env.AWS_S3_BUCKET }}/docs/${tarball}" \
|
||||
--cache-control "public,max-age=3600" \
|
||||
--metadata "{\"surrogate-key\":\"${surrogate_key}\",\"surrogate-control\":\"public,max-age=604800\"}"
|
||||
purge "${surrogate_key}"
|
||||
fi
|
||||
done
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
otp_release: ['OTP-23.0', 'OTP-22.3', 'OTP-22.0', 'OTP-21.3.8', 'OTP-21.0']
|
||||
otp_release: ['OTP-24.0', 'OTP-23.0', 'OTP-22.3', 'OTP-22.0', 'OTP-21.3.8', 'OTP-21.0']
|
||||
development: [false]
|
||||
include:
|
||||
- otp_release: master
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
name: "Release pre built"
|
||||
description: "Builds elixir release, ExDoc and generates docs"
|
||||
inputs:
|
||||
otp:
|
||||
description: "The major OTP version"
|
||||
otp_version:
|
||||
description: "The exact OTP version (major.minor[.patch])"
|
||||
build_docs:
|
||||
description: "If docs have to be built or not"
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: erlef/setup-beam@v1
|
||||
with:
|
||||
otp-version: ${{ inputs.otp_version }}
|
||||
version-type: strict
|
||||
- name: Build Elixir Release
|
||||
shell: bash
|
||||
run: |
|
||||
make Precompiled.zip
|
||||
mv Precompiled.zip elixir-otp-${{ inputs.otp }}.zip
|
||||
shasum -a 1 elixir-otp-${{ inputs.otp }}.zip > elixir-otp-${{ inputs.otp }}.zip.sha1sum
|
||||
shasum -a 256 elixir-otp-${{ inputs.otp }}.zip > elixir-otp-${{ inputs.otp }}.zip.sha256sum
|
||||
echo "$PWD/bin" >> $GITHUB_PATH
|
||||
- name: Get latest stable ExDoc version
|
||||
if: ${{ inputs.build_docs }}
|
||||
shell: bash
|
||||
run: |
|
||||
EX_DOC_LATEST_STABLE_VERSION=$(curl -s https://hex.pm/api/packages/ex_doc | jq --raw-output '.latest_stable_version')
|
||||
echo "EX_DOC_LATEST_STABLE_VERSION=${EX_DOC_LATEST_STABLE_VERSION}" >> $GITHUB_ENV
|
||||
- uses: actions/checkout@v3
|
||||
if: ${{ inputs.build_docs }}
|
||||
with:
|
||||
repository: elixir-lang/ex_doc
|
||||
ref: v${{ env.EX_DOC_LATEST_STABLE_VERSION }}
|
||||
path: ex_doc
|
||||
- name: Build ex_doc
|
||||
if: ${{ inputs.build_docs }}
|
||||
shell: bash
|
||||
run: |
|
||||
mv ex_doc ../ex_doc
|
||||
cd ../ex_doc
|
||||
../elixir/bin/mix do local.rebar --force, local.hex --force, deps.get, compile
|
||||
cd ../elixir
|
||||
- name: Build Docs
|
||||
if: ${{ inputs.build_docs }}
|
||||
shell: bash
|
||||
run: |
|
||||
make Docs.zip
|
||||
shasum -a 1 Docs.zip > Docs.zip.sha1sum
|
||||
shasum -a 256 Docs.zip > Docs.zip.sha256sum
|
||||
@@ -243,6 +243,21 @@ The Calendar module ships with a new `Calendar.strftime/3` function, which provi
|
||||
|
||||
Mix also includes two new tasks: `mix app.config`, for application runtime configuration, and `mix test.coverage`, which generates aggregated coverage reports for umbrella projects and for test suites partitioned across processes.
|
||||
|
||||
## v1.11.4 (2021-03-16)
|
||||
|
||||
This release introduces fixes for better support of Erlang/OTP 24+.
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
#### Elixir
|
||||
|
||||
* [Kernel] Update formatting when printing warnings and errors from Erlang/OTP 24+
|
||||
* [Kernel] Support float-16 on bitstrings
|
||||
|
||||
#### Mix
|
||||
|
||||
* [mix local.rebar] This task will now install rebar3 version 3.14.4, compiled with Erlang/OTP 21
|
||||
|
||||
## v1.11.3 (2021-01-04)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
@@ -178,40 +178,48 @@ clean_residual_files:
|
||||
|
||||
LOGO_PATH = $(shell test -f ../docs/logo.png && echo "--logo ../docs/logo.png")
|
||||
SOURCE_REF = $(shell tag="$(call GIT_TAG)" revision="$(call GIT_REVISION)"; echo "$${tag:-$$revision}")
|
||||
|
||||
DOCS_FORMAT = html
|
||||
COMPILE_DOCS = bin/elixir ../ex_doc/bin/ex_doc "$(1)" "$(VERSION)" "lib/$(2)/ebin" --main "$(3)" --source-url "https://github.com/elixir-lang/elixir" --source-ref "$(call SOURCE_REF)" $(call LOGO_PATH) --output doc/$(2) --canonical "https://hexdocs.pm/$(2)/$(CANONICAL)" --homepage-url "https://elixir-lang.org/docs.html" --formatter "$(DOCS_FORMAT)" $(4)
|
||||
DOCS_COMPILE = CANONICAL=$(CANONICAL) bin/elixir ../ex_doc/bin/ex_doc "$(1)" "$(VERSION)" "lib/$(2)/ebin" --main "$(3)" --source-url "https://github.com/elixir-lang/elixir" --source-ref "$(call SOURCE_REF)" $(call LOGO_PATH) --output doc/$(2) --canonical "https://hexdocs.pm/$(2)/$(CANONICAL)" --homepage-url "https://elixir-lang.org/docs.html" --formatter "$(DOCS_FORMAT)" $(4)
|
||||
DOCS_CONFIG = bin/elixir lib/elixir/scripts/docs_config.exs "$(1)"
|
||||
|
||||
docs: compile ../ex_doc/bin/ex_doc docs_elixir docs_eex docs_mix docs_iex docs_ex_unit docs_logger
|
||||
|
||||
docs_elixir: compile ../ex_doc/bin/ex_doc
|
||||
@ echo "==> ex_doc (elixir)"
|
||||
$(Q) rm -rf doc/elixir
|
||||
$(call COMPILE_DOCS,Elixir,elixir,Kernel,--config "lib/elixir/docs.exs")
|
||||
$(call DOCS_COMPILE,Elixir,elixir,Kernel,--config "lib/elixir/scripts/elixir_docs.exs")
|
||||
$(call DOCS_CONFIG,elixir)
|
||||
|
||||
docs_eex: compile ../ex_doc/bin/ex_doc
|
||||
@ echo "==> ex_doc (eex)"
|
||||
$(Q) rm -rf doc/eex
|
||||
$(call COMPILE_DOCS,EEx,eex,EEx)
|
||||
$(call DOCS_COMPILE,EEx,eex,EEx,--config "lib/elixir/scripts/mix_docs.exs")
|
||||
$(call DOCS_CONFIG,eex)
|
||||
|
||||
docs_mix: compile ../ex_doc/bin/ex_doc
|
||||
@ echo "==> ex_doc (mix)"
|
||||
$(Q) rm -rf doc/mix
|
||||
$(call COMPILE_DOCS,Mix,mix,Mix)
|
||||
$(call DOCS_COMPILE,Mix,mix,Mix,--config "lib/elixir/scripts/mix_docs.exs")
|
||||
$(call DOCS_CONFIG,mix)
|
||||
|
||||
docs_iex: compile ../ex_doc/bin/ex_doc
|
||||
@ echo "==> ex_doc (iex)"
|
||||
$(Q) rm -rf doc/iex
|
||||
$(call COMPILE_DOCS,IEx,iex,IEx)
|
||||
$(call DOCS_COMPILE,IEx,iex,IEx,--config "lib/elixir/scripts/mix_docs.exs")
|
||||
$(call DOCS_CONFIG,iex)
|
||||
|
||||
docs_ex_unit: compile ../ex_doc/bin/ex_doc
|
||||
@ echo "==> ex_doc (ex_unit)"
|
||||
$(Q) rm -rf doc/ex_unit
|
||||
$(call COMPILE_DOCS,ExUnit,ex_unit,ExUnit)
|
||||
$(call DOCS_COMPILE,ExUnit,ex_unit,ExUnit,--config "lib/elixir/scripts/mix_docs.exs")
|
||||
$(call DOCS_CONFIG,ex_unit)
|
||||
|
||||
docs_logger: compile ../ex_doc/bin/ex_doc
|
||||
@ echo "==> ex_doc (logger)"
|
||||
$(Q) rm -rf doc/logger
|
||||
$(call COMPILE_DOCS,Logger,logger,Logger)
|
||||
$(call DOCS_COMPILE,Logger,logger,Logger,--config "lib/elixir/scripts/mix_docs.exs")
|
||||
$(call DOCS_CONFIG,logger)
|
||||
|
||||
../ex_doc/bin/ex_doc:
|
||||
@ echo "ex_doc is not found in ../ex_doc as expected. See README for more information."
|
||||
@@ -220,23 +228,23 @@ docs_logger: compile ../ex_doc/bin/ex_doc
|
||||
#==> Zip tasks
|
||||
|
||||
Docs.zip: docs
|
||||
rm -f Docs-v$(VERSION).zip
|
||||
zip -9 -r Docs-v$(VERSION).zip CHANGELOG.md doc NOTICE LICENSE README.md
|
||||
@ echo "Docs file created $(CURDIR)/Docs-v$(VERSION).zip"
|
||||
rm -f Docs.zip
|
||||
zip -9 -r Docs.zip CHANGELOG.md doc NOTICE LICENSE README.md
|
||||
@ echo "Docs file created $(CURDIR)/Docs.zip"
|
||||
|
||||
Precompiled.zip: build_man compile
|
||||
rm -f Precompiled-v$(VERSION).zip
|
||||
zip -9 -r Precompiled-v$(VERSION).zip bin CHANGELOG.md lib/*/ebin lib/*/lib LICENSE man NOTICE README.md VERSION
|
||||
@ echo "Precompiled file created $(CURDIR)/Precompiled-v$(VERSION).zip"
|
||||
rm -f Precompiled.zip
|
||||
zip -9 -r Precompiled.zip bin CHANGELOG.md lib/*/ebin lib/*/lib LICENSE man NOTICE README.md VERSION
|
||||
@ echo "Precompiled file created $(CURDIR)/Precompiled.zip"
|
||||
|
||||
zips: Precompiled.zip Docs.zip
|
||||
@ echo ""
|
||||
@ echo "### Checksums"
|
||||
@ echo ""
|
||||
@ shasum -a 1 < Precompiled-v$(VERSION).zip | sed -e "s/-//" | xargs echo " * Precompiled.zip SHA1:"
|
||||
@ shasum -a 512 < Precompiled-v$(VERSION).zip | sed -e "s/-//" | xargs echo " * Precompiled.zip SHA512:"
|
||||
@ shasum -a 1 < Docs-v$(VERSION).zip | sed -e "s/-//" | xargs echo " * Docs.zip SHA1:"
|
||||
@ shasum -a 512 < Docs-v$(VERSION).zip | sed -e "s/-//" | xargs echo " * Docs.zip SHA512:"
|
||||
@ shasum -a 1 < Precompiled.zip | sed -e "s/-//" | xargs echo " * Precompiled.zip SHA1:"
|
||||
@ shasum -a 512 < Precompiled.zip | sed -e "s/-//" | xargs echo " * Precompiled.zip SHA512:"
|
||||
@ shasum -a 1 < Docs.zip | sed -e "s/-//" | xargs echo " * Docs.zip SHA1:"
|
||||
@ shasum -a 512 < Docs.zip | sed -e "s/-//" | xargs echo " * Docs.zip SHA512:"
|
||||
@ echo ""
|
||||
|
||||
#==> Test tasks
|
||||
|
||||
@@ -233,9 +233,9 @@ defmodule Kernel.SpecialForms do
|
||||
|
||||
Sizes for types are a bit more nuanced. The default size for integers is 8.
|
||||
|
||||
For floats, it is 64. For floats, `size * unit` must result in 32 or 64,
|
||||
For floats, it is 64. For floats, `size * unit` must result in 16, 32, or 64,
|
||||
corresponding to [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point)
|
||||
binary32 and binary64, respectively.
|
||||
binary16, binary32, and binary64, respectively.
|
||||
|
||||
For binaries, the default is the size of the binary. Only the last binary in a
|
||||
match can use the default size. All others must have their size specified
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generate docs_config.js for version chooser in ExDoc
|
||||
[app] = System.argv()
|
||||
|
||||
{text_tags, 0} = System.cmd("git", ["tag"])
|
||||
skipped = Version.parse!("1.0.3")
|
||||
|
||||
list_contents =
|
||||
text_tags
|
||||
|> String.split()
|
||||
|> Enum.map(fn "v" <> rest -> Version.parse!(rest) end)
|
||||
|> Enum.filter(&(Version.compare(&1, skipped) == :gt))
|
||||
|> Enum.sort({:desc, Version})
|
||||
|> Enum.map_intersperse(", ", fn version ->
|
||||
version_string = to_string(version)
|
||||
~s[{"version":"v#{version_string}", "url":"https://hexdocs.pm/#{app}/#{version_string}"}]
|
||||
end)
|
||||
|
||||
File.mkdir_p!("doc/#{app}")
|
||||
File.write!("doc/#{app}/docs_config.js", ["var versionNodes = [", list_contents, "];\n"])
|
||||
@@ -0,0 +1,12 @@
|
||||
canonical = System.fetch_env!("CANONICAL")
|
||||
|
||||
[
|
||||
deps: [
|
||||
eex: "https://hexdocs.pm/eex/#{canonical}",
|
||||
elixir: "https://hexdocs.pm/elixir/#{canonical}",
|
||||
ex_unit: "https://hexdocs.pm/ex_unit/#{canonical}",
|
||||
iex: "https://hexdocs.pm/iex/#{canonical}",
|
||||
logger: "https://hexdocs.pm/logger/#{canonical}",
|
||||
mix: "https://hexdocs.pm/mix/#{canonical}"
|
||||
]
|
||||
]
|
||||
@@ -319,8 +319,13 @@ build_spec(Meta, _Size, Unit, Type, _Endianness, Sign, Spec, E) when Type == bin
|
||||
build_spec(Meta, Size, Unit, Type, Endianness, Sign, Spec, E) when Type == integer; Type == float ->
|
||||
NumberSize = number_size(Size, Unit),
|
||||
if
|
||||
Type == float, is_integer(NumberSize), NumberSize /= 32, NumberSize /= 64 ->
|
||||
form_error(Meta, E, ?MODULE, {bittype_float_size, NumberSize});
|
||||
Type == float, is_integer(NumberSize) ->
|
||||
case valid_float_size(NumberSize) of
|
||||
true ->
|
||||
add_spec(Type, add_spec(Endianness, add_spec(Sign, Spec)));
|
||||
false ->
|
||||
form_error(Meta, E, ?MODULE, {bittype_float_size, NumberSize})
|
||||
end;
|
||||
Size == default, Unit /= default ->
|
||||
form_error(Meta, E, ?MODULE, bittype_unit);
|
||||
true ->
|
||||
@@ -331,6 +336,12 @@ number_size(Size, default) when is_integer(Size) -> Size;
|
||||
number_size(Size, Unit) when is_integer(Size) -> Size * Unit;
|
||||
number_size(Size, _) -> Size.
|
||||
|
||||
%% TODO: Simplify when we require OTP 24
|
||||
valid_float_size(16) -> erlang:system_info(otp_release) >= "24";
|
||||
valid_float_size(32) -> true;
|
||||
valid_float_size(64) -> true;
|
||||
valid_float_size(_) -> false.
|
||||
|
||||
add_spec(default, Spec) -> Spec;
|
||||
add_spec(Key, Spec) -> [{Key, [], []} | Spec].
|
||||
|
||||
@@ -372,7 +383,12 @@ format_error(bittype_signed) ->
|
||||
format_error(bittype_unit) ->
|
||||
"integer and float types require a size specifier if the unit specifier is given";
|
||||
format_error({bittype_float_size, Other}) ->
|
||||
io_lib:format("float requires size*unit to be 32 or 64 (default), got: ~p", [Other]);
|
||||
Message =
|
||||
case erlang:system_info(otp_release) >= "24" of
|
||||
true -> "16, 32, or 64";
|
||||
false -> "32 or 64"
|
||||
end,
|
||||
io_lib:format("float requires size*unit to be ~s (default), got: ~p", [Message, Other]);
|
||||
format_error({invalid_literal, Literal}) ->
|
||||
io_lib:format("invalid literal ~ts in <<>>", ['Elixir.Macro':to_string(Literal)]);
|
||||
format_error({undefined_bittype, Expr}) ->
|
||||
|
||||
@@ -94,6 +94,8 @@ handle_file_warning(true, _File, {_Line, sys_core_fold, {nomatch_shadow, _}}) ->
|
||||
|
||||
%% Those we implement ourselves
|
||||
handle_file_warning(_, _File, {_Line, v3_core, {map_key_repeated, _}}) -> ok;
|
||||
handle_file_warning(_, _File, {_Line, sys_core_fold, {ignored, useless_building}}) -> ok;
|
||||
%% TODO: remove when we require Erlang/OTP 24
|
||||
handle_file_warning(_, _File, {_Line, sys_core_fold, useless_building}) -> ok;
|
||||
|
||||
%% Ignore all linting errors (only come up on parse transforms)
|
||||
@@ -112,11 +114,11 @@ handle_file_error(File, {Line, Module, Desc}) ->
|
||||
elixir_errors:compile_error([{line, Line}], File, Message).
|
||||
|
||||
%% Mention the capture operator in make_fun
|
||||
custom_format(sys_core_fold, {no_effect, {erlang, make_fun, 3}}) ->
|
||||
custom_format(sys_core_fold, {ignored, {no_effect, {erlang, make_fun, 3}}}) ->
|
||||
"the result of the capture operator & (:erlang.make_fun/3) is never used";
|
||||
|
||||
%% Make no_effect clauses pretty
|
||||
custom_format(sys_core_fold, {no_effect, {erlang, F, A}}) ->
|
||||
custom_format(sys_core_fold, {ignored, {no_effect, {erlang, F, A}}}) ->
|
||||
{Fmt, Args} = case erl_internal:comp_op(F, A) of
|
||||
true -> {"use of operator ~ts has no effect", [elixir_utils:erlang_comparison_op_to_elixir(F)]};
|
||||
false ->
|
||||
@@ -127,16 +129,11 @@ custom_format(sys_core_fold, {no_effect, {erlang, F, A}}) ->
|
||||
end,
|
||||
io_lib:format(Fmt, Args);
|
||||
|
||||
%% Rewrite nomatch_guard to be more generic it can happen inside if, unless, and the like
|
||||
custom_format(sys_core_fold, nomatch_guard) ->
|
||||
%% Rewrite nomatch to be more generic, it can happen inside if, unless, and the like
|
||||
custom_format(sys_core_fold, {nomatch, X}) when X == guard; X == no_clause ->
|
||||
"this check/guard will always yield the same result";
|
||||
|
||||
%% Handle literal eval failures
|
||||
custom_format(sys_core_fold, {eval_failure, Error}) ->
|
||||
#{'__struct__' := Struct} = 'Elixir.Exception':normalize(error, Error),
|
||||
["this expression will fail with ", elixir_aliases:inspect(Struct)];
|
||||
|
||||
custom_format(sys_core_fold, {nomatch_shadow,Line,{ErlName,ErlArity}}) ->
|
||||
custom_format(sys_core_fold, {nomatch, {shadow, Line, {ErlName, ErlArity}}}) ->
|
||||
{Name, Arity} = elixir_utils:erl_fa_to_elixir_fa(ErlName, ErlArity),
|
||||
|
||||
io_lib:format(
|
||||
@@ -144,6 +141,28 @@ custom_format(sys_core_fold, {nomatch_shadow,Line,{ErlName,ErlArity}}) ->
|
||||
[Name, Arity, Line]
|
||||
);
|
||||
|
||||
%% Handle literal eval failures
|
||||
custom_format(sys_core_fold, {failed, {eval_failure, {Mod, Name, Arity}, Error}}) ->
|
||||
#{'__struct__' := Struct} = 'Elixir.Exception':normalize(error, Error),
|
||||
{ExMod, ExName, ExArgs} = elixir_rewrite:erl_to_ex(Mod, Name, lists:duplicate(Arity, nil)),
|
||||
Call = 'Elixir.Exception':format_mfa(ExMod, ExName, length(ExArgs)),
|
||||
Trimmed = case Call of
|
||||
<<"Kernel.", Rest/binary>> -> Rest;
|
||||
_ -> Call
|
||||
end,
|
||||
["the call to ", Trimmed, " will fail with ", elixir_aliases:inspect(Struct)];
|
||||
|
||||
%% TODO: remove when we require OTP 24
|
||||
custom_format(sys_core_fold, {nomatch_shadow, Line, FA}) ->
|
||||
custom_format(sys_core_fold, {nomatch, {shadow, Line, FA}});
|
||||
custom_format(sys_core_fold, nomatch_guard) ->
|
||||
custom_format(sys_core_fold, {nomatch, guard});
|
||||
custom_format(sys_core_fold, {no_effect, X}) ->
|
||||
custom_format(sys_core_fold, {ignored, {no_effect, X}});
|
||||
custom_format(sys_core_fold, {eval_failure, Error}) ->
|
||||
#{'__struct__' := Struct} = 'Elixir.Exception':normalize(error, Error),
|
||||
["this expression will fail with ", elixir_aliases:inspect(Struct)];
|
||||
|
||||
custom_format([], Desc) ->
|
||||
io_lib:format("~p", [Desc]);
|
||||
|
||||
|
||||
@@ -446,11 +446,12 @@ defmodule ExceptionTest do
|
||||
* min/1
|
||||
"""
|
||||
|
||||
assert blame_message(:erlang, & &1.gt_cookie()) == """
|
||||
function :erlang.gt_cookie/0 is undefined or private. Did you mean one of:
|
||||
assert blame_message(:erlang, & &1.hal()) == """
|
||||
function :erlang.hal/0 is undefined or private. Did you mean one of:
|
||||
|
||||
* get_cookie/0
|
||||
* set_cookie/2
|
||||
* halt/0
|
||||
* halt/1
|
||||
* halt/2
|
||||
"""
|
||||
end
|
||||
|
||||
|
||||
@@ -2387,17 +2387,49 @@ defmodule Kernel.ExpansionTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "raises for invalid size * unit for floats" do
|
||||
message = ~r"float requires size\*unit to be 32 or 64 \(default\), got: 128"
|
||||
# TODO: Simplify when we require OTP 24
|
||||
if System.otp_release() >= "24" do
|
||||
test "16-bit floats" do
|
||||
import Kernel, except: [-: 2]
|
||||
|
||||
assert_raise CompileError, message, fn ->
|
||||
expand(quote(do: <<12.3::32*4>>))
|
||||
assert expand(quote(do: <<12.3::float-16>>)) |> clean_meta([:alignment]) ==
|
||||
quote(do: <<12.3::float()-size(16)>>)
|
||||
end
|
||||
|
||||
message = ~r"float requires size\*unit to be 32 or 64 \(default\), got: 256"
|
||||
test "raises for invalid size * unit for floats" do
|
||||
message = ~r"float requires size\*unit to be 16, 32, or 64 \(default\), got: 128"
|
||||
|
||||
assert_raise CompileError, message, fn ->
|
||||
expand(quote(do: <<12.3::256>>))
|
||||
assert_raise CompileError, message, fn ->
|
||||
expand(quote(do: <<12.3::32*4>>))
|
||||
end
|
||||
|
||||
message = ~r"float requires size\*unit to be 16, 32, or 64 \(default\), got: 256"
|
||||
|
||||
assert_raise CompileError, message, fn ->
|
||||
expand(quote(do: <<12.3::256>>))
|
||||
end
|
||||
end
|
||||
else
|
||||
test "16-bit floats" do
|
||||
message = ~r"float requires size\*unit to be 32 or 64 \(default\), got: 16"
|
||||
|
||||
assert_raise CompileError, message, fn ->
|
||||
expand(quote(do: <<12.3::16>>))
|
||||
end
|
||||
end
|
||||
|
||||
test "raises for invalid size * unit for floats" do
|
||||
message = ~r"float requires size\*unit to be 32 or 64 \(default\), got: 128"
|
||||
|
||||
assert_raise CompileError, message, fn ->
|
||||
expand(quote(do: <<12.3::32*4>>))
|
||||
end
|
||||
|
||||
message = ~r"float requires size\*unit to be 32 or 64 \(default\), got: 256"
|
||||
|
||||
assert_raise CompileError, message, fn ->
|
||||
expand(quote(do: <<12.3::256>>))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -931,6 +931,15 @@ defmodule Kernel.WarningTest do
|
||||
purge(Sample)
|
||||
end
|
||||
|
||||
# TODO: Simplify when we require OTP 24
|
||||
if System.otp_release() >= "24" do
|
||||
@argument_error_message "the call to :erlang.atom_to_binary/2"
|
||||
@arithmetic_error_message "the call to +/2"
|
||||
else
|
||||
@argument_error_message "this expression"
|
||||
@arithmetic_error_message "this expression"
|
||||
end
|
||||
|
||||
test "eval failure warning" do
|
||||
assert capture_err(fn ->
|
||||
Code.eval_string("""
|
||||
@@ -938,7 +947,7 @@ defmodule Kernel.WarningTest do
|
||||
def foo, do: Atom.to_string "abc"
|
||||
end
|
||||
""")
|
||||
end) =~ ~r"this expression will fail with ArgumentError\n.*nofile:2"
|
||||
end) =~ "#{@argument_error_message} will fail with ArgumentError\n nofile:2"
|
||||
|
||||
assert capture_err(fn ->
|
||||
Code.eval_string("""
|
||||
@@ -946,7 +955,7 @@ defmodule Kernel.WarningTest do
|
||||
def foo, do: 1 + nil
|
||||
end
|
||||
""")
|
||||
end) =~ ~r"this expression will fail with ArithmeticError\n.*nofile:2"
|
||||
end) =~ "#{@arithmetic_error_message} will fail with ArithmeticError\n nofile:2"
|
||||
after
|
||||
purge([Sample1, Sample2])
|
||||
end
|
||||
@@ -1145,31 +1154,6 @@ defmodule Kernel.WarningTest do
|
||||
purge(Sample)
|
||||
end
|
||||
|
||||
test "with and do clauses emit errors, else clauses do not" do
|
||||
assert capture_err(fn ->
|
||||
Code.compile_string("""
|
||||
with {:first, int} when is_integer(int) <- {:second, Integer.gcd(2, 4)} do
|
||||
int
|
||||
end
|
||||
""")
|
||||
end) =~ "this clause cannot match"
|
||||
|
||||
assert capture_err(fn ->
|
||||
Code.compile_string("""
|
||||
with {:first, int1} when is_integer(int1) <- {:first, Integer.gcd(2, 4)},
|
||||
{:second, int2} when is_integer(int2) <- {:second, Integer.gcd(2, 4)} do
|
||||
{:ok, int1 + int2}
|
||||
else
|
||||
{:first, nil} -> {:error, "first number is not integer"}
|
||||
{:second, nil} -> {:error, "second number is not integer"}
|
||||
end
|
||||
""")
|
||||
end) == ""
|
||||
after
|
||||
purge(Sample1)
|
||||
purge(Sample2)
|
||||
end
|
||||
|
||||
test "warning on code point escape" do
|
||||
assert capture_err(fn ->
|
||||
Code.eval_string("? ")
|
||||
|
||||
@@ -357,15 +357,22 @@ defmodule Logger.Translator do
|
||||
[]
|
||||
end
|
||||
|
||||
defp child_debug(:debug, restart_type: restart, shutdown: shutdown, child_type: type) do
|
||||
["\nRestart: ", inspect(restart), "\nShutdown: ", inspect(shutdown)] ++
|
||||
["\nType: ", inspect(type)]
|
||||
defp child_debug(:debug, opts) do
|
||||
for {key, value} <- opts do
|
||||
child_debug_key(key, value)
|
||||
end
|
||||
end
|
||||
|
||||
defp child_debug(_min_level, _child) do
|
||||
[]
|
||||
end
|
||||
|
||||
defp child_debug_key(:restart_type, value), do: ["\nRestart: " | inspect(value)]
|
||||
defp child_debug_key(:shutdown, value), do: ["\nShutdown: " | inspect(value)]
|
||||
defp child_debug_key(:child_type, value), do: ["\nType: " | inspect(value)]
|
||||
defp child_debug_key(:significant, value), do: if(value, do: "\nSignificant: true", else: [])
|
||||
defp child_debug_key(_, _), do: []
|
||||
|
||||
defp report_crash(min_level, [[{:initial_call, initial_call} | crashed], linked]) do
|
||||
mfa = initial_call_to_mfa(initial_call)
|
||||
report_crash(min_level, crashed, [{:initial_call, mfa}], linked)
|
||||
|
||||
@@ -271,7 +271,7 @@ defmodule Mix.Compilers.Erlang do
|
||||
defp to_diagnostics(warnings_or_errors, severity) do
|
||||
for {file, issues} <- warnings_or_errors,
|
||||
{line, module, data} <- issues do
|
||||
position = if is_integer(line) and line >= 1, do: line
|
||||
position = line(line)
|
||||
|
||||
%Mix.Task.Compiler.Diagnostic{
|
||||
file: Path.absname(file),
|
||||
@@ -288,7 +288,12 @@ defmodule Mix.Compilers.Erlang do
|
||||
for {_, warnings} <- entries,
|
||||
{file, issues} <- warnings,
|
||||
{line, module, message} <- issues do
|
||||
IO.puts("#{file}:#{line}: Warning: #{module.format_error(message)}")
|
||||
IO.puts("#{file}:#{line(line)}: Warning: #{module.format_error(message)}")
|
||||
end
|
||||
end
|
||||
|
||||
defp line({line, _column}) when is_integer(line) and line >= 1, do: line
|
||||
# TODO: remove when we require OTP 24
|
||||
defp line(line) when is_integer(line) and line >= 1, do: line
|
||||
defp line(_), do: nil
|
||||
end
|
||||
|
||||
@@ -176,7 +176,11 @@ defmodule Mix.Config do
|
||||
"""
|
||||
@doc deprecated: "Use Config.Reader.read_imports!/2 instead"
|
||||
def eval!(file, imported_paths \\ []) do
|
||||
Config.Reader.read_imports!(file, imports: imported_paths)
|
||||
Config.Reader.read_imports!(file,
|
||||
imports: imported_paths,
|
||||
env: Mix.env(),
|
||||
target: Mix.target()
|
||||
)
|
||||
end
|
||||
|
||||
@doc """
|
||||
@@ -195,7 +199,7 @@ defmodule Mix.Config do
|
||||
@doc deprecated: "Use Config.Reader.read!/2 instead"
|
||||
@spec read!(Path.t(), [Path.t()]) :: keyword
|
||||
def read!(file, imported_paths \\ []) do
|
||||
Config.Reader.read!(file, imports: imported_paths)
|
||||
Config.Reader.read!(file, imports: imported_paths, env: Mix.env(), target: Mix.target())
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
||||
+18
-9
@@ -387,15 +387,16 @@ defmodule Mix.Task do
|
||||
Mix.ProjectStack.on_recursing_root(fn -> run(task, args) end)
|
||||
|
||||
Mix.TasksServer.run({:task, task, proj}) ->
|
||||
if Mix.debug?(), do: output_task_debug_info(task, args, proj)
|
||||
run_requirements(module)
|
||||
|
||||
try do
|
||||
module.run(args)
|
||||
rescue
|
||||
e in OptionParser.ParseError ->
|
||||
Mix.raise("Could not invoke task #{inspect(task)}: " <> Exception.message(e))
|
||||
end
|
||||
with_debug(task, args, proj, fn ->
|
||||
try do
|
||||
module.run(args)
|
||||
rescue
|
||||
e in OptionParser.ParseError ->
|
||||
Mix.raise("Could not invoke task #{inspect(task)}: " <> Exception.message(e))
|
||||
end
|
||||
end)
|
||||
|
||||
true ->
|
||||
:noop
|
||||
@@ -409,8 +410,16 @@ defmodule Mix.Task do
|
||||
end)
|
||||
end
|
||||
|
||||
defp output_task_debug_info(task, args, proj) do
|
||||
Mix.shell().info("** Running mix " <> task_to_string(task, args) <> project_to_string(proj))
|
||||
defp with_debug(task, args, proj, fun) do
|
||||
if Mix.debug?() do
|
||||
shell = Mix.shell()
|
||||
shell.info(["-> Running mix ", task_to_string(task, args), project_to_string(proj)])
|
||||
{time, res} = :timer.tc(fun)
|
||||
shell.info(["<- Ran mix ", task, " in ", Integer.to_string(div(time, 1000)), "ms"])
|
||||
res
|
||||
else
|
||||
fun.()
|
||||
end
|
||||
end
|
||||
|
||||
defp project_to_string(nil), do: ""
|
||||
|
||||
@@ -100,9 +100,10 @@ defmodule Mix.Tasks.Compile.Erlang do
|
||||
file = Erlang.to_erl_file(Path.rootname(input, ".erl"))
|
||||
|
||||
case :compile.file(file, erlc_options) do
|
||||
{:error, :badarg} ->
|
||||
# TODO: Don't handle {:error, :badarg} when we require OTP 24
|
||||
error when error == :error or error == {:error, :badarg} ->
|
||||
message =
|
||||
"Compiling Erlang #{inspect(file)} failed with ArgumentError, probably because of invalid :erlc_options"
|
||||
"Compiling Erlang file #{inspect(file)} failed, probably because of invalid :erlc_options"
|
||||
|
||||
Mix.raise(message)
|
||||
|
||||
|
||||
@@ -60,11 +60,11 @@ defmodule Mix.CLITest do
|
||||
assert contents =~ "This won't appear"
|
||||
|
||||
contents = mix(~w[my_hello], [{"MIX_DEBUG", "1"}])
|
||||
assert contents =~ "** Running mix my_hello (inside MyProject)"
|
||||
assert contents =~ "-> Running mix my_hello (inside MyProject)"
|
||||
assert contents =~ "** (Mix.Error) oops"
|
||||
|
||||
contents = mix(~w[my_hello], [{"MIX_DEBUG", "0"}])
|
||||
refute contents =~ "** Running mix my_hello (inside MyProject)"
|
||||
refute contents =~ "-> Running mix my_hello (inside MyProject)"
|
||||
refute contents =~ "** (Mix.Error) oops"
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -59,7 +59,8 @@ defmodule Mix.TaskTest do
|
||||
Mix.shell(Mix.Shell.IO)
|
||||
Mix.debug(true)
|
||||
|
||||
assert ExUnit.CaptureIO.capture_io(fn -> Mix.Task.run("hello") end) =~ "** Running mix hello"
|
||||
assert ExUnit.CaptureIO.capture_io(fn -> Mix.Task.run("hello") end) =~
|
||||
~r"-> Running mix hello\n<- Ran mix hello in \d+ms"
|
||||
after
|
||||
Mix.shell(Mix.Shell.Process)
|
||||
Mix.debug(false)
|
||||
|
||||
@@ -14,7 +14,7 @@ defmodule Mix.Tasks.Compile.ErlangTest do
|
||||
@tag erlc_options: [{:d, 'foo', 'bar'}]
|
||||
test "raises on invalid erlc_options" do
|
||||
in_fixture("compile_erlang", fn ->
|
||||
assert_raise Mix.Error, ~r"failed with ArgumentError", fn ->
|
||||
assert_raise Mix.Error, ~r"Compiling Erlang file '.*' failed", fn ->
|
||||
capture_io(fn ->
|
||||
Mix.Tasks.Compile.Erlang.run([])
|
||||
end)
|
||||
|
||||
@@ -23,10 +23,12 @@ defmodule Mix.Tasks.Compile.YeccTest do
|
||||
assert %Mix.Task.Compiler.Diagnostic{
|
||||
compiler_name: "yecc",
|
||||
file: ^file,
|
||||
message: "syntax error before: '.'",
|
||||
message: message,
|
||||
position: 1,
|
||||
severity: :error
|
||||
} = diagnostic
|
||||
|
||||
assert message =~ "syntax error before: "
|
||||
end)
|
||||
|
||||
assert File.regular?("src/test_ok.erl")
|
||||
|
||||
Reference in New Issue
Block a user