From 6543a6c0cf7fa55d813dcd39457bb3a190f03b7d Mon Sep 17 00:00:00 2001 From: Alex Arslan Date: Tue, 22 May 2018 16:59:25 -0700 Subject: [PATCH] Add Sys.which and Sys.isexecutable --- README.md | 3 +++ src/Compat.jl | 39 +++++++++++++++++++++++++++++++++++++++ test/runtests.jl | 10 ++++++++++ 3 files changed, 52 insertions(+) diff --git a/README.md b/README.md index 33341cc95..4ca2297b9 100644 --- a/README.md +++ b/README.md @@ -295,6 +295,8 @@ Currently, the `@compat` macro supports the following syntaxes: * `squeeze` with `dims` as keyword argument ([#26660]). +* `Compat.Sys.which` and `Compat.Sys.isexecutable` ([#26559]). + * `Compat.qr` takes `pivot` as a `Val` _instance_ and keyword argument `full` ([#22475], [#24279]). * `Compat.rmul!` provides a subset of the functionality of `LinearAlgebra.rmul!` for @@ -630,6 +632,7 @@ includes this fix. Find the minimum version from there. [#26369]: https://github.com/JuliaLang/julia/issues/26369 [#26436]: https://github.com/JuliaLang/julia/issues/26436 [#26442]: https://github.com/JuliaLang/julia/issues/26442 +[#26559]: https://github.com/JuliaLang/julia/issues/26559 [#26660]: https://github.com/JuliaLang/julia/issues/26660 [#26670]: https://github.com/JuliaLang/julia/issues/26670 [#27077]: https://github.com/JuliaLang/julia/issues/27077 diff --git a/src/Compat.jl b/src/Compat.jl index 99dea1564..a35c89baf 100644 --- a/src/Compat.jl +++ b/src/Compat.jl @@ -461,6 +461,45 @@ module Sys import Base.Sys: isapple, isbsd, islinux, isunix, iswindows end + @static if VERSION < v"0.7.0-DEV.5171" + 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 + error("$program not found") + 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. diff --git a/test/runtests.jl b/test/runtests.jl index bf8394b17..629353e36 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1707,4 +1707,14 @@ end @test isletter('β') @test !isletter('3') +# 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_throws ErrorException Compat.Sys.which("reallyseriouslynotathingyoushouldhave") + end +end + nothing