Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

automatically detect musl, allow overriding target #109

Merged
merged 2 commits into from
Feb 3, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 66 additions & 17 deletions lib/tailwind.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ defmodule Tailwind do

## Tailwind configuration

There are two global configurations for the tailwind application:
There are four global configurations for the tailwind application:

* `:version` - the expected tailwind version

Expand All @@ -36,6 +36,10 @@ defmodule Tailwind do
default, it is automatically downloaded and placed inside
the `_build` directory of your current app

* `:target` - the target architecture for the tailwind executable.
For example `"linux-x64-musl"`. By default, it is automatically detected
based on system information.

Overriding the `:path` is not recommended, as we will automatically
download and manage `tailwind` for you. But in case you can't download
it (for example, GitHub behind a proxy), you may want to
Expand Down Expand Up @@ -109,6 +113,13 @@ defmodule Tailwind do
Application.get_env(:tailwind, :version, latest_version())
end

@doc """
Returns the configured tailwind target. By default, it is automatically detected.
"""
def configured_target do
Application.get_env(:tailwind, :target, target())
end

@doc """
Returns the configuration for the given profile.

Expand Down Expand Up @@ -138,7 +149,7 @@ defmodule Tailwind do
The executable may not be available if it was not yet installed.
"""
def bin_path do
name = "tailwind-#{target()}"
name = "tailwind-#{configured_target()}"

Application.get_env(:tailwind, :path) ||
if Code.ensure_loaded?(Mix.Project) do
Expand Down Expand Up @@ -248,19 +259,45 @@ defmodule Tailwind do
# tailwindcss-windows-x64.exe
defp target do
arch_str = :erlang.system_info(:system_architecture)
[arch | _] = arch_str |> List.to_string() |> String.split("-")

case {:os.type(), arch, :erlang.system_info(:wordsize) * 8} do
{{:win32, _}, _arch, 64} -> "windows-x64.exe"
{{:unix, :darwin}, arch, 64} when arch in ~w(arm aarch64) -> "macos-arm64"
{{:unix, :darwin}, "x86_64", 64} -> "macos-x64"
{{:unix, :freebsd}, "aarch64", 64} -> "freebsd-arm64"
{{:unix, :freebsd}, arch, 64} when arch in ~w(x86_64 amd64) -> "freebsd-x64"
{{:unix, :linux}, "aarch64", 64} -> "linux-arm64"
{{:unix, :linux}, "arm", 32} -> "linux-armv7"
{{:unix, :linux}, "armv7" <> _, 32} -> "linux-armv7"
{{:unix, _osname}, arch, 64} when arch in ~w(x86_64 amd64) -> "linux-x64"
{_os, _arch, _wordsize} -> raise "tailwind is not available for architecture: #{arch_str}"
target_triple = arch_str |> List.to_string() |> String.split("-")

{arch, abi} =
case target_triple do
[arch, _vendor, _system, abi] -> {arch, abi}
[arch, _vendor, abi] -> {arch, abi}
[arch | _] -> {arch, nil}
end

case {:os.type(), arch, abi, :erlang.system_info(:wordsize) * 8} do
{{:win32, _}, _arch, _abi, 64} ->
"windows-x64.exe"

{{:unix, :darwin}, arch, _abi, 64} when arch in ~w(arm aarch64) ->
"macos-arm64"

{{:unix, :darwin}, "x86_64", _abi, 64} ->
"macos-x64"

{{:unix, :freebsd}, "aarch64", _abi, 64} ->
"freebsd-arm64"

{{:unix, :freebsd}, arch, _abi, 64} when arch in ~w(x86_64 amd64) ->
"freebsd-x64"

{{:unix, :linux}, "aarch64", "musl", 64} ->
"linux-arm64-musl"

{{:unix, :linux}, "aarch64", _abi, 64} ->
"linux-arm64"

{{:unix, _osname}, arch, "musl", 64} when arch in ~w(x86_64 amd64) ->
"linux-x64-musl"

{{:unix, _osname}, arch, _abi, 64} when arch in ~w(x86_64 amd64) ->
"linux-x64"

{_os, _arch, _abi, _wordsize} ->
raise "tailwind is not available for architecture: #{arch_str}"
end
end

Expand Down Expand Up @@ -299,6 +336,18 @@ defmodule Tailwind do
{_, {:ok, {{_, 200, _}, _headers, body}}} ->
body

{_, {:ok, {{_, 404, _}, _headers, _body}}} ->
raise """
The tailwind binary couldn't be found at: #{url}

This could mean that you're trying to install a version that does not support the detected
target architecture.

You can see the available files for the configured version at:

https://github.com/tailwindlabs/tailwindcss/releases/tag/v#{configured_version()}
"""

{true, {:error, {:failed_connect, [{:to_address, _}, {inet, _, reason}]}}}
when inet in [:inet, :inet6] and
reason in [:ehostunreach, :enetunreach, :eprotonosupport, :nxdomain] ->
Expand All @@ -316,7 +365,7 @@ defmodule Tailwind do
your certificates are set via OTP ca certfile overide via SSL configuration.

2. Manually download the executable from the URL above and
place it inside "_build/tailwind-#{target()}"
place it inside "_build/tailwind-#{configured_target()}"

3. Install and use Tailwind from npmJS. See our module documentation
to learn more: https://hexdocs.pm/tailwind
Expand Down Expand Up @@ -363,6 +412,6 @@ defmodule Tailwind do
defp get_url(base_url) do
base_url
|> String.replace("$version", configured_version())
|> String.replace("$target", target())
|> String.replace("$target", configured_target())
end
end