diff --git a/Project.toml b/Project.toml index 07da5491f..fdb0ead33 100644 --- a/Project.toml +++ b/Project.toml @@ -1,10 +1,11 @@ name = "Compat" uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "4.10.1" +version = "4.11.0" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [compat] diff --git a/README.md b/README.md index 42566cbe3..17ce22b9d 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,8 @@ changes in `julia`. * `@something` and `@coalesce` as short-circuiting versions of `something` and `coalesce` ([#40729]) (since Compat 3.29) +* `pkgversion(m::Module)` returns the version of the package that loaded a given module ([#45607]) (since Compat 4.11) + ## Developer tips One of the most important rules for `Compat.jl` is to avoid breaking user code @@ -170,5 +172,7 @@ Note that you should specify the correct minimum version for `Compat` in the [#43334]: https://github.com/JuliaLang/julia/issues/43334 [#43354]: https://github.com/JuliaLang/julia/issues/43354 [#43852]: https://github.com/JuliaLang/julia/issues/43852 +[#45607]: https://github.com/JuliaLang/julia/issues/45607 +[#46104]: https://github.com/JuliaLang/julia/issues/46104 [#48038]: https://github.com/JuliaLang/julia/issues/48038 [#50105]: https://github.com/JuliaLang/julia/issues/50105 diff --git a/src/Compat.jl b/src/Compat.jl index 83e327dfd..751355a1f 100644 --- a/src/Compat.jl +++ b/src/Compat.jl @@ -385,6 +385,71 @@ end end end +# this function is available as of Julia 1.9 +# https://github.com/JuliaLang/julia/pull/45607 +# https://github.com/JuliaLang/julia/pull/45695 +# https://github.com/JuliaLang/julia/pull/45861 +# https://github.com/JuliaLang/julia/pull/46738 +@static if !isdefined(Base, :pkgversion) + using TOML: parsefile + export pkgversion + + const require_lock = isdefined(Base, :require_lock) ? Base.require_lock : Base.ReentrantLock() + const project_names = ("JuliaProject.toml", "Project.toml") + + function locate_project_file(env::String) + for proj in project_names + project_file = joinpath(env, proj) + if Base.isfile_casesensitive(project_file) + return project_file + end + end + return nothing + end + + function get_pkgversion_from_path(path) + project_file = locate_project_file(path) + if project_file isa String + d = parsefile(project_file) + v = get(d, "version", nothing) + if v !== nothing + return VersionNumber(v::String) + end + end + return nothing + end + + """ + pkgversion(m::Module) + + Return the version of the package that imported module `m`, + or `nothing` if `m` was not imported from a package, or imported + from a package without a version field set. + + The version is read from the package's Project.toml during package + load. + + To get the version of the package that imported the current module + the form `pkgversion(@__MODULE__)` can be used. + """ + function pkgversion(m::Module) + path = pkgdir(m) + path === nothing && return nothing + Base.@lock require_lock begin + v = get_pkgversion_from_path(path) + # https://github.com/JuliaLang/julia/pull/44318 + @static if hasfield(Base.PkgOrigin, :version) + pkgorigin = get(Base.pkgorigins, Base.PkgId(Base.moduleroot(m)), nothing) + # Cache the version + if pkgorigin !== nothing && pkgorigin.version === nothing + pkgorigin.version = v + end + end + return v + end + end +end + # https://github.com/JuliaLang/julia/pull/43334 if VERSION < v"1.9.0-DEV.1163" import Base: IteratorSize, HasLength, HasShape, OneTo diff --git a/test/runtests.jl b/test/runtests.jl index 04c110616..2268b610c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,5 +1,6 @@ using Compat using Dates +using TOML using Test @test isempty(detect_ambiguities(Base, Core, Compat)) @@ -457,6 +458,12 @@ end @test isempty(ea) end +@testset "pkgversion" begin + toml = joinpath(pkgdir(Compat), "Project.toml") + @test pkgversion(Compat) == VersionNumber(TOML.parsefile(toml)["version"]) + @test pkgversion(Base) === nothing +end + # https://github.com/JuliaLang/julia/pull/43334 @testset "stack" begin # Basics