From 9f2cadad123eab9bcc8163e2f34754e3311a7073 Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Wed, 21 Aug 2024 11:15:58 +0200 Subject: [PATCH] provide a scratchspace for AtlasRep data if necessary If AtlasRep does not know a writable directory for downloaded data, i.e., if the value of its user preference AtlasRepDataDirectory is an empty string, provide a scratchspace and adjust the user preference. For that, we check for the empty string when GAP has been started (which may trigger that AtlasRep gets loaded) and in `GAP.Packages.load` calls. Thus this mechanism will fail if one starts GAP without packages and then loads GAP packages only via the GAP function `LoadPackage`. --- src/GAP.jl | 3 +++ src/packages.jl | 70 ++++++++++++++++++++++++++++++++++++++++++++++--- src/wrappers.jl | 4 +++ 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/GAP.jl b/src/GAP.jl index bac57f3a6..cdf5adb83 100644 --- a/src/GAP.jl +++ b/src/GAP.jl @@ -306,6 +306,9 @@ function __init__() end Packages.init_packagemanager() + + # The AtlasRep package may get loaded automatically when GAP starts. + Packages.init_atlasrep() end """ diff --git a/src/packages.jl b/src/packages.jl index 312745fc4..0efd1d8fb 100644 --- a/src/packages.jl +++ b/src/packages.jl @@ -3,6 +3,7 @@ module Packages import Downloads import Pidfile +import Scratch: @get_scratch! import ...GAP: Globals, GapObj, replace_global!, RNamObj, sysinfo, Wrappers const DEFAULT_PKGDIR = Ref{String}() @@ -119,7 +120,7 @@ function load(spec::String, version::String = ""; install::Union{Bool, String} = warning_level_orig = Wrappers.InfoLevel(Globals.InfoWarning) Wrappers.SetInfoLevel(Globals.InfoWarning, 0) end - loaded = Wrappers.LoadPackage(gspec, gversion, !quiet) + loaded = _load_internal(gspec, gversion, !quiet) if spec_is_path Wrappers.SetInfoLevel(Globals.InfoWarning, warning_level_orig) end @@ -172,7 +173,7 @@ function load(spec::String, version::String = ""; install::Union{Bool, String} = # ... then try to load the package, ... Wrappers.SetPackagePath(pkgname, gspec) - loaded = Wrappers.LoadPackage(pkgname, gversion, !quiet) + loaded = _load_internal(pkgname, gversion, !quiet) # ..., and reinstall the old info records # (which were removed by `Wrappers.SetPackagePath`). @@ -191,14 +192,14 @@ function load(spec::String, version::String = ""; install::Union{Bool, String} = # without showing messages. if Packages.install(spec, version; interactive = false, quiet) # Make sure that the installed version is admissible. - return Wrappers.LoadPackage(gspec, gversion, !quiet) == true + return _load_internal(gspec, gversion, !quiet) == true end elseif install isa String # `Packages.install` deals with the `install` information. if Packages.install(install, version; interactive = false, quiet) # Make sure that the installed version is admissible # (and that the package given by `install` fits to `spec`). - return Wrappers.LoadPackage(gspec, gversion, !quiet) == true + return _load_internal(gspec, gversion, !quiet) == true end end @@ -207,6 +208,18 @@ function load(spec::String, version::String = ""; install::Union{Bool, String} = # GAP unfortunately only gives us info messages... end +function _load_internal(gspec::GapObj, gversion::GapObj, quiet::Bool) + loaded = Wrappers.LoadPackage(gspec, gversion, quiet) + + # If the AtlasRep package is loaded afterwards (perhaps indirectly) + # then provide its scratchspace if necessary. + if atlasrep_download_cache == "" && Wrappers.IsPackageLoaded(GapObj("AtlasRep")) + init_atlasrep() + end + + return loaded +end + """ install(spec::String, version::String = ""; interactive::Bool = true, quiet::Bool = false, @@ -374,4 +387,53 @@ function locate_package(name::String) return String(Wrappers.ELM_REC(loaded, lname)[1]) end + +############################################################################## +# +# special handling for the GAP package AtlasRep +# +# GAP.jl supports Julia artifacts for GAP packages. +# One feature of the AtlasRep package is to download data files and +# (if wanted) to store them in a local directory. +# The path of this directory is either explicitly set in the user preference +# `AtlasRepDataDirectory` of the package, or it is computed when the AtlasRep +# package gets loaded. +# The value of the user preference is an empty string if and only if +# GAP does not know a path to a writable directory for the data files, +# which means that downloaded files cannot be cached; +# in this case, GAP.jl provides a scratchspace for the data, +# and sets the value of the user preference accordingly. +# We can use this scratchspace independent of the version of Julia, GAP.jl, +# and AtlasRep. + +# The path to the scratchspace, will be filled by `init_atlasrep()` +atlasrep_download_cache = "" + +# If GAP's AtlasRep package does not yet know a writable directory +# for storing downloaded data, provide a Julia scratch space. +function init_atlasrep() + atlasrep_download_cache == "" || return + atlasrep = GapObj("atlasrep") + AtlasRepDataDirectory = GapObj("AtlasRepDataDirectory") + val = Wrappers.UserPreference(atlasrep, AtlasRepDataDirectory) + if Wrappers.IsString(val) + # A default is set. + if length(val) == 0 + # There is no writable directory yet. + # If the scratch space is not yet there, create it and the relevant + # subdirectories. + # (The AtlasRep package is perhaps not yet loaded at this time.) + global atlasrep_download_cache = @get_scratch!("atlasrep_cache") + Wrappers.SetUserPreference(atlasrep, AtlasRepDataDirectory, + GapObj(atlasrep_download_cache)) + for dir in ["datagens", "dataword", "dataext"] + fname = joinpath(atlasrep_download_cache, dir) + isdir(fname) || mkdir(fname) + end + else + global atlasrep_download_cache = String(val) + end + end +end + end diff --git a/src/wrappers.jl b/src/wrappers.jl index 0852d7c13..9491b94f3 100644 --- a/src/wrappers.jl +++ b/src/wrappers.jl @@ -69,6 +69,8 @@ import GAP: @wrap @wrap RNamObj(x::Any)::Int @wrap SetInfoLevel(x::GapObj, y::Int)::Nothing @wrap SetPackagePath(x::GapObj, y::GapObj)::Nothing +@wrap SetUserPreference(x::GapObj, y::Any)::Nothing +@wrap SetUserPreference(x::GapObj, y::GapObj, z::Any)::Nothing @wrap ShallowCopy(x::Any)::Any @wrap String(x::Any)::Any @wrap StringDisplayObj(x::Any)::GapObj @@ -76,6 +78,8 @@ import GAP: @wrap @wrap StructuralCopy(x::Any)::Any @wrap SUM(x::Any, y::Any)::Any @wrap UNB_REC(x::GapObj, y::Int)::Nothing +@wrap UserPreference(x::GapObj)::Any +@wrap UserPreference(x::GapObj, y::GapObj)::Any @wrap ZeroSameMutability(x::Any)::Any end