diff --git a/README.md b/README.md index 5b2afba8d..55fedb608 100644 --- a/README.md +++ b/README.md @@ -295,6 +295,8 @@ Currently, the `@compat` macro supports the following syntaxes: * `Compat.qr` takes `pivot` as a `Val` _instance_ ([#22475]). +* `Compat.Sys.which` and `Compat.Sys.isexecutable` ([#26559], [#27298]). + * `Compat.rmul!` provides a subset of the functionality of `LinearAlgebra.rmul!` for use with Julia 0.6 ([#25701], [#25812]). @@ -633,8 +635,10 @@ includes this fix. Find the minimum version from there. [#26436]: https://github.com/JuliaLang/julia/issues/26436 [#26442]: https://github.com/JuliaLang/julia/issues/26442 [#26486]: https://github.com/JuliaLang/julia/issues/26486 +[#26559]: https://github.com/JuliaLang/julia/issues/26559 [#26660]: https://github.com/JuliaLang/julia/issues/26660 [#26670]: https://github.com/JuliaLang/julia/issues/26670 [#26850]: https://github.com/JuliaLang/julia/issues/26850 [#27077]: https://github.com/JuliaLang/julia/issues/27077 -[#27258]: https://github.com/JuliaLang/julia/issues/27258 \ No newline at end of file +[#27258]: https://github.com/JuliaLang/julia/issues/27258 +[#27298]: https://github.com/JuliaLang/julia/issues/27298 diff --git a/src/Compat.jl b/src/Compat.jl index d99c275f2..268b347f7 100644 --- a/src/Compat.jl +++ b/src/Compat.jl @@ -442,6 +442,13 @@ end # https://github.com/JuliaLang/julia/pull/21746 const macros_have_sourceloc = VERSION >= v"0.7-" && length(:(@test).args) == 2 +# 0.7.0-DEV.3155 +@static if !isdefined(Base, :pushfirst!) + const pushfirst! = unshift! + const popfirst! = shift! + export pushfirst!, popfirst! +end + # https://github.com/JuliaLang/julia/pull/22182 module Sys const KERNEL = Base.Sys.KERNEL @@ -455,6 +462,56 @@ module Sys import Base.Sys: isapple, isbsd, islinux, isunix, iswindows end + @static if VERSION < v"0.7.0-DEV.5171" + using ..Compat: pushfirst! + + function isexecutable(path::AbstractString) + if iswindows() + isfile(path) + else + ccall(:access, Cint, (Ptr{UInt8}, Cint), path, 0x01) == 0 + end + end + + function which(program::AbstractString) + progs = String[] + base = basename(program) + if iswindows() + isempty(last(splitext(base))) || push!(progs, base) + for p = [".exe", ".com"] + push!(progs, base * p) + end + else + push!(progs, base) + end + dirs = String[] + dir = dirname(program) + if isempty(dir) + pathsep = iswindows() ? ';' : ':' + append!(dirs, map(abspath, split(get(ENV, "PATH", ""), pathsep))) + iswindows() && pushfirst!(dirs, pwd()) + else + push!(dirs, abspath(dir)) + end + for d in dirs, p in progs + path = joinpath(d, p) + isexecutable(path) && return realpath(path) + end + nothing + end + elseif VERSION < v"0.7.0-alpha.6" + import Base.Sys: isexecutable + + which(program::AbstractString) = try + Base.Sys.which(program) + catch err + err isa ErrorException || rethrow(err) + nothing + end + else + import Base.Sys: which, isexecutable + end + # https://github.com/JuliaLang/julia/pull/25102 # NOTE: This needs to be in an __init__ because JULIA_HOME is not # defined when building system images. @@ -1130,13 +1187,6 @@ else import Base: notnothing end -# 0.7.0-DEV.3155 -@static if !isdefined(Base, :pushfirst!) - const pushfirst! = unshift! - const popfirst! = shift! - export pushfirst!, popfirst! -end - # 0.7.0-DEV.3309 @static if VERSION < v"0.7.0-DEV.3309" const IteratorSize = Base.iteratorsize diff --git a/test/runtests.jl b/test/runtests.jl index 4d2a9345e..f6cedcd55 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1756,4 +1756,14 @@ end @test something(Some(2), 1) === 2 @test something(nothing, Some(1)) === 1 +# 0.7.0-DEV.5171 +let sep = Compat.Sys.iswindows() ? ';' : ':' + withenv("PATH" => string(Compat.Sys.BINDIR, sep, get(ENV, "PATH", ""))) do + jl = joinpath(Compat.Sys.BINDIR, "julia") * (Compat.Sys.iswindows() ? ".exe" : "") + @test Compat.Sys.which("julia") == realpath(jl) + @test Compat.Sys.isexecutable(jl) + @test Compat.Sys.which("reallyseriouslynotathingyoushouldhave") === nothing + end +end + nothing