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

GitHub Actions #253

Merged
merged 7 commits into from
Oct 19, 2019
Merged
Show file tree
Hide file tree
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
98 changes: 98 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
name: CI

on: push

jobs:
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- id: component
uses: actions-rs/components-nightly@v1
with:
component: clippy
- run: rustup component add clippy
- uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --all-targets --all-features -- -D warnings

format:
name: Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- id: component
uses: actions-rs/components-nightly@v1
with:
component: rustfmt
- name: Install rustfmt
run: rustup component add rustfmt

- name: Install Erlang/Elixir
uses: actions/setup-elixir@v1.0.0
with:
otp-version: 22.1.3
elixir-version: 1.9.2

- name: Check cargo fmt
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check

- name: Check mix format (rustler_mix)
working-directory: rustler_mix
run: mix format --check-formatted

- name: Check mix format (rustler_tests)
working-directory: rustler_tests
run: mix format --check-formatted

test:
name: OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}} / Rust ${{matrix.rust}}
runs-on: ubuntu-latest
evnu marked this conversation as resolved.
Show resolved Hide resolved
strategy:
matrix:
otp:
- 22.1.3
- 21.3.8
elixir:
- 1.9.2
- 1.8.2
- 1.7.4
- 1.6.6
rust:
- stable
- beta
- nightly
steps:
- name: Checkout sources
uses: actions/checkout@v1

- name: Install Erlang/Elixir
uses: actions/setup-elixir@v1.0.0
with:
otp-version: ${{matrix.otp}}
elixir-version: ${{matrix.elixir}}

- name: Install Rust ${{matrix.rust}} toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{matrix.rust}}
override: true

- run: cargo test

- name: Test rustler_mix
working-directory: rustler_mix
run: |
mix deps.get
mix test

- name: Test rustler_tests
working-directory: rustler_tests
run: |
mix deps.get
mix test
19 changes: 10 additions & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ language: elixir

matrix:
include:
- otp_release: 21.0
- otp_release: 20.0
elixir: 1.6
- otp_release: 21.3
elixir: 1.7.4
- otp_release: 21.3
elixir: 1.8.1
- otp_release: 22.0
elixir: 1.8.1

- otp_release: 20.0
elixir: 1.7

- otp_release: 20.0
elixir: 1.8

- otp_release: 20.0
elixir: 1.9

env:
global:
Expand All @@ -24,11 +27,9 @@ install:
- mix local.rebar --force
- mix local.hex --force
- source $HOME/.cargo/env
- rustup component add clippy

script:
- source $HOME/.cargo/env
- cargo test
- cd rustler_mix && mix do deps.get, test && cd -
- cd rustler_tests && mix do deps.get, test && cd -
- cargo clippy --all-targets --all-features -- -D warnings
6 changes: 1 addition & 5 deletions rustler/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,7 @@ fn get_version_from_erl() -> Option<String> {
r#"io:format("~s~n", [erlang:system_info(nif_version)]), init:stop()."#,
];

let version = Command::new(erl)
.args(&args)
.output()
.ok()?
.stdout;
let version = Command::new(erl).args(&args).output().ok()?.stdout;

let version = String::from_utf8(version).ok()?;

Expand Down
12 changes: 8 additions & 4 deletions rustler/src/types/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,14 @@ impl<'a> Term<'a> {
keys: &[Term<'a>],
values: &[Term<'a>],
) -> NifResult<Term<'a>> {
let map = map_new(env);
keys.iter()
.zip(values.iter())
.try_fold(map, |map, (k, v)| map.map_put(*k, *v))
if keys.len() == values.len() {
let map = map_new(env);
keys.iter()
.zip(values.iter())
.try_fold(map, |map, (k, v)| map.map_put(*k, *v))
} else {
Err(Error::BadArg)
}
}

/// Gets the value corresponding to a key in a map term.
Expand Down
3 changes: 3 additions & 0 deletions rustler_mix/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
49 changes: 31 additions & 18 deletions rustler_mix/lib/mix/tasks/compile.rustler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,30 @@ defmodule Mix.Tasks.Compile.Rustler do
Enum.map(crates, &compile_crate/1)

# Workaround for a mix problem. We should REALLY get this fixed properly.
_ = symlink_or_copy(config,
Path.expand("priv"),
Path.join(Mix.Project.app_path(config), "priv"))
_ =
symlink_or_copy(
config,
Path.expand("priv"),
Path.join(Mix.Project.app_path(config), "priv")
)
end


defp priv_dir, do: "priv/native"

def compile_crate({name, config}) do
crate_path = Keyword.get(config, :path, "native/#{name}")
build_mode = Keyword.get(config, :mode, :release)

Mix.shell.info "Compiling NIF crate #{inspect name} (#{crate_path})..."
Mix.shell().info("Compiling NIF crate #{inspect(name)} (#{crate_path})...")

crate_full_path = Path.expand(crate_path, File.cwd!())

crate_full_path = Path.expand(crate_path, File.cwd!)
target_dir = Keyword.get(config, :target_dir,
Path.join([Mix.Project.build_path(), "rustler_crates", Atom.to_string(name)]))
target_dir =
Keyword.get(
config,
:target_dir,
Path.join([Mix.Project.build_path(), "rustler_crates", Atom.to_string(name)])
)

cargo_data = check_crate_env(crate_full_path)

Expand All @@ -56,12 +63,13 @@ defmodule Mix.Tasks.Compile.Rustler do

[cmd_bin | args] = compile_command

compile_return = System.cmd(cmd_bin, args, [
cd: crate_full_path,
stderr_to_stdout: true,
env: [{"CARGO_TARGET_DIR", target_dir} | Keyword.get(config, :env, [])],
into: IO.stream(:stdio, :line),
])
compile_return =
System.cmd(cmd_bin, args,
cd: crate_full_path,
stderr_to_stdout: true,
env: [{"CARGO_TARGET_DIR", target_dir} | Keyword.get(config, :env, [])],
into: IO.stream(:stdio, :line)
)

case compile_return do
{_, 0} -> nil
Expand All @@ -82,8 +90,9 @@ defmodule Mix.Tasks.Compile.Rustler do

defp make_base_command(:system), do: ["cargo", "rustc"]
defp make_base_command({:bin, path}), do: [path, "rustc"]

defp make_base_command({:rustup, version}) do
if Rustup.version == :none do
if Rustup.version() == :none do
throw_error(:rustup_not_installed)
end

Expand Down Expand Up @@ -131,6 +140,7 @@ defmodule Mix.Tasks.Compile.Rustler do
args ++ ["--", "-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup"]
end
end

defp make_platform_hacks(args, _, _, _), do: args

defp make_no_default_features_flag(args, true), do: args ++ []
Expand All @@ -153,6 +163,7 @@ defmodule Mix.Tasks.Compile.Rustler do
{:unix, _} -> {"lib#{base_name}.so", "lib#{base_name}.so"}
end
end

def make_file_names(base_name, :bin) do
case :os.type() do
{:win32, _} -> {"#{base_name}.exe", "#{base_name}.exe"}
Expand All @@ -161,7 +172,7 @@ defmodule Mix.Tasks.Compile.Rustler do
end

def throw_error(error_descr) do
Mix.shell.error Messages.message(error_descr)
Mix.shell().error(Messages.message(error_descr))
raise "Compilation error"
end

Expand All @@ -173,15 +184,16 @@ defmodule Mix.Tasks.Compile.Rustler do
case File.read("#{crate}/Cargo.toml") do
{:error, :enoent} ->
throw_error({:cargo_toml_not_found, crate})

{:ok, text} ->
Toml.decode!(text)
end
end

defp raise_missing_crates do
Mix.raise """
Mix.raise("""
Missing required :rustler_crates option in mix.exs.
"""
""")
end

# https://github.com/elixir-lang/elixir/blob/b13404e913fff70e080c08c2da3dbd5c41793b54/lib/mix/lib/mix/project.ex#L553-L562
Expand All @@ -191,6 +203,7 @@ defmodule Mix.Tasks.Compile.Rustler do
File.rm_rf!(target)
File.cp_r!(source, target)
end

:ok
else
Mix.Utils.symlink_or_copy(source, target)
Expand Down
40 changes: 26 additions & 14 deletions rustler_mix/lib/mix/tasks/rustler.new.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ defmodule Mix.Tasks.Rustler.New do
{:eex, "basic/.cargo/config", ".cargo/config"},
{:eex, "basic/README.md", "README.md"},
{:eex, "basic/Cargo.toml.eex", "Cargo.toml"},
{:eex, "basic/src/lib.rs", "src/lib.rs"},
{:eex, "basic/src/lib.rs", "src/lib.rs"}
]

root = Path.join(:code.priv_dir(:rustler), "templates/")

for {format, source, _} <- @basic do
unless format == :keep do
@external_resource Path.join(root, source)
Expand All @@ -30,35 +31,44 @@ defmodule Mix.Tasks.Rustler.New do
def run(argv) do
{opts, _argv, _} = OptionParser.parse(argv, switches: @switches)

module = prompt("This is the name of the Elixir module the NIF module will be registered to.\nModule name")
module =
prompt(
"This is the name of the Elixir module the NIF module will be registered to.\nModule name"
)

name =
prompt_default(
"This is the name used for the generated Rust crate. The default is most likely fine.\nLibrary name",
format_module_name_as_name(module)
)

name = prompt_default("This is the name used for the generated Rust crate. The default is most likely fine.\nLibrary name", format_module_name_as_name(module))
check_module_name_validity!(module)

path = Path.join([File.cwd!, "native/", name])
path = Path.join([File.cwd!(), "native/", name])
new(path, module, name, opts)
end

def new(path, module, name, _opts) do

module_elixir = "Elixir." <> module

binding = [
project_name: module_elixir,
native_module: module_elixir,
module: module,
library_name: name,
rustler_version: Rustler.rustler_version,
rustler_version: Rustler.rustler_version()
]

copy_from path, binding, @basic
copy_from(path, binding, @basic)

Mix.Shell.IO.info [:green, "Ready to go! See #{path}/README.md for further instructions."]
Mix.Shell.IO.info([:green, "Ready to go! See #{path}/README.md for further instructions."])
end

defp check_module_name_validity!(name) do
unless name =~ ~r/^[A-Z]\w*(\.[A-Z]\w*)*$/ do
Mix.raise "Module name must be a valid Elixir alias (for example: Foo.Bar), got: #{inspect name}"
Mix.raise(
"Module name must be a valid Elixir alias (for example: Foo.Bar), got: #{inspect(name)}"
)
end
end

Expand All @@ -73,9 +83,11 @@ defmodule Mix.Tasks.Rustler.New do
case format do
:keep ->
File.mkdir_p!(target)

:text ->
create_file(target, render(source))
:eex ->

:eex ->
contents = EEx.eval_string(render(source), binding, file: source)
create_file(target, contents)
end
Expand All @@ -84,17 +96,17 @@ defmodule Mix.Tasks.Rustler.New do

def prompt_default(message, default) do
response = prompt([message, :white, " (", default, ")"])

case response do
"" -> default
_ -> response
end
end

def prompt(message) do
Mix.Shell.IO.print_app
resp = IO.gets IO.ANSI.format([message, :white, " > "])
Mix.Shell.IO.print_app()
resp = IO.gets(IO.ANSI.format([message, :white, " > "]))
?\n = :binary.last(resp)
:binary.part(resp, {0, byte_size(resp)-1})
:binary.part(resp, {0, byte_size(resp) - 1})
end

end
Loading