Skip to content

Commit 0fb323e

Browse files
authored
Don't clear executable bits in set_readonly() on Windows (#3349)
* Don't clear executable bits in `set_readonly()` on Windows On windows, `filemode()` doesn't include executable bits. This is already worked around in `gitmode()` but we don't quite want to do something as intrusive as `gitmode()` in `set_readonly()`; let's just work around this one platform-specific foible. This fixes problems like executable permissions disappearing when creating artifacts on Windows, packages that contain executable files losing those permissions on install, etc... * Blindly try running all tests on windows now * Get rid of special-case on Windows * Update Artifacts.jl * Update Artifacts.jl
1 parent 5bc49c8 commit 0fb323e

File tree

3 files changed

+54
-80
lines changed

3 files changed

+54
-80
lines changed

src/Artifacts.jl

+36-61
Original file line numberDiff line numberDiff line change
@@ -287,71 +287,46 @@ function download_artifact(
287287
return true
288288
end
289289

290-
if Sys.iswindows()
291-
# The destination directory we're hoping to fill:
292-
dest_dir = artifact_path(tree_hash; honor_overrides=false)
293-
mkpath(dest_dir)
294-
295-
# On Windows, we have some issues around stat() and chmod() that make properly
296-
# determining the git tree hash problematic; for this reason, we use the "unsafe"
297-
# artifact unpacking method, which does not properly verify unpacked git tree
298-
# hash. This will be fixed in a future Julia release which will properly interrogate
299-
# the filesystem ACLs for executable permissions, which git tree hashes care about.
300-
try
301-
download_verify_unpack(tarball_url, tarball_hash, dest_dir, ignore_existence=true,
302-
verbose=verbose, quiet_download=quiet_download, io=io)
303-
catch err
304-
@debug "download_artifact error" tree_hash tarball_url tarball_hash err
305-
# Clean that destination directory out if something went wrong
306-
rm(dest_dir; force=true, recursive=true)
307-
308-
if isa(err, InterruptException)
309-
rethrow(err)
310-
end
311-
return err
290+
# We download by using `create_artifact()`. We do this because the download may
291+
# be corrupted or even malicious; we don't want to clobber someone else's artifact
292+
# by trusting the tree hash that has been given to us; we will instead download it
293+
# to a temporary directory, calculate the true tree hash, then move it to the proper
294+
# location only after knowing what it is, and if something goes wrong in the process,
295+
# everything should be cleaned up. Luckily, that is precisely what our
296+
# `create_artifact()` wrapper does, so we use that here.
297+
calc_hash = try
298+
create_artifact() do dir
299+
download_verify_unpack(tarball_url, tarball_hash, dir, ignore_existence=true, verbose=verbose,
300+
quiet_download=quiet_download, io=io)
312301
end
313-
else
314-
# We download by using `create_artifact()`. We do this because the download may
315-
# be corrupted or even malicious; we don't want to clobber someone else's artifact
316-
# by trusting the tree hash that has been given to us; we will instead download it
317-
# to a temporary directory, calculate the true tree hash, then move it to the proper
318-
# location only after knowing what it is, and if something goes wrong in the process,
319-
# everything should be cleaned up. Luckily, that is precisely what our
320-
# `create_artifact()` wrapper does, so we use that here.
321-
calc_hash = try
322-
create_artifact() do dir
323-
download_verify_unpack(tarball_url, tarball_hash, dir, ignore_existence=true, verbose=verbose,
324-
quiet_download=quiet_download, io=io)
325-
end
326-
catch err
327-
@debug "download_artifact error" tree_hash tarball_url tarball_hash err
328-
if isa(err, InterruptException)
329-
rethrow(err)
330-
end
331-
# If something went wrong during download, return the error
332-
return err
302+
catch err
303+
@debug "download_artifact error" tree_hash tarball_url tarball_hash err
304+
if isa(err, InterruptException)
305+
rethrow(err)
333306
end
307+
# If something went wrong during download, return the error
308+
return err
309+
end
334310

335-
# Did we get what we expected? If not, freak out.
336-
if calc_hash.bytes != tree_hash.bytes
337-
msg = "Tree Hash Mismatch!\n"
338-
msg *= " Expected git-tree-sha1: $(bytes2hex(tree_hash.bytes))\n"
339-
msg *= " Calculated git-tree-sha1: $(bytes2hex(calc_hash.bytes))"
340-
# Since tree hash calculation is still broken on some systems, e.g. Pkg.jl#1860,
341-
# and Pkg.jl#2317 so we allow setting JULIA_PKG_IGNORE_HASHES=1 to ignore the
342-
# error and move the artifact to the expected location and return true
343-
ignore_hash = Base.get_bool_env("JULIA_PKG_IGNORE_HASHES", false)
344-
if ignore_hash
345-
msg *= "\n\$JULIA_PKG_IGNORE_HASHES is set to 1: ignoring error and moving artifact to the expected location"
346-
@error(msg)
347-
# Move it to the location we expected
348-
src = artifact_path(calc_hash; honor_overrides=false)
349-
dst = artifact_path(tree_hash; honor_overrides=false)
350-
mv(src, dst; force=true)
351-
return true
352-
end
353-
return ErrorException(msg)
311+
# Did we get what we expected? If not, freak out.
312+
if calc_hash.bytes != tree_hash.bytes
313+
msg = "Tree Hash Mismatch!\n"
314+
msg *= " Expected git-tree-sha1: $(bytes2hex(tree_hash.bytes))\n"
315+
msg *= " Calculated git-tree-sha1: $(bytes2hex(calc_hash.bytes))"
316+
# Since tree hash calculation is still broken on some systems, e.g. Pkg.jl#1860,
317+
# and Pkg.jl#2317, we allow setting JULIA_PKG_IGNORE_HASHES=1 to ignore the
318+
# error and move the artifact to the expected location and return true
319+
ignore_hash = Base.get_bool_env("JULIA_PKG_IGNORE_HASHES", false)
320+
if ignore_hash
321+
msg *= "\n\$JULIA_PKG_IGNORE_HASHES is set to 1: ignoring error and moving artifact to the expected location"
322+
@error(msg)
323+
# Move it to the location we expected
324+
src = artifact_path(calc_hash; honor_overrides=false)
325+
dst = artifact_path(tree_hash; honor_overrides=false)
326+
mv(src, dst; force=true)
327+
return true
354328
end
329+
return ErrorException(msg)
355330
end
356331

357332
return true

src/utils.jl

+5
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ function set_readonly(path)
4646
# outside of the root, links to non-file/non-directories, etc...)
4747
islink(filepath) && continue
4848
fmode = filemode(filepath)
49+
@static if Sys.iswindows()
50+
if Sys.isexecutable(filepath)
51+
fmode |= 0o111
52+
end
53+
end
4954
try
5055
chmod(filepath, fmode & (typemax(fmode) 0o222))
5156
catch

test/artifacts.jl

+13-19
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,7 @@ end
117117
@test artifact_exists(hash)
118118

119119
# Test that the artifact verifies
120-
if !Sys.iswindows()
121-
@test verify_artifact(hash)
122-
end
120+
@test verify_artifact(hash)
123121
end
124122

125123
@testset "File permissions" begin
@@ -190,9 +188,7 @@ end
190188
@test !artifact_exists(arty_hash)
191189

192190
@test ensure_artifact_installed("arty", artifacts_toml) == artifact_path(arty_hash)
193-
if !Sys.iswindows()
194-
@test verify_artifact(arty_hash)
195-
end
191+
@test verify_artifact(arty_hash)
196192

197193
# Make sure doing it twice "just works"
198194
@test ensure_artifact_installed("arty", artifacts_toml) == artifact_path(arty_hash)
@@ -274,22 +270,20 @@ end
274270
@test_logs (:error, r"malformed, must be array or dict!") artifact_meta("broken_artifact", joinpath(badifact_dir, "not_a_table.toml"))
275271

276272
# Next, test incorrect download errors
277-
if !Sys.iswindows()
278-
for ignore_hash in (false, true); withenv("JULIA_PKG_IGNORE_HASHES" => ignore_hash ? "1" : nothing) do; mktempdir() do dir
279-
with_artifacts_directory(dir) do
280-
@test artifact_meta("broken_artifact", joinpath(badifact_dir, "incorrect_gitsha.toml")) != nothing
281-
if !ignore_hash
282-
@test_throws ErrorException ensure_artifact_installed("broken_artifact", joinpath(badifact_dir, "incorrect_gitsha.toml"))
283-
else
284-
@test_logs (:error, r"Tree Hash Mismatch!") match_mode=:any begin
285-
path = ensure_artifact_installed("broken_artifact", joinpath(badifact_dir, "incorrect_gitsha.toml"))
286-
@test endswith(path, "0000000000000000000000000000000000000000")
287-
@test isdir(path)
273+
for ignore_hash in (false, true); withenv("JULIA_PKG_IGNORE_HASHES" => ignore_hash ? "1" : nothing) do; mktempdir() do dir
274+
with_artifacts_directory(dir) do
275+
@test artifact_meta("broken_artifact", joinpath(badifact_dir, "incorrect_gitsha.toml")) != nothing
276+
if !ignore_hash
277+
@test_throws ErrorException ensure_artifact_installed("broken_artifact", joinpath(badifact_dir, "incorrect_gitsha.toml"))
278+
else
279+
@test_logs (:error, r"Tree Hash Mismatch!") match_mode=:any begin
280+
path = ensure_artifact_installed("broken_artifact", joinpath(badifact_dir, "incorrect_gitsha.toml"))
281+
@test endswith(path, "0000000000000000000000000000000000000000")
282+
@test isdir(path)
288283
end
289284
end
290285
end
291-
end end end
292-
end
286+
end end end
293287

294288
mktempdir() do dir
295289
with_artifacts_directory(dir) do

0 commit comments

Comments
 (0)