Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fd85b06dc | ||
|
|
ec81110b3e | ||
|
|
094a76d514 | ||
|
|
7d737bc5ec | ||
|
|
3eb074282a | ||
|
|
b8732bd248 | ||
|
|
2252a8ff55 | ||
|
|
9a9cf419a1 | ||
|
|
0f92512030 | ||
|
|
e0806f9d6c | ||
|
|
5db9d55926 | ||
|
|
3cb3d41368 | ||
|
|
a3a081c949 | ||
|
|
207350fb44 | ||
|
|
6f7a68c9e3 | ||
|
|
0936fb45d5 | ||
|
|
bccfca4ffe | ||
|
|
417255fe1b |
@@ -30,7 +30,7 @@ jobs:
|
||||
- otp: 26
|
||||
otp_version: '26.0'
|
||||
build_docs: build_docs
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
|
||||
@@ -15,7 +15,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
create_draft_release:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
- otp: 26
|
||||
otp_version: '26.0'
|
||||
build_docs: build_docs
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
@@ -56,7 +56,9 @@ jobs:
|
||||
run: |
|
||||
gh release upload --clobber "${{ github.ref_name }}" \
|
||||
elixir-otp-${{ matrix.otp }}.zip \
|
||||
elixir-otp-${{ matrix.otp }}.zip.sha{1,256}sum
|
||||
elixir-otp-${{ matrix.otp }}.zip.sha{1,256}sum \
|
||||
elixir-otp-${{ matrix.otp }}.exe \
|
||||
elixir-otp-${{ matrix.otp }}.exe.sha{1,256}sum
|
||||
- name: Upload Docs to GitHub
|
||||
if: ${{ matrix.build_docs }}
|
||||
env:
|
||||
|
||||
@@ -22,6 +22,20 @@ runs:
|
||||
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: Install NSIS
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y nsis
|
||||
- name: Build Elixir Windows Installer
|
||||
shell: bash
|
||||
run: |
|
||||
export OTP_VERSION=${{ inputs.otp_version }}
|
||||
export ELIXIR_ZIP=$PWD/elixir-otp-${{ inputs.otp }}.zip
|
||||
(cd lib/elixir/scripts/windows_installer && ./build.sh)
|
||||
mv lib/elixir/scripts/windows_installer/tmp/elixir-otp-${{ inputs.otp }}.exe .
|
||||
shasum -a 1 elixir-otp-${{ inputs.otp }}.exe > elixir-otp-${{ inputs.otp }}.exe.sha1sum
|
||||
shasum -a 256 elixir-otp-${{ inputs.otp }}.exe > elixir-otp-${{ inputs.otp }}.exe.sha256sum
|
||||
- name: Get latest stable ExDoc version
|
||||
if: ${{ inputs.build_docs }}
|
||||
shell: bash
|
||||
|
||||
+19
-50
@@ -68,7 +68,7 @@ In Elixir v1.15, the new reports will look like:
|
||||
error: undefined function foo/0 (there is no such import)
|
||||
my_file.exs:1
|
||||
|
||||
** (CompileError) nofile: cannot compile file (errors have been logged)
|
||||
** (CompileError) my_file.exs: cannot compile file (errors have been logged)
|
||||
|
||||
A new function, called `Code.with_diagnostics/2`, has been added so this
|
||||
information can be leveraged by editors, allowing them to point to several
|
||||
@@ -100,61 +100,16 @@ config :logger, :default_formatter,
|
||||
format: "$time $message $metadata"
|
||||
```
|
||||
|
||||
If you use `Logger.Backends.Console` or other backends, they are
|
||||
still fully supported and functional. If you implement your own
|
||||
backends, you want to consider migrating to
|
||||
If you use `Logger.Backends.Console` with a custom device or other
|
||||
backends, they are still fully supported and functional. If you
|
||||
implement your own backends, you want to consider migrating to
|
||||
[`:logger_backends`](https://github.com/elixir-lang/logger_backends)
|
||||
in the long term.
|
||||
|
||||
See the new `Logger` documentation for more information on the
|
||||
new features and on compatibility.
|
||||
|
||||
## v1.15.0-rc.1 (2022-05-29)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
#### Elixir
|
||||
|
||||
* [File] Support distributed `File.Stream`
|
||||
* [Module] Add `Module.get_last_attribute/3`
|
||||
* [Task] Reduce footprint of tasks by avoiding unecessary work during spawning
|
||||
|
||||
#### ExUnit
|
||||
|
||||
* [ExUnit.Case] Add `ExUnit.Case.get_last_registered_test/1`
|
||||
|
||||
### 2. Bug fixes
|
||||
|
||||
#### Elixir
|
||||
|
||||
* [Code] Ensure `:on_undefined_variable` option works as advertised (regression)
|
||||
* [Code] Format paths in `Code.with_diagnostic/2` as relative paths (regression)
|
||||
* [Kernel] Raise when macros are given to dialyzer
|
||||
* [Kernel] Support bitstring specifiers as map keys in pattern (regression)
|
||||
* [Module] Ensure that `Module.get_attribute/3` returns `nil` and not the given default value when an attribute has been explicitly set as `nil`
|
||||
* [Task] Do not double log Task failure reports
|
||||
|
||||
#### ExUnit
|
||||
|
||||
* [ExUnit.CaptureLog] Allow capturing deprecated log level (regression)
|
||||
* [ExUnit.DocTest] Ensure proper line is returned when failing to parse doctest results
|
||||
|
||||
#### IEx
|
||||
|
||||
* [IEx] Fix IO operations not returning when booting IEx (regression)
|
||||
|
||||
#### Mix
|
||||
|
||||
* [mix deps] Ensure dependencies with `included_applications` can be loaded (regression)
|
||||
* [mix format] Ensure proper formatter options are returned for files (regression)
|
||||
|
||||
### 3. Soft deprecations
|
||||
|
||||
#### Elixir
|
||||
|
||||
* [Kernel] Require pin variable when accessing variable inside binary size in match
|
||||
|
||||
## v1.15.0-rc.0 (2022-05-22)
|
||||
## v1.15.0 (2023-06-19)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
@@ -175,6 +130,7 @@ new features and on compatibility.
|
||||
* [Date] Add `Date.before?/2` and `Date.after?/2`
|
||||
* [DateTime] Add `DateTime.before?/2` and `DateTime.after?/2`
|
||||
* [DateTime] Support precision in `DateTime.utc_now/2`
|
||||
* [File] Support distributed `File.Stream`
|
||||
* [Inspect] `Inspect` now renders `'charlists'` as `~c"charlists"` by default
|
||||
* [Kernel] Break down `case` and `cond` inside `dbg/2`
|
||||
* [Kernel] Add `t:nonempty_binary/0` and `t:nonempty_bitstring/0`
|
||||
@@ -195,6 +151,8 @@ new features and on compatibility.
|
||||
* [NaiveDateTime] Add `NaiveDateTime.beginning_of_day/1` and `NaiveDateTime.end_of_day/1`
|
||||
* [NaiveDateTime] Add `NaiveDateTime.before?/2` and `NaiveDateTime.after?/2`
|
||||
* [NaiveDateTime] Support precision in `NaiveDateTime.utc_now/2`
|
||||
* [Module] Mark functions as generated in "Docs" chunk
|
||||
* [Module] Add `Module.get_last_attribute/3`
|
||||
* [OptionParser] Support `:return_separator` option
|
||||
* [Process] Add `Process.alias/0,1` and `Process.unalias/1`
|
||||
* [Range] Add `Range.split/2`
|
||||
@@ -204,6 +162,7 @@ new features and on compatibility.
|
||||
* [System] Support `:lines` in `System.cmd/3` to capture output line by line
|
||||
* [Task] Remove head of line blocking on `Task.yield_many/2`
|
||||
* [Task] Enable selective receive optimizations in Erlang/OTP 26+
|
||||
* [Task] Reduce tasks footprint by avoiding unecessary work during spawning
|
||||
* [Task.Supervisor] Do not copy args on temporary `Task.Supervisor.start_child/2`
|
||||
* [Time] Add `Time.before?/2` and `Time.after?/2`
|
||||
* [URI] Add `URI.append_path/2`
|
||||
@@ -212,7 +171,9 @@ new features and on compatibility.
|
||||
|
||||
* [ExUnit] Add more color configuration to ExUnit CLI formatter
|
||||
* [ExUnit.Callbacks] Accept `{module, function}` tuples in ExUnit `setup` callbacks
|
||||
* [ExUnit.Case] Add `ExUnit.Case.get_last_registered_test/1`
|
||||
* [ExUnit.Doctest] Add `ExUnit.DocTest.doctest_file/2`
|
||||
* [ExUnit.Doctest] Include `doctest_data` in doctest tags
|
||||
* [ExUnit.Formatter] When comparing two anonymous functions, defined at the same place but capturing a different environment, we will now also diff the environments
|
||||
|
||||
#### IEx
|
||||
@@ -267,16 +228,22 @@ new features and on compatibility.
|
||||
* [Kernel] Expand macros on the left side of -> in `try/rescue`
|
||||
* [Kernel] Raise on misplaced `...` inside typespecs
|
||||
* [Kernel] Do not import `behaviour_info` and `module_info` functions from Erlang modules
|
||||
* [Kernel] Raise when macros are given to dialyzer
|
||||
* [Kernel.ParallelCompiler] Make sure compiler doesn't crash when there are stray messages in the inbox
|
||||
* [Kernel.ParallelCompiler] Track compile and runtime warnings separately
|
||||
* [Module] Ensure that `Module.get_attribute/3` returns `nil` and not the given default value when an attribute has been explicitly set as `nil`
|
||||
* [System] Fix race condition when a script would terminate before `System.stop/1` executes
|
||||
* [Task] Do not double log Task failure reports
|
||||
* [URI] Make sure `URI.merge/2` works accordingly with relative paths
|
||||
|
||||
#### ExUnit
|
||||
|
||||
* [ExUnit] Fix crash when `@tag capture_log: true` was set to true and the Logger application was shut down in the middle of the test
|
||||
* [ExUnit] Do not merge context as tags inside the runner to reduce memory usage when emitting events to formatters
|
||||
* [ExUnit] Mark test cases as invalid when an exit occurs during `setup_all`
|
||||
* [ExUnit] Do not expand or collect vars from quote in ExUnit assertions
|
||||
* [ExUnit.DocTest] Ensure proper line is returned when failing to parse doctest results
|
||||
* [ExUnit.Doctest] Fix line information when a doctest with multiple assertions fails
|
||||
|
||||
#### IEx
|
||||
|
||||
@@ -288,6 +255,7 @@ new features and on compatibility.
|
||||
|
||||
* [mix compile] Include `cwd` in compiler cache key
|
||||
* [mix release] Fix Windows service when invoking `erlsrv.exe` in path with spaces
|
||||
* [mix xref] Raise early if `mix xref` is used at the umbrella root
|
||||
|
||||
### 3. Soft deprecations (no warnings emitted)
|
||||
|
||||
@@ -295,6 +263,7 @@ new features and on compatibility.
|
||||
|
||||
* [File] `File.cp/3` and `File.cp_r/3` with a function as third argument
|
||||
is deprecated in favor of a keyword list
|
||||
* [Kernel] Require pin variable when accessing variable inside binary size in match
|
||||
* [Kernel.ParallelCompiler] Require the `:return_diagnostics` option to be
|
||||
set to true when compiling or requiring code
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ PREFIX ?= /usr/local
|
||||
TEST_FILES ?= "*_test.exs"
|
||||
SHARE_PREFIX ?= $(PREFIX)/share
|
||||
MAN_PREFIX ?= $(SHARE_PREFIX)/man
|
||||
#CANONICAL := MAJOR.MINOR/
|
||||
CANONICAL := 1.15/
|
||||
CANONICAL ?= main/
|
||||
DOCS_FORMAT ?= html
|
||||
ELIXIRC := bin/elixirc --ignore-module-conflict $(ELIXIRC_OPTS)
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
|
||||
6. Copy the relevant bits from /CHANGELOG.md to the GitHub release and publish it
|
||||
|
||||
7. Add the release to `elixir.csv` with the minimum supported OTP version (all releases), update `erlang.csv` to the latest supported OTP version, and `_data/elixir-versions.yml` (except for RCs) files in `elixir-lang/elixir-lang.github.com`
|
||||
7. Update `_data/elixir-versions.yml` (except for RCs) in `elixir-lang/elixir-lang.github.com`
|
||||
|
||||
## Creating a new vMAJOR.MINOR branch (after first rc)
|
||||
|
||||
|
||||
+2
-3
@@ -6,12 +6,11 @@ Elixir applies bug fixes only to the latest minor branch. Security patches are a
|
||||
|
||||
Elixir version | Support
|
||||
:------------- | :-----------------------------
|
||||
1.15 | Development
|
||||
1.14 | Bug fixes and security patches
|
||||
1.15 | Bug fixes and security patches
|
||||
1.14 | Security patches only
|
||||
1.13 | Security patches only
|
||||
1.12 | Security patches only
|
||||
1.11 | Security patches only
|
||||
1.10 | Security patches only
|
||||
|
||||
## Announcements
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
ELIXIR_VERSION=1.15.0-rc.1
|
||||
ELIXIR_VERSION=1.15.0
|
||||
|
||||
if [ $# -eq 0 ] || { [ $# -eq 1 ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; }; then
|
||||
cat <<USAGE >&2
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
@if defined ELIXIR_CLI_ECHO (@echo on) else (@echo off)
|
||||
|
||||
set ELIXIR_VERSION=1.15.0-rc.1
|
||||
set ELIXIR_VERSION=1.15.0
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
if ""%1""=="""" if ""%2""=="""" goto documentation
|
||||
|
||||
@@ -3,10 +3,6 @@ defmodule Code.Fragment do
|
||||
This module provides conveniences for analyzing fragments of
|
||||
textual code and extract available information whenever possible.
|
||||
|
||||
Most of the functions in this module provide a best-effort
|
||||
and may not be accurate under all circumstances. Read each
|
||||
documentation for more information.
|
||||
|
||||
This module should be considered experimental.
|
||||
"""
|
||||
|
||||
|
||||
@@ -3009,13 +3009,16 @@ defmodule Enum do
|
||||
|
||||
if first < count and amount > 0 do
|
||||
amount = Kernel.min(amount, count - first)
|
||||
amount = if step == 1, do: amount, else: div(amount - 1, step) + 1
|
||||
amount = amount_with_step(amount, step)
|
||||
fun.(first, amount, step)
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
defp amount_with_step(amount, 1), do: amount
|
||||
defp amount_with_step(amount, step), do: div(amount - 1, step) + 1
|
||||
|
||||
@doc """
|
||||
Returns a subset list of the given `enumerable`, from `start_index` (zero-based)
|
||||
with `amount` number of elements if available.
|
||||
@@ -4440,7 +4443,7 @@ defmodule Enum do
|
||||
|
||||
if start >= 0 do
|
||||
amount = Kernel.min(amount, count - start)
|
||||
amount = if step == 1, do: amount, else: div(amount - 1, step) + 1
|
||||
amount = amount_with_step(amount, step)
|
||||
fun.(start, amount, step)
|
||||
else
|
||||
[]
|
||||
@@ -4448,7 +4451,7 @@ defmodule Enum do
|
||||
end
|
||||
|
||||
defp slice_forward(list, start, amount, step) when is_list(list) do
|
||||
amount = if step == 1, do: amount, else: div(amount - 1, step) + 1
|
||||
amount = amount_with_step(amount, step)
|
||||
slice_list(list, start, amount, step)
|
||||
end
|
||||
|
||||
@@ -4458,7 +4461,7 @@ defmodule Enum do
|
||||
[]
|
||||
|
||||
{:ok, count, fun} when is_function(fun, 1) ->
|
||||
amount = Kernel.min(amount, count - start)
|
||||
amount = Kernel.min(amount, count - start) |> amount_with_step(step)
|
||||
enumerable |> fun.() |> slice_exact(start, amount, step, count)
|
||||
|
||||
# TODO: Deprecate me in Elixir v1.18.
|
||||
@@ -4473,8 +4476,7 @@ defmodule Enum do
|
||||
end
|
||||
|
||||
{:ok, count, fun} when is_function(fun, 3) ->
|
||||
amount = Kernel.min(amount, count - start)
|
||||
amount = if step == 1, do: amount, else: div(amount - 1, step) + 1
|
||||
amount = Kernel.min(amount, count - start) |> amount_with_step(step)
|
||||
fun.(start, amount, step)
|
||||
|
||||
{:error, module} ->
|
||||
|
||||
@@ -3555,10 +3555,12 @@ defmodule Kernel do
|
||||
not bootstrapped?(Macro) ->
|
||||
nil
|
||||
|
||||
not function? and __CALLER__.context == :match ->
|
||||
not function? and (__CALLER__.context == :match or __CALLER__.context == :guard) ->
|
||||
raise ArgumentError,
|
||||
"""
|
||||
invalid write attribute syntax. If you want to define an attribute, don't do this:
|
||||
invalid usage of module attributes. Module attributes cannot be used inside \
|
||||
pattern matching (and guards) outside of a function. If you are trying to \
|
||||
define an attribute, do not do this:
|
||||
|
||||
@foo = :value
|
||||
|
||||
|
||||
@@ -8,12 +8,11 @@ Elixir applies bug fixes only to the latest minor branch. Security patches are a
|
||||
|
||||
Elixir version | Support
|
||||
:------------- | :-----------------------------
|
||||
1.15 | Development
|
||||
1.14 | Bug fixes and security patches
|
||||
1.15 | Bug fixes and security patches
|
||||
1.14 | Security patches only
|
||||
1.13 | Security patches only
|
||||
1.12 | Security patches only
|
||||
1.11 | Security patches only
|
||||
1.10 | Security patches only
|
||||
|
||||
New releases are announced in the read-only [announcements mailing list](https://groups.google.com/group/elixir-lang-ann). All security releases [will be tagged with `[security]`](https://groups.google.com/forum/#!searchin/elixir-lang-ann/%5Bsecurity%5D%7Csort:date).
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
tmp/
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
+46
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
# Usage:
|
||||
#
|
||||
# With Elixir archive:
|
||||
#
|
||||
# ELIXIR_ZIP=Precompiled.zip OTP_VERSION=25.3.2.2 ./build.sh
|
||||
#
|
||||
# With Elixir version:
|
||||
#
|
||||
# ELIXIR_VERSION=1.14.5 OTP_VERSION=25.3.2.2 ./build.sh
|
||||
set -euo pipefail
|
||||
|
||||
OTP_VERSION="${OTP_VERSION:-26.0}"
|
||||
otp_release=`echo "${OTP_VERSION}" | cut -d. -f1`
|
||||
|
||||
mkdir -p tmp
|
||||
|
||||
ELIXIR_VERSION="${ELIXIR_VERSION:-}"
|
||||
if [ -n "${ELIXIR_VERSION}" ]; then
|
||||
ELIXIR_ZIP="tmp/elixir-${ELIXIR_VERSION}-otp-${otp_release}.zip"
|
||||
if [ ! -f "${ELIXIR_ZIP}" ]; then
|
||||
url="https://github.com/elixir-lang/elixir/releases/download/v${ELIXIR_VERSION}/elixir-otp-${otp_release}.zip"
|
||||
echo "downloading ${url}"
|
||||
curl --fail -L -o "${ELIXIR_ZIP}" "${url}"
|
||||
fi
|
||||
basename=elixir-${ELIXIR_VERSION}-otp-${otp_release}
|
||||
else
|
||||
basename=elixir-otp-${otp_release}
|
||||
fi
|
||||
|
||||
if [ ! -d "tmp/${basename}" ]; then
|
||||
unzip -d "tmp/${basename}" "${ELIXIR_ZIP}"
|
||||
fi
|
||||
|
||||
# brew install makensis
|
||||
# apt install -y nsis
|
||||
# choco install -y nsis
|
||||
export PATH="/c/Program Files (x86)/NSIS:${PATH}"
|
||||
makensis \
|
||||
-X"OutFile tmp\\${basename}.exe" \
|
||||
-DOTP_VERSION=${OTP_VERSION} \
|
||||
-DOTP_RELEASE="${otp_release}" \
|
||||
-DELIXIR_DIR=tmp\\${basename} \
|
||||
installer.nsi
|
||||
|
||||
echo "Installer path: tmp/${basename}.exe"
|
||||
@@ -0,0 +1,209 @@
|
||||
!include "MUI2.nsh"
|
||||
!include "StrFunc.nsh"
|
||||
${Using:StrFunc} StrStr
|
||||
${Using:StrFunc} UnStrStr
|
||||
${Using:StrFunc} UnStrRep
|
||||
|
||||
Name "Elixir"
|
||||
ManifestDPIAware true
|
||||
Unicode True
|
||||
InstallDir "$PROGRAMFILES64\Elixir"
|
||||
!define MUI_ICON "assets\drop.ico"
|
||||
|
||||
; Install Page: Install Erlang/OTP
|
||||
|
||||
Page custom CheckOTPPageShow CheckOTPPageLeave
|
||||
|
||||
var Dialog
|
||||
var DownloadOTPLink
|
||||
var InstalledERTSVersion
|
||||
var InstalledOTPRelease
|
||||
var OTPPath
|
||||
Function CheckOTPPageShow
|
||||
!insertmacro MUI_HEADER_TEXT "Checking Erlang/OTP" ""
|
||||
|
||||
nsDialogs::Create 1018
|
||||
Pop $Dialog
|
||||
|
||||
${If} $Dialog == error
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
EnumRegKey $0 HKLM "SOFTWARE\WOW6432NODE\Ericsson\Erlang" 0
|
||||
ReadRegStr $1 HKLM "SOFTWARE\WOW6432NODE\Ericsson\Erlang\$0" ""
|
||||
StrCpy $InstalledERTSVersion $0
|
||||
StrCpy $OTPPath $1
|
||||
|
||||
${If} $1 == ""
|
||||
${NSD_CreateLabel} 0 0 100% 20u "Couldn't find existing Erlang/OTP installation. Click the link below to download and install it before proceeding."
|
||||
${NSD_CreateLink} 0 25u 100% 20u "Download Erlang/OTP ${OTP_RELEASE}"
|
||||
Pop $DownloadOTPLink
|
||||
${NSD_OnClick} $DownloadOTPLink OpenOTPDownloads
|
||||
${Else}
|
||||
nsExec::ExecToStack `$OTPPath\bin\erl.exe -noinput -eval "\
|
||||
io:put_chars(erlang:system_info(otp_release)),\
|
||||
halt()."`
|
||||
Pop $0
|
||||
Pop $1
|
||||
|
||||
${If} $0 == 0
|
||||
StrCpy $InstalledOTPRelease $1
|
||||
${If} $InstalledOTPRelease == ${OTP_RELEASE}
|
||||
${NSD_CreateLabel} 0 0 100% 20u "Found existing Erlang/OTP $InstalledOTPRelease installation at $OTPPath. Please proceed."
|
||||
${ElseIf} $2 < ${OTP_RELEASE}
|
||||
${NSD_CreateLabel} 0 0 100% 30u "Found existing Erlang/OTP $InstalledOTPRelease installation at $OTPPath but this Elixir installer was precompiled for Erlang/OTP ${OTP_RELEASE}. \
|
||||
We recommend checking if there is an Elixir version precompiled for Erlang/OTP $InstalledOTPRelease. Otherwise, proceed."
|
||||
${Else}
|
||||
SetErrorlevel 5
|
||||
MessageBox MB_ICONSTOP "Found existing Erlang/OTP $InstalledOTPRelease installation at $OTPPath but this Elixir version was precompiled for Erlang/OTP ${OTP_RELEASE}. \
|
||||
Please upgrade your Erlang/OTP version or choose an Elixir installer matching your Erlang/OTP version"
|
||||
Quit
|
||||
${EndIf}
|
||||
${Else}
|
||||
SetErrorlevel 5
|
||||
MessageBox MB_ICONSTOP "Found existing Erlang/OTP installation at $OTPPath but checking it exited with $0: $1"
|
||||
Quit
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
|
||||
nsDialogs::Show
|
||||
FunctionEnd
|
||||
|
||||
Function OpenOTPDownloads
|
||||
ExecShell "open" "https://www.erlang.org/downloads/${OTP_RELEASE}"
|
||||
FunctionEnd
|
||||
|
||||
Function CheckOTPPageLeave
|
||||
FunctionEnd
|
||||
|
||||
; Install Page: Files
|
||||
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
|
||||
; Install Page: Finish
|
||||
|
||||
Page custom FinishPageShow FinishPageLeave
|
||||
|
||||
var AddOTPToPathCheckbox
|
||||
var AddElixirToPathCheckbox
|
||||
Function FinishPageShow
|
||||
!insertmacro MUI_HEADER_TEXT "Finish Setup" ""
|
||||
|
||||
nsDialogs::Create 1018
|
||||
Pop $Dialog
|
||||
|
||||
${If} $Dialog == error
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
${NSD_CreateCheckbox} 0 0 195u 10u "&Add $INSTDIR\bin to %PATH%"
|
||||
Pop $AddElixirToPathCheckbox
|
||||
SendMessage $AddElixirToPathCheckbox ${BM_SETCHECK} ${BST_CHECKED} 0
|
||||
|
||||
EnumRegKey $0 HKLM "SOFTWARE\WOW6432NODE\Ericsson\Erlang" 0
|
||||
ReadRegStr $0 HKLM "SOFTWARE\WOW6432NODE\Ericsson\Erlang\$0" ""
|
||||
StrCpy $OTPPath $0
|
||||
${If} $0 != ""
|
||||
${NSD_CreateCheckbox} 0 20u 195u 10u "&Add $0\bin to %PATH%"
|
||||
Pop $AddOTPToPathCheckbox
|
||||
SendMessage $AddOTPToPathCheckbox ${BM_SETCHECK} ${BST_CHECKED} 0
|
||||
${EndIf}
|
||||
|
||||
nsDialogs::Show
|
||||
FunctionEnd
|
||||
|
||||
Function FinishPageLeave
|
||||
${NSD_GetState} $AddOTPToPathCheckbox $0
|
||||
${If} $0 <> ${BST_UNCHECKED}
|
||||
ReadRegStr $0 HKCU "Environment" "Path"
|
||||
${StrStr} $1 "$0" "$OTPPath\bin"
|
||||
${If} $1 == ""
|
||||
WriteRegExpandStr HKCU "Environment" "Path" "$OTPPath\bin;$0"
|
||||
${Else}
|
||||
MessageBox MB_OK "$OTPPath\bin already in %PATH%"
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
|
||||
${NSD_GetState} $AddElixirToPathCheckbox $0
|
||||
${If} $0 <> ${BST_UNCHECKED}
|
||||
ReadRegStr $0 HKCU "Environment" "Path"
|
||||
${StrStr} $1 "$0" "$INSTDIR\bin"
|
||||
${If} $1 == ""
|
||||
WriteRegExpandStr HKCU "Environment" "Path" "$INSTDIR\bin;$0"
|
||||
${Else}
|
||||
MessageBox MB_OK "$INSTDIR\bin already in %PATH%"
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
Section "Install Elixir" SectionElixir
|
||||
SetOutPath "$INSTDIR"
|
||||
File /r "${ELIXIR_DIR}\"
|
||||
|
||||
WriteUninstaller "Uninstall.exe"
|
||||
SectionEnd
|
||||
|
||||
; Uninstall Page: Files
|
||||
|
||||
!insertmacro MUI_UNPAGE_DIRECTORY
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
Section "Uninstall"
|
||||
RMDir /r "$INSTDIR"
|
||||
SectionEnd
|
||||
|
||||
; Uninstall Page: Finish
|
||||
|
||||
var RemoveOTPFromPathCheckbox
|
||||
var RemoveElixirFromPathCheckbox
|
||||
Function un.FinishPageShow
|
||||
!insertmacro MUI_HEADER_TEXT "Finish Setup" ""
|
||||
|
||||
nsDialogs::Create 1018
|
||||
Pop $Dialog
|
||||
|
||||
${If} $Dialog == error
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
ReadRegStr $0 HKCU "Environment" "Path"
|
||||
${UnStrStr} $1 "$0" "$INSTDIR\bin"
|
||||
${If} $1 != ""
|
||||
${NSD_CreateCheckbox} 0 0 195u 10u "&Remove $INSTDIR\bin from %PATH%"
|
||||
Pop $RemoveElixirFromPathCheckbox
|
||||
SendMessage $RemoveElixirFromPathCheckbox ${BM_SETCHECK} ${BST_CHECKED} 0
|
||||
${EndIf}
|
||||
|
||||
EnumRegKey $1 HKLM "SOFTWARE\WOW6432NODE\Ericsson\Erlang" 0
|
||||
ReadRegStr $1 HKLM "SOFTWARE\WOW6432NODE\Ericsson\Erlang\$1" ""
|
||||
StrCpy $OTPPath $1
|
||||
${UnStrStr} $1 "$0" "$OTPPath\bin"
|
||||
${If} $1 != ""
|
||||
${NSD_CreateCheckbox} 0 20u 195u 10u "&Remove $OTPPath\bin from %PATH%"
|
||||
Pop $RemoveOTPFromPathCheckbox
|
||||
SendMessage $RemoveOTPFromPathCheckbox ${BM_SETCHECK} ${BST_CHECKED} 0
|
||||
${EndIf}
|
||||
|
||||
nsDialogs::Show
|
||||
FunctionEnd
|
||||
|
||||
Function un.FinishPageLeave
|
||||
ReadRegStr $0 HKCU "Environment" "Path"
|
||||
|
||||
${NSD_GetState} $RemoveOTPFromPathCheckbox $1
|
||||
${If} $1 <> ${BST_UNCHECKED}
|
||||
${UnStrRep} $0 "$0" "$OTPPath\bin;" ""
|
||||
${EndIf}
|
||||
|
||||
${NSD_GetState} $RemoveElixirFromPathCheckbox $1
|
||||
${If} $1 <> ${BST_UNCHECKED}
|
||||
${UnStrRep} $0 "$0" "$INSTDIR\bin;" ""
|
||||
${EndIf}
|
||||
|
||||
WriteRegExpandStr HKCU "Environment" "Path" "$0"
|
||||
FunctionEnd
|
||||
|
||||
UninstPage custom un.FinishPageShow un.FinishPageLeave
|
||||
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
@@ -510,12 +510,15 @@ get_moduledoc_meta(Set) ->
|
||||
|
||||
get_docs(Set, Module, Definitions, Kind) ->
|
||||
[{Key,
|
||||
erl_anno:new(Line),
|
||||
maybe_generated(erl_anno:new(Line), Ctx),
|
||||
[signature_to_binary(Module, Name, Signature)],
|
||||
doc_value(Doc, Name),
|
||||
Meta
|
||||
} || {Name, Arity} <- Definitions,
|
||||
{Key, _Ctx, Line, Signature, Doc, Meta} <- ets:lookup(Set, {Kind, Name, Arity})].
|
||||
{Key, Ctx, Line, Signature, Doc, Meta} <- ets:lookup(Set, {Kind, Name, Arity})].
|
||||
|
||||
maybe_generated(Ann, nil) -> Ann;
|
||||
maybe_generated(Ann, _Ctx) -> erl_anno:set_generated(true, Ann).
|
||||
|
||||
get_callback_docs(Set, Callbacks) ->
|
||||
[{Key,
|
||||
|
||||
@@ -1030,8 +1030,8 @@ extract_heredoc_with_interpolation(Line, Column, Scope, Interpol, T, H) ->
|
||||
end;
|
||||
|
||||
error ->
|
||||
Message = "heredoc allows only zero or more whitespace characters followed by a new line after ",
|
||||
{error, {Line, Column, io_lib:format(Message, []), [H, H, H]}}
|
||||
Message = "heredoc allows only whitespace characters followed by a new line after opening ",
|
||||
{error, {Line, Column + 3, io_lib:format(Message, []), [H, H, H]}}
|
||||
end.
|
||||
|
||||
extract_heredoc_header("\r\n" ++ Rest) ->
|
||||
@@ -1796,7 +1796,7 @@ prune_tokens([{OpType, _, _} | _] = Tokens, [], Terminators)
|
||||
OpType =:= in_match_op; OpType =:= type_op; OpType =:= dual_op; OpType =:= mult_op;
|
||||
OpType =:= power_op; OpType =:= concat_op; OpType =:= range_op; OpType =:= xor_op;
|
||||
OpType =:= pipe_op; OpType =:= stab_op; OpType =:= when_op; OpType =:= assoc_op;
|
||||
OpType =:= rel_op; OpType =:= ternary_op ->
|
||||
OpType =:= rel_op; OpType =:= ternary_op; OpType =:= capture_op ->
|
||||
{Tokens, Terminators};
|
||||
%%% or we traverse until the end.
|
||||
prune_tokens([_ | Tokens], Opener, Terminators) ->
|
||||
|
||||
@@ -1098,6 +1098,8 @@ defmodule CodeFragmentTest do
|
||||
|
||||
test "keeps operators" do
|
||||
assert cc2q("1 + 2") == s2q("1 + __cursor__()")
|
||||
assert cc2q("&foo") == s2q("&__cursor__()")
|
||||
assert cc2q("&foo/") == s2q("&foo/__cursor__()")
|
||||
end
|
||||
|
||||
test "keeps function calls without parens" do
|
||||
@@ -1200,11 +1202,6 @@ defmodule CodeFragmentTest do
|
||||
assert cc2q("(fn x, y -> x + y end") == s2q("(__cursor__())")
|
||||
end
|
||||
|
||||
test "removes captures" do
|
||||
assert cc2q("[& &1") == s2q("[__cursor__()]")
|
||||
assert cc2q("[&(&1") == s2q("[__cursor__()]")
|
||||
end
|
||||
|
||||
test "removes closed terminators" do
|
||||
assert cc2q("foo([1, 2, 3]") == s2q("foo(__cursor__())")
|
||||
assert cc2q("foo({1, 2, 3}") == s2q("foo(__cursor__())")
|
||||
|
||||
@@ -1102,6 +1102,16 @@ defmodule EnumTest do
|
||||
[2, 1, 3]
|
||||
end
|
||||
|
||||
test "slice on MapSets" do
|
||||
assert MapSet.new(1..10) |> Enum.slice(0, 2) |> Enum.count() == 2
|
||||
assert MapSet.new(1..3) |> Enum.slice(0, 10) |> Enum.count() == 3
|
||||
assert MapSet.new(1..10) |> Enum.slice(0..1) |> Enum.count() == 2
|
||||
assert MapSet.new(1..3) |> Enum.slice(0..10) |> Enum.count() == 3
|
||||
|
||||
assert MapSet.new(1..10) |> Enum.slice(0..4//2) |> Enum.count() == 3
|
||||
assert MapSet.new(1..10) |> Enum.slice(0..5//2) |> Enum.count() == 3
|
||||
end
|
||||
|
||||
test "sort/1" do
|
||||
assert Enum.sort([5, 3, 2, 4, 1]) == [1, 2, 3, 4, 5]
|
||||
end
|
||||
|
||||
@@ -381,4 +381,30 @@ defmodule Kernel.DocsTest do
|
||||
{{:fuz, 0}, :none}
|
||||
] = Enum.sort(function_docs)
|
||||
end
|
||||
|
||||
test "generated functions are annotated as such" do
|
||||
write_beam(
|
||||
defmodule ToBeUsed do
|
||||
defmacro __using__(_) do
|
||||
quote do
|
||||
@doc "Hello"
|
||||
def foo, do: :bar
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
write_beam(
|
||||
defmodule WillBeUsing do
|
||||
use ToBeUsed
|
||||
end
|
||||
)
|
||||
|
||||
{:docs_v1, _, _, _, _, _, docs} = Code.fetch_docs(WillBeUsing)
|
||||
|
||||
assert [
|
||||
{{:function, :foo, 0}, [generated: true, location: 399], ["foo()"],
|
||||
%{"en" => "Hello"}, %{}}
|
||||
] = docs
|
||||
end
|
||||
end
|
||||
|
||||
@@ -538,7 +538,7 @@ defmodule Kernel.ParserTest do
|
||||
describe "syntax errors" do
|
||||
test "invalid heredoc start" do
|
||||
assert_syntax_error(
|
||||
~r/nofile:1:1: heredoc allows only zero or more whitespace characters followed by a new line after \"\"\"/,
|
||||
~r/nofile:1:4: heredoc allows only whitespace characters followed by a new line after opening \"\"\"/,
|
||||
~c"\"\"\"bar\n\"\"\""
|
||||
)
|
||||
end
|
||||
|
||||
@@ -831,11 +831,25 @@ defmodule KernelTest do
|
||||
end
|
||||
|
||||
test "matching attribute" do
|
||||
assert_raise ArgumentError, ~r"invalid write attribute syntax", fn ->
|
||||
assert_raise ArgumentError, ~r"invalid usage of module attributes", fn ->
|
||||
defmodule MatchAttributeInModule do
|
||||
@foo = 42
|
||||
end
|
||||
end
|
||||
|
||||
assert_raise ArgumentError, ~r"invalid usage of module attributes", fn ->
|
||||
defmodule MatchAttributeInModule do
|
||||
@foo 16
|
||||
<<_::@foo>> = "ab"
|
||||
end
|
||||
end
|
||||
|
||||
assert_raise ArgumentError, ~r"invalid usage of module attributes", fn ->
|
||||
defmodule MatchAttributeInModule do
|
||||
@foo 16
|
||||
<<_::size(@foo)>> = "ab"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -293,8 +293,9 @@ defmodule ExUnit.Runner do
|
||||
{test_module, invalid_tests, []}
|
||||
|
||||
{:DOWN, ^module_ref, :process, ^module_pid, error} ->
|
||||
invalid_tests = Enum.map(tests, &%{&1 | state: {:invalid, test_module}})
|
||||
test_module = %{test_module | state: failed({:EXIT, module_pid}, error, [])}
|
||||
{test_module, [], []}
|
||||
{test_module, invalid_tests, []}
|
||||
end
|
||||
|
||||
timeout = get_timeout(config, %{})
|
||||
|
||||
@@ -124,6 +124,22 @@ defmodule ExUnit.CallbacksTest do
|
||||
"** (MatchError) no match of right hand side value: :error"
|
||||
end
|
||||
|
||||
test "doesn't choke on setup_all exits" do
|
||||
defmodule SetupAllExitTest do
|
||||
use ExUnit.Case
|
||||
|
||||
setup_all _ do
|
||||
Process.exit(self(), :error)
|
||||
end
|
||||
|
||||
test "ok" do
|
||||
assert true
|
||||
end
|
||||
end
|
||||
|
||||
assert capture_io(fn -> ExUnit.run() end) =~ "1 test, 0 failures, 1 invalid"
|
||||
end
|
||||
|
||||
test "doesn't choke on dead supervisor" do
|
||||
defmodule StartSupervisedErrorTest do
|
||||
use ExUnit.Case
|
||||
|
||||
@@ -689,6 +689,8 @@ defmodule IEx.Pry do
|
||||
[asts_string, :faint, " #=> ", :reset, inspect(value, options), "\n\n"]
|
||||
|> IO.ANSI.format()
|
||||
|> IO.write()
|
||||
|
||||
value
|
||||
end
|
||||
|
||||
defp chunk_pipeline_asts_by_line(asts, %Macro.Env{line: env_line}) do
|
||||
|
||||
+25
-18
@@ -210,7 +210,7 @@ defmodule Logger do
|
||||
metadata: [:error_code, :file]
|
||||
|
||||
Or to configure default handler, for instance, to log into a file with
|
||||
built-in support for log rotation:
|
||||
built-in support for log rotation and compression:
|
||||
|
||||
config :logger, :default_handler,
|
||||
config: [
|
||||
@@ -218,9 +218,18 @@ defmodule Logger do
|
||||
filesync_repeat_interval: 5000,
|
||||
file_check: 5000,
|
||||
max_no_bytes: 10_000_000,
|
||||
max_no_files: 5
|
||||
max_no_files: 5,
|
||||
compress_on_rotate: true
|
||||
]
|
||||
|
||||
See [`:logger_std_h`](`:logger_std_h`) for all relevant configuration,
|
||||
including overload protection. Or set `:default_handler` to false to
|
||||
disable the default logging altogether:
|
||||
|
||||
config :logger, :default_handler, false
|
||||
|
||||
How to add new handlers is covered in later sections.
|
||||
|
||||
> #### Keywords or maps {: .tip}
|
||||
>
|
||||
> While Erlang's logger expects `:config` to be a map, Elixir's Logger
|
||||
@@ -231,14 +240,6 @@ defmodule Logger do
|
||||
> When reading the handler configuration using Erlang's APIs,
|
||||
> the configuration will always be read (and written) as a map.
|
||||
|
||||
See [`:logger_std_h`](`:logger_std_h`) for all relevant configuration,
|
||||
including overload protection. Or set `:default_handler` to false to
|
||||
disable the default logging altogether:
|
||||
|
||||
config :logger, :default_handler, false
|
||||
|
||||
How to add new handlers is covered in later sections.
|
||||
|
||||
### Compile configuration
|
||||
|
||||
The following configuration must be set via config files (such as
|
||||
@@ -329,16 +330,19 @@ defmodule Logger do
|
||||
default handler, but you can use Erlang's [`:logger`](`:logger`) module
|
||||
to add other handlers too.
|
||||
|
||||
Erlang/OTP handlers must be listed under your own application. For example,
|
||||
to setup an additional handler that writes to disk:
|
||||
Erlang/OTP handlers must be listed under your own application.
|
||||
For example, to setup an additional handler, so you write to
|
||||
console and file:
|
||||
|
||||
config :my_app, :logger, [
|
||||
{:handler, :disk_log, :logger_disk_log_h, %{
|
||||
{:handler, :file_log, :logger_std_h, %{
|
||||
config: %{
|
||||
file: 'system.log',
|
||||
file: ~c"system.log",
|
||||
filesync_repeat_interval: 5000,
|
||||
file_check: 5000,
|
||||
max_no_bytes: 10_000_000,
|
||||
max_no_files: 5
|
||||
max_no_files: 5,
|
||||
compress_on_rotate: true
|
||||
},
|
||||
formatter: Logger.Formatter.new()
|
||||
}}
|
||||
@@ -355,9 +359,12 @@ defmodule Logger do
|
||||
flexibility but they should avoid performing any long running action in
|
||||
such handlers, as it may slow down the action being executed considerably.
|
||||
At the moment, there is no built-in overload protection for Erlang handlers,
|
||||
so it is your responsibility to implement it. Alternatively, you can use the
|
||||
[`:logger_backends`](https://github.com/elixir-lang/logger_backends)
|
||||
project.
|
||||
so it is your responsibility to implement it.
|
||||
|
||||
Alternatively, you can use the
|
||||
[`:logger_backends`](https://github.com/elixir-lang/logger_backends) project.
|
||||
It sets up a log handler with overload protection and allows incoming events
|
||||
to be dispatched to multiple backends.
|
||||
|
||||
## Backends and backwards compatibility
|
||||
|
||||
|
||||
@@ -136,8 +136,12 @@ defmodule Mix.AppLoader do
|
||||
end
|
||||
|
||||
# We have processed all apps.
|
||||
defp traverse_apps([], _seen, _deps_children, _builtin_paths, _lib_path) do
|
||||
[]
|
||||
defp traverse_apps([], seen, _deps_children, builtin_paths, _lib_path) do
|
||||
# We want to keep erts in the load path but it doesn't require to be loaded.
|
||||
case builtin_paths do
|
||||
%{erts: path} when not is_map_key(seen, :erts) -> [{:erts, path}]
|
||||
%{} -> []
|
||||
end
|
||||
end
|
||||
|
||||
defp app_children(app) do
|
||||
|
||||
@@ -31,7 +31,7 @@ defmodule Mix.Tasks.Compile.All do
|
||||
{loaded_paths, loaded_modules} =
|
||||
Mix.AppLoader.load_apps(apps, deps, config, {[], []}, fn {app, path}, {paths, mods} ->
|
||||
paths = if path, do: [path | paths], else: paths
|
||||
mods = if app_cache, do: [{app, Application.spec(app, :modules)} | mods], else: mods
|
||||
mods = if app_cache, do: [{app, Application.spec(app, :modules) || []} | mods], else: mods
|
||||
{paths, mods}
|
||||
end)
|
||||
|
||||
|
||||
@@ -38,8 +38,9 @@ defmodule Mix.Tasks.Xref do
|
||||
$ mix xref trace lib/my_app/router.ex --label compile
|
||||
|
||||
If you have an umbrella application, we also recommend using the
|
||||
`--include-siblings` flag to see the dependencies on other
|
||||
umbrella applications.
|
||||
`--include-siblings` flag to see the dependencies from sibling
|
||||
applications. The `trace` command is not currently supported at the
|
||||
umbrella root.
|
||||
|
||||
### Example
|
||||
|
||||
@@ -222,6 +223,12 @@ defmodule Mix.Tasks.Xref do
|
||||
lib/a.ex
|
||||
└── lib/b.ex (compile)
|
||||
|
||||
If you have an umbrella application, we also recommend using the
|
||||
`--include-siblings` flag to see the dependencies from sibling
|
||||
applications. When invoked at the umbrella root, the `graph`
|
||||
command will list all files from all umbrella children, without
|
||||
any namespacing.
|
||||
|
||||
### Dependency types
|
||||
|
||||
Elixir tracks three types of dependencies between modules: compile,
|
||||
@@ -289,12 +296,6 @@ defmodule Mix.Tasks.Xref do
|
||||
|
||||
@impl true
|
||||
def run(args) do
|
||||
if Mix.Project.umbrella?() do
|
||||
Mix.raise(
|
||||
"mix xref is not supported in the umbrella root. Please run it inside the umbrella applications instead"
|
||||
)
|
||||
end
|
||||
|
||||
Mix.Task.run("compile", args)
|
||||
Mix.Task.reenable("xref")
|
||||
|
||||
@@ -302,9 +303,11 @@ defmodule Mix.Tasks.Xref do
|
||||
|
||||
case args do
|
||||
["callers", module] ->
|
||||
no_umbrella!("callers")
|
||||
handle_callers(module, opts)
|
||||
|
||||
["trace", file] ->
|
||||
no_umbrella!("trace")
|
||||
handle_trace(file, opts)
|
||||
|
||||
["graph"] ->
|
||||
@@ -327,6 +330,14 @@ defmodule Mix.Tasks.Xref do
|
||||
end
|
||||
end
|
||||
|
||||
defp no_umbrella!(task) do
|
||||
if Mix.Project.umbrella?() do
|
||||
Mix.raise(
|
||||
"mix xref #{task} is not supported in the umbrella root. Please run it inside the umbrella applications instead"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns a list of information of all the runtime function calls in the project.
|
||||
|
||||
@@ -1058,12 +1069,18 @@ defmodule Mix.Tasks.Xref do
|
||||
|
||||
defp manifests(opts) do
|
||||
siblings =
|
||||
if opts[:include_siblings] do
|
||||
for %{scm: Mix.SCM.Path, opts: opts} <- Mix.Dep.cached(),
|
||||
opts[:in_umbrella],
|
||||
do: Path.join([opts[:build], ".mix", @manifest])
|
||||
else
|
||||
[]
|
||||
cond do
|
||||
Mix.Project.umbrella?() ->
|
||||
for %{opts: opts} <- Mix.Dep.Umbrella.cached(),
|
||||
do: Path.join([opts[:build], ".mix", @manifest])
|
||||
|
||||
opts[:include_siblings] ->
|
||||
for %{scm: Mix.SCM.Path, opts: opts} <- Mix.Dep.cached(),
|
||||
opts[:in_umbrella],
|
||||
do: Path.join([opts[:build], ".mix", @manifest])
|
||||
|
||||
true ->
|
||||
[]
|
||||
end
|
||||
|
||||
[Path.join(Mix.Project.manifest_path(), @manifest) | siblings]
|
||||
|
||||
@@ -335,6 +335,10 @@ defmodule Mix.Tasks.CompileTest do
|
||||
in_fixture("no_mixfile", fn ->
|
||||
assert Mix.Task.run("compile", []) == {:ok, []}
|
||||
assert :code.where_is_file(~c"parsetools.app") == :non_existing
|
||||
|
||||
# Make sure erts is also kept but not loaded
|
||||
assert {:docs_v1, _, _, _, _, _, _} = Code.fetch_docs(:zlib)
|
||||
assert Application.spec(:erts, :vsn) == nil
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
@@ -915,6 +915,43 @@ defmodule Mix.Tasks.XrefTest do
|
||||
end)
|
||||
end
|
||||
|
||||
test "generates reports from the umbrella root" do
|
||||
Mix.Project.pop()
|
||||
|
||||
in_fixture("umbrella_dep/deps/umbrella", fn ->
|
||||
Mix.Project.in_project(:umbrella, ".", fn _ ->
|
||||
File.write!("apps/bar/lib/bar.ex", """
|
||||
defmodule Bar do
|
||||
def bar do
|
||||
Foo.foo()
|
||||
end
|
||||
end
|
||||
""")
|
||||
|
||||
Mix.Task.run("compile")
|
||||
Mix.shell().flush()
|
||||
|
||||
Mix.Tasks.Xref.run(["graph", "--format", "stats", "--include-siblings"])
|
||||
|
||||
assert receive_until_no_messages([]) == """
|
||||
Tracked files: 2 (nodes)
|
||||
Compile dependencies: 0 (edges)
|
||||
Exports dependencies: 0 (edges)
|
||||
Runtime dependencies: 1 (edges)
|
||||
Cycles: 0
|
||||
|
||||
Top 2 files with most outgoing dependencies:
|
||||
* lib/bar.ex (1)
|
||||
* lib/foo.ex (0)
|
||||
|
||||
Top 2 files with most incoming dependencies:
|
||||
* lib/foo.ex (1)
|
||||
* lib/bar.ex (0)
|
||||
"""
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
test "generates reports considering siblings inside umbrellas" do
|
||||
Mix.Project.pop()
|
||||
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
home = Path.expand("../tmp/.home", __DIR__)
|
||||
File.mkdir_p!(home)
|
||||
System.put_env("HOME", home)
|
||||
|
||||
mix = Path.expand("../tmp/.mix", __DIR__)
|
||||
File.mkdir_p!(mix)
|
||||
System.put_env("MIX_HOME", mix)
|
||||
|
||||
System.delete_env("XDG_DATA_HOME")
|
||||
System.delete_env("XDG_CONFIG_HOME")
|
||||
|
||||
## Setup Mix
|
||||
|
||||
Mix.start()
|
||||
Mix.shell(Mix.Shell.Process)
|
||||
Application.put_env(:mix, :colors, enabled: false)
|
||||
@@ -5,6 +18,8 @@ Application.put_env(:mix, :colors, enabled: false)
|
||||
Logger.remove_backend(:console)
|
||||
Application.put_env(:logger, :backends, [])
|
||||
|
||||
## Setup ExUnit
|
||||
|
||||
os_exclude = if match?({:win32, _}, :os.type()), do: [unix: true], else: [windows: true]
|
||||
epmd_exclude = if match?({:win32, _}, :os.type()), do: [epmd: true], else: []
|
||||
git_exclude = if Mix.SCM.Git.git_version() <= {1, 7, 4}, do: [git_sparse: true], else: []
|
||||
@@ -212,18 +227,7 @@ defmodule MixTest.Case do
|
||||
end
|
||||
end
|
||||
|
||||
## Set up globals
|
||||
|
||||
home = MixTest.Case.tmp_path(".home")
|
||||
File.mkdir_p!(home)
|
||||
System.put_env("HOME", home)
|
||||
|
||||
mix = MixTest.Case.tmp_path(".mix")
|
||||
File.mkdir_p!(mix)
|
||||
System.put_env("MIX_HOME", mix)
|
||||
|
||||
System.delete_env("XDG_DATA_HOME")
|
||||
System.delete_env("XDG_CONFIG_HOME")
|
||||
## Set up Rebar fixtures
|
||||
|
||||
rebar3_source = System.get_env("REBAR3") || Path.expand("fixtures/rebar3", __DIR__)
|
||||
[major, minor | _] = String.split(System.version(), ".")
|
||||
@@ -231,8 +235,6 @@ rebar3_target = Path.join([mix, "elixir", "#{major}-#{minor}", "rebar3"])
|
||||
File.mkdir_p!(Path.dirname(rebar3_target))
|
||||
File.cp!(rebar3_source, rebar3_target)
|
||||
|
||||
## Copy fixtures to tmp
|
||||
|
||||
fixtures = ~w(rebar_dep rebar_override)
|
||||
|
||||
Enum.each(fixtures, fn fixture ->
|
||||
@@ -242,12 +244,13 @@ Enum.each(fixtures, fn fixture ->
|
||||
File.cp_r!(source, dest)
|
||||
end)
|
||||
|
||||
## Generate Git repo fixtures
|
||||
## Set up Git fixtures
|
||||
|
||||
System.cmd("git", ~w[config --global user.email mix@example.com])
|
||||
System.cmd("git", ~w[config --global user.name mix-repo])
|
||||
System.cmd("git", ~w[config --global init.defaultBranch not-main])
|
||||
|
||||
# Git repo
|
||||
### Git repo
|
||||
target = Path.expand("fixtures/git_repo", __DIR__)
|
||||
|
||||
unless File.dir?(target) do
|
||||
@@ -329,7 +332,7 @@ unless File.dir?(target) do
|
||||
end)
|
||||
end
|
||||
|
||||
# Deps on Git repo
|
||||
### Deps on Git repo
|
||||
target = Path.expand("fixtures/deps_on_git_repo", __DIR__)
|
||||
|
||||
unless File.dir?(target) do
|
||||
@@ -423,7 +426,7 @@ Enum.each([:invalidapp, :invalidvsn, :noappfile, :nosemver, :ok], fn dep ->
|
||||
File.mkdir_p!(Path.expand("fixtures/deps_status/deps/#{dep}/.git", __DIR__))
|
||||
end)
|
||||
|
||||
# Archive ebin
|
||||
### Archive ebin
|
||||
target = Path.expand("fixtures/archive", __DIR__)
|
||||
|
||||
unless File.dir?(Path.join(target, "ebin")) do
|
||||
|
||||
Reference in New Issue
Block a user