From ea21b2367a13cb94a979762ac83b5d70b0e9bcd0 Mon Sep 17 00:00:00 2001 From: meddle Date: Mon, 11 Jun 2018 21:49:09 +0300 Subject: [PATCH] Add version 0.2.0-rc1 --- README.md | 17 +++++++++-- lib/mix/compilers/lfe.ex | 42 +++++++++++++++++++++++++++ lib/mix/tasks/compile.lfe.ex | 23 ++------------- lib/mix/tasks/test.lfe.ex | 56 ++++++++++++++++++++++++++++++++++++ mix.exs | 16 +++++++++-- mix.lock | 6 ++++ 6 files changed, 135 insertions(+), 25 deletions(-) create mode 100644 lib/mix/compilers/lfe.ex create mode 100644 lib/mix/tasks/test.lfe.ex diff --git a/README.md b/README.md index 0cb13d3..b5f8031 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ It is a Mix compiler which uses the Erlang Mix compiler. Lisp is a great language to get into the functional way of thinking and LFE is Lisp 2+ which runs on the greatest platform (personal opinion). Elixir's Mix is a great (or the greatest) configuration/package/build manager, so why not use it to compile LFE? -Also Elixir developers should try LFE! This little project has the purpose to make that an easier. +Also Elixir developers should try LFE! This little project has the purpose to make that easier. ## Installation @@ -15,7 +15,7 @@ You can create a Mix project with `mix new ` and add this as depen ```elixir def deps do [ - {:mix_lfe, "~> 0.1.0"} + {:mix_lfe, "0.2.0-rc1"} ] end ``` @@ -37,6 +37,17 @@ To use the compiled modules with the LFE REPL, you can run: Also if you want to just run `mix compile` add `compilers: Mix.compilers() ++ [:lfe]` to the list returned by `project/0` which is defined in your `mix.exs`. +## Using it for running tests + +The compiler can compile and run [ltest](https://github.com/lfex/ltest) tests. +Just put all the tests in the `test` folder of the project and run: + +```bash +mix test.lfe +``` + +Works with umbrella applications. + ## Example projects TODO @@ -47,7 +58,7 @@ The tests of this project mirror the ones for the Erlang Mix compiler. For now the source is very simple and uses an [idea](https://github.com/elixir-lang/elixir/blob/e1c903a5956e4cb9075f0aac00638145788b0da4/lib/mix/lib/mix/compilers/erlang.ex#L20) from the Erlang Mix compiler. All works well, but requires some manual work and doesn't support LFE compiler fine tunning, so that's what we'll be after next. -1. Add task for running LFE tests. What kind of tests? Will see... +1. Make it possible to add options when running `mix test.lfe`. 2. Automate the installation & setup process in a way. Maybe by using something similar to the Phoenix generator tasks. 3. Pass more options to the LFE compiler, using mix configuration. 4. Use LFE syntax for configuration (not sure this is needed, really). diff --git a/lib/mix/compilers/lfe.ex b/lib/mix/compilers/lfe.ex new file mode 100644 index 0000000..6707399 --- /dev/null +++ b/lib/mix/compilers/lfe.ex @@ -0,0 +1,42 @@ +defmodule Mix.Compilers.Lfe do + alias Mix.Compilers.Erlang, as: ErlangCompiler + + @moduledoc false + + @doc """ + Compiles the files in `mappings` with '.lfe' extensions into + the destinations. + Does this for each stale input and output pair (or for all if `force` is `true`) and + removes files that no longer have a source, while keeping the `manifest` up to date. + + `mappings` should be a list of tuples in the form of `{src, dest}` paths. + + Uses an [idea](https://github.com/elixir-lang/elixir/blob/e1c903a5956e4cb9075f0aac00638145788b0da4/lib/mix/lib/mix/compilers/erlang.ex#L20) from the Erlang Mix compiler to do so. + + It supports the options of the Erlang Mix compiler under the covers as it is used. + """ + def compile(manifest, [{_, _} | _] = mappings, opts) do + callback = fn input, output -> + module = input |> Path.basename(".lfe") |> String.to_atom() + :code.purge(module) + :code.delete(module) + + outdir = output |> Path.dirname() |> ErlangCompiler.to_erl_file() + + compile_result(:lfe_comp.file(ErlangCompiler.to_erl_file(input), [{:outdir, outdir}, :return, :report])) + end + + ErlangCompiler.compile(manifest, mappings, :lfe, :beam, opts, callback) + end + + @doc """ + Removes compiled files for the given `manifest`. + """ + def clean(manifest), do: ErlangCompiler.clean(manifest) + + defp compile_result({:error, [{:error, [{file, [error | _]}], []}], [], []}) do + {:error, [{file, [error]}], []} + end + + defp compile_result(result), do: result +end diff --git a/lib/mix/tasks/compile.lfe.ex b/lib/mix/tasks/compile.lfe.ex index 6e19cf4..ee17e82 100644 --- a/lib/mix/tasks/compile.lfe.ex +++ b/lib/mix/tasks/compile.lfe.ex @@ -1,6 +1,6 @@ defmodule Mix.Tasks.Compile.Lfe do use Mix.Task.Compiler - import Mix.Compilers.Erlang + import Mix.Compilers.Lfe @recursive true @manifest "compile.lfe" @@ -11,8 +11,7 @@ defmodule Mix.Tasks.Compile.Lfe do Uses an [idea](https://github.com/elixir-lang/elixir/blob/e1c903a5956e4cb9075f0aac00638145788b0da4/lib/mix/lib/mix/compilers/erlang.ex#L20) from the Erlang Mix compiler to do so. - It supports the options of the Erlang Mix compiler under the covers at it is used. - This means that these options are supported: + These options are supported: ## Command line options * `--force` - forces compilation regardless of modification times @@ -35,17 +34,7 @@ defmodule Mix.Tasks.Compile.Lfe do defp do_run(opts) do dest = Mix.Project.compile_path() - callback = fn input, output -> - module = input |> Path.basename(".lfe") |> String.to_atom() - :code.purge(module) - :code.delete(module) - - outdir = output |> Path.dirname() |> to_erl_file() - - compile_result(:lfe_comp.file(to_erl_file(input), [{:outdir, outdir}, :return, :report])) - end - - compile(manifest(), [{"src", dest}], :lfe, :beam, opts, callback) + compile(manifest(), [{"src", dest}], opts) end @doc """ @@ -59,10 +48,4 @@ defmodule Mix.Tasks.Compile.Lfe do def clean, do: clean(manifest()) defp manifest, do: Path.join(Mix.Project.manifest_path(), @manifest) - - defp compile_result({:error, [{:error, [{file, [error | _]}], []}], [], []}) do - {:error, [{file, [error]}], []} - end - - defp compile_result(result), do: result end diff --git a/lib/mix/tasks/test.lfe.ex b/lib/mix/tasks/test.lfe.ex new file mode 100644 index 0000000..acbff62 --- /dev/null +++ b/lib/mix/tasks/test.lfe.ex @@ -0,0 +1,56 @@ +defmodule Mix.Tasks.Test.Lfe do + use Mix.Task.Compiler + import Mix.Compilers.Lfe + + @recursive true + @manifest "test.lfe" + @switches [force: :boolean, all_warnings: :boolean] + + @moduledoc """ + Compiles the source LFE source files of the project, using `Mix.Compilers.Lfe` + and also compiles and runs all the test LFE files with the '-tests.lfe' extension in the + 'test' folder of the project. + + Uses the [ltest](https://github.com/lfex/ltest) library to do so. + + For the compilation it supports the command line options and the configuration of the `Mix.Tasks.Compile.Lfe` task. + """ + + @doc """ + Runs this task. + """ + def run(args) do + {opts, _, _} = OptionParser.parse(args, switches: @switches) + Mix.env(:test) + + do_run(opts) + end + + @doc """ + Returns LFE test manifests. + """ + def manifests, do: [manifest()] + + defp do_run(opts) do + dest = Mix.Project.compile_path() |> String.replace("_build/dev", "_build/test") + location = String.split(dest, "_build") |> List.last() + {:ok, root} = File.cwd() + dest = root |> Path.join("_build") |> Path.join(location) + + File.rmdir(dest) + File.mkdir_p!(dest) + + dest_test = dest |> Path.join("_build") |> Path.join(location) + + File.rmdir(dest_test) + File.mkdir_p!(dest_test) + + compile(manifest(), [{"src", dest}, {"test", dest_test}], opts) + + File.cd(dest) + + :"ltest-runner".unit() + end + + defp manifest, do: Path.join(Mix.Project.manifest_path(), @manifest) +end diff --git a/mix.exs b/mix.exs index 69db5ea..4c4b1e5 100644 --- a/mix.exs +++ b/mix.exs @@ -1,13 +1,21 @@ defmodule MixLfe.MixProject do use Mix.Project + @version "0.2.0-rc1" + def project do [ app: :mix_lfe, - version: "0.1.0", + version: @version, elixir: "~> 1.6", start_permanent: Mix.env() == :prod, description: "A LFE compiler for Mix", + docs: [ + extras: ["README.md"], + main: "readme", + source_ref: "v#{@version}", + source_url: "https://github.com/meddle0x53/mix_lfe" + ], package: package(), deps: deps() ] @@ -27,7 +35,11 @@ defmodule MixLfe.MixProject do def deps do [ - {:lfe, "~> 1.2", override: true, manager: :rebar} + {:lfe, "~> 1.2"}, + {:ltest, "0.10.0-rc6"}, + {:color, "~> 1.0", hex: :erlang_color}, + {:lutil, "~> 0.10.0-rc6"}, + {:ex_doc, ">= 0.0.0", only: :dev} ] end end diff --git a/mix.lock b/mix.lock index f9f5c41..c3990aa 100644 --- a/mix.lock +++ b/mix.lock @@ -1,3 +1,9 @@ %{ + "color": {:hex, :erlang_color, "1.0.0", "145fe1d2e65c4516e4f03fefca6c2f47ebad5899d978d70382a5cfe643e4ac9e", [:rebar3], [], "hexpm"}, + "earmark": {:hex, :earmark, "1.2.5", "4d21980d5d2862a2e13ec3c49ad9ad783ffc7ca5769cf6ff891a4553fbaae761", [:mix], [], "hexpm"}, + "erlang_color": {:hex, :erlang_color, "1.0.0", "145fe1d2e65c4516e4f03fefca6c2f47ebad5899d978d70382a5cfe643e4ac9e", [:rebar3], [], "hexpm"}, + "ex_doc": {:hex, :ex_doc, "0.18.3", "f4b0e4a2ec6f333dccf761838a4b253d75e11f714b85ae271c9ae361367897b7", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"}, "lfe": {:hex, :lfe, "1.2.0", "257708859c0a6949f174cecee6f08bb5d6f08c0f97ec7b75c07072014723ecbc", [:rebar3], [], "hexpm"}, + "ltest": {:hex, :ltest, "0.10.0-rc6", "a605158832d4dc2704cbb572423ec13d1a18dd4d48dec7aff7a3011d0261f9db", [:rebar3], [], "hexpm"}, + "lutil": {:hex, :lutil, "0.10.0-rc6", "c3a560c9ed8cdc34b689591cf60336981ad4ea6ce299624ba87191d3fffb8da2", [:rebar3], [], "hexpm"}, }