Skip to content

Commit 0c3628b

Browse files
committed
improvement: don't assume --yes with no tty when in test mode
improvement: clean up and deprecate macros in `Igniter.Mix.Task`
1 parent f4cb490 commit 0c3628b

2 files changed

Lines changed: 126 additions & 118 deletions

File tree

lib/mix/task.ex

Lines changed: 122 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,10 @@ defmodule Igniter.Mix.Task do
129129

130130
@impl Igniter.Mix.Task
131131
def parse_argv(argv) do
132-
{positional, argv_flags} = positional_args!(argv)
133-
options = options!(argv_flags)
132+
{positional, argv_flags} =
133+
Igniter.Mix.Task.__positional_args__!(__MODULE__, argv)
134+
135+
options = Igniter.Mix.Task.__options__!(__MODULE__, argv_flags)
134136
%Args{positional: positional, options: options, argv: argv, argv_flags: argv_flags}
135137
end
136138

@@ -174,6 +176,13 @@ defmodule Igniter.Mix.Task do
174176
def configure_and_run(igniter, task_module, argv) do
175177
case task_module.parse_argv(argv) do
176178
%Args{} = args ->
179+
args =
180+
if !igniter.assigns[:test_mode?] and !Igniter.Mix.Task.tty?() do
181+
%{args | options: Keyword.put(args.options, :yes, true)}
182+
else
183+
args
184+
end
185+
177186
igniter = %{igniter | args: args}
178187

179188
if function_exported?(task_module, :igniter, 1) do
@@ -192,107 +201,101 @@ defmodule Igniter.Mix.Task do
192201

193202
@doc "Parses the options for the task based on its info."
194203
@spec options!(argv :: term()) :: term() | no_return
204+
@deprecated "use `igniter.args.options` instead"
195205
defmacro options!(argv) do
196206
quote generated: true do
197207
argv = unquote(argv)
208+
Igniter.Mix.Task.__options__!(__MODULE__, argv)
209+
end
210+
end
198211

199-
task_name = Mix.Task.task_name(__MODULE__)
212+
def __options__!(mod, argv) do
213+
task_name = Mix.Task.task_name(mod)
200214

201-
info = info(argv, task_name)
215+
info = mod.info(argv, task_name)
202216

203-
argv = Igniter.Util.Info.args_for_group(argv, Igniter.Util.Info.group(info, task_name))
217+
argv = Igniter.Util.Info.args_for_group(argv, Igniter.Util.Info.group(info, task_name))
204218

205-
schema =
206-
Enum.map(info.schema, fn
207-
{k, :csv} ->
208-
{k, :keep}
219+
schema =
220+
Enum.map(info.schema, fn
221+
{k, :csv} ->
222+
{k, :keep}
209223

210-
{k, v} ->
211-
{k, v}
212-
end)
224+
{k, v} ->
225+
{k, v}
226+
end)
213227

214-
{parsed, _} = OptionParser.parse!(argv, switches: schema, aliases: info.aliases)
228+
{parsed, _} = OptionParser.parse!(argv, switches: schema, aliases: info.aliases)
215229

216-
parsed =
217-
schema
218-
|> Enum.filter(fn {_, type} ->
219-
type == :keep
220-
end)
221-
|> Enum.reduce(parsed, fn {k, _}, parsed ->
222-
parsed_without = Keyword.delete(parsed, k)
230+
parsed =
231+
schema
232+
|> Enum.filter(fn {_, type} ->
233+
type == :keep
234+
end)
235+
|> Enum.reduce(parsed, fn {k, _}, parsed ->
236+
parsed_without = Keyword.delete(parsed, k)
223237

224-
values =
225-
parsed
226-
|> Keyword.get_values(k)
227-
|> List.wrap()
238+
values =
239+
parsed
240+
|> Keyword.get_values(k)
241+
|> List.wrap()
228242

229-
Keyword.put(parsed_without, k, values)
230-
end)
243+
Keyword.put(parsed_without, k, values)
244+
end)
231245

232-
parsed =
233-
info.schema
234-
|> Enum.reduce(parsed, fn
235-
{k, :csv}, parsed ->
236-
case Keyword.fetch(parsed, k) do
237-
{:ok, value} ->
238-
value
239-
|> List.wrap()
240-
|> tap(fn list ->
241-
last = List.last(list)
242-
243-
if last && String.ends_with?(last, ",") do
244-
arg_name = String.replace(to_string(k), "_", "-")
245-
246-
Mix.shell().error("""
247-
Found trailing comma in `--#{arg_name}` at `#{last}`
248-
249-
Please remove the trailing comma.
250-
251-
On some platforms, argument parsing requires quotes around argument values containing commas.
252-
So instead of `--#{arg_name} foo,bar`, you may need `--#{arg_name} "foo,bar"`
253-
""")
254-
255-
exit({:shutdown, 1})
256-
end
257-
end)
258-
|> Enum.flat_map(&String.split(&1, ",", trim: true))
259-
|> then(fn v ->
260-
Keyword.put(parsed, k, v)
261-
end)
262-
263-
:error ->
264-
Keyword.put(parsed, k, [])
265-
end
266-
267-
{k, :keep}, parsed ->
268-
Keyword.put_new(parsed, k, [])
269-
270-
_, parsed ->
271-
parsed
272-
end)
246+
parsed =
247+
info.schema
248+
|> Enum.reduce(parsed, fn
249+
{k, :csv}, parsed ->
250+
case Keyword.fetch(parsed, k) do
251+
{:ok, value} ->
252+
value
253+
|> List.wrap()
254+
|> tap(fn list ->
255+
last = List.last(list)
256+
257+
if last && String.ends_with?(last, ",") do
258+
arg_name = String.replace(to_string(k), "_", "-")
259+
260+
Mix.shell().error("""
261+
Found trailing comma in `--#{arg_name}` at `#{last}`
262+
263+
Please remove the trailing comma.
264+
265+
On some platforms, argument parsing requires quotes around argument values containing commas.
266+
So instead of `--#{arg_name} foo,bar`, you may need `--#{arg_name} "foo,bar"`
267+
""")
268+
269+
exit({:shutdown, 1})
270+
end
271+
end)
272+
|> Enum.flat_map(&String.split(&1, ",", trim: true))
273+
|> then(fn v ->
274+
Keyword.put(parsed, k, v)
275+
end)
276+
277+
:error ->
278+
Keyword.put(parsed, k, [])
279+
end
273280

274-
with_yes =
275-
if info.schema[:yes] == :boolean && !Keyword.has_key?(parsed, :yes) &&
276-
not Igniter.Mix.Task.tty?() do
277-
Keyword.put(parsed, :yes, true)
278-
else
281+
{k, :keep}, parsed ->
282+
Keyword.put_new(parsed, k, [])
283+
284+
_, parsed ->
279285
parsed
280-
end
286+
end)
281287

282-
with_defaults = Keyword.merge(info.defaults, with_yes)
288+
with_defaults = Keyword.merge(info.defaults, parsed)
283289

284-
Enum.each(info.required, fn option ->
285-
if !with_defaults[option] do
286-
Mix.shell().error(
287-
"Missing required flag #{String.replace(to_string(option), "_", "-")} "
288-
)
290+
Enum.each(info.required, fn option ->
291+
if !with_defaults[option] do
292+
Mix.shell().error("Missing required flag #{String.replace(to_string(option), "_", "-")} ")
289293

290-
exit({:shutdown, 1})
291-
end
292-
end)
294+
exit({:shutdown, 1})
295+
end
296+
end)
293297

294-
with_defaults
295-
end
298+
with_defaults
296299
end
297300

298301
@doc false
@@ -310,49 +313,54 @@ defmodule Igniter.Mix.Task do
310313
true
311314
end
312315

316+
@deprecated "use `igniter.args.positional` instead"
313317
defmacro positional_args!(argv) do
314318
quote generated: true do
315319
argv = unquote(argv)
316-
task_name = Mix.Task.task_name(__MODULE__)
317-
info = info(argv, task_name)
320+
Igniter.Mix.Task.__positional_args__!(__MODULE__, argv)
321+
end
322+
end
318323

319-
argv = Igniter.Util.Info.args_for_group(argv, Igniter.Util.Info.group(info, task_name))
324+
def __positional_args__!(mod, argv) do
325+
task_name = Mix.Task.task_name(mod)
326+
info = mod.info(argv, task_name)
320327

321-
{argv, positional} = Igniter.Mix.Task.extract_positional_args(argv)
328+
argv = Igniter.Util.Info.args_for_group(argv, Igniter.Util.Info.group(info, task_name))
322329

323-
desired =
324-
Enum.map(info.positional, fn
325-
value when is_atom(value) ->
326-
{value, []}
330+
{argv, positional} = Igniter.Mix.Task.extract_positional_args(argv)
327331

328-
other ->
329-
other
330-
end)
332+
desired =
333+
Enum.map(info.positional, fn
334+
value when is_atom(value) ->
335+
{value, []}
331336

332-
{remaining_desired, got} =
333-
Igniter.Mix.Task.consume_args(positional, desired)
337+
other ->
338+
other
339+
end)
334340

335-
case Enum.find(remaining_desired, fn {_arg, config} -> !config[:optional] end) do
336-
{name, config} ->
337-
line =
338-
if config[:rest] do
339-
"Must provide one or more values for positional argument `#{name}`"
340-
else
341-
"Required positional argument `#{name}` was not supplied."
342-
end
341+
{remaining_desired, got} =
342+
Igniter.Mix.Task.consume_args(positional, desired)
343343

344-
raise ArgumentError, """
345-
#{line}
344+
case Enum.find(remaining_desired, fn {_arg, config} -> !config[:optional] end) do
345+
{name, config} ->
346+
line =
347+
if config[:rest] do
348+
"Must provide one or more values for positional argument `#{name}`"
349+
else
350+
"Required positional argument `#{name}` was not supplied."
351+
end
346352

347-
Command: `#{Igniter.Mix.Task.call_structure(task_name, desired)}`
348-
#{Igniter.Mix.Task.call_example(info)}
353+
raise ArgumentError, """
354+
#{line}
349355
350-
Run `mix help #{task_name}` for more information.
351-
"""
356+
Command: `#{Igniter.Mix.Task.call_structure(task_name, desired)}`
357+
#{Igniter.Mix.Task.call_example(info)}
352358
353-
_ ->
354-
{Igniter.Mix.Task.add_default_values(Map.new(got), desired), argv}
355-
end
359+
Run `mix help #{task_name}` for more information.
360+
"""
361+
362+
_ ->
363+
{Igniter.Mix.Task.add_default_values(Map.new(got), desired), argv}
356364
end
357365
end
358366

test/mix/tasks/igniter.install_test.exs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,18 @@ defmodule Mix.Tasks.Igniter.InstallTest do
2323
describe "installing a new project" do
2424
test "basic installer works" do
2525
cmd!("mix", ["deps.compile"], cd: "test_project")
26-
output = cmd!("mix", ["igniter.install", "jason", "--yes"], cd: "test_project")
26+
output = cmd!("mix", ["igniter.install", "jason"], cd: "test_project")
2727
refute String.contains?(output, "jason\nCompiling")
2828
end
2929

3030
test "displays additional information with `--verbose` option" do
31-
output = cmd!("mix", ["igniter.install", "jason", "--yes", "--verbose"], cd: "test_project")
31+
output = cmd!("mix", ["igniter.install", "jason", "--verbose"], cd: "test_project")
3232
assert String.contains?(output, "jason\nCompiling")
3333
end
3434

3535
test "rerunning the same installer lets you know the dependency was not changed" do
36-
_ = cmd!("mix", ["igniter.install", "jason", "--yes"], cd: "test_project")
37-
output = cmd!("mix", ["igniter.install", "jason", "--yes"], cd: "test_project")
36+
_ = cmd!("mix", ["igniter.install", "jason"], cd: "test_project")
37+
output = cmd!("mix", ["igniter.install", "jason"], cd: "test_project")
3838

3939
assert String.contains?(
4040
output,

0 commit comments

Comments
 (0)