Skip to content

Commit a39c252

Browse files
add Downloads stdlib; replace Base.download
- Base.download is deprecated in favor of Downloads.download - the former is now implemented by calling the latter
1 parent b5a53c2 commit a39c252

File tree

11 files changed

+36
-103
lines changed

11 files changed

+36
-103
lines changed

NEWS.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,9 @@ Build system changes
5858

5959
Library functions
6060
-----------------
61-
* The `Base.Grisu` code has been officially removed (float printing was switched to the ryu algorithm code in 1.4)
6261

62+
* The `Base.download` function has been deprecated (silently, by default) in favor of the new `Downloads.download` standard library function ([#37340]).
63+
* The `Base.Grisu` code has been officially removed (float printing was switched to the ryu algorithm code in 1.4)
6364

6465
New library functions
6566
---------------------
@@ -81,6 +82,7 @@ New library features
8182

8283
Standard library changes
8384
------------------------
85+
8486
* The `nextprod` function now accepts tuples and other array types for its first argument ([#35791]).
8587
* The `reverse(A; dims)` function for multidimensional `A` can now reverse multiple dimensions at once
8688
by passing a tuple for `dims`, and defaults to reversing all dimensions; there is also a multidimensional
@@ -99,6 +101,7 @@ Standard library changes
99101
* `RegexMatch` objects can now be probed for whether a named capture group exists within it through `haskey()` ([#36717]).
100102
* For consistency `haskey(r::RegexMatch, i::Integer)` has also been added and returns if the capture group for `i` exists ([#37300]).
101103
* A new standard library `TOML` has been added for parsing and printing [TOML files](https://toml.io) ([#37034]).
104+
* A new standard library `Downloads` has been added, which replaces the old `Base.download` function with `Downloads.download`, providing cross-platform, multi-protocol, in-process download functionality implemented with [libcurl](https://curl.haxx.se/libcurl/) ([#37340]).
102105
* The `Pkg.BinaryPlatforms` module has been moved into `Base` as `Base.BinaryPlatforms` and heavily reworked.
103106
Applications that want to be compatible with the old API should continue to import `Pkg.BinaryPlatforms`,
104107
however new users should use `Base.BinaryPlatforms` directly. ([#37320])
@@ -107,6 +110,7 @@ Standard library changes
107110
all of `Pkg` alongside. ([#37320])
108111

109112
#### LinearAlgebra
113+
110114
* New method `LinearAlgebra.issuccess(::CholeskyPivoted)` for checking whether pivoted Cholesky factorization was successful ([#36002]).
111115
* `UniformScaling` can now be indexed into using ranges to return dense matrices and vectors ([#24359]).
112116
* New function `LinearAlgebra.BLAS.get_num_threads()` for getting the number of BLAS threads. ([#36360])

base/download.jl

Lines changed: 17 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,5 @@
11
# This file is a part of Julia. License is MIT: https://julialang.org/license
22

3-
# file downloading
4-
5-
if Sys.iswindows()
6-
function download_powershell(url::AbstractString, filename::AbstractString)
7-
ps = joinpath(get(ENV, "SYSTEMROOT", "C:\\Windows"), "System32\\WindowsPowerShell\\v1.0\\powershell.exe")
8-
tls12 = "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12"
9-
client = "New-Object System.Net.Webclient"
10-
# in the following we escape ' with '' (see https://ss64.com/ps/syntax-esc.html)
11-
downloadfile = "($client).DownloadFile('$(replace(url, "'" => "''"))', '$(replace(filename, "'" => "''"))')"
12-
# PowerShell v3 or later is required for Tls12
13-
proc = run(pipeline(`$ps -Version 3 -NoProfile -Command "$tls12; $downloadfile"`; stderr=stderr); wait=false)
14-
if !success(proc)
15-
if proc.exitcode % Int32 == -393216
16-
# appears to be "wrong version" exit code, based on
17-
# https://docs.microsoft.com/en-us/azure/cloud-services/cloud-services-startup-tasks-common
18-
@error "Downloading files requires Windows Management Framework 3.0 or later."
19-
end
20-
pipeline_error(proc)
21-
end
22-
return filename
23-
end
24-
end
25-
26-
function find_curl()
27-
if Sys.isapple() && Sys.isexecutable("/usr/bin/curl")
28-
"/usr/bin/curl"
29-
elseif Sys.iswindows() && Sys.isexecutable(joinpath(get(ENV, "SYSTEMROOT", "C:\\Windows"), "System32\\curl.exe"))
30-
joinpath(get(ENV, "SYSTEMROOT", "C:\\Windows"), "System32\\curl.exe")
31-
elseif !Sys.iswindows() && Sys.which("curl") !== nothing
32-
"curl"
33-
else
34-
nothing
35-
end
36-
end
37-
38-
function download_curl(curl_exe::AbstractString, url::AbstractString, filename::AbstractString)
39-
err = PipeBuffer()
40-
process = run(pipeline(`$curl_exe -s -S -g -L -f -o $filename $url`, stderr=err), wait=false)
41-
if !success(process)
42-
error_msg = readline(err)
43-
@error "Download failed: $error_msg"
44-
pipeline_error(process)
45-
end
46-
return filename
47-
end
48-
493
const DOWNLOAD_HOOKS = Callable[]
504

515
function download_url(url::AbstractString)
@@ -55,50 +9,25 @@ function download_url(url::AbstractString)
559
return url
5610
end
5711

58-
function download(url::AbstractString, filename::AbstractString)
59-
url = download_url(url)
60-
curl_exe = find_curl()
61-
if curl_exe !== nothing
62-
return download_curl(curl_exe, url, filename)
63-
elseif Sys.iswindows()
64-
return download_powershell(url, filename)
65-
elseif Sys.which("wget") !== nothing
66-
try
67-
run(`wget -O $filename $url`)
68-
catch
69-
rm(filename, force=true) # wget always creates a file
70-
rethrow()
71-
end
72-
elseif Sys.which("busybox") !== nothing
73-
try
74-
run(`busybox wget -O $filename $url`)
75-
catch
76-
rm(filename, force=true) # wget always creates a file
77-
rethrow()
78-
end
79-
elseif Sys.which("fetch") !== nothing
80-
run(`fetch -f $filename $url`)
81-
else
82-
error("No download agent available; install curl, wget, busybox or fetch.")
83-
end
84-
return filename
85-
end
86-
87-
function download(url::AbstractString)
88-
filename = tempname()
89-
download(url, filename)
90-
end
12+
Downloads() = require(PkgId(
13+
UUID((0xf43a241f_c20a_4ad4, 0x852c_f6b1247861c6)),
14+
"Downloads",
15+
))
9116

9217
"""
93-
download(url::AbstractString, [localfile::AbstractString])
18+
download(url::AbstractString, [path::AbstractString = tempname()]) -> path
9419
95-
Download a file from the given url, optionally renaming it to the given local file name. If
96-
no filename is given this will download into a randomly-named file in your temp directory.
97-
Note that this function relies on the availability of external tools such as `curl`, `wget`
98-
or `fetch` to download the file and is provided for convenience. For production use or
99-
situations in which more options are needed, please use a package that provides the desired
100-
functionality instead.
20+
Download a file from the given url, saving it to the location `path`, or if not
21+
specified, a temporary path. Returns the path of the downloaded file.
10122
102-
Returns the filename of the downloaded file.
23+
!!! note
24+
Since Julia 1.6, this function is deprecated and is just a thin wrapper
25+
around `Downloads.download`. In new code, you should use that function
26+
directly instead of calling this.
10327
"""
104-
download(url, filename)
28+
function download(url::AbstractString, path::AbstractString)
29+
invokelatest(Downloads().download, download_url(url), path)
30+
end
31+
function download(url::AbstractString)
32+
invokelatest(Downloads().download, download_url(url))
33+
end

base/sysimg.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ let
5555
:MozillaCACerts_jll,
5656
:LibCURL_jll,
5757
:LibCURL,
58+
:Downloads,
5859
]
5960

6061
maxlen = reduce(max, textwidth.(string.(stdlibs)); init=0)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
24a8b8fc2398d20c24a13ce73482a3d7
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
4b652be535dce6a5cf36e546a31d3221f4c2534d1a3ac710f31f9ed2dfbeabd21b36c0186e4abe12cfee992ff557317aefe2bdeb9cb8b1c44da085b030719329

stdlib/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@
55
/Statistics
66
/LibCURL-*
77
/LibCURL
8+
/Downloads-*
9+
/Downloads

stdlib/Downloads.version

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
DOWNLOADS_BRANCH = master
2+
DOWNLOADS_SHA1 = 1a1d2e0a10209512f5b29e585bfd78e7a47f8f61

stdlib/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ STDLIBS = Artifacts Base64 CRC32c Dates DelimitedFiles Distributed FileWatching
2020
SharedArrays Sockets SparseArrays SuiteSparse Test TOML Unicode UUIDs \
2121
MozillaCACerts_jll LibCURL_jll
2222

23-
STDLIBS_EXT = Pkg Statistics LibCURL
23+
STDLIBS_EXT = Pkg Statistics LibCURL Downloads
2424
PKG_GIT_URL := git://github.com/JuliaLang/Pkg.jl.git
2525
PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1
2626
STATISTICS_GIT_URL := git://github.com/JuliaLang/Statistics.jl.git
2727
STATISTICS_TAR_URL = https://api.github.com/repos/JuliaLang/Statistics.jl/tarball/$1
2828
LIBCURL_GIT_URL := git://github.com/JuliaWeb/LibCURL.jl.git
2929
LIBCURL_TAR_URL = https://api.github.com/repos/JuliaWeb/LibCURL.jl/tarball/$1
30+
DOWNLOADS_GIT_URL := git://github.com/JuliaLang/Downloads.jl.git
31+
DOWNLOADS_TAR_URL = https://api.github.com/repos/JuliaLang/Downloads.jl/tarball/$1
3032

3133
$(foreach module, $(STDLIBS_EXT), $(eval $(call stdlib-external,$(module),$(shell echo $(module) | tr a-z A-Z))))
3234

test/choosetests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ function choosetests(choices = [])
111111
filter!(x -> (x != "Profile"), tests)
112112
end
113113

114-
net_required_for = ["Sockets", "LibGit2", "LibCURL"]
114+
net_required_for = ["Sockets", "LibGit2", "LibCURL", "Downloads"]
115115
net_on = true
116116
try
117117
ipa = getipaddr()

test/download.jl

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,11 @@ mktempdir() do temp_dir
4040

4141
# Make sure that failed downloads do not leave files around
4242
missing_file = joinpath(temp_dir, "missing")
43-
@test_throws ProcessFailedException download("https://httpbin.julialang.org/status/404", missing_file)
43+
@test_throws ErrorException download("https://httpbin.julialang.org/status/404", missing_file)
4444
@test !isfile(missing_file)
4545

46-
# Make sure we properly handle metachar ' on windows with ^ escaping
47-
if Sys.iswindows()
48-
metachar_file = joinpath(temp_dir, "metachar")
49-
Base.download_powershell("https://httpbin.julialang.org/get?test='^'", metachar_file)
50-
metachar_string = read(metachar_file, String)
51-
m = match(r"\"test\"\s*:\s*\"(.*)\"", metachar_string)
52-
@test m.captures[1] == "'^'"
53-
end
54-
5546
# Use a TEST-NET (192.0.2.0/24) address which shouldn't be bound
5647
invalid_host_file = joinpath(temp_dir, "invalid_host")
57-
@test_throws ProcessFailedException download("http://192.0.2.1", invalid_host_file)
48+
@test_throws ErrorException download("http://192.0.2.1", invalid_host_file)
5849
@test !isfile(invalid_host_file)
5950
end

0 commit comments

Comments
 (0)