Skip to content

Commit

Permalink
Wrap sass execution in a bash script to address zombie processes (Car…
Browse files Browse the repository at this point in the history
…goSense#1)

* Simplify path functions
* Add wrapper bash script to address zombie processes when --watch is given
  • Loading branch information
mcrumm authored Jul 30, 2021
1 parent 9b0d4c1 commit 2e8eba4
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 17 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGELOG

## v0.1.1 (Unreleased)

* Add wrapper script to address zombie processes

## v0.1.0 (2021-07-25)

* First release
41 changes: 24 additions & 17 deletions lib/dart_sass.ex
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,6 @@ defmodule DartSass do
end
end

@doc """
Returns the path to the executable.
The executable may not be available if it was not yet installed.
"""
def bin_path do
{path, _snapshot} = bin_paths()
path
end

@doc """
Returns the path to the executable and optional snapshot.
Expand Down Expand Up @@ -130,6 +120,12 @@ defmodule DartSass do
Path.join(Path.dirname(Mix.Project.build_path()), "dart")
end

# TODO: Remove when dart-sass will exit when stdin is closed.
@doc false
def script_path() do
Path.join(:code.priv_dir(:dart_sass), "dart_sass.bash")
end

@doc """
Returns the version of the dart_sass executable.
Expand All @@ -148,9 +144,20 @@ defmodule DartSass do
end

defp sass(args) do
case bin_paths() do
{sass, nil} -> {sass, args}
{vm, snapshot} -> {vm, [snapshot] ++ args}
{path, args} =
case bin_paths() do
{sass, nil} -> {sass, args}
{vm, snapshot} -> {vm, [snapshot] ++ args}
end

# TODO: Remove when dart-sass will exit when stdin is closed.
# Link: https://github.com/sass/dart-sass/pull/1411
cond do
"--watch" in args and not match?({:win32, _}, :os.type()) ->
{script_path(), [path] ++ args}

true ->
{path, args}
end
end

Expand All @@ -172,9 +179,9 @@ defmodule DartSass do
stderr_to_stdout: true
]

{sass_path, args} = sass(args ++ extra_args)
{path, args} = sass(args ++ extra_args)

sass_path
path
|> System.cmd(args, opts)
|> elem(1)
end
Expand Down Expand Up @@ -210,7 +217,7 @@ defmodule DartSass do
other -> raise "couldn't unpack archive: #{inspect(other)}"
end

bin_path = DartSass.bin_path()
sass_path = DartSass.sass_path()
snapshot_path = DartSass.snapshot_path()
vm_path = DartSass.vm_path()

Expand All @@ -224,7 +231,7 @@ defmodule DartSass do
File.cp!(Path.join([tmp_dir, "dart-sass", "src", "sass.snapshot"]), snapshot_path)

_ ->
File.cp!(Path.join([tmp_dir, "dart-sass", "sass"]), bin_path)
File.cp!(Path.join([tmp_dir, "dart-sass", "sass"]), sass_path)
end
end

Expand Down
31 changes: 31 additions & 0 deletions priv/dart_sass.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env bash

# This script was taken from the Elixir Port guide. It is used to ensure
# graceful termination of the `sass` process when it detects that stdin
# has been closed.
# Link: https://hexdocs.pm/elixir/Port.html#module-zombie-operating-system-processes
#
# This script is required until dart-sass supports listening on stdin and
# gracefully terminating when stdin is closed. There is currently a PR for
# this behaviour: https://github.com/sass/dart-sass/pull/1411
#
# Start the program in the background
exec "$@" &
pid1=$!

# Silence warnings from here on
exec >/dev/null 2>&1

# Read from stdin in the background and
# kill running program when stdin closes
exec 0<&0 $(
while read; do :; done
kill -KILL $pid1
) &
pid2=$!

# Clean up
wait $pid1
ret=$?
kill -KILL $pid2
exit $ret

0 comments on commit 2e8eba4

Please sign in to comment.