diff --git a/lib/caramel.ex b/lib/caramel.ex index 6102877..6de5d25 100644 --- a/lib/caramel.ex +++ b/lib/caramel.ex @@ -12,16 +12,32 @@ defmodule Caramel do IO.puts("🍬 Using Caramel #{version}") end - def compile([]), do: :ok - def compile(files) do + def compile(files, opts \\ []) + def compile([], _opts), do: :ok + def compile(files, opts) do + bin = Path.expand(@caramel_bin) Mix.Shell.cmd( - "#{@caramel_bin} compile " <> Enum.join(files, " "), - [], + "#{bin} compile " <> Enum.join(files, " "), + opts, fn res -> IO.puts(res) end ) + target_dir = Path.join(opts[:cd] || ".", "src") + + if not File.dir?(target_dir) do + Mix.raise "caramel: target dir `#{target_dir}` is not a diretory" + end + + + # move the given files to target directory + basedir = Path.dirname(target_dir) + erlfiles = + for file <- files do + Path.join(basedir, Path.basename(file, Path.extname(file)) <> ".erl") + end + Mix.Shell.cmd( - "mv *.erl src", + "mv #{Enum.join(erlfiles, " ")} #{target_dir}", [], fn _ -> :ok end ) diff --git a/lib/caramel/installer.ex b/lib/caramel/installer.ex index 19bd40a..04e3f4e 100644 --- a/lib/caramel/installer.ex +++ b/lib/caramel/installer.ex @@ -18,6 +18,11 @@ defmodule Caramel.Installer do def download_caramel(version, tarball_name, release_url) do IO.puts("📦 Installing Caramel #{version}...") Mix.Shell.cmd("wget " <> release_url, [], fn _ -> :ok end) + + if not File.exists?(tarball_name) do + Mix.raise("carmel: failed to download release tarball for #{version}.") + end + Mix.Shell.cmd("tar -xzf " <> tarball_name, [], fn _ -> :ok end) Mix.Shell.cmd("rm " <> tarball_name, [], fn _ -> :ok end) Mix.Shell.cmd("mv caramel _build/", [], fn _ -> :ok end) diff --git a/lib/mix/tasks/compiler/caramel.ex b/lib/mix/tasks/compiler/caramel.ex index c9d0a4f..5e27603 100644 --- a/lib/mix/tasks/compiler/caramel.ex +++ b/lib/mix/tasks/compiler/caramel.ex @@ -1,13 +1,75 @@ defmodule Mix.Tasks.Compile.Caramel do use Mix.Task.Compiler + require Logger + def run(_) do project = Mix.Project.config() - source_paths = project[:caramel_paths] - version = project[:caramel_release] - :ok = Caramel.ensure_version(version) + version = project[:caramel_release] || current_version + + # If we're running in an umbrella project we need to specify exactly + # where each source file it within apps path. This has the sideeffect + # of compiling all files accross all umbrella projects instead of + # compiling one by one + if Mix.Project.umbrella?(project) do + for {_app, path} <- Mix.Project.apps_paths(project) do + compile(version, sources: project[:caramel_paths], path: path) + end + :ok + else + :ok = compile(version, sources: project[:caramel_paths]) + end + end + + defp compile(version, opts \\ []) do + source_paths = opts[:source] || ["src"] + + if nil == source_paths do + Mix.raise("Caramel configuration error: `caramel_paths` not set in mix.config") + end + + if nil == version do + Mix.raise("Caramel configuration error: `caramel_release` not set in mix.config") + end + + Mix.Compilers.Erlang.assert_valid_erlc_paths(source_paths) - files = Mix.Utils.extract_files(source_paths, [:ml, :mli, :re, :rei]) - :ok = Caramel.compile(files) + + if opts[:path] do + len = byte_size(opts[:path]) + source_paths = for s <- source_paths, do: Path.join(opts[:path], s) + files = Mix.Utils.extract_files(source_paths, [:ml, :mli, :re, :rei]) + + if files != source_paths do + files = + for f <- files do + <<_ :: binary-size(len), "/", file :: binary()>> = f + file + end + + if files != [] do + :ok = Caramel.ensure_version(version) + end + + Caramel.compile(files, cd: opts[:path]) + end + else + files = Mix.Utils.extract_files(source_paths, [:ml, :mli, :re, :rei]) + + if files != [] do + :ok = Caramel.ensure_version(version) + end + + Caramel.compile(files) + end + + + end + + defp current_version() do + case System.shell("command -v caramel > /dev/null && caramel version") do + {"v" <> _ = buf, 0} -> List.last(String.split(buf)) + _ -> nil + end end end