diff --git a/CHANGES.md b/CHANGES.md index 341750ad..4301657e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -45,6 +45,7 @@ - simpcomp - singular - zeromqinterface +- Add `GAP.versioninfo()` - Optimize conversion of GAP strings to Julia strings, symbols or `Vector{UInt8}` ## Version 0.12.3 (released 2025-01-01) diff --git a/Project.toml b/Project.toml index 21094639..56d515ee 100644 --- a/Project.toml +++ b/Project.toml @@ -58,7 +58,7 @@ nauty_jll = "55c6dc9b-343a-50ca-8ff2-b71adb3733d5" AbstractAlgebra = "0.41.11, 0.42.1, 0.43, 0.44" Artifacts = "1.6" BinaryWrappers = "0.1.3" -Compat = "4.4.0" +Compat = "4.11" Downloads = "1.4.3" GAP_jll = "~400.1400.000" GAP_lib_jll = "~400.1400.000" diff --git a/docs/src/internal.md b/docs/src/internal.md index 24b525ae..f3b95c19 100644 --- a/docs/src/internal.md +++ b/docs/src/internal.md @@ -6,6 +6,7 @@ DocTestSetup = :(using GAP) # Internal ```@docs +GAP.versioninfo GAP.get_symbols_in_module GAP.GAP GAP.RecDict diff --git a/src/GAP.jl b/src/GAP.jl index 4d65e5e0..c8b2d464 100644 --- a/src/GAP.jl +++ b/src/GAP.jl @@ -1,9 +1,11 @@ """ GAP.jl is the Julia interface to the GAP-System. - For the package manual see https://oscar-system.github.io/GAP.jl/. + For the package manual see + [https://oscar-system.github.io/GAP.jl/](https://oscar-system.github.io/GAP.jl/). - For more information about GAP see https://www.gap-system.org/. + For more information about GAP see + [https://www.gap-system.org/](https://www.gap-system.org/). """ module GAP @@ -318,6 +320,28 @@ function randseed!(seed::Union{Integer,Nothing}=nothing) nothing end +""" + versioninfo(io::IO = stdout; jll::Bool = false, full::Bool = false) + +Print the version numbers of GAP.jl and GAP, +and version numbers and installation paths of all currently loaded GAP packages. +Note that these paths can be nonstandard because Julia's package manager +does not control which available version of a GAP package gets loaded. + +If `jll` or `full` is `true` then also the underlying binary packages (jll), +if available, of all installed (not necessarily loaded) packages +are included in the output. +""" +function versioninfo(io::IO = stdout; jll::Bool = false, full::Bool = false, padding::String = "") + if full + jll = true + end + # We cannot use `Pkg.dependencies()` because (depending on the project) + # GAP is perhaps not contained. + println(io, "GAP.jl version ", Compat.pkgversion(@__MODULE__)) + GAP.Packages.versioninfo(io; GAP = true, full = full, jll = jll, padding = padding) +end + include("lowlevel.jl") include("ccalls.jl") include("globals.jl") diff --git a/src/packages.jl b/src/packages.jl index 7b803ceb..6937a2fe 100644 --- a/src/packages.jl +++ b/src/packages.jl @@ -3,6 +3,7 @@ module Packages import Downloads import Pidfile +import Pkg import ...GAP: disable_error_handler, Globals, GapObj, replace_global!, RNamObj, sysinfo, Wrappers const DEFAULT_PKGDIR = Ref{String}() @@ -525,4 +526,57 @@ function locate_package(name::String) return String(Wrappers.ELM_REC(loaded, lname)[1]) end +# `GAP.Packages.versioninfo` is called by `GAP.versioninfo`. +function versioninfo(io::IO = stdout; GAP::Bool = false, jll::Bool = false, full::Bool = false, padding::String = "") + if full + GAP = jll = true + end + GAP && println(io, padding, "GAP version ", String(Globals.GAPInfo.Version)) + println(io, padding, "GAP packages:") + dict = Dict{Symbol, Any}(Globals.GAPInfo.PackagesLoaded) + default_artifacts_path = realpath(joinpath(DEPOT_PATH[1], "artifacts")) + names = String[] + paths = String[] + versions = String[] + for key in sort(collect(keys(dict))) + name = String(key) + push!(names, name) + vals = dict[key] + path = replace(realpath(vals[1]), default_artifacts_path => "ARTIFACTS") + if startswith(path, "ARTIFACTS") + pos = findall("/", path) + if length(pos) > 1 && pos[2][1]-pos[1][1] > 10 + path = path[1:(pos[1][1]+7)] * "..." * path[pos[2][1]:end] + end + end + push!(paths, path) + push!(versions, vals[2]) + end + namewidth = maximum(length.(names)) + 2 + verswidth = maximum(length.(versions)) + 2 + for i in 1:length(names) + println(io, padding, " ", + rpad(names[i], namewidth, ' '), + rpad(versions[i], verswidth, ' '), + paths[i]) + end + if jll + deps = collect(values(Pkg.dependencies())) + jlldeps = filter(x -> startswith(x.name, "GAP_pkg_"), deps) + sort!(jlldeps, by = x -> x.name) + if GAP + jllname = "GAP_jll" + jllpos = findfirst(x -> x.name == jllname, deps) + pushfirst!(jlldeps, deps[jllpos]) + end + jllnamewidth = maximum([length(d.name) for d in jlldeps]) + 2 + println(io, padding, "building on:") + for d in jlldeps + println(io, padding, " ", + rpad(d.name, jllnamewidth, ' '), + d.version) + end + end +end + end diff --git a/test/basics.jl b/test/basics.jl index e966b9b2..cc6a756f 100644 --- a/test/basics.jl +++ b/test/basics.jl @@ -175,3 +175,10 @@ end print(io, GAP.AbstractAlgebra.Lowercase(), GapObj([1, 2, 3])) @test String(take!(io)) == "GAP: [ 1, 2, 3 ]" end + +@testset "versioninfo" begin + io = IOBuffer() + GAP.versioninfo(io; full = true) + str = String(take!(io)) + @test startswith(str, "GAP.jl version") +end