Majic.
This commit is contained in:
parent
52f6aa7281
commit
b5777bf9e8
31 changed files with 373 additions and 218 deletions
20
.builds/alpine.yaml
Normal file
20
.builds/alpine.yaml
Normal file
|
@ -0,0 +1,20 @@
|
|||
image: alpine/latest
|
||||
packages:
|
||||
- g++
|
||||
- make
|
||||
- elixir
|
||||
- file
|
||||
- file-dev
|
||||
sources:
|
||||
- https://git.sr.ht/~href/gen_magic
|
||||
tasks:
|
||||
- setup: |
|
||||
mix local.hex --force
|
||||
- build: |
|
||||
cd gen_magic
|
||||
mix deps.get
|
||||
MIX_ENV=test mix compile
|
||||
- test: |
|
||||
cd gen_magic
|
||||
mix test
|
||||
|
17
.builds/archlinux.yaml
Normal file
17
.builds/archlinux.yaml
Normal file
|
@ -0,0 +1,17 @@
|
|||
image: archlinux
|
||||
packages:
|
||||
- elixir
|
||||
- file
|
||||
sources:
|
||||
- https://git.sr.ht/~href/gen_magic
|
||||
tasks:
|
||||
- setup: |
|
||||
mix local.hex --force
|
||||
- build: |
|
||||
cd gen_magic
|
||||
mix deps.get
|
||||
MIX_ENV=test mix compile
|
||||
- test: |
|
||||
cd gen_magic
|
||||
mix test
|
||||
|
20
.builds/debian-oldstable.yaml
Normal file
20
.builds/debian-oldstable.yaml
Normal file
|
@ -0,0 +1,20 @@
|
|||
image: debian/oldstable
|
||||
packages:
|
||||
- build-essential
|
||||
- erlang
|
||||
- erlang-dev
|
||||
- elixir
|
||||
- libmagic-dev
|
||||
sources:
|
||||
- https://git.sr.ht/~href/gen_magic
|
||||
tasks:
|
||||
- setup: |
|
||||
mix local.hex --force
|
||||
- build: |
|
||||
cd gen_magic
|
||||
mix deps.get
|
||||
MIX_ENV=test mix compile
|
||||
- test: |
|
||||
cd gen_magic
|
||||
mix test
|
||||
|
20
.builds/debian-stable.yaml
Normal file
20
.builds/debian-stable.yaml
Normal file
|
@ -0,0 +1,20 @@
|
|||
image: debian/stable
|
||||
packages:
|
||||
- build-essential
|
||||
- erlang
|
||||
- erlang-dev
|
||||
- elixir
|
||||
- libmagic-dev
|
||||
sources:
|
||||
- https://git.sr.ht/~href/gen_magic
|
||||
tasks:
|
||||
- setup: |
|
||||
mix local.hex --force
|
||||
- build: |
|
||||
cd gen_magic
|
||||
mix deps.get
|
||||
MIX_ENV=test mix compile
|
||||
- test: |
|
||||
cd gen_magic
|
||||
mix test
|
||||
|
20
.builds/debian-testing.yaml
Normal file
20
.builds/debian-testing.yaml
Normal file
|
@ -0,0 +1,20 @@
|
|||
image: debian/testing
|
||||
packages:
|
||||
- build-essential
|
||||
- erlang
|
||||
- erlang-dev
|
||||
- elixir
|
||||
- libmagic-dev
|
||||
sources:
|
||||
- https://git.sr.ht/~hrefhref/gen_magic
|
||||
tasks:
|
||||
- setup: |
|
||||
mix local.hex --force
|
||||
- build: |
|
||||
cd gen_magic
|
||||
mix deps.get
|
||||
MIX_ENV=test mix compile
|
||||
- test: |
|
||||
cd gen_magic
|
||||
mix test
|
||||
|
22
.builds/fedora-latest.yaml
Normal file
22
.builds/fedora-latest.yaml
Normal file
|
@ -0,0 +1,22 @@
|
|||
image: fedora/latest
|
||||
packages:
|
||||
- make
|
||||
- gcc
|
||||
- kernel-devel
|
||||
- erlang
|
||||
- elixir
|
||||
- file-devel
|
||||
sources:
|
||||
- https://git.sr.ht/~href/gen_magic
|
||||
tasks:
|
||||
- setup: |
|
||||
sudo dnf -y group install 'Development Tools'
|
||||
mix local.hex --force
|
||||
- build: |
|
||||
cd gen_magic
|
||||
mix deps.get
|
||||
MIX_ENV=test mix compile
|
||||
- test: |
|
||||
cd gen_magic
|
||||
mix test
|
||||
|
17
.builds/freebsd.yaml
Normal file
17
.builds/freebsd.yaml
Normal file
|
@ -0,0 +1,17 @@
|
|||
image: freebsd/latest
|
||||
packages:
|
||||
- elixir
|
||||
- gmake
|
||||
sources:
|
||||
- https://git.sr.ht/~href/gen_magic
|
||||
tasks:
|
||||
- setup: |
|
||||
mix local.hex --force
|
||||
- build: |
|
||||
cd gen_magic
|
||||
mix deps.get
|
||||
MIX_ENV=test mix compile
|
||||
- test: |
|
||||
cd gen_magic
|
||||
mix test
|
||||
|
19
CHANGELOG.md
19
CHANGELOG.md
|
@ -7,7 +7,24 @@ The format is based on [Keep a Changelog][1], and this project adheres to [Seman
|
|||
[1]: https://keepachangelog.com/en/1.0.0/
|
||||
[2]: https://semver.org/spec/v2.0.0.html
|
||||
|
||||
## [Unreleased]
|
||||
## majic [Unreleased]
|
||||
|
||||
## Added
|
||||
|
||||
- Forked gen_magic.
|
||||
- Pool: `Majic.Pool`
|
||||
- Unified API: `Majic.perform/1,2,3`
|
||||
|
||||
## Changed
|
||||
|
||||
- C port now using erl_interface
|
||||
- `Majic.Server.reload/2,3`
|
||||
- `Majic.Server.recycle/2,3`
|
||||
- Bytes support: `Majic.Server.perform(ref, {:bytes, <<>>})`
|
||||
- Builds on Musl
|
||||
- Better error and timeout handling
|
||||
|
||||
## gen_majic [1.0]
|
||||
|
||||
### Added
|
||||
|
||||
|
|
6
Makefile
6
Makefile
|
@ -1,5 +1,3 @@
|
|||
# Apprentice binary
|
||||
|
||||
ERL_EI_INCLUDE:=$(shell erl -eval 'io:format("~s", [code:lib_dir(erl_interface, include)])' -s init stop -noshell | head -1)
|
||||
ERL_EI_LIB:=$(shell erl -eval 'io:format("~s", [code:lib_dir(erl_interface, lib)])' -s init stop -noshell | head -1)
|
||||
CFLAGS = -std=c99 -g -Wall -Werror
|
||||
|
@ -9,9 +7,9 @@ LDLIBS = -lpthread -lei -lm -lmagic
|
|||
PRIV = priv/
|
||||
RM = rm -Rf
|
||||
|
||||
all: priv/apprentice
|
||||
all: priv/libmagic_port
|
||||
|
||||
priv/apprentice: src/apprentice.c
|
||||
priv/libmagic_port: src/libmagic_port.c
|
||||
mkdir -p priv
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
|
|
72
README.md
72
README.md
|
@ -1,17 +1,24 @@
|
|||
# GenMagic
|
||||
# Majic
|
||||
|
||||
**GenMagic** provides supervised and customisable access to [libmagic](http://man7.org/linux/man-pages/man3/libmagic.3.html) using a supervised external process.
|
||||
**Majic** provides a robust integration of [libmagic](http://man7.org/linux/man-pages/man3/libmagic.3.html) for Elixir.
|
||||
|
||||
With this library, you can start an one-off process to run a single check, or run the process as a daemon if you expect to run many checks.
|
||||
With this library, you can start an one-off process to run a single check, or run the process as a daemon if you expect to run
|
||||
many checks.
|
||||
|
||||
It is a friendly fork of [gen_magic](https://github.com/evadne/gen_magic) featuring a (arguably) more robust C-code
|
||||
using erl_interface, built in pooling, unified/clean API, and an optional Plug.
|
||||
|
||||
This package is regulary tested on multiple platforms (Debian, macOS, Fedora, Alpine, FreeBSD) to ensure it'll work fine
|
||||
in any environment.
|
||||
|
||||
## Installation
|
||||
|
||||
The package can be installed by adding `gen_magic` to your list of dependencies in `mix.exs`:
|
||||
The package can be installed by adding `majic` to your list of dependencies in `mix.exs`:
|
||||
|
||||
```elixir
|
||||
def deps do
|
||||
[
|
||||
{:gen_magic, "~> 1.0.0"}
|
||||
{:majic, "~> 1.0"}
|
||||
]
|
||||
end
|
||||
```
|
||||
|
@ -22,34 +29,34 @@ Compilation of the underlying C program is automatic and handled by [elixir_make
|
|||
|
||||
## Usage
|
||||
|
||||
Depending on the use case, you may utilise a single (one-off) GenMagic process without reusing it as a daemon, or utilise a connection pool (such as Poolboy) in your application to run multiple persistent GenMagic processes.
|
||||
Depending on the use case, you may utilise a single (one-off) Majic process without reusing it as a daemon, or utilise a connection pool (such as Poolboy) in your application to run multiple persistent Majic processes.
|
||||
|
||||
To use GenMagic directly, you can use `GenMagic.Helpers.perform_once/1`:
|
||||
To use Majic directly, you can use `Majic.Helpers.perform_once/1`:
|
||||
|
||||
```elixir
|
||||
iex(1)> GenMagic.perform(".", once: true)
|
||||
iex(1)> Majic.perform(".", once: true)
|
||||
{:ok,
|
||||
%GenMagic.Result{
|
||||
%Majic.Result{
|
||||
content: "directory",
|
||||
encoding: "binary",
|
||||
mime_type: "inode/directory"
|
||||
}}
|
||||
```
|
||||
|
||||
To use the GenMagic server as a daemon, you can start it first, keep a reference, then feed messages to it as you require:
|
||||
To use the Majic server as a daemon, you can start it first, keep a reference, then feed messages to it as you require:
|
||||
|
||||
```elixir
|
||||
{:ok, pid} = GenMagic.Server.start_link([])
|
||||
{:ok, result} = GenMagic.perform(path, server: pid)
|
||||
{:ok, pid} = Majic.Server.start_link([])
|
||||
{:ok, result} = Majic.perform(path, server: pid)
|
||||
```
|
||||
|
||||
See `GenMagic.Server.start_link/1` and `t:GenMagic.Server.option/0` for more information on startup parameters.
|
||||
See `Majic.Server.start_link/1` and `t:Majic.Server.option/0` for more information on startup parameters.
|
||||
|
||||
See `GenMagic.Result` for details on the result provided.
|
||||
See `Majic.Result` for details on the result provided.
|
||||
|
||||
## Configuration
|
||||
|
||||
When using `GenMagic.Server.start_link/1` to start a persistent server, or `GenMagic.Helpers.perform_once/2` to run an ad-hoc request, you can override specific options to suit your use case.
|
||||
When using `Majic.Server.start_link/1` to start a persistent server, or `Majic.Helpers.perform_once/2` to run an ad-hoc request, you can override specific options to suit your use case.
|
||||
|
||||
| Name | Default | Description |
|
||||
| - | - | - |
|
||||
|
@ -58,18 +65,18 @@ When using `GenMagic.Server.start_link/1` to start a persistent server, or `GenM
|
|||
| `:recycle_threshold` | 10 | Number of cycles before the C process is replaced |
|
||||
| `:database_patterns` | `[:default]` | Databases to load |
|
||||
|
||||
See `t:GenMagic.Server.option/0` for details.
|
||||
See `t:Majic.Server.option/0` for details.
|
||||
|
||||
### Use Cases
|
||||
|
||||
### Ad-Hoc Requests
|
||||
|
||||
For ad-hoc requests, you can use the helper method `GenMagic.Helpers.perform_once/2`:
|
||||
For ad-hoc requests, you can use the helper method `Majic.Helpers.perform_once/2`:
|
||||
|
||||
```elixir
|
||||
iex(1)> GenMagic.perform(Path.join(File.cwd!(), "Makefile"), once: true)
|
||||
iex(1)> Majic.perform(Path.join(File.cwd!(), "Makefile"), once: true)
|
||||
{:ok,
|
||||
%GenMagic.Result{
|
||||
%Majic.Result{
|
||||
content: "makefile script, ASCII text",
|
||||
encoding: "us-ascii",
|
||||
mime_type: "text/x-makefile"
|
||||
|
@ -83,22 +90,22 @@ The Server should be run under a supervisor which provides resiliency.
|
|||
Here we run it under a supervisor:
|
||||
|
||||
```elixir
|
||||
iex(1)> {:ok, pid} = Supervisor.start_link([{GenMagic.Server, name: :gen_magic}], strategy: :one_for_one)
|
||||
iex(1)> {:ok, pid} = Supervisor.start_link([{Majic.Server, name: :gen_magic}], strategy: :one_for_one)
|
||||
{:ok, #PID<0.199.0>}
|
||||
```
|
||||
|
||||
Now we can ask it to inspect a file:
|
||||
|
||||
```elixir
|
||||
iex(2)> GenMagic.perform(Path.expand("~/.bash_history"), server: :gen_magic)
|
||||
{:ok, %GenMagic.Result{mime_type: "text/plain", encoding: "us-ascii", content: "ASCII text"}}
|
||||
iex(2)> Majic.perform(Path.expand("~/.bash_history"), server: :gen_magic)
|
||||
{:ok, %Majic.Result{mime_type: "text/plain", encoding: "us-ascii", content: "ASCII text"}}
|
||||
```
|
||||
|
||||
Note that in this case we have opted to use a named process.
|
||||
|
||||
### Pool
|
||||
|
||||
For concurrency *and* resiliency, you may start the `GenMagic.Pool`. By default, it will start a `GenMagic.Server`
|
||||
For concurrency *and* resiliency, you may start the `Majic.Pool`. By default, it will start a `Majic.Server`
|
||||
worker per online scheduler:
|
||||
|
||||
You can add a pool in your application supervisor by adding it as a child:
|
||||
|
@ -107,18 +114,18 @@ You can add a pool in your application supervisor by adding it as a child:
|
|||
children =
|
||||
[
|
||||
# ...
|
||||
{GenMagic.Pool, [name: YourApp.GenMagicPool, pool_size: 2]}
|
||||
{Majic.Pool, [name: YourApp.MajicPool, pool_size: 2]}
|
||||
]
|
||||
|
||||
opts = [strategy: :one_for_one, name: Pleroma.Supervisor]
|
||||
opts = [strategy: :one_for_one, name: YourApp.Supervisor]
|
||||
Supervisor.start_link(children, opts)
|
||||
```
|
||||
|
||||
And then you can use it with `GenMagic.perform/2` with `pool: YourApp.GenMagicPool` option:
|
||||
And then you can use it with `Majic.perform/2` with `pool: YourApp.MajicPool` option:
|
||||
|
||||
```
|
||||
iex(1)> GenMagic.perform(Path.expand("~/.bash_history"), pool: YourApp.GenMagicPool)
|
||||
{:ok, %GenMagic.Result{mime_type: "text/plain", encoding: "us-ascii", content: "ASCII text"}}
|
||||
iex(1)> Majic.perform(Path.expand("~/.bash_history"), pool: YourApp.MajicPool)
|
||||
{:ok, %Majic.Result{mime_type: "text/plain", encoding: "us-ascii", content: "ASCII text"}}
|
||||
```
|
||||
|
||||
### Check Uploaded Files
|
||||
|
@ -127,12 +134,12 @@ If you use Phoenix, you can inspect the file from your controller:
|
|||
|
||||
```elixir
|
||||
def upload(conn, %{"upload" => %{path: path}}) do,
|
||||
{:ok, result} = GenMagic.perform(path, server: :gen_magic)
|
||||
{:ok, result} = Majic.perform(path, server: :gen_magic)
|
||||
text(conn, "Received your file containing #{result.content}")
|
||||
end
|
||||
```
|
||||
|
||||
Obviously, it will be more ideal if you have wrapped `GenMagic.Server` in a pool such as Poolboy, to avoid constantly starting and stopping the underlying C program.
|
||||
Obviously, it will be more ideal if you have wrapped `Majic.Server` in a pool such as Poolboy, to avoid constantly starting and stopping the underlying C program.
|
||||
|
||||
## Notes
|
||||
|
||||
|
@ -147,8 +154,11 @@ find . -name *ex | xargs mix run test/soak.exs
|
|||
|
||||
## Acknowledgements
|
||||
|
||||
During design and prototype development of this library, the Author has drawn inspiration from the following individuals, and therefore thanks all contributors for their generosity:
|
||||
During design and prototype development of this library, the Author has drawn inspiration from the following individuals, and therefore
|
||||
thanks all contributors for their generosity:
|
||||
|
||||
- [Evadne Wu](https://github.com/evadne)
|
||||
- Original work
|
||||
- Mr [James Every](https://github.com/devstopfix)
|
||||
- Enhanced Elixir Wrapper (based on GenServer)
|
||||
- Initial Hex packaging (v.0.22)
|
||||
|
|
|
@ -1,17 +1,11 @@
|
|||
defmodule GenMagic do
|
||||
@moduledoc """
|
||||
Top-level namespace for GenMagic, the libmagic client for Elixir.
|
||||
|
||||
See `GenMagic.Server` or the README for usage.
|
||||
"""
|
||||
|
||||
defmodule Majic do
|
||||
@doc """
|
||||
Perform on `path`.
|
||||
|
||||
An option of `server: ServerName`, `pool: PoolName` or `once: true` must be passed.
|
||||
"""
|
||||
@type name :: {:pool, atom()} | {:server, GenMagic.Server.t()} | {:once, true}
|
||||
@type option :: name
|
||||
when name: {:pool, atom()} | {:server, GenMagic.Server.t()} | {:once, true}
|
||||
|
||||
@spec perform(GenMagic.Server.target(), [option()]) :: GenMagic.Server.result()
|
||||
def perform(path, opts, timeout \\ 5000) do
|
||||
|
@ -34,7 +28,7 @@ defmodule GenMagic do
|
|||
end
|
||||
|
||||
defp do_perform({mod, name}, path, timeout) do
|
||||
mod.perform(name, path, tiemout)
|
||||
mod.perform(name, path, timeout)
|
||||
end
|
||||
|
||||
end
|
|
@ -1,7 +1,7 @@
|
|||
defmodule GenMagic.Config do
|
||||
defmodule Majic.Config do
|
||||
@moduledoc false
|
||||
@otp_app Mix.Project.config()[:app]
|
||||
@executable_name "apprentice"
|
||||
@executable_name "libmagic_port"
|
||||
@startup_timeout 1_000
|
||||
@process_timeout 30_000
|
||||
@recycle_threshold :infinity
|
|
@ -1,10 +1,10 @@
|
|||
defmodule GenMagic.Helpers do
|
||||
defmodule Majic.Helpers do
|
||||
@moduledoc """
|
||||
Contains convenience functions for one-off use.
|
||||
"""
|
||||
|
||||
alias GenMagic.Result
|
||||
alias GenMagic.Server
|
||||
alias Majic.Result
|
||||
alias Majic.Server
|
||||
|
||||
@spec perform_once(Path.t() | {:bytes, binary}, [Server.option()]) ::
|
||||
{:ok, Result.t()} | {:error, term()}
|
||||
|
@ -16,9 +16,9 @@ defmodule GenMagic.Helpers do
|
|||
|
||||
## Example
|
||||
|
||||
iex(1)> {:ok, result} = GenMagic.Helpers.perform_once(".")
|
||||
iex(1)> {:ok, result} = Majic.Helpers.perform_once(".")
|
||||
iex(2)> result
|
||||
%GenMagic.Result{content: "directory", encoding: "binary", mime_type: "inode/directory"}
|
||||
%Majic.Result{content: "directory", encoding: "binary", mime_type: "inode/directory"}
|
||||
"""
|
||||
def perform_once(path, options \\ []) do
|
||||
with {:ok, pid} <- Server.start_link(options),
|
|
@ -1,6 +1,6 @@
|
|||
defmodule GenMagic.Pool do
|
||||
defmodule Majic.Pool do
|
||||
@behaviour NimblePool
|
||||
@moduledoc "Pool of `GenMagic.Server`"
|
||||
@moduledoc "Pool of `Majic.Server`"
|
||||
|
||||
def child_spec(opts) do
|
||||
%{
|
||||
|
@ -25,7 +25,7 @@ defmodule GenMagic.Pool do
|
|||
pool,
|
||||
:checkout,
|
||||
fn _, server ->
|
||||
{GenMagic.Server.perform(server, path, timeout), server}
|
||||
{Majic.Server.perform(server, path, timeout), server}
|
||||
end,
|
||||
pool_timeout
|
||||
)
|
||||
|
@ -46,7 +46,7 @@ defmodule GenMagic.Pool do
|
|||
|
||||
@impl NimblePool
|
||||
def init_worker(options) do
|
||||
{:ok, server} = GenMagic.Server.start_link(options || [])
|
||||
{:ok, server} = Majic.Server.start_link(options || [])
|
||||
{:ok, server, options}
|
||||
end
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
defmodule GenMagic.Result do
|
||||
defmodule Majic.Result do
|
||||
@moduledoc """
|
||||
Represents the results obtained from libmagic.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
defmodule GenMagic.Server do
|
||||
defmodule Majic.Server do
|
||||
@moduledoc """
|
||||
Provides access to the underlying libmagic client, which performs file introspection.
|
||||
|
||||
|
@ -6,9 +6,9 @@ defmodule GenMagic.Server do
|
|||
"""
|
||||
|
||||
@behaviour :gen_statem
|
||||
alias GenMagic.Result
|
||||
alias GenMagic.Server.Data
|
||||
alias GenMagic.Server.Status
|
||||
alias Majic.Result
|
||||
alias Majic.Server.Data
|
||||
alias Majic.Server.Status
|
||||
import Kernel, except: [send: 2]
|
||||
require Logger
|
||||
|
||||
|
@ -34,7 +34,7 @@ defmodule GenMagic.Server do
|
|||
Can be set to `:infinity`.
|
||||
|
||||
Please note that, if you have chosen a custom timeout value, you should also pass it when
|
||||
using `GenMagic.Server.perform/3`.
|
||||
using `Majic.Server.perform/3`.
|
||||
|
||||
- `:recycle_threshold`: Specifies the number of requests processed before the underlying C
|
||||
program is recycled.
|
||||
|
@ -169,7 +169,7 @@ defmodule GenMagic.Server do
|
|||
|
||||
@impl :gen_statem
|
||||
def init(options) do
|
||||
import GenMagic.Config
|
||||
import Majic.Config
|
||||
|
||||
data = %Data{
|
||||
port_name: get_port_name(),
|
|
@ -1,4 +1,4 @@
|
|||
defmodule GenMagic.Server.Data do
|
||||
defmodule Majic.Server.Data do
|
||||
@moduledoc false
|
||||
|
||||
@type request :: {Path.t(), {pid(), term()}, requested_at :: integer()}
|
|
@ -1,4 +1,4 @@
|
|||
defmodule GenMagic.Server.Status do
|
||||
defmodule Majic.Server.Status do
|
||||
@moduledoc """
|
||||
Represents Status of the underlying Server.
|
||||
"""
|
||||
|
@ -12,7 +12,7 @@ defmodule GenMagic.Server.Status do
|
|||
recycling is enabled.
|
||||
"""
|
||||
@type t :: %__MODULE__{
|
||||
state: GenMagic.Server.state(),
|
||||
state: Majic.Server.state(),
|
||||
cycles: non_neg_integer()
|
||||
}
|
||||
|
10
mix.exs
10
mix.exs
|
@ -1,13 +1,13 @@
|
|||
defmodule GenMagic.MixProject do
|
||||
defmodule Majic.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
if :erlang.system_info(:otp_release) < '21' do
|
||||
raise "GenMagic requires Erlang/OTP 21 or newer"
|
||||
raise "Majic requires Erlang/OTP 21 or newer"
|
||||
end
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :gen_magic,
|
||||
app: :majic,
|
||||
version: "1.0.0",
|
||||
elixir: "~> 1.7",
|
||||
elixirc_paths: elixirc_paths(Mix.env()),
|
||||
|
@ -16,9 +16,9 @@ defmodule GenMagic.MixProject do
|
|||
package: package(),
|
||||
deps: deps(),
|
||||
dialyzer: dialyzer(),
|
||||
name: "GenMagic",
|
||||
name: "Majic",
|
||||
description: "File introspection with libmagic",
|
||||
source_url: "https://github.com/evadne/gen_magic",
|
||||
source_url: "https://github.com/hrefhref/majic",
|
||||
docs: docs()
|
||||
]
|
||||
end
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
defmodule GenMagicTest do
|
||||
use GenMagic.MagicCase
|
||||
alias GenMagic.Result
|
||||
|
||||
doctest GenMagic
|
||||
@iterations 100
|
||||
|
||||
test "Makefile is text file" do
|
||||
{:ok, pid} = GenMagic.Server.start_link([])
|
||||
path = absolute_path("Makefile")
|
||||
assert {:ok, %{mime_type: "text/x-makefile"}} = GenMagic.Server.perform(pid, path)
|
||||
end
|
||||
|
||||
@tag external: true
|
||||
test "Load test local files" do
|
||||
{:ok, pid} = GenMagic.Server.start_link([])
|
||||
|
||||
files_stream()
|
||||
|> Stream.cycle()
|
||||
|> Stream.take(@iterations)
|
||||
|> Stream.map(&assert {:ok, %Result{}} = GenMagic.Server.perform(pid, &1))
|
||||
|> Enum.all?()
|
||||
|> assert
|
||||
end
|
||||
|
||||
test "Non-existent file" do
|
||||
{:ok, pid} = GenMagic.Server.start_link([])
|
||||
path = missing_filename()
|
||||
assert_no_file(GenMagic.Server.perform(pid, path))
|
||||
end
|
||||
|
||||
test "Named process" do
|
||||
{:ok, pid} = GenMagic.Server.start_link(name: :gen_magic)
|
||||
path = absolute_path("Makefile")
|
||||
assert {:ok, %{cycles: 0}} = GenMagic.Server.status(:gen_magic)
|
||||
assert {:ok, %{cycles: 0}} = GenMagic.Server.status(pid)
|
||||
assert {:ok, %Result{} = result} = GenMagic.Server.perform(:gen_magic, path)
|
||||
assert {:ok, %{cycles: 1}} = GenMagic.Server.status(:gen_magic)
|
||||
assert {:ok, %{cycles: 1}} = GenMagic.Server.status(pid)
|
||||
assert "text/x-makefile" = result.mime_type
|
||||
end
|
||||
|
||||
describe "custom database" do
|
||||
setup do
|
||||
database = absolute_path("elixir.mgc")
|
||||
on_exit(fn -> File.rm(database) end)
|
||||
{_, 0} = System.cmd("file", ["-C", "-m", absolute_path("test/elixir")])
|
||||
[database: database]
|
||||
end
|
||||
|
||||
test "recognises Elixir files", %{database: database} do
|
||||
{:ok, pid} = GenMagic.Server.start_link(database_patterns: [database])
|
||||
path = absolute_path("mix.exs")
|
||||
assert {:ok, %Result{} = result} = GenMagic.Server.perform(pid, path)
|
||||
assert "text/x-elixir" = result.mime_type
|
||||
assert "us-ascii" = result.encoding
|
||||
assert "Elixir module source text" = result.content
|
||||
end
|
||||
|
||||
test "recognises Elixir files after a reload", %{database: database} do
|
||||
{:ok, pid} = GenMagic.Server.start_link([])
|
||||
path = absolute_path("mix.exs")
|
||||
{:ok, %Result{mime_type: mime}} = GenMagic.Server.perform(pid, path)
|
||||
refute mime == "text/x-elixir"
|
||||
:ok = GenMagic.Server.reload(pid, [database])
|
||||
assert {:ok, %Result{mime_type: "text/x-elixir"}} = GenMagic.Server.perform(pid, path)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,9 +0,0 @@
|
|||
defmodule GenMagic.HelpersTest do
|
||||
use GenMagic.MagicCase
|
||||
doctest GenMagic.Helpers
|
||||
|
||||
test "perform_once" do
|
||||
path = absolute_path("Makefile")
|
||||
assert {:ok, %{mime_type: "text/x-makefile"}} = GenMagic.Helpers.perform_once(path)
|
||||
end
|
||||
end
|
|
@ -1,16 +0,0 @@
|
|||
defmodule GenMagic.PoollTest do
|
||||
use GenMagic.MagicCase
|
||||
|
||||
test "pool" do
|
||||
{:ok, _} = GenMagic.Pool.start_link(name: TestPool, pool_size: 2)
|
||||
assert {:ok, _} = GenMagic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
assert {:ok, _} = GenMagic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
assert {:ok, _} = GenMagic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
assert {:ok, _} = GenMagic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
assert {:ok, _} = GenMagic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
assert {:ok, _} = GenMagic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
assert {:ok, _} = GenMagic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
assert {:ok, _} = GenMagic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
assert {:ok, _} = GenMagic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
end
|
||||
end
|
|
@ -1,44 +0,0 @@
|
|||
defmodule GenMagic.ServerTest do
|
||||
use GenMagic.MagicCase
|
||||
doctest GenMagic.Server
|
||||
|
||||
describe "recycle_threshold" do
|
||||
test "resets" do
|
||||
{:ok, pid} = GenMagic.Server.start_link(recycle_threshold: 3)
|
||||
path = absolute_path("Makefile")
|
||||
assert {:ok, %{cycles: 0}} = GenMagic.Server.status(pid)
|
||||
assert {:ok, _} = GenMagic.Server.perform(pid, path)
|
||||
assert {:ok, %{cycles: 1}} = GenMagic.Server.status(pid)
|
||||
assert {:ok, _} = GenMagic.Server.perform(pid, path)
|
||||
assert {:ok, %{cycles: 2}} = GenMagic.Server.status(pid)
|
||||
assert {:ok, _} = GenMagic.Server.perform(pid, path)
|
||||
Process.sleep(100)
|
||||
assert {:ok, %{cycles: 0}} = GenMagic.Server.status(pid)
|
||||
end
|
||||
|
||||
test "resets before reply" do
|
||||
{:ok, pid} = GenMagic.Server.start_link(recycle_threshold: 1)
|
||||
path = absolute_path("Makefile")
|
||||
assert {:ok, %{cycles: 0}} = GenMagic.Server.status(pid)
|
||||
assert {:ok, _} = GenMagic.Server.perform(pid, path)
|
||||
Process.sleep(100)
|
||||
assert {:ok, %{cycles: 0}} = GenMagic.Server.status(pid)
|
||||
assert {:ok, _} = GenMagic.Server.perform(pid, path)
|
||||
Process.sleep(100)
|
||||
assert {:ok, %{cycles: 0}} = GenMagic.Server.status(pid)
|
||||
assert {:ok, _} = GenMagic.Server.perform(pid, path)
|
||||
Process.sleep(100)
|
||||
assert {:ok, %{cycles: 0}} = GenMagic.Server.status(pid)
|
||||
end
|
||||
end
|
||||
|
||||
test "recycle" do
|
||||
{:ok, pid} = GenMagic.Server.start_link([])
|
||||
path = absolute_path("Makefile")
|
||||
assert {:ok, %{cycles: 0}} = GenMagic.Server.status(pid)
|
||||
assert {:ok, _} = GenMagic.Server.perform(pid, path)
|
||||
assert {:ok, %{cycles: 1}} = GenMagic.Server.status(pid)
|
||||
assert :ok = GenMagic.Server.recycle(pid)
|
||||
assert {:ok, %{cycles: 0}} = GenMagic.Server.status(pid)
|
||||
end
|
||||
end
|
9
test/majic/helpers_test.exs
Normal file
9
test/majic/helpers_test.exs
Normal file
|
@ -0,0 +1,9 @@
|
|||
defmodule Majic.HelpersTest do
|
||||
use Majic.MagicCase
|
||||
doctest Majic.Helpers
|
||||
|
||||
test "perform_once" do
|
||||
path = absolute_path("Makefile")
|
||||
assert {:ok, %{mime_type: "text/x-makefile"}} = Majic.Helpers.perform_once(path)
|
||||
end
|
||||
end
|
69
test/majic/majic_test.exs
Normal file
69
test/majic/majic_test.exs
Normal file
|
@ -0,0 +1,69 @@
|
|||
defmodule MajicTest do
|
||||
use Majic.MagicCase
|
||||
alias Majic.Result
|
||||
|
||||
doctest Majic
|
||||
@iterations 100
|
||||
|
||||
test "Makefile is text file" do
|
||||
{:ok, pid} = Majic.Server.start_link([])
|
||||
path = absolute_path("Makefile")
|
||||
assert {:ok, %{mime_type: "text/x-makefile"}} = Majic.Server.perform(pid, path)
|
||||
end
|
||||
|
||||
@tag external: true
|
||||
test "Load test local files" do
|
||||
{:ok, pid} = Majic.Server.start_link([])
|
||||
|
||||
files_stream()
|
||||
|> Stream.cycle()
|
||||
|> Stream.take(@iterations)
|
||||
|> Stream.map(&assert {:ok, %Result{}} = Majic.Server.perform(pid, &1))
|
||||
|> Enum.all?()
|
||||
|> assert
|
||||
end
|
||||
|
||||
test "Non-existent file" do
|
||||
{:ok, pid} = Majic.Server.start_link([])
|
||||
path = missing_filename()
|
||||
assert_no_file(Majic.Server.perform(pid, path))
|
||||
end
|
||||
|
||||
test "Named process" do
|
||||
{:ok, pid} = Majic.Server.start_link(name: :gen_magic)
|
||||
path = absolute_path("Makefile")
|
||||
assert {:ok, %{cycles: 0}} = Majic.Server.status(:gen_magic)
|
||||
assert {:ok, %{cycles: 0}} = Majic.Server.status(pid)
|
||||
assert {:ok, %Result{} = result} = Majic.Server.perform(:gen_magic, path)
|
||||
assert {:ok, %{cycles: 1}} = Majic.Server.status(:gen_magic)
|
||||
assert {:ok, %{cycles: 1}} = Majic.Server.status(pid)
|
||||
assert "text/x-makefile" = result.mime_type
|
||||
end
|
||||
|
||||
describe "custom database" do
|
||||
setup do
|
||||
database = absolute_path("elixir.mgc")
|
||||
on_exit(fn -> File.rm(database) end)
|
||||
{_, 0} = System.cmd("file", ["-C", "-m", absolute_path("test/elixir")])
|
||||
[database: database]
|
||||
end
|
||||
|
||||
test "recognises Elixir files", %{database: database} do
|
||||
{:ok, pid} = Majic.Server.start_link(database_patterns: [database])
|
||||
path = absolute_path("mix.exs")
|
||||
assert {:ok, %Result{} = result} = Majic.Server.perform(pid, path)
|
||||
assert "text/x-elixir" = result.mime_type
|
||||
assert "us-ascii" = result.encoding
|
||||
assert "Elixir module source text" = result.content
|
||||
end
|
||||
|
||||
test "recognises Elixir files after a reload", %{database: database} do
|
||||
{:ok, pid} = Majic.Server.start_link([])
|
||||
path = absolute_path("mix.exs")
|
||||
{:ok, %Result{mime_type: mime}} = Majic.Server.perform(pid, path)
|
||||
refute mime == "text/x-elixir"
|
||||
:ok = Majic.Server.reload(pid, [database])
|
||||
assert {:ok, %Result{mime_type: "text/x-elixir"}} = Majic.Server.perform(pid, path)
|
||||
end
|
||||
end
|
||||
end
|
16
test/majic/pool_test.exs
Normal file
16
test/majic/pool_test.exs
Normal file
|
@ -0,0 +1,16 @@
|
|||
defmodule Majic.PoollTest do
|
||||
use Majic.MagicCase
|
||||
|
||||
test "pool" do
|
||||
{:ok, _} = Majic.Pool.start_link(name: TestPool, pool_size: 2)
|
||||
assert {:ok, _} = Majic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
assert {:ok, _} = Majic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
assert {:ok, _} = Majic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
assert {:ok, _} = Majic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
assert {:ok, _} = Majic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
assert {:ok, _} = Majic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
assert {:ok, _} = Majic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
assert {:ok, _} = Majic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
assert {:ok, _} = Majic.Pool.perform(TestPool, absolute_path("Makefile"))
|
||||
end
|
||||
end
|
|
@ -1,17 +1,17 @@
|
|||
defmodule GenMagic.ApprenticeTest do
|
||||
use GenMagic.MagicCase
|
||||
defmodule Majic.ApprenticeTest do
|
||||
use Majic.MagicCase
|
||||
|
||||
@tmp_path "/tmp/testgenmagicx"
|
||||
require Logger
|
||||
|
||||
test "sends ready" do
|
||||
port = Port.open(GenMagic.Config.get_port_name(), GenMagic.Config.get_port_options([]))
|
||||
port = Port.open(Majic.Config.get_port_name(), Majic.Config.get_port_options([]))
|
||||
on_exit(fn -> send(port, {self(), :close}) end)
|
||||
assert_ready_and_init_default(port)
|
||||
end
|
||||
|
||||
test "stops" do
|
||||
port = Port.open(GenMagic.Config.get_port_name(), GenMagic.Config.get_port_options([]))
|
||||
port = Port.open(Majic.Config.get_port_name(), Majic.Config.get_port_options([]))
|
||||
on_exit(fn -> send(port, {self(), :close}) end)
|
||||
assert_ready_and_init_default(port)
|
||||
send(port, {self(), {:command, :erlang.term_to_binary({:stop, :stop})}})
|
||||
|
@ -20,7 +20,7 @@ defmodule GenMagic.ApprenticeTest do
|
|||
|
||||
test "exits with non existent database with an error" do
|
||||
opts = [:use_stdio, :binary, :exit_status, {:packet, 2}, {:args, []}]
|
||||
port = Port.open(GenMagic.Config.get_port_name(), opts)
|
||||
port = Port.open(Majic.Config.get_port_name(), opts)
|
||||
on_exit(fn -> send(port, {self(), :close}) end)
|
||||
assert_ready(port)
|
||||
|
||||
|
@ -34,7 +34,7 @@ defmodule GenMagic.ApprenticeTest do
|
|||
|
||||
describe "port" do
|
||||
setup do
|
||||
port = Port.open(GenMagic.Config.get_port_name(), GenMagic.Config.get_port_options([]))
|
||||
port = Port.open(Majic.Config.get_port_name(), Majic.Config.get_port_options([]))
|
||||
on_exit(fn -> send(port, {self(), :close}) end)
|
||||
assert_ready_and_init_default(port)
|
||||
%{port: port}
|
44
test/majic/server_test.exs
Normal file
44
test/majic/server_test.exs
Normal file
|
@ -0,0 +1,44 @@
|
|||
defmodule Majic.ServerTest do
|
||||
use Majic.MagicCase
|
||||
doctest Majic.Server
|
||||
|
||||
describe "recycle_threshold" do
|
||||
test "resets" do
|
||||
{:ok, pid} = Majic.Server.start_link(recycle_threshold: 3)
|
||||
path = absolute_path("Makefile")
|
||||
assert {:ok, %{cycles: 0}} = Majic.Server.status(pid)
|
||||
assert {:ok, _} = Majic.Server.perform(pid, path)
|
||||
assert {:ok, %{cycles: 1}} = Majic.Server.status(pid)
|
||||
assert {:ok, _} = Majic.Server.perform(pid, path)
|
||||
assert {:ok, %{cycles: 2}} = Majic.Server.status(pid)
|
||||
assert {:ok, _} = Majic.Server.perform(pid, path)
|
||||
Process.sleep(100)
|
||||
assert {:ok, %{cycles: 0}} = Majic.Server.status(pid)
|
||||
end
|
||||
|
||||
test "resets before reply" do
|
||||
{:ok, pid} = Majic.Server.start_link(recycle_threshold: 1)
|
||||
path = absolute_path("Makefile")
|
||||
assert {:ok, %{cycles: 0}} = Majic.Server.status(pid)
|
||||
assert {:ok, _} = Majic.Server.perform(pid, path)
|
||||
Process.sleep(100)
|
||||
assert {:ok, %{cycles: 0}} = Majic.Server.status(pid)
|
||||
assert {:ok, _} = Majic.Server.perform(pid, path)
|
||||
Process.sleep(100)
|
||||
assert {:ok, %{cycles: 0}} = Majic.Server.status(pid)
|
||||
assert {:ok, _} = Majic.Server.perform(pid, path)
|
||||
Process.sleep(100)
|
||||
assert {:ok, %{cycles: 0}} = Majic.Server.status(pid)
|
||||
end
|
||||
end
|
||||
|
||||
test "recycle" do
|
||||
{:ok, pid} = Majic.Server.start_link([])
|
||||
path = absolute_path("Makefile")
|
||||
assert {:ok, %{cycles: 0}} = Majic.Server.status(pid)
|
||||
assert {:ok, _} = Majic.Server.perform(pid, path)
|
||||
assert {:ok, %{cycles: 1}} = Majic.Server.status(pid)
|
||||
assert :ok = Majic.Server.recycle(pid)
|
||||
assert {:ok, %{cycles: 0}} = Majic.Server.status(pid)
|
||||
end
|
||||
end
|
|
@ -8,7 +8,7 @@ defmodule Soak do
|
|||
def perform_infinite([]), do: false
|
||||
|
||||
def perform_infinite(paths) do
|
||||
{:ok, pid} = GenMagic.Server.start_link(database_patterns: ["/usr/local/share/misc/*.mgc"])
|
||||
{:ok, pid} = Majic.Server.start_link(database_patterns: ["/usr/local/share/misc/*.mgc"])
|
||||
|
||||
perform_infinite(paths, [], pid, 0)
|
||||
end
|
||||
|
@ -19,7 +19,7 @@ defmodule Soak do
|
|||
|
||||
defp perform_infinite([path | paths], done, pid, count) do
|
||||
if rem(count, 1000) == 0, do: IO.puts(Integer.to_string(count))
|
||||
{:ok, %GenMagic.Result{}} = GenMagic.Server.perform(pid, path)
|
||||
{:ok, %Majic.Result{}} = Majic.Server.perform(pid, path)
|
||||
perform_infinite(paths, [path | done], pid, count + 1)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
defmodule GenMagic.MagicCase do
|
||||
defmodule Majic.MagicCase do
|
||||
@moduledoc false
|
||||
use ExUnit.CaseTemplate
|
||||
|
||||
|
|
Loading…
Reference in a new issue