diff --git a/base/version.jl b/base/version.jl index 2ff1842b79caf6..9f8b0fc7b8cef2 100644 --- a/base/version.jl +++ b/base/version.jl @@ -21,6 +21,7 @@ v"1.2.3" julia> VersionNumber("2.0.1-rc1") v"2.0.1-rc1" ``` +See also: [`isequal`](@ref). """ struct VersionNumber major::VInt @@ -166,15 +167,40 @@ function ident_cmp(A::VerTuple, B::VerTuple) length(B) < length(A) ? +1 : 0 end -function ==(a::VersionNumber, b::VersionNumber) +""" + isequal(v1::VersionNumber, v2::VersionNumber; downto::Symbol = :patch) + +Compare two VersionNumbers for equality in fields cascading down to the `downto` field of the VersionNumbers, +which by default is the `build` thus all fields are compared. + +```julia-repl +julia> isequal(v"1.6", v"1.6.3") +false + +julia> isequal(v"1.6", v"1.6.3", downto = :minor) +true + +julia> isequal(v"1.5", v"1.6.3", downto = :major) +true +``` +See also: [`VersionNumber`](@ref). +""" +function isequal(a::VersionNumber, b::VersionNumber; downto::Symbol = :build) + downto in fieldnames(VersionNumber) || error("Unrecognized `downto` value. Must be :major, :minor, :patch, :prerelease, or :build") (a.major != b.major) && return false + downto == :major && return true (a.minor != b.minor) && return false + downto == :minor && return true (a.patch != b.patch) && return false + downto == :patch && return true (ident_cmp(a.prerelease, b.prerelease) != 0) && return false + downto == :prerelease && return true (ident_cmp(a.build, b.build) != 0) && return false return true end +==(a::VersionNumber, b::VersionNumber) = isequal(a, b; downto = :build) + issupbuild(v::VersionNumber) = length(v.build)==1 && isempty(v.build[1]) function isless(a::VersionNumber, b::VersionNumber) diff --git a/doc/src/base/base.md b/doc/src/base/base.md index d03542691782a1..8a9ffbeb76e660 100644 --- a/doc/src/base/base.md +++ b/doc/src/base/base.md @@ -347,6 +347,7 @@ Base.@static ```@docs Base.VersionNumber Base.@v_str +Base.isequal(::VersionNumber, ::VersionNumber) ``` ## Errors diff --git a/test/version.jl b/test/version.jl index d9083b9c49cf18..5f7c15370cf570 100644 --- a/test/version.jl +++ b/test/version.jl @@ -63,6 +63,39 @@ using Random @test v"3.2+1.a" == VersionNumber(3, 2, 0, (), (1, "a")) @test v"4.3.2+1.a" == VersionNumber(4, 3, 2, (), (1, "a")) +# full equality +@test isequal(v"1", v"1") +@test isequal(v"1", v"2") == false +@test isequal(v"1.2", v"1.2") +@test isequal(v"1.1", v"1.2") == false +@test isequal(v"1.2.3", v"1.2.3") +@test isequal(v"1.2.1", v"1.2.3") == false +@test isequal(v"1.2.3-dev", v"1.2.3-dev") +@test isequal(v"1.2.3", v"1.2.3-dev") == false +@test isequal(v"1.2.3-dev+1.a", v"1.2.3-dev+1.a") +@test isequal(v"1.2.3-dev", v"1.2.3-dev+1.a") == false + +# partial equality +@test isequal(v"1", v"1", downto = :major) +@test isequal(v"1", v"1.2.3-dev+1.a", downto = :major) +@test isequal(v"1", v"2", downto = :major) == false + +@test isequal(v"1.2", v"1.2", downto = :minor) +@test isequal(v"1.2", v"1.2.3-dev+1.a", downto = :minor) +@test isequal(v"1.1", v"1.2", downto = :minor) == false + +@test isequal(v"1.2.3", v"1.2.3", downto = :patch) +@test isequal(v"1.2.3", v"1.2.3-dev+1.a", downto = :patch) +@test isequal(v"1.2.1", v"1.2.3", downto = :patch) == false + +@test isequal(v"1.2.3-dev", v"1.2.3-dev", downto = :prerelease) +@test isequal(v"1.2.3-dev", v"1.2.3-dev+1.a", downto = :prerelease) +@test isequal(v"1.2.3-foo", v"1.2.3-dev+1.a", downto = :prerelease) == false + +@test isequal(v"1.2.3-dev+1.a", v"1.2.3-dev+1.a", downto = :build) +@test isequal(v"1.2.3-dev", v"1.2.3-dev+1.a", downto = :build) == false +@test isequal(v"1.2.3-dev+2.a", v"1.2.3-dev+1.a", downto = :build) == false + # ArgumentErrors in constructor @test_throws ArgumentError VersionNumber(4, 3, 2, ("nonalphanumeric!",), ()) @test_throws ArgumentError VersionNumber(4, 3, 2, ("nonalphanumeric!", 1), ())