Skip to content

Commit 0dfd799

Browse files
authored
Merge pull request #4 from Intellection/rustler-precompiled
Integrate RustlerPrecompiled for Precompiled NIFs & CI/CD Enhancements
2 parents 796dc94 + 050a33d commit 0dfd799

File tree

7 files changed

+185
-113
lines changed

7 files changed

+185
-113
lines changed

.github/workflows/ci.yml

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
name: CI
2+
on:
3+
push:
4+
branches:
5+
- main
6+
pull_request:
7+
workflow_dispatch:
8+
9+
env:
10+
EXSTATIC_BUILD: true
11+
MIX_ENV: test
12+
13+
jobs:
14+
test:
15+
strategy:
16+
matrix:
17+
include:
18+
- otp_version: "27.2"
19+
elixir_version: "1.18"
20+
os: ubuntu-latest
21+
22+
runs-on: ${{ matrix.os }}
23+
name: Test on Elixir ${{ matrix.elixir_version }} / OTP ${{ matrix.otp_version }}
24+
steps:
25+
- name: Checkout code
26+
uses: actions/checkout@v4
27+
28+
- name: Setup Elixir and Erlang
29+
uses: erlef/setup-beam@v1
30+
with:
31+
otp-version: ${{ matrix.otp_version }}
32+
elixir-version: ${{ matrix.elixir_version }}
33+
34+
- name: Cache Mix dependencies
35+
uses: actions/cache@v4
36+
id: cache-deps
37+
with:
38+
path: |
39+
deps
40+
_build
41+
_build/test
42+
key: mix-${{ runner.os }}-${{ matrix.elixir_version }}-${{ matrix.otp_version }}-${{ hashFiles('mix.lock') }}
43+
restore-keys: |
44+
mix-${{ runner.os }}-${{ matrix.elixir_version }}-${{ matrix.otp_version }}-
45+
46+
- name: Cache Rust dependencies
47+
uses: Swatinem/rust-cache@v2
48+
with:
49+
workspaces: native/exstatic
50+
51+
- name: Install dependencies
52+
env:
53+
HEX_API_KEY: ${{ secrets.HEX_API_KEY }}
54+
run: mix deps.get
55+
56+
- name: Compile
57+
run: mix compile --warnings-as-errors
58+
59+
- name: Check for unused packages
60+
run: mix deps.unlock --check-unused
61+
62+
- name: Check code formatting
63+
run: mix format --check-formatted
64+
65+
- name: Run Credo (Code Linter)
66+
run: mix credo --strict
67+
68+
- name: Run Dialyzer (Static Analysis)
69+
run: mix dialyzer
70+
71+
- name: Check for abandoned dependencies
72+
run: mix hex.audit
73+
74+
- name: Check for outdated dependencies
75+
run: mix hex.outdated --within-requirements || true
76+
77+
- name: Run tests
78+
run: mix test
79+
80+
- name: Run tests with coverage
81+
run: mix test --cover --export-coverage default
82+
83+
- name: Check test coverage
84+
run: mix test.coverage
85+
86+
- name: Scan for security vulnerabilities
87+
run: mix sobelow --exit --threshold medium

.github/workflows/release.yml

Lines changed: 83 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,87 @@
1-
name: Release
1+
name: Compile & Upload NIFs
2+
23
on:
3-
release:
4-
types: [published]
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- "native/**"
9+
- ".github/workflows/release.yml"
10+
tags:
11+
- "*"
12+
pull_request:
13+
paths:
14+
- ".github/workflows/release.yml"
15+
workflow_dispatch:
16+
517
jobs:
6-
publish:
7-
name: Publish
8-
runs-on: ubuntu-22.04
18+
compile_nifs:
19+
name: ${{ matrix.job.platform }} (NIF ${{ matrix.nif }})
20+
runs-on: ${{ matrix.job.os }}
21+
22+
permissions:
23+
contents: write
24+
id-token: write
25+
26+
strategy:
27+
fail-fast: false
28+
matrix:
29+
nif: ["2.16"]
30+
job:
31+
- { target: aarch64-apple-darwin, os: macos-13, platform: "macOS (ARM64)" }
32+
- { target: aarch64-unknown-linux-gnu, os: ubuntu-22.04, use-cross: true, platform: "Linux (ARM64)" }
33+
- { target: x86_64-apple-darwin, os: macos-13, platform: "macOS (x86_64)" }
34+
- { target: x86_64-unknown-linux-gnu, os: ubuntu-22.04, platform: "Linux (x86_64)" }
35+
36+
env:
37+
EXSTATIC_BUILD: true # Ensure RustlerPrecompiled forces a build
38+
939
steps:
10-
- uses: actions/checkout@v4
11-
- uses: erlef/setup-beam@v1
40+
- name: Checkout source code
41+
uses: actions/checkout@v4
42+
43+
- name: Install Rust toolchain
44+
uses: dtolnay/rust-toolchain@stable
1245
with:
13-
elixir-version: 1.18
14-
otp-version: 27.2
15-
- name: Fetch dependencies
16-
run: mix deps.get
17-
- name: Publish package
18-
env:
19-
HEX_API_KEY: ${{ secrets.HEX_API_KEY }}
20-
run: mix hex.publish --organization ${{ vars.HEX_ORG }} --replace --yes
46+
toolchain: stable
47+
targets: ${{ matrix.job.target }}
48+
49+
- name: Install Cross for cross-compilation
50+
if: ${{ matrix.job.use-cross }}
51+
run: cargo install cross --git https://github.com/cross-rs/cross
52+
53+
- name: Extract project version
54+
shell: bash
55+
run: |
56+
echo "PROJECT_VERSION=$(sed -n 's/^ @version "\(.*\)"/\1/p' mix.exs | head -n1)" >> $GITHUB_ENV
57+
58+
- uses: Swatinem/rust-cache@v2
59+
with:
60+
prefix-key: v0-precomp
61+
shared-key: ${{ matrix.job.target }}-${{ matrix.nif }}
62+
workspaces: |
63+
native/exstatic
64+
65+
- name: Compile the NIFs
66+
id: build-crate
67+
uses: philss/[email protected]
68+
with:
69+
project-name: exstatic
70+
project-version: ${{ env.PROJECT_VERSION }}
71+
target: ${{ matrix.job.target }}
72+
nif-version: ${{ matrix.nif }}
73+
use-cross: ${{ matrix.job.use-cross }}
74+
project-dir: "native/exstatic"
75+
76+
- name: Upload compiled NIF artifact
77+
uses: actions/upload-artifact@v4
78+
with:
79+
name: ${{ steps.build-crate.outputs.file-name }}
80+
path: ${{ steps.build-crate.outputs.file-path }}
81+
82+
- name: Publish NIFs to GitHub Releases
83+
uses: softprops/action-gh-release@v2
84+
with:
85+
files: |
86+
${{ steps.build-crate.outputs.file-path }}
87+
if: startsWith(github.ref, 'refs/tags/')

.github/workflows/test.yml

Lines changed: 0 additions & 93 deletions
This file was deleted.

lib/exstatic/native.ex

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
defmodule Exstatic.Native do
22
@moduledoc false
3-
use Rustler, otp_app: :exstatic, crate: "exstatic"
3+
version = Mix.Project.config()[:version]
4+
5+
use RustlerPrecompiled,
6+
otp_app: :exstatic,
7+
crate: "exstatic",
8+
base_url: "https://github.com/intellection/exstatic/releases/download/v#{version}",
9+
force_build: System.get_env("EXSTATIC_BUILD") == "true",
10+
nif_versions: ["2.16"],
11+
version: version
412

513
@spec normal_pdf(float(), float(), float()) :: float()
614
def normal_pdf(_mean, _std_dev, _x), do: :erlang.nif_error(:nif_not_loaded)

mix.exs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ defmodule Exstatic.MixProject do
6161
[
6262
name: "exstatic",
6363
organization: "zappi",
64-
files: ~w(lib .formatter.exs mix.exs README*),
64+
files: ~w(lib mix.exs README.md checksum-*.exs),
6565
licenses: ["MIT"],
6666
links: %{"GitHub" => @source_url}
6767
]
@@ -70,7 +70,8 @@ defmodule Exstatic.MixProject do
7070
# Run "mix help deps" to learn about dependencies.
7171
defp deps do
7272
[
73-
{:rustler, "~> 0.35.1", runtime: false},
73+
{:rustler_precompiled, "~> 0.8"},
74+
{:rustler, ">= 0.0.0", optional: true},
7475
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
7576
{:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false},
7677
{:ex_doc, "~> 0.34", only: :dev, runtime: false},

mix.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
%{
22
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
3+
"castore": {:hex, :castore, "1.0.11", "4bbd584741601eb658007339ea730b082cc61f3554cf2e8f39bf693a11b49073", [:mix], [], "hexpm", "e03990b4db988df56262852f20de0f659871c35154691427a5047f4967a16a62"},
34
"credo": {:hex, :credo, "1.7.11", "d3e805f7ddf6c9c854fd36f089649d7cf6ba74c42bc3795d587814e3c9847102", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "56826b4306843253a66e47ae45e98e7d284ee1f95d53d1612bb483f88a8cf219"},
45
"dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"},
56
"earmark_parser": {:hex, :earmark_parser, "1.4.43", "34b2f401fe473080e39ff2b90feb8ddfeef7639f8ee0bbf71bb41911831d77c5", [:mix], [], "hexpm", "970a3cd19503f5e8e527a190662be2cee5d98eed1ff72ed9b3d1a3d466692de8"},
@@ -19,6 +20,7 @@
1920
"nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"},
2021
"req": {:hex, :req, "0.5.8", "50d8d65279d6e343a5e46980ac2a70e97136182950833a1968b371e753f6a662", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d7fc5898a566477e174f26887821a3c5082b243885520ee4b45555f5d53f40ef"},
2122
"rustler": {:hex, :rustler, "0.35.1", "ec81961ef9ee833d721dafb4449cab29b16b969a3063a842bb9e3ea912f6b938", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:toml, "~> 0.6", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "3713b2e70e68ec2bfa8291dfd9cb811fe64a770f254cd9c331f8b34fa7989115"},
23+
"rustler_precompiled": {:hex, :rustler_precompiled, "0.8.2", "5f25cbe220a8fac3e7ad62e6f950fcdca5a5a5f8501835d2823e8c74bf4268d5", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "63d1bd5f8e23096d1ff851839923162096364bac8656a4a3c00d1fff8e83ee0a"},
2224
"sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"},
2325
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
2426
"toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"},

native/exstatic/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ path = "src/lib.rs"
1010
crate-type = ["cdylib"]
1111

1212
[dependencies]
13-
rustler = "0.35.1"
13+
rustler = { version = "0.35.1", default-features = false, features = ["nif_version_2_16"] }
1414
statrs = "0.18.0"

0 commit comments

Comments
 (0)