@@ -354,10 +354,8 @@ defmodule Mix.Utils do
354
354
end
355
355
356
356
@ 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.
361
359
362
360
Raises if the given path is not a URL, nor a file or if the
363
361
file or URL are invalid.
@@ -370,21 +368,74 @@ defmodule Mix.Utils do
370
368
def read_path! ( path , opts \\ [ ] ) do
371
369
cond do
372
370
url? ( path ) && opts [ :shell ] ->
373
- read_shell ( path )
371
+ read_shell ( path , [ ] )
374
372
url? ( path ) ->
375
- read_httpc ( path )
373
+ read_httpc ( path , [ ] )
376
374
file? ( path ) ->
377
375
read_file ( path )
378
376
true ->
379
377
Mix . raise "Expected #{ path } to be a url or a local file path"
380
378
end
381
379
end
382
380
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
+
383
430
defp read_file ( path ) do
384
431
File . read! ( path )
385
432
end
386
433
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
388
439
{ :ok , _ } = Application . ensure_all_started ( :ssl )
389
440
{ :ok , _ } = Application . ensure_all_started ( :inets )
390
441
@@ -401,11 +452,20 @@ defmodule Mix.Utils do
401
452
if http_proxy , do: proxy ( http_proxy )
402
453
if https_proxy , do: proxy ( https_proxy )
403
454
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
405
463
# header with relative paths, which does not follow the spec. This would
406
464
# cause the request to fail with {:error, :no_scheme} unless :relaxed
407
465
# 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
409
469
{ :ok , { { _ , status , _ } , _ , body } } when status in 200 .. 299 ->
410
470
body
411
471
{ :ok , { { _ , status , _ } , _ , _ } } ->
@@ -430,9 +490,10 @@ defmodule Mix.Utils do
430
490
end
431
491
end
432
492
433
- defp read_shell ( path ) do
493
+ defp read_shell ( path , opts ) do
434
494
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
+
436
497
File . rm ( out_path )
437
498
438
499
status = cond do
@@ -450,14 +511,20 @@ defmodule Mix.Utils do
450
511
1
451
512
end
452
513
453
- check_command! ( status , path , out_path )
514
+ check_command! ( status , path , opts [ :file ] )
454
515
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
458
521
end
459
522
460
523
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
461
528
defp check_command! ( _status , path , out_path ) do
462
529
Mix . raise "Could not fetch data, please download manually from " <>
463
530
"#{ inspect path } and copy it to #{ inspect out_path } "
@@ -467,6 +534,10 @@ defmodule Mix.Utils do
467
534
match? ( { :win32 , _ } , :os . type )
468
535
end
469
536
537
+ defp put_creating_file ( path ) do
538
+ Mix . shell . info [ :green , "* creating " , :reset , Path . relative_to_cwd ( path ) ]
539
+ end
540
+
470
541
defp file? ( path ) do
471
542
File . regular? ( path )
472
543
end
0 commit comments