Skip to content

Commit

Permalink
Do not define a generic collectable implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
José Valim committed Sep 28, 2017
1 parent 66c3750 commit e804815
Show file tree
Hide file tree
Showing 12 changed files with 94 additions and 94 deletions.
6 changes: 0 additions & 6 deletions lib/elixir/lib/collectable.ex
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,3 @@ defimpl Collectable, for: Map do
end}
end
end

defimpl Collectable, for: Tuple do
def into({_, fun} = tuple) when is_function(fun, 2) do
tuple
end
end
9 changes: 0 additions & 9 deletions lib/elixir/test/elixir/collectable_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,4 @@ defmodule CollectableTest do
use ExUnit.Case, async: true

doctest Collectable

test "is implemented for tuples" do
fun = fn
list, {:cont, x} -> [x | list]
list, :done -> :lists.reverse(list)
_, :halt -> :ok
end
assert Enum.into(1..3, {[], fun}) == [1, 2, 3]
end
end
2 changes: 1 addition & 1 deletion lib/mix/lib/mix/scm/git.ex
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ defmodule Mix.SCM.Git do
:ok
end

defp git!(args, into \\ Mix.shell.into) do
defp git!(args, into \\ %Mix.Shell{}) do
case System.cmd("git", args, into: into, stderr_to_stdout: true) do
{response, 0} -> response
{_, _} -> Mix.raise "Command \"git #{Enum.join(args, " ")}\" failed"
Expand Down
48 changes: 37 additions & 11 deletions lib/mix/lib/mix/shell.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,61 @@ defmodule Mix.Shell do
"""

@doc """
Prints the given message to the shell.
Prints the given ANSI message to the shell.
"""
@callback info(message :: IO.ANSI.ansidata) :: any
@callback info(message :: IO.ANSI.ansidata) :: :ok

@doc """
Prints the given error to the shell.
Prints the given ANSI error to the shell.
"""
@callback error(message :: IO.ANSI.ansidata) :: any
@callback error(message :: IO.ANSI.ansidata) :: :ok

@doc """
Prompts the user for input.
Writes data directly into the shell.
"""
@callback prompt(message :: String.t) :: String.t
@callback write(message :: binary) :: :ok

@doc """
Prompts the user for confirmation.
Prompts the user for input.
"""
@callback yes?(message :: String.t) :: boolean
@callback prompt(message :: binary) :: binary

@doc """
Returns a collectable to be used when executing commands.
Prompts the user for confirmation.
"""
@callback into :: Collectable.t
@callback yes?(message :: binary) :: boolean

@doc """
Prints the current application to the shell if
it was not printed yet.
"""
@callback print_app() :: any
@callback print_app() :: :ok

@doc """
A collectable shell struct.
"""
defstruct [print_app?: true]

defimpl Collectable do
def into(%Mix.Shell{print_app?: print_app?} = original) do
fun = fn
{:cont, shell}, {:cont, data} ->
shell.write(data)
{:cont, shell}
{:print, shell}, {:cont, data} ->
shell.print_app()
shell.write(data)
{:cont, shell}
_, _ ->
original
end

case print_app? do
true -> {{:print, Mix.shell}, fun}
false -> {{:cont, Mix.shell}, fun}
end
end
end

@doc """
Returns the printable app name.
Expand Down
38 changes: 15 additions & 23 deletions lib/mix/lib/mix/shell/io.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,42 +15,24 @@ defmodule Mix.Shell.IO do
if name = Mix.Shell.printable_app_name do
IO.puts "==> #{name}"
end
:ok
end

@doc """
Returns a collectable to be used along side System.cmd.
Writes data directly into the shell.
"""
def into do
fun = fn
:ok, {:cont, data} ->
print_app()
IO.write(data)
:ok, _ ->
:ok
end
{:ok, fun}
end

@doc false
# TODO: Deprecate on Elixir v1.8
def cmd(command, opts \\ []) do
print_app? = Keyword.get(opts, :print_app, true)
Mix.Shell.cmd(command, opts, fn data ->
if print_app?, do: print_app()
IO.write(data)
end)
end
defdelegate write(data), to: IO

@doc """
Prints the given message to the shell followed by a newline.
Prints the given ANSI message to the shell followed by a newline.
"""
def info(message) do
print_app()
IO.puts IO.ANSI.format message
end

@doc """
Prints the given error to the shell followed by a newline.
Prints the given ANSI error to the shell followed by a newline.
"""
def error(message) do
print_app()
Expand Down Expand Up @@ -82,4 +64,14 @@ defmodule Mix.Shell.IO do
defp red(message) do
[:red, :bright, message]
end

@doc false
# TODO: Deprecate on Elixir v1.8
def cmd(command, opts \\ []) do
print_app? = Keyword.get(opts, :print_app, true)
Mix.Shell.cmd(command, opts, fn data ->
if print_app?, do: print_app()
IO.write(data)
end)
end
end
37 changes: 16 additions & 21 deletions lib/mix/lib/mix/shell/process.ex
Original file line number Diff line number Diff line change
Expand Up @@ -66,28 +66,11 @@ defmodule Mix.Shell.Process do
end

@doc """
Returns a collectable to be used along side System.cmd.
Forwards the message to the current process.
"""
def into do
fun = fn
:ok, {:cont, data} ->
print_app()
send self(), {:mix_shell, :run, [data]}
:ok
:ok, _ ->
:ok
end
{:ok, fun}
end

@doc false
# TODO: Deprecate on Elixir v1.8
def cmd(command, opts \\ []) do
print_app? = Keyword.get(opts, :print_app, true)
Mix.Shell.cmd(command, opts, fn(data) ->
if print_app?, do: print_app()
send self(), {:mix_shell, :run, [data]}
end)
def write(data) do
send self(), {:mix_shell, :write, [data]}
:ok
end

@doc """
Expand All @@ -96,6 +79,7 @@ defmodule Mix.Shell.Process do
def info(message) do
print_app()
send self(), {:mix_shell, :info, [format(message)]}
:ok
end

@doc """
Expand All @@ -104,6 +88,7 @@ defmodule Mix.Shell.Process do
def error(message) do
print_app()
send self(), {:mix_shell, :error, [format(message)]}
:ok
end

defp format(message) do
Expand Down Expand Up @@ -168,4 +153,14 @@ defmodule Mix.Shell.Process do
0 -> raise "no shell process input given for yes?/1"
end
end

@doc false
# TODO: Deprecate on Elixir v1.8
def cmd(command, opts \\ []) do
print_app? = Keyword.get(opts, :print_app, true)
Mix.Shell.cmd(command, opts, fn(data) ->
if print_app?, do: print_app()
send self(), {:mix_shell, :run, [data]}
end)
end
end
22 changes: 10 additions & 12 deletions lib/mix/lib/mix/shell/quiet.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,14 @@ defmodule Mix.Shell.Quiet do
defdelegate print_app, to: Mix.Shell.IO

@doc """
Returns a collectable to be used along side System.cmd.
Writes nothing to the shell.
"""
def into do
{:ok, fn :ok, _ -> :ok end}
end

@doc false
# TODO: Deprecate on Elixir v1.8
def cmd(command, opts \\ []) do
Mix.Shell.cmd(command, opts, fn data -> data end)
end
def write(_data), do: :ok

@doc """
Writes nothing to the shell.
Prints nothing to the shell.
"""
def info(_message), do: nil
def info(_message), do: :ok

@doc """
Prints the error to the shell followed by a newline.
Expand All @@ -51,4 +43,10 @@ defmodule Mix.Shell.Quiet do
"Yes".
"""
defdelegate yes?(message), to: Mix.Shell.IO

@doc false
# TODO: Deprecate on Elixir v1.8
def cmd(command, opts \\ []) do
Mix.Shell.cmd(command, opts, fn data -> data end)
end
end
2 changes: 1 addition & 1 deletion lib/mix/lib/mix/tasks/cmd.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ defmodule Mix.Tasks.Cmd do
def run(args) do
{args, apps} = parse_apps(args, [])
if apps == [] or Mix.Project.config[:app] in apps do
case Mix.Shell.cmd(Enum.join(args, " "), into: Mix.shell.into) do
case Mix.Shell.cmd(Enum.join(args, " "), into: %Mix.Shell{}) do
0 -> :ok
status -> exit(status)
end
Expand Down
2 changes: 1 addition & 1 deletion lib/mix/lib/mix/tasks/deps.compile.ex
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ defmodule Mix.Tasks.Deps.Compile do
defp do_command(%Mix.Dep{app: app, opts: opts}, config, command, print_app?, env \\ []) do
File.cd!(opts[:dest], fn ->
env = [{"ERL_LIBS", Path.join(config[:env_path], "lib")}] ++ env
if Mix.shell.cmd(command, print_app: print_app?, env: env) != 0 do
if Mix.Shell.cmd(command, env: env, into: %Mix.Shell{print_app?: print_app?}) != 0 do
Mix.raise "Could not compile dependency #{inspect app}, \"#{command}\" command failed. " <>
"You can recompile this dependency with \"mix deps.compile #{app}\", update it " <>
"with \"mix deps.update #{app}\" or clean it with \"mix deps.clean #{app}\""
Expand Down
8 changes: 4 additions & 4 deletions lib/mix/test/mix/rebar_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ defmodule Mix.RebarTest do
assert_received {:mix_shell, :info, ["* Getting git_rebar" <> _]}

Mix.Tasks.Deps.Compile.run []
assert_received {:mix_shell, :run, ["===> Compiling git_rebar\n"]}
assert_received {:mix_shell, :run, ["===> Compiling rebar_dep\n"]}
assert_received {:mix_shell, :write, ["===> Compiling git_rebar\n"]}
assert_received {:mix_shell, :write, ["===> Compiling rebar_dep\n"]}
assert :git_rebar.any_function == :ok
assert :rebar_dep.any_function == :ok

Expand Down Expand Up @@ -214,8 +214,8 @@ defmodule Mix.RebarTest do
assert_received {:mix_shell, :info, ["* Getting git_rebar " <> _]}

Mix.Tasks.Deps.Compile.run []
assert_received {:mix_shell, :run, ["===> Compiling git_rebar\n"]}
assert_received {:mix_shell, :run, ["===> Compiling rebar_dep\n"]}
assert_received {:mix_shell, :write, ["===> Compiling git_rebar\n"]}
assert_received {:mix_shell, :write, ["===> Compiling rebar_dep\n"]}
assert :git_rebar.any_function == :ok
assert :rebar_dep.any_function == :ok

Expand Down
6 changes: 5 additions & 1 deletion lib/mix/test/mix/shell_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ defmodule Mix.ShellTest do
end

test "executes cmd with expressions" do
Mix.shell Mix.Shell.IO

assert capture_io(fn ->
assert Mix.Shell.cmd("echo first && echo second", into: Mix.Shell.IO.into) == 0
assert Mix.Shell.cmd("echo first && echo second", into: %Mix.Shell{}) == 0
end) |> String.replace(" \n", "\n") == "first\nsecond\n"
after
Mix.shell Mix.Shell.Process
end
end
8 changes: 4 additions & 4 deletions lib/mix/test/mix/tasks/cmd_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ defmodule Mix.Tasks.CmdTest do
Mix.Task.run "cmd", ["echo", "hello"]
nl = os_newline()
assert_received {:mix_shell, :info, ["==> bar"]}
assert_received {:mix_shell, :run, ["hello" <> ^nl]}
assert_received {:mix_shell, :write, ["hello" <> ^nl]}
assert_received {:mix_shell, :info, ["==> foo"]}
assert_received {:mix_shell, :run, ["hello" <> ^nl]}
assert_received {:mix_shell, :write, ["hello" <> ^nl]}
end)
end
end
Expand All @@ -22,9 +22,9 @@ defmodule Mix.Tasks.CmdTest do
Mix.Task.run "cmd", ["--app", "bar", "echo", "hello"]
nl = os_newline()
assert_received {:mix_shell, :info, ["==> bar"]}
assert_received {:mix_shell, :run, ["hello" <> ^nl]}
assert_received {:mix_shell, :write, ["hello" <> ^nl]}
refute_received {:mix_shell, :info, ["==> foo"]}
refute_received {:mix_shell, :run, ["hello" <> ^nl]}
refute_received {:mix_shell, :write, ["hello" <> ^nl]}
end)
end
end
Expand Down

0 comments on commit e804815

Please sign in to comment.