Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
georgelima committed Aug 1, 2022
0 parents commit fbee293
Show file tree
Hide file tree
Showing 14 changed files with 343 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
152 changes: 152 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
name: Build precompiled NIFs

env:
NIF_DIRECTORY: "native/hmac"

on:
push:
tags:
- "*"

defaults:
run:
# Sets the working dir for "run" scripts.
# Note that this won't change the directory for actions (tasks with "uses").
working-directory: "./native/hmac"

jobs:
build_release:
name: NIF ${{ matrix.nif }} - ${{ matrix.job.target }} (${{ matrix.job.os }})
runs-on: ${{ matrix.job.os }}
strategy:
fail-fast: false
matrix:
nif: ["2.16"]
job:
- {
target: arm-unknown-linux-gnueabihf,
os: ubuntu-20.04,
use-cross: true,
}
- {
target: aarch64-unknown-linux-gnu,
os: ubuntu-20.04,
use-cross: true,
}
- { target: aarch64-apple-darwin, os: macos-11 }
- { target: x86_64-apple-darwin, os: macos-11 }
- { target: x86_64-unknown-linux-gnu, os: ubuntu-20.04 }
- {
target: x86_64-unknown-linux-musl,
os: ubuntu-20.04,
use-cross: true,
}
- { target: x86_64-pc-windows-gnu, os: windows-2019 }
- { target: x86_64-pc-windows-msvc, os: windows-2019 }

env:
RUSTLER_NIF_VERSION: ${{ matrix.nif }}
steps:
- name: Checkout source code
uses: actions/checkout@v2

- name: Install prerequisites
shell: bash
run: |
case ${{ matrix.job.target }} in
arm-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;;
aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;;
esac
- name: Extract crate information
shell: bash
run: |
echo "PROJECT_NAME=$(sed -n 's/^name = "\(.*\)"/\1/p' Cargo.toml | head -n1)" >> $GITHUB_ENV
# Get the project version from mix.exs
echo "PROJECT_VERSION=$(sed -n 's/^ @version "\(.*\)"/\1/p' ../../mix.exs | head -n1)" >> $GITHUB_ENV
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: ${{ matrix.job.target }}
override: true
profile: minimal

- name: Show version information (Rust, cargo, GCC)
shell: bash
run: |
gcc --version || true
rustup -V
rustup toolchain list
rustup default
cargo -V
rustc -V
rustc --print=cfg
- name: Download cross from GitHub releases
uses: giantswarm/[email protected]
if: ${{ matrix.job.use-cross }}
with:
binary: "cross"
version: "v0.2.2"
download_url: "https://github.com/cross-rs/cross/releases/download/${version}/cross-x86_64-unknown-linux-gnu.tar.gz"
tarball_binary_path: "${binary}"
smoke_test: "${binary} --version"

- name: Build
shell: bash
run: |
if [ "${{ matrix.job.use-cross }}" == "true" ]; then
cross build --release --target=${{ matrix.job.target }}
else
cargo build --release --target=${{ matrix.job.target }}
fi
- name: Rename lib to the final name
id: rename
shell: bash
run: |
LIB_PREFIX="lib"
case ${{ matrix.job.target }} in
*-pc-windows-*) LIB_PREFIX="" ;;
esac;
# Figure out suffix of lib
# See: https://doc.rust-lang.org/reference/linkage.html
LIB_SUFFIX=".so"
case ${{ matrix.job.target }} in
*-apple-darwin) LIB_SUFFIX=".dylib" ;;
*-pc-windows-*) LIB_SUFFIX=".dll" ;;
esac;
CICD_INTERMEDIATES_DIR=$(mktemp -d)
# Setup paths
LIB_DIR="${CICD_INTERMEDIATES_DIR}/released-lib"
mkdir -p "${LIB_DIR}"
LIB_NAME="${LIB_PREFIX}${{ env.PROJECT_NAME }}${LIB_SUFFIX}"
LIB_PATH="${LIB_DIR}/${LIB_NAME}"
# Copy the release build lib to the result location
cp "target/${{ matrix.job.target }}/release/${LIB_NAME}" "${LIB_DIR}"
# Final paths
# In the end we use ".so" for MacOS in the final build
# See: https://www.erlang.org/doc/man/erlang.html#load_nif-2
LIB_FINAL_SUFFIX="${LIB_SUFFIX}"
case ${{ matrix.job.target }} in
*-apple-darwin) LIB_FINAL_SUFFIX=".so" ;;
esac;
LIB_FINAL_NAME="${LIB_PREFIX}${PROJECT_NAME}-v${PROJECT_VERSION}-nif-${RUSTLER_NIF_VERSION}-${{ matrix.job.target }}${LIB_FINAL_SUFFIX}"
# Copy lib to final name on this directory
cp "${LIB_PATH}" "${LIB_FINAL_NAME}"
tar -cvzf "${LIB_FINAL_NAME}.tar.gz" "${LIB_FINAL_NAME}"
# Passes the path relative to the root of the project.
LIB_FINAL_PATH="${NIF_DIRECTORY}/${LIB_FINAL_NAME}.tar.gz"
# Let subsequent steps know where to find the lib
echo ::set-output name=LIB_FINAL_PATH::${LIB_FINAL_PATH}
echo ::set-output name=LIB_FINAL_NAME::${LIB_FINAL_NAME}.tar.gz
- name: "Artifact upload"
uses: actions/upload-artifact@v2
with:
name: ${{ steps.rename.outputs.LIB_FINAL_NAME }}
path: ${{ steps.rename.outputs.LIB_FINAL_PATH }}

- name: Publish archives and packages
uses: softprops/action-gh-release@v1
with:
files: |
${{ steps.rename.outputs.LIB_FINAL_PATH }}
if: startsWith(github.ref, 'refs/tags/')
30 changes: 30 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# The directory Mix will write compiled artifacts to.
/_build/

# If you run "mix test --cover", coverage assets end up here.
/cover/

# The directory Mix downloads your dependencies sources to.
/deps/

# Where third-party dependencies like ExDoc output generated docs.
/doc/

# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

# Ignore package tarball (built via "mix hex.build").
rustler_hmac-*.tar

# Temporary files, for example, from tests.
/tmp/

.elixir_ls

priv/native
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# RustlerHmac

**TODO: Add description**

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `rustler_hmac` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[
{:rustler_hmac, "~> 0.1.0"}
]
end
```

Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at <https://hexdocs.pm/rustler_hmac>.

13 changes: 13 additions & 0 deletions lib/rustler_hmac.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
defmodule RustlerHmac do
version = Mix.Project.config()[:version]

use RustlerPrecompiled,
otp_app: :rustler_hmac,
crate: "hmac",
base_url: "https://github.com/Astrocoders/rustler_hmac/releases/download/v#{version}",
force_build: System.get_env("RUSTLER_PRECOMPILATION") in ["1", "true"],
version: version

# When your NIF is loaded, it will override this function.
def generate(_, _), do: :erlang.nif_error(:nif_not_loaded)
end
30 changes: 30 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
defmodule RustlerHmac.MixProject do
use Mix.Project

@version "0.0.1"

def project do
[
app: :rustler_hmac,
version: @version,
elixir: "~> 1.13",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end

# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end

# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:rustler_precompiled, "~> 0.5"},
{:rustler, ">= 0.0.0", optional: true}
]
end
end
7 changes: 7 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
%{
"castore": {:hex, :castore, "0.1.17", "ba672681de4e51ed8ec1f74ed624d104c0db72742ea1a5e74edbc770c815182f", [:mix], [], "hexpm", "d9844227ed52d26e7519224525cb6868650c272d4a3d327ce3ca5570c12163f9"},
"jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"},
"rustler": {:hex, :rustler, "0.25.0", "32526b51af7e58a740f61941bf923486ce6415a91c3934cc16c281aa201a2240", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:toml, "~> 0.6", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "6b43a11a37fe79c6234d88c4102ab5dfede7a6a764dc5c7b539956cfa02f3cf4"},
"rustler_precompiled": {:hex, :rustler_precompiled, "0.5.1", "93df423bd7b14b67dcacf994443d132d300623f80756974cac4febeab40af74a", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "3f8cbc8e92eef4e1a71bf441b568b868b16a3730f63f5b803c68073017e30b13"},
"toml": {:hex, :toml, "0.6.2", "38f445df384a17e5d382befe30e3489112a48d3ba4c459e543f748c2f25dd4d1", [:mix], [], "hexpm", "d013e45126d74c0c26a38d31f5e8e9b83ea19fc752470feb9a86071ca5a672fa"},
}
20 changes: 20 additions & 0 deletions native/hmac/.cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[target.x86_64-apple-darwin]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]

[target.aarch64-apple-darwin]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]

# See https://github.com/rust-lang/rust/issues/59302
[target.x86_64-unknown-linux-musl]
rustflags = [
"-C", "target-feature=-crt-static"
]

[profile.release]
lto = true
1 change: 1 addition & 0 deletions native/hmac/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
16 changes: 16 additions & 0 deletions native/hmac/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "hmac"
version = "0.1.0"
authors = []
edition = "2018"

[lib]
name = "hmac"
path = "src/lib.rs"
crate-type = ["cdylib"]

[dependencies]
rustler = "0.25.0"
hmac = "0.12.1"
sha2 = " 0.10.2"
hex = "0.4.3"
20 changes: 20 additions & 0 deletions native/hmac/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# NIF for Elixir.HMAC

## To build the NIF module:

- Your NIF will now build along with your project.

## To load the NIF:

```elixir
defmodule HMAC do
use Rustler, otp_app: :rustler_hmac, crate: "hmac"

# When your NIF is loaded, it will override this function.
def add(_a, _b), do: :erlang.nif_error(:nif_not_loaded)
end
```

## Examples

[This](https://github.com/hansihe/NifIo) is a complete example of a NIF written in Rust.
20 changes: 20 additions & 0 deletions native/hmac/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use hmac::{Hmac, Mac};
use sha2::Sha256;

type HmacSha256 = Hmac<Sha256>;

#[rustler::nif]
fn generate(secret: String, message: String) -> String {
let mut mac =
HmacSha256::new_from_slice(secret.as_bytes()).expect("HMAC can take key of any size");

mac.update(message.as_bytes());

let result = mac.finalize();

let code_bytes = result.into_bytes();

hex::encode(code_bytes)
}

rustler::init!("Elixir.RustlerHmac", [generate]);
8 changes: 8 additions & 0 deletions test/rustler_hmac_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
defmodule RustlerHmacTest do
use ExUnit.Case
doctest RustlerHmac

test "greets the world" do
assert RustlerHmac.hello() == :world
end
end
1 change: 1 addition & 0 deletions test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ExUnit.start()

0 comments on commit fbee293

Please sign in to comment.