diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml
index 8dbf42a..35e398c 100644
--- a/.github/workflows/build-windows.yml
+++ b/.github/workflows/build-windows.yml
@@ -87,8 +87,8 @@ jobs:
mix local.rebar --force
- name: Fetch dependencies
- # No ELIXIR_TORRENT_PATH on CI: mix.exs falls back to the published
- # :elixir_torrent package, never a local sibling checkout.
+ # CI is set on GitHub runners, so mix.exs takes the published
+ # :elixir_torrent package pinned by mix.lock, never a local checkout.
run: mix deps.get
- name: Compile (dev)
diff --git a/.gitignore b/.gitignore
index 401340c..ddab27b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,9 @@ erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
+# Dependency lock of a build against a local engine checkout (see mix.exs).
+/mix.local.lock
+
# Temporary files, for example, from tests.
/tmp/
diff --git a/.tool-versions b/.tool-versions
index 5617120..8dfeb9e 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1,2 +1,2 @@
-erlang 29.1.1
+erlang 29.1.2
elixir 1.20.4-otp-29
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4e02ac4..c63e310 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -22,11 +22,7 @@ mix setup
mix phx.server
```
-Requires Elixir 1.20+ on OTP 29 (see `.tool-versions` for the exact toolchain CI pins). By default the engine is pulled from Hex. To develop against a local engine checkout instead, point `ELIXIR_TORRENT_PATH` at it — but never commit the resulting `mix.lock` change:
-
-```bash
-ELIXIR_TORRENT_PATH=../ElixirTorrent mix deps.get
-```
+Requires Elixir 1.20+ on OTP 29 (see `.tool-versions` for the exact toolchain CI pins). With the engine checked out next to this repository as `../ElixirTorrent`, it is used automatically; `ELIXIR_TORRENT_PATH` points at a checkout elsewhere, and `ELIXIR_TORRENT_HEX=1` (or CI) takes the published Hex package. A local engine build keeps its own gitignored `mix.local.lock`, so `mix.lock` only ever pins the Hex release. See the README's "Engine dependency" section.
The native launchers are optional for most work and only build on their own platform: the Swift shell (`priv/macos/src/`) needs Xcode 27 with the Swift 6.4 toolchain, and the C# WinUI 3 shell (`priv/windows/Launcher/`) needs the .NET 10 SDK on Windows 11 x64.
diff --git a/README.md b/README.md
index 12b4762..091307e 100644
--- a/README.md
+++ b/README.md
@@ -107,17 +107,26 @@ handler registration.
## Engine dependency
-The committed dependency remains the published Hex package. While both projects
-evolve together, validate the WebUI against a local Engine checkout by setting:
+`mix.exs` picks the engine source in this order:
+
+1. `ELIXIR_TORRENT_PATH=
`: that local Engine checkout.
+2. `ELIXIR_TORRENT_HEX=1`, or any CI run (`CI` set): the published Hex package
+ pinned by `mix.lock`.
+3. Otherwise the sibling `../ElixirTorrent` checkout when it exists, and Hex
+ when it does not.
+
+So with both repositories checked out side by side, `mix deps.get`, `mix test`
+and `mix mac.dmg` build against the local Engine with no extra setup.
+
+A local Engine resolves its own dependencies, which drift ahead of the committed
+lock whenever the Engine bumps one. Local builds therefore use their own
+`mix.local.lock` (gitignored, seeded from `mix.lock` on first use), and
+`mix.lock` changes only when the Hex dependency itself is updated:
```bash
-export ELIXIR_TORRENT_PATH=../ElixirTorrent
-mix deps.get
+ELIXIR_TORRENT_HEX=1 mix deps.update elixir_torrent
```
-The local path and Engine revision are development inputs, not committed pins.
-Do not commit lock-file changes caused only by switching dependency sources.
-
## Tests and quality
The deterministic ExUnit/ConnTest/LiveViewTest suite has a 60-second ceiling.
@@ -125,7 +134,6 @@ ExCoveralls currently enforces the first 55% project gate (57.2% at introduction
the roadmap raises this to 70% and then above 80%.
```bash
-export ELIXIR_TORRENT_PATH=../ElixirTorrent
mix format --check-formatted
mix quality
perl -e 'alarm shift; exec @ARGV' 60 mix coveralls
diff --git a/config/prod.exs b/config/prod.exs
index da8d861..0e51f8a 100644
--- a/config/prod.exs
+++ b/config/prod.exs
@@ -23,8 +23,25 @@ end
# A diagnostic build (`ELIXIR_TORRENT_DEBUG_BUILD=1 mix mac.dmg`) keeps the
# `Logger.debug` call sites instead of purging them at compile time, so the
# level can still be raised back to `:info` over RPC without a rebuild.
+#
+# Its volume (~500-900 lines/s with a dozen torrents) is above the default
+# handler's overload protection: `burst_limit_max_count: 500` per second and
+# `drop_mode_qlen: 200` silently discarded every line past the cap, info and
+# warning included, so a debug log read 501 lines in a median second and was
+# missing whole events. A diagnostic log that drops lines is no diagnostic, so
+# the debug build turns the burst limit off and lets the queue grow before it
+# blocks or drops.
if System.get_env("ELIXIR_TORRENT_DEBUG_BUILD") == "1" do
config :logger, level: :debug
+
+ config :logger, :default_handler,
+ config: [
+ burst_limit_enable: false,
+ sync_mode_qlen: 5_000,
+ drop_mode_qlen: 20_000,
+ flush_qlen: 50_000
+ ]
+
config :elixir_torrent_web_ui, :debug_tools, true
else
config :logger,
diff --git a/mix.exs b/mix.exs
index 9fdaf34..e5b29fd 100644
--- a/mix.exs
+++ b/mix.exs
@@ -11,6 +11,7 @@ defmodule ElixirTorrentWebUI.MixProject do
start_permanent: Mix.env() == :prod,
aliases: aliases(),
deps: deps(),
+ lockfile: lockfile(),
test_coverage: [tool: ExCoveralls],
compilers: [:phoenix_live_view] ++ Mix.compilers(),
listeners: [Phoenix.CodeReloader]
@@ -85,12 +86,52 @@ defmodule ElixirTorrentWebUI.MixProject do
# ELIXIR_TORRENT_PATH=../ElixirTorrent mix deps.get
# ELIXIR_TORRENT_PATH=../ElixirTorrent mix phx.server
defp elixir_torrent_dep do
- case System.get_env("ELIXIR_TORRENT_PATH") do
- nil -> {:elixir_torrent, "~> 0.6.8"}
+ case engine_path() do
+ nil -> {:elixir_torrent, "~> 0.7.0"}
path -> {:elixir_torrent, path: path}
end
end
+ # Where the engine comes from:
+ # * `ELIXIR_TORRENT_PATH` names a local checkout explicitly;
+ # * `ELIXIR_TORRENT_HEX=1`, or any CI run, takes the published package;
+ # * otherwise the sibling `../ElixirTorrent` checkout, when it exists.
+ # So a developer machine with both repos builds against the local engine by
+ # default, and CI keeps building the release users get from Hex.
+ defp engine_path do
+ explicit = System.get_env("ELIXIR_TORRENT_PATH")
+ sibling = Path.expand("../ElixirTorrent", __DIR__)
+
+ cond do
+ explicit not in [nil, ""] -> explicit
+ System.get_env("ELIXIR_TORRENT_HEX") == "1" or System.get_env("CI") != nil -> nil
+ File.regular?(Path.join(sibling, "mix.exs")) -> sibling
+ true -> nil
+ end
+ end
+
+ # The committed `mix.lock` pins the Hex engine and the versions it brings. A
+ # local engine resolves its own dependencies, which drift ahead of that lock as
+ # soon as the engine bumps one, and `deps.get --check-locked` then fails. A local
+ # build therefore keeps its own lock, seeded from the committed one, so switching
+ # sources never touches `mix.lock`.
+ @local_lockfile "mix.local.lock"
+
+ defp lockfile do
+ if engine_path() do
+ local = Path.join(__DIR__, @local_lockfile)
+ committed = Path.join(__DIR__, "mix.lock")
+
+ if not File.exists?(local) and File.exists?(committed) do
+ File.cp!(committed, local)
+ end
+
+ @local_lockfile
+ else
+ "mix.lock"
+ end
+ end
+
# Aliases are shortcuts or tasks specific to the current project.
# For example, to install project dependencies and perform other setup tasks, run:
#
diff --git a/mix.lock b/mix.lock
index 5a23c51..c279ec0 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,5 +1,5 @@
%{
- "bandit": {:hex, :bandit, "1.12.5", "af205a8e550f304caae09a97d29fd3c79a7f337526ea7cd772d2ff11d2f7c800", [:mix], [{:hpax, "~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.18", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.5", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "c5684ca062fa407cac115aec3256383f3e2ec9fdced7904d59cf5a7bb7ed6181"},
+ "bandit": {:hex, :bandit, "1.13.1", "1ce25a7beb750ed3fa2e905962f1f9a679cb585f1da0ae45637d06e385ce2eae", [:mix], [{:hpax, "~> 1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.18", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.6", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "39028f0b5a21404661410a6c19275060a9822c9dcca70b7c3e4e4fa50b11da58"},
"bento": {:hex, :bento, "1.0.0", "5097e6f02e4980b72d08bf0270026f6f5c9bf5d8ca606b43d41321b549d49de8", [:mix], [], "hexpm", "b921b335a555f7570adfac0cc41864c76377f6852617cf1f25fbb88578b993c8"},
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
"cc_precompiler": {:hex, :cc_precompiler, "0.1.11", "8c844d0b9fb98a3edea067f94f616b3f6b29b959b6b3bf25fee94ffe34364768", [:mix], [{:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "3427232caf0835f94680e5bcf082408a70b48ad68a5f5c0b02a3bea9f3a075b9"},
@@ -8,7 +8,7 @@
"dialyxir": {:hex, :dialyxir, "1.4.8", "7ef671a8aff9948b091d8c30f09467fbb16e77305cda451bce48109a0f5e021c", [:mix], [{:erlex, ">= 0.2.8", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "cbd5a851571e5dfeb32aaf2e840bfa98b7864cb3071bf2ef5d95d1276b12e072"},
"dns_cluster": {:hex, :dns_cluster, "0.3.1", "b4e707e4ddaf0d3f13580ee7dc4ab0e685f7f7f5bbe90e84535524bc12d1cf3e", [:mix], [], "hexpm", "afa60bbbd84463e977eeeecc0c564d8c5ddea260beccdb8d5f45cbb860846627"},
"elixir_make": {:hex, :elixir_make, "0.10.0", "16577e2583a79bb79237bbff349619ef5d80afffc07eac6e4faf0d00e2ddaf7d", [:mix], [], "hexpm", "dc1f09fb7fa68866b886abd5f0f3c83553b1a19a52359a899e92af1bb3b31982"},
- "elixir_torrent": {:hex, :elixir_torrent, "0.6.8", "c54a92d7c7bb898c564de48e0c821378bf473fd68a923ac9d460db1afe7ba955", [:mix], [{:bento, "~> 1.0.0", [hex: :bento, repo: "hexpm", optional: false]}, {:httpoison, "~> 3.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:logger_backends, "~> 1.0", [hex: :logger_backends, repo: "hexpm", optional: false]}, {:logger_file_backend, "~> 0.1.1", [hex: :logger_file_backend, repo: "hexpm", optional: false]}, {:recon, "~> 2.5.6", [hex: :recon, repo: "hexpm", optional: false]}], "hexpm", "a5ca789924b3cb02613c1467e89e2fdf4318177f665d6880045cee7f25570cfc"},
+ "elixir_torrent": {:hex, :elixir_torrent, "0.7.0", "8fd9566757c3c1cbce393e3f147106d95f00b14ee60697fe964a86b9f5f3bc59", [:mix], [{:bento, "~> 1.0.0", [hex: :bento, repo: "hexpm", optional: false]}, {:httpoison, "~> 3.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:logger_backends, "~> 1.0", [hex: :logger_backends, repo: "hexpm", optional: false]}, {:logger_file_backend, "~> 0.1.1", [hex: :logger_file_backend, repo: "hexpm", optional: false]}, {:recon, "~> 2.5.6", [hex: :recon, repo: "hexpm", optional: false]}], "hexpm", "a544b80fd4d0651e6b269f9a6dbb89671a1864c294919f2f0cec452842552672"},
"erlex": {:hex, :erlex, "0.2.9", "7debbbaa9f4f368b8cd648983e0f1d7963028508e9c59e9d4ed504e94ef52a55", [:mix], [], "hexpm", "8cfffc0ec7159e6d73de2ab28a588064de80f88b2798d5cbe4482cbbc200178b"},
"esbuild": {:hex, :esbuild, "0.10.0", "b0aa3388a1c23e727c5a3e7427c932d89ee791746b0081bbe56103e9ef3d291f", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "468489cda427b974a7cc9f03ace55368a83e1a7be12fba7e30969af78e5f8c70"},
"excoveralls": {:hex, :excoveralls, "0.18.5", "e229d0a65982613332ec30f07940038fe451a2e5b29bce2a5022165f0c9b157e", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "523fe8a15603f86d64852aab2abe8ddbd78e68579c8525ae765facc5eae01562"},
@@ -16,8 +16,8 @@
"file_system": {:hex, :file_system, "1.1.1", "31864f4685b0148f25bd3fbef2b1228457c0c89024ad67f7a81a3ffbc0bbad3a", [:mix], [], "hexpm", "7a15ff97dfe526aeefb090a7a9d3d03aa907e100e262a0f8f7746b78f8f87a5d"},
"fine": {:hex, :fine, "0.1.6", "4bf7151493443c454aac9f2fa2f34f5fefd0346a83fb5586a016c4a135c63247", [:mix], [], "hexpm", "5638eb4495488e885ebec167fa57973e5c35e1a50c344eb7666c90ec1c4e3b12"},
"gettext": {:hex, :gettext, "1.0.2", "5457e1fd3f4abe47b0e13ff85086aabae760497a3497909b8473e0acee57673b", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "eab805501886802071ad290714515c8c4a17196ea76e5afc9d06ca85fb1bfeb3"},
- "h2": {:hex, :h2, "0.12.3", "20e3fd0e384ec6f586e4736acd409a57ea87b4a56002d8dcf1132514b3d7600a", [:rebar3], [], "hexpm", "996af98698f7dc68bcc7688d70d97384b53ddd0286ba07e6d4a9ac54f1970d32"},
- "hackney": {:hex, :hackney, "4.8.4", "73d1c4389a7a41b90c169e8af2253d307213506b4f199e8c216265a563b49b55", [:rebar3], [{:certifi, "~> 2.17.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:h2, "~> 0.12.3", [hex: :h2, repo: "hexpm", optional: false]}, {:idna, "~> 7.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.5", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.2", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:quic, "~> 2.0", [hex: :quic, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:webtransport, "~> 0.4.7", [hex: :webtransport, repo: "hexpm", optional: false]}], "hexpm", "4d3f3575c1d9a50a66e0469e303477fe72acffe98b108cd164621b75c22bb583"},
+ "h2": {:hex, :h2, "0.12.4", "f8cb769ccc17369d185717135353bee1d50f2cd193a9e8cd998d88ce6cafc51d", [:rebar3], [], "hexpm", "238553579d2599e823f1f7b1cacb763362ee6e2df8e8f3b0c8fc67da982c0675"},
+ "hackney": {:hex, :hackney, "4.8.5", "214a58c2e77115b0e2c171f01e59b7fbcb257e07471fc0ae1814b4654f8e2fa4", [:rebar3], [{:certifi, "~> 2.17.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:h2, "~> 0.12.4", [hex: :h2, repo: "hexpm", optional: false]}, {:idna, "~> 7.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.5", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.2", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:quic, "~> 2.1.1", [hex: :quic, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:webtransport, "~> 0.4.8", [hex: :webtransport, repo: "hexpm", optional: false]}], "hexpm", "d1c18324ce5eaa5e45a245f31e68d212c4f3f24ee0a27e4eac09c5959831c138"},
"heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "0435d4ca364a608cc75e2f8683d374e55abbae26", [tag: "v2.2.0", sparse: "optimized", depth: 1]},
"hpax": {:hex, :hpax, "1.1.0", "782931867cc23217c68fb5f68fe1a11f5e7544c7fda82c8a7019a5df5a4a1cdf", [:mix], [], "hexpm", "0b8d0f05832f55571d65ac720f79bf8994138ffbb133209dc4685eae0ad456a8"},
"httpoison": {:hex, :httpoison, "3.0.0", "8566a933bb9175236d1ec335978445b67cd1f5b5d3ead6ca4b80be469d41f5d9", [:mix], [{:hackney, "~> 4.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "9130197b7658901c493d6fcfb842fb9676300fa8a6c8ed058c8889cf1a77f3c2"},
@@ -34,11 +34,11 @@
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.9.1", "d4786b24bbe1eacc431049dbbb8d377f5359fce57b9d7cdd773bba4ac0af2ef6", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "de25e1a28cfb64413d8bdaf3ba5b64da1a19e0ed44a02320119523cc45da051d"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.7.0", "fb1e429f6d8778ce3a6962debdc5e555428a05a6e7b058d6dbad13d281a2c31f", [:mix], [{:file_system, "~> 0.2.10 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "dc9f44271aa6fc4ab7797f2aa374ba096ef2c87520586280eb095626b7387a68"},
"phoenix_live_view": {:hex, :phoenix_live_view, "1.2.12", "35848150bbab579e9d0aff79525269d7c0801a4f61232b84f635c11222cee88f", [:mix], [{:igniter, ">= 0.6.16 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:lazy_html, "~> 0.1.0", [hex: :lazy_html, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0 or ~> 1.8.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "656810d716e3369545dd63981196a5d68b77fdb253afe02ef0c6fa14cfd8dc2b"},
- "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.3.0", "03916bfbc31a5121945b3cfffe5aec647a5c97fe1dc172a319b94428562359c9", [:mix], [], "hexpm", "eec7be6e9cf02e2551d389b558402d6c637cd3973796326e7ba4bb03c6b2e91d"},
+ "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.4.1", "2ff3e7ba8b432120989870997b9adaefb76e1f63805554ab0b9e948987981f4b", [:mix], [], "hexpm", "352fba7a87bf61395b6e97da66944ad9b1bfe5459e5981039f60d68270bd9700"},
"phoenix_template": {:hex, :phoenix_template, "1.1.0", "b329582281b1e00e4dc664afd60ef5b489cbb356923caa3b1e00abe8651b9a18", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "eba70070de79b2c3501ef205a74a69f98ab352f3785aa15da9ed161f9fe0fd5d"},
"plug": {:hex, :plug, "1.20.3", "56c480c633ec2ce10140e236e15233bf576e1d323887d7c96711bd02ab5160db", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "be266aee1b8536ef6409d58cf39a3121319f0ec47cfa1b24024485aa0e76ad76"},
"plug_crypto": {:hex, :plug_crypto, "2.2.0", "144014737daaf485407f5ed77daeaad74d651b216a28c87543f8cc7043f8efc8", [:mix], [], "hexpm", "83a95744ab1c75876542b6fab135fcc176280e0f301a111c1f757fddcec95d2c"},
- "quic": {:hex, :quic, "2.1.0", "abfea35b8abd108510ccd693b78fcb0844b8fb75ed09d227dc1fa72477d4baac", [:rebar3], [], "hexpm", "58b250ae21045bd3838a448de0592e2cd61b73586307bd6cdcbab1bf246f52ed"},
+ "quic": {:hex, :quic, "2.1.1", "e5099110061f5f68fcd57ece30dfb419a2360cbaff2f58a40517b08f831b630f", [:rebar3], [], "hexpm", "305d78a857298d940f6621a9acd7391c02980555d5e7fffef364eccd330fd64d"},
"recon": {:hex, :recon, "2.5.6", "9052588e83bfedfd9b72e1034532aee2a5369d9d9343b61aeb7fbce761010741", [:mix, :rebar3], [], "hexpm", "96c6799792d735cc0f0fd0f86267e9d351e63339cbe03df9d162010cefc26bb0"},
"sobelow": {:hex, :sobelow, "0.16.0", "13e3f761bc7fcc88e81ae23ddef9140617a12a3efb26601e5516453290539398", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "00a0260edf9aeac35d9116366f55dc9451d11e0e696e28ec5570c6a56bd41f1e"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
@@ -46,8 +46,8 @@
"telemetry": {:hex, :telemetry, "1.4.2", "a0cb522801dffb1c49fe6e30561badffc7b6d0e180db1300df759faa22062855", [:rebar3], [], "hexpm", "928f6495066506077862c0d1646609eed891a4326bee3126ba54b60af61febb1"},
"telemetry_metrics": {:hex, :telemetry_metrics, "1.2.0", "7632c19c01d88d8aaca5da1a0e8912f5af39b79e7c08a2c253aeb3c14c2c957e", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "71dde12fc29b58b9c77ec17ec319109e5ca848d010fc1965ed4463bba1837c07"},
"telemetry_poller": {:hex, :telemetry_poller, "1.3.0", "d5c46420126b5ac2d72bc6580fb4f537d35e851cc0f8dbd571acf6d6e10f5ec7", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "51f18bed7128544a50f75897db9974436ea9bfba560420b646af27a9a9b35211"},
- "thousand_island": {:hex, :thousand_island, "1.5.0", "f50a213cac97262b6d5ebb85745aa2c00fec1413191e6e66834788d45425cecb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "708923d40523e43cf99041ab37a0d4b0ec426ac6438fa3716ab23d919eaeb412"},
+ "thousand_island": {:hex, :thousand_island, "1.6.0", "d6ad7c2220c96a270cc8ca1586ec4d8bde648a4a3a53f003ce093f41beec0288", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4d4720470f091fc21a1311777c2ac66916c43621bffc068590c9f9bb3cd057a3"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
"websock_adapter": {:hex, :websock_adapter, "0.6.0", "73db5ab8aaefd1a876a97ce3e6afc96562625de69ef17a4e04426e034849d0b8", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "50021a85bce8f203b086705d9e0c5415e2c7eb05d319111b0428fe71f9934617"},
- "webtransport": {:hex, :webtransport, "0.4.7", "8e0abd5875daab05c7020b8fc0c3b318fe93aa9329302fe5ecda2a0f953cf688", [:rebar3], [{:h2, "~> 0.12", [hex: :h2, repo: "hexpm", optional: false]}, {:quic, "~> 2.0", [hex: :quic, repo: "hexpm", optional: false]}], "hexpm", "9d2fcbfc561a172cf6f2eef00b89fc89774c039ce850414356964c147707f85e"},
+ "webtransport": {:hex, :webtransport, "0.4.8", "3c340d7ea381e3f639ece90378d85fb46b1da4eece17bba3223051e833166501", [:rebar3], [{:h2, "~> 0.12", [hex: :h2, repo: "hexpm", optional: false]}, {:quic, "~> 2.0", [hex: :quic, repo: "hexpm", optional: false]}], "hexpm", "08477a2195ccbf944da0b78f85dc4e6ee4498790e3dd7fe84ee7a245938e1b26"},
}
diff --git a/priv/scripts/macos/build-macos-dmg.sh b/priv/scripts/macos/build-macos-dmg.sh
index cfb5f2e..7acf7a5 100755
--- a/priv/scripts/macos/build-macos-dmg.sh
+++ b/priv/scripts/macos/build-macos-dmg.sh
@@ -6,7 +6,16 @@ cd "$ROOT"
APP_DISPLAY_NAME="ElixirTorrent Web"
EXECUTABLE_NAME="ElixirTorrentWebUI"
-VERSION="$(mix run -e 'IO.write(Mix.Project.config()[:version])' --no-start --no-compile 2>/dev/null || echo 0.1.0)"
+# --no-deps-check: these probes only read mix.exs, and must not fail (and fall
+# back to a stale default) just because deps are not fetched or locked yet.
+mix_config() {
+ mix run -e "IO.write(Mix.Project.config()[:$1])" --no-start --no-compile --no-deps-check 2>/dev/null
+}
+VERSION="$(mix_config version || echo 0.1.0)"
+# mix.exs builds against the sibling ../ElixirTorrent checkout when it exists
+# (or ELIXIR_TORRENT_PATH), with its own lock; only the Hex build is held to the
+# committed mix.lock.
+LOCKFILE="$(mix_config lockfile || echo mix.lock)"
DIST="$ROOT/dist"
APP="$DIST/${APP_DISPLAY_NAME}.app"
STAGING="$DIST/dmg-staging"
@@ -38,7 +47,13 @@ echo "==> Building release (prod, desktop)…"
export ELIXIR_TORRENT_DESKTOP_BUILD=1
export MIX_ENV=prod
-mix deps.get --only prod --check-locked
+if [[ "$LOCKFILE" == "mix.lock" ]]; then
+ echo "==> Engine: elixir_torrent from Hex (mix.lock)"
+ mix deps.get --only prod --check-locked
+else
+ echo "==> Engine: local checkout (${LOCKFILE})"
+ mix deps.get --only prod
+fi
MIX_ENV=prod mix compile
mix phx.digest.clean --all
mix assets.deploy