Do not deprecate Mix.shell.cmd/3
Between the two evils of hardcoding a shell name on the Git SCM and deprecating (or enlarging) the shell API, we prefer the former.
This commit is contained in:
@@ -59,10 +59,6 @@
|
||||
|
||||
* [ExUnit.Formatter] `:case_started` and `:case_finished` events are deprecated in favor of `:module_started` and `:module_finished`
|
||||
|
||||
#### Mix
|
||||
|
||||
* [Mix.Shell] The `cmd/2` callback is deprecated in favor of `System.cmd/3` and `Mix.Shell.cmd/3`
|
||||
|
||||
### 4. Deprecations
|
||||
|
||||
#### Elixir
|
||||
|
||||
@@ -107,6 +107,8 @@ defmodule Mix.SCM.Git do
|
||||
end
|
||||
|
||||
defp checkout(_path, opts) do
|
||||
Mix.shell.print_app()
|
||||
|
||||
# Set configuration
|
||||
sparse_toggle(opts)
|
||||
update_origin(opts[:git])
|
||||
@@ -244,13 +246,20 @@ defmodule Mix.SCM.Git do
|
||||
:ok
|
||||
end
|
||||
|
||||
defp git!(args, into \\ %Mix.Shell{}) do
|
||||
defp git!(args, into \\ default_into()) do
|
||||
case System.cmd("git", args, into: into, stderr_to_stdout: true) do
|
||||
{response, 0} -> response
|
||||
{_, _} -> Mix.raise("Command \"git #{Enum.join(args, " ")}\" failed")
|
||||
end
|
||||
end
|
||||
|
||||
defp default_into() do
|
||||
case Mix.shell do
|
||||
Mix.Shell.IO -> IO.stream(:stdio, :line)
|
||||
_ -> ""
|
||||
end
|
||||
end
|
||||
|
||||
defp assert_git! do
|
||||
case Mix.State.fetch(:git_available) do
|
||||
{:ok, true} ->
|
||||
|
||||
+38
-63
@@ -14,9 +14,27 @@ defmodule Mix.Shell do
|
||||
@callback error(message :: IO.ANSI.ansidata()) :: :ok
|
||||
|
||||
@doc """
|
||||
Writes data directly into the shell.
|
||||
Executes the given command and returns its exit status.
|
||||
"""
|
||||
@callback write(message :: binary) :: :ok
|
||||
@callback cmd(command :: String.t) :: integer
|
||||
|
||||
@doc """
|
||||
Executes the given command and returns its exit status.
|
||||
|
||||
## Options
|
||||
|
||||
* `:print_app` - when `false`, does not print the app name
|
||||
when the command outputs something
|
||||
|
||||
* `:stderr_to_stdout` - when `false`, does not redirect
|
||||
stderr to stdout
|
||||
|
||||
* `:quiet` - when `true`, do not print the command output
|
||||
|
||||
* `:env` - environment options to the executed command
|
||||
|
||||
"""
|
||||
@callback cmd(command :: String.t, options :: keyword) :: integer
|
||||
|
||||
@doc """
|
||||
Prompts the user for input.
|
||||
@@ -34,34 +52,6 @@ defmodule Mix.Shell do
|
||||
"""
|
||||
@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.
|
||||
|
||||
@@ -77,8 +67,20 @@ defmodule Mix.Shell do
|
||||
Mix.ProjectStack.printable_app_name()
|
||||
end
|
||||
|
||||
@doc false
|
||||
# TODO: Deprecate on Mix v1.8
|
||||
@doc """
|
||||
Executes the given `command` as a shell command and
|
||||
invokes the `callback` for the streamed response.
|
||||
|
||||
This is most commonly used by shell implementations
|
||||
but can also be invoked directly.
|
||||
|
||||
## Options
|
||||
|
||||
* `:stderr_to_stdout` - redirects stderr to stdout, defaults to true
|
||||
* `:env` - a list of environment variables, defaults to `[]`
|
||||
* `:quiet` - overrides the callback to no-op
|
||||
|
||||
"""
|
||||
def cmd(command, options, callback) when is_function(callback, 1) do
|
||||
callback =
|
||||
if Keyword.get(options, :quiet, false) do
|
||||
@@ -87,33 +89,6 @@ defmodule Mix.Shell do
|
||||
callback
|
||||
end
|
||||
|
||||
fun = fn
|
||||
_, {:cont, data} -> callback.(data)
|
||||
_, _ -> :ok
|
||||
end
|
||||
|
||||
cmd(command, options, :ok, fun)
|
||||
end
|
||||
|
||||
def cmd(command, callback) when is_function(callback, 1) do
|
||||
cmd(command, [], callback)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Executes the given `string` as a shell command.
|
||||
|
||||
* `:into` - a collectable to print the result to, defaults to `""`
|
||||
* `:stderr_to_stdout` - redirects stderr to stdout, defaults to true
|
||||
* `:env` - a list of environment variables, defaults to `[]`
|
||||
|
||||
"""
|
||||
def cmd(command, options) when is_binary(command) and is_list(options) do
|
||||
collectable = Keyword.get(options, :into, "")
|
||||
{acc, callback} = Collectable.into(collectable)
|
||||
cmd(command, options, acc, callback)
|
||||
end
|
||||
|
||||
defp cmd(command, options, acc, callback) do
|
||||
env = validate_env(Keyword.get(options, :env, []))
|
||||
|
||||
args =
|
||||
@@ -125,16 +100,16 @@ defmodule Mix.Shell do
|
||||
|
||||
opts = [:stream, :binary, :exit_status, :hide, :use_stdio, {:env, env} | args]
|
||||
port = Port.open({:spawn, shell_command(command)}, opts)
|
||||
port_read(port, acc, callback)
|
||||
port_read(port, callback)
|
||||
end
|
||||
|
||||
defp port_read(port, acc, callback) do
|
||||
defp port_read(port, callback) do
|
||||
receive do
|
||||
{^port, {:data, data}} ->
|
||||
port_read(port, callback.(acc, {:cont, data}), callback)
|
||||
_ = callback.(data)
|
||||
port_read(port, callback)
|
||||
|
||||
{^port, {:exit_status, status}} ->
|
||||
callback.(acc, :done)
|
||||
status
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,11 +19,6 @@ defmodule Mix.Shell.IO do
|
||||
:ok
|
||||
end
|
||||
|
||||
@doc """
|
||||
Writes data directly into the shell.
|
||||
"""
|
||||
defdelegate write(data), to: IO
|
||||
|
||||
@doc """
|
||||
Prints the given ANSI message to the shell followed by a newline.
|
||||
"""
|
||||
@@ -66,8 +61,10 @@ defmodule Mix.Shell.IO do
|
||||
[:red, :bright, message]
|
||||
end
|
||||
|
||||
@doc false
|
||||
# TODO: Deprecate on Elixir v1.8
|
||||
@doc """
|
||||
Executes the given command and prints its output
|
||||
to stdout as it comes.
|
||||
"""
|
||||
def cmd(command, opts \\ []) do
|
||||
print_app? = Keyword.get(opts, :print_app, true)
|
||||
|
||||
|
||||
@@ -65,14 +65,6 @@ defmodule Mix.Shell.Process do
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Forwards the message to the current process.
|
||||
"""
|
||||
def write(data) do
|
||||
send(self(), {:mix_shell, :write, [data]})
|
||||
:ok
|
||||
end
|
||||
|
||||
@doc """
|
||||
Forwards the message to the current process.
|
||||
"""
|
||||
@@ -154,8 +146,10 @@ defmodule Mix.Shell.Process do
|
||||
end
|
||||
end
|
||||
|
||||
@doc false
|
||||
# TODO: Deprecate on Elixir v1.8
|
||||
@doc """
|
||||
Executes the given command and forwards its messages to
|
||||
the current process.
|
||||
"""
|
||||
def cmd(command, opts \\ []) do
|
||||
print_app? = Keyword.get(opts, :print_app, true)
|
||||
|
||||
|
||||
@@ -14,11 +14,6 @@ defmodule Mix.Shell.Quiet do
|
||||
"""
|
||||
defdelegate print_app, to: Mix.Shell.IO
|
||||
|
||||
@doc """
|
||||
Writes nothing to the shell.
|
||||
"""
|
||||
def write(_data), do: :ok
|
||||
|
||||
@doc """
|
||||
Prints nothing to the shell.
|
||||
"""
|
||||
@@ -44,8 +39,9 @@ defmodule Mix.Shell.Quiet do
|
||||
"""
|
||||
defdelegate yes?(message), to: Mix.Shell.IO
|
||||
|
||||
@doc false
|
||||
# TODO: Deprecate on Elixir v1.8
|
||||
@doc """
|
||||
Executes the given command quietly without outputting anything.
|
||||
"""
|
||||
def cmd(command, opts \\ []) do
|
||||
Mix.Shell.cmd(command, opts, fn data -> data end)
|
||||
end
|
||||
|
||||
@@ -24,7 +24,7 @@ defmodule Mix.Tasks.Cmd 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{}) do
|
||||
case Mix.shell.cmd(Enum.join(args, " ")) do
|
||||
0 -> :ok
|
||||
status -> exit(status)
|
||||
end
|
||||
|
||||
@@ -265,7 +265,7 @@ defmodule Mix.Tasks.Deps.Compile do
|
||||
File.cd!(opts[:dest], fn ->
|
||||
env = [{"ERL_LIBS", Path.join(config[:env_path], "lib")}] ++ env
|
||||
|
||||
if Mix.Shell.cmd(command, env: env, into: %Mix.Shell{print_app?: print_app?}) != 0 do
|
||||
if Mix.shell.cmd(command, env: env, 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 " <>
|
||||
|
||||
@@ -202,8 +202,8 @@ defmodule Mix.RebarTest do
|
||||
assert_received {:mix_shell, :info, ["* Getting git_rebar" <> _]}
|
||||
|
||||
Mix.Tasks.Deps.Compile.run([])
|
||||
assert_received {:mix_shell, :write, ["===> Compiling git_rebar\n"]}
|
||||
assert_received {:mix_shell, :write, ["===> Compiling rebar_dep\n"]}
|
||||
assert_received {:mix_shell, :run, ["===> Compiling git_rebar\n"]}
|
||||
assert_received {:mix_shell, :run, ["===> Compiling rebar_dep\n"]}
|
||||
assert :git_rebar.any_function() == :ok
|
||||
assert :rebar_dep.any_function() == :ok
|
||||
|
||||
@@ -233,8 +233,8 @@ defmodule Mix.RebarTest do
|
||||
assert_received {:mix_shell, :info, ["* Getting git_rebar " <> _]}
|
||||
|
||||
Mix.Tasks.Deps.Compile.run([])
|
||||
assert_received {:mix_shell, :write, ["===> Compiling git_rebar\n"]}
|
||||
assert_received {:mix_shell, :write, ["===> Compiling rebar_dep\n"]}
|
||||
assert_received {:mix_shell, :run, ["===> Compiling git_rebar\n"]}
|
||||
assert_received {:mix_shell, :run, ["===> Compiling rebar_dep\n"]}
|
||||
assert :git_rebar.any_function() == :ok
|
||||
assert :rebar_dep.any_function() == :ok
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ defmodule Mix.ShellTest do
|
||||
Mix.shell(Mix.Shell.IO)
|
||||
|
||||
assert capture_io(fn ->
|
||||
assert Mix.Shell.cmd("echo first && echo second", into: %Mix.Shell{}) == 0
|
||||
assert Mix.shell.cmd("echo first && echo second") == 0
|
||||
end)
|
||||
|> String.replace(" \n", "\n") == "first\nsecond\n"
|
||||
after
|
||||
|
||||
@@ -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, :write, ["hello" <> ^nl]}
|
||||
assert_received {:mix_shell, :run, ["hello" <> ^nl]}
|
||||
assert_received {:mix_shell, :info, ["==> foo"]}
|
||||
assert_received {:mix_shell, :write, ["hello" <> ^nl]}
|
||||
assert_received {:mix_shell, :run, ["hello" <> ^nl]}
|
||||
end)
|
||||
end
|
||||
end
|
||||
@@ -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, :write, ["hello" <> ^nl]}
|
||||
assert_received {:mix_shell, :run, ["hello" <> ^nl]}
|
||||
refute_received {:mix_shell, :info, ["==> foo"]}
|
||||
refute_received {:mix_shell, :write, ["hello" <> ^nl]}
|
||||
refute_received {:mix_shell, :run, ["hello" <> ^nl]}
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user