Skip to content

Commit e7ef3fc

Browse files
josevalimJosé Valim
authored andcommitted
Merge pull request #2787 from elixir-lang/emj-hex-file-error
Report correct location if local.hex failed Signed-off-by: José Valim <[email protected]>
1 parent 2d01aa1 commit e7ef3fc

File tree

4 files changed

+91
-32
lines changed

4 files changed

+91
-32
lines changed

lib/mix/lib/mix/generator.ex

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ defmodule Mix.Generator do
1717
def create_file(path, contents, opts \\ []) when is_binary(path) do
1818
Mix.shell.info [:green, "* creating ", :reset, Path.relative_to_cwd(path)]
1919

20-
if opts[:force] || overwriting?(path) do
20+
if opts[:force] || Mix.Utils.overwriting?(path) do
2121
File.mkdir_p!(Path.dirname(path))
2222
File.write!(path, contents)
2323
end
@@ -31,15 +31,6 @@ defmodule Mix.Generator do
3131
File.mkdir_p! path
3232
end
3333

34-
defp overwriting?(path) do
35-
if File.exists?(path) do
36-
full = Path.expand(path)
37-
Mix.shell.yes?(Path.relative_to_cwd(full) <> " already exists, overwrite?")
38-
else
39-
true
40-
end
41-
end
42-
4334
@doc false
4435
defmacro from_file(path) do
4536
quote do

lib/mix/lib/mix/tasks/archive.install.ex

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@ defmodule Mix.Tasks.Archive.Install do
5959
check_file_exists(archive)
6060

6161
File.mkdir_p!(dest)
62-
File.write!(archive, Mix.Utils.read_path!(src, opts))
63-
Mix.shell.info [:green, "* creating ", :reset, Path.relative_to_cwd(archive)]
62+
Mix.Utils.copy_path!(src, archive, opts)
6463

6564
true = Code.append_path(Mix.Archive.ebin(archive))
6665
else
@@ -80,7 +79,7 @@ defmodule Mix.Tasks.Archive.Install do
8079
defp should_install?(_src, previous_files) do
8180
files = Enum.map_join(previous_files, ", ", &Path.basename/1)
8281

83-
Mix.shell.yes?("Found existing archives: #{files}.\n" <>
82+
Mix.shell.yes?("Found existing archive(s): #{files}.\n" <>
8483
"Are you sure you want to replace them?")
8584
end
8685

lib/mix/lib/mix/tasks/local.rebar.ex

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
defmodule Mix.Tasks.Local.Rebar do
22
use Mix.Task
33

4-
import Mix.Generator, only: [create_file: 3]
5-
64
@rebar_url "http://s3.hex.pm/rebar"
75
@shortdoc "Install rebar locally"
86

@@ -31,10 +29,10 @@ defmodule Mix.Tasks.Local.Rebar do
3129
end
3230

3331
defp do_install(path, opts) do
34-
rebar = Mix.Utils.read_path!(path)
3532
local_rebar_path = Mix.Rebar.local_rebar_path
3633
File.mkdir_p! Path.dirname(local_rebar_path)
37-
create_file local_rebar_path, rebar, opts
34+
35+
Mix.Utils.copy_path!(path, local_rebar_path, opts)
3836
:ok = :file.change_mode local_rebar_path, 0o755
3937
true
4038
end

lib/mix/lib/mix/utils.ex

Lines changed: 86 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -354,10 +354,8 @@ defmodule Mix.Utils do
354354
end
355355

356356
@doc """
357-
Opens and reads content from either a URL or a local filesystem path.
358-
359-
Used by tasks like `archive.install` and `local.rebar` that support
360-
installation either from a URL or a local file.
357+
Opens and reads content from either a URL or a local filesystem path
358+
and returns the contents as a binary.
361359
362360
Raises if the given path is not a URL, nor a file or if the
363361
file or URL are invalid.
@@ -370,21 +368,74 @@ defmodule Mix.Utils do
370368
def read_path!(path, opts \\ []) do
371369
cond do
372370
url?(path) && opts[:shell] ->
373-
read_shell(path)
371+
read_shell(path, [])
374372
url?(path) ->
375-
read_httpc(path)
373+
read_httpc(path, [])
376374
file?(path) ->
377375
read_file(path)
378376
true ->
379377
Mix.raise "Expected #{path} to be a url or a local file path"
380378
end
381379
end
382380

381+
@doc """
382+
Copies content from either a URL or a local filesystem path to
383+
target path.
384+
385+
Used by tasks like `archive.install` and `local.rebar` that support
386+
installation either from a URL or a local file.
387+
388+
Raises if the given path is not a URL, nor a file or if the
389+
file or URL are invalid.
390+
391+
## Options
392+
393+
* `:shell` - Forces the use of `wget` or `curl` to fetch the file if the
394+
given path is a URL.
395+
396+
* `:force` - Forces overwriting target file without a shell prompt.
397+
"""
398+
def copy_path!(source, target, opts \\ []) do
399+
if opts[:force] || overwriting?(target) do
400+
cond do
401+
url?(source) && opts[:shell] ->
402+
read_shell(source, file: target)
403+
url?(source) ->
404+
read_httpc(source, file: target)
405+
file?(source) ->
406+
copy_file(source, target)
407+
true ->
408+
Mix.raise "Expected #{source} to be a url or a local file path"
409+
end
410+
411+
put_creating_file(target)
412+
end
413+
414+
:ok
415+
end
416+
417+
@doc """
418+
Prompts the user to overwrite the file if it exists. Returns
419+
the user input.
420+
"""
421+
def overwriting?(path) do
422+
if File.exists?(path) do
423+
full = Path.expand(path)
424+
Mix.shell.yes?(Path.relative_to_cwd(full) <> " already exists, overwrite?")
425+
else
426+
true
427+
end
428+
end
429+
383430
defp read_file(path) do
384431
File.read!(path)
385432
end
386433

387-
defp read_httpc(path) do
434+
defp copy_file(source, target) do
435+
File.cp!(source, target)
436+
end
437+
438+
defp read_httpc(path, opts) do
388439
{:ok, _} = Application.ensure_all_started(:ssl)
389440
{:ok, _} = Application.ensure_all_started(:inets)
390441

@@ -401,11 +452,20 @@ defmodule Mix.Utils do
401452
if http_proxy, do: proxy(http_proxy)
402453
if https_proxy, do: proxy(https_proxy)
403454

404-
# We are using relaxed: true because some clients is returning a Location
455+
if out_path = opts[:file] do
456+
File.rm(out_path)
457+
req_opts = [stream: String.to_char_list(out_path)]
458+
else
459+
req_opts = [body_format: :binary]
460+
end
461+
462+
# We are using relaxed: true because some servers is returning a Location
405463
# header with relative paths, which does not follow the spec. This would
406464
# cause the request to fail with {:error, :no_scheme} unless :relaxed
407465
# is given.
408-
case :httpc.request(:get, request, [relaxed: true], [body_format: :binary], :mix) do
466+
case :httpc.request(:get, request, [relaxed: true], req_opts, :mix) do
467+
{:ok, :saved_to_file} ->
468+
:ok
409469
{:ok, {{_, status, _}, _, body}} when status in 200..299 ->
410470
body
411471
{:ok, {{_, status, _}, _, _}} ->
@@ -430,9 +490,10 @@ defmodule Mix.Utils do
430490
end
431491
end
432492

433-
defp read_shell(path) do
493+
defp read_shell(path, opts) do
434494
filename = URI.parse(path).path |> Path.basename
435-
out_path = Path.join(System.tmp_dir!, filename)
495+
out_path = opts[:file] || Path.join(System.tmp_dir!, filename)
496+
436497
File.rm(out_path)
437498

438499
status = cond do
@@ -450,14 +511,20 @@ defmodule Mix.Utils do
450511
1
451512
end
452513

453-
check_command!(status, path, out_path)
514+
check_command!(status, path, opts[:file])
454515

455-
data = File.read!(out_path)
456-
File.rm!(out_path)
457-
data
516+
unless opts[:file] do
517+
data = File.read!(out_path)
518+
File.rm!(out_path)
519+
data
520+
end
458521
end
459522

460523
defp check_command!(0, _path, _out_path), do: :ok
524+
defp check_command!(_status, path, nil) do
525+
Mix.raise "Could not fetch data, please download manually from " <>
526+
"#{inspect path}"
527+
end
461528
defp check_command!(_status, path, out_path) do
462529
Mix.raise "Could not fetch data, please download manually from " <>
463530
"#{inspect path} and copy it to #{inspect out_path}"
@@ -467,6 +534,10 @@ defmodule Mix.Utils do
467534
match?({:win32, _}, :os.type)
468535
end
469536

537+
defp put_creating_file(path) do
538+
Mix.shell.info [:green, "* creating ", :reset, Path.relative_to_cwd(path)]
539+
end
540+
470541
defp file?(path) do
471542
File.regular?(path)
472543
end

0 commit comments

Comments
 (0)