Current section

Files

Jump to
lightning_css lib lightning_css runner.ex
Raw

lib/lightning_css/runner.ex

defmodule LightningCSS.Runner do
@moduledoc false
use GenServer
require Logger
@type init_args :: %{
profile: atom(),
extra_args: [String.t()],
watch: boolean()
}
@spec start_link(args :: init_args) :: GenServer.on_start()
def start_link(args) do
GenServer.start_link(__MODULE__, args)
end
@spec init(args :: init_args) :: {:ok, any()}
def init(%{profile: profile, extra_args: _, watch: watch} = args) do
config = LightningCSS.Configuration.config_for!(profile)
cd = Keyword.get(config, :cd, File.cwd!())
watcher_pid =
case {watch, config[:watch_files]} do
{true, glob} when is_binary(glob) ->
dirs = expand_glob(Path.join(cd, glob))
{:ok, watcher_pid} = FileSystem.start_link(dirs: dirs)
FileSystem.subscribe(watcher_pid)
watcher_pid
_ ->
nil
end
args =
args |> Map.put(:config, config) |> Map.put(:cd, cd) |> Map.put(:watcher_pid, watcher_pid)
gen_server_pid = self()
args = Map.put(args, :gen_server_pid, gen_server_pid)
%{pid: process_pid} =
Task.async(fn ->
Logger.info("Running Lightning CSS")
__MODULE__.run_lightning_css(args)
end)
args = Map.put(args, :process_pid, process_pid)
{:ok, args}
end
defp expand_glob(watch_files) do
watch_files
|> List.wrap()
|> Enum.flat_map(&Path.wildcard/1)
|> Enum.uniq()
end
def run_lightning_css(%{config: config, extra_args: extra_args, cd: cd, gen_server_pid: gen_server_pid}) do
args = config[:args] || []
if args == [] and extra_args == [] do
raise "no arguments passed to lightning_css"
end
opts = [
cd: cd,
env: config[:env] || %{},
into: IO.stream(:stdio, :line),
stderr_to_stdout: true
]
command_string = Enum.join([Path.relative_to_cwd(LightningCSS.Paths.bin())] ++ args ++ extra_args, " ")
Logger.debug("Command: #{command_string}", opts)
exit_status =
LightningCSS.Paths.bin()
|> System.cmd(args ++ extra_args, opts)
|> elem(1)
Logger.debug("Command completed with exit status #{exit_status}")
send(gen_server_pid, {:lightning_css_exited, exit_status})
end
def handle_info({:file_event, _watcher_pid, {_path, _events}}, state) do
%{pid: process_pid} =
Task.async(fn ->
Logger.info("Changes detected. Running Lightning CSS")
__MODULE__.run_lightning_css(state)
end)
state = Map.put(state, :process_pid, process_pid)
{:noreply, state}
end
def handle_info({:file_event, watcher_pid, :stop}, %{watcher_pid: watcher_pid} = state) do
{:stop, :normal, state}
end
def handle_info({:lightning_css_exited, exit_status}, %{watch: watch} = state) do
case {watch, exit_status} do
{true, 0} ->
{:noreply, state}
{false, 0} ->
{:stop, :normal, state}
{true, _status} ->
{:no_reply, state}
{false, status} ->
{:stop, {:error_and_no_watch, status}, state}
end
end
def handle_info(_, state) do
{:noreply, state}
end
def terminate(:normal, _state) do
:ok
end
def terminate(_, _) do
:ok
end
end