-
Notifications
You must be signed in to change notification settings - Fork 186
Start GAP with prescribed package versions #6057
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1365,3 +1365,34 @@ DeclareGlobalFunction( "Cite" ); | |
| DeclareGlobalFunction( "ShowPackageVariables" ); | ||
|
|
||
| DeclareGlobalFunction( "PackageVariablesInfo" ); | ||
|
|
||
|
|
||
| # a utility function | ||
| DeclareGlobalName( "PrescribedPackageVersions" ); | ||
|
|
||
|
|
||
| ############################################################################# | ||
| ## | ||
| #F PackagesLoaded() | ||
| ## | ||
| ## <ManSection> | ||
| ## <Func Name="PackagesLoaded" Arg=''/> | ||
| ## | ||
| ## <Returns> | ||
| ## a string that describes the names of all currently loaded &GAP; packages | ||
| ## and their version numbers. | ||
| ## </Returns> | ||
| ## | ||
| ## <Description> | ||
| ## The result consists of <C>\n</C> separated lines of the form | ||
| ## <C>name = "version"</C>, | ||
| ## where <C>name</C> is the name of a loaded &GAP; package | ||
| ## and <C>version</C> is its version. | ||
| ## <P/> | ||
| ## One can print this string to a file and set the user preference | ||
| ## <C>"PrescribedPackageVersions"</C> to the name of this file, | ||
| ## Then starting &GAP; anew will load exactly the same packages. | ||
| ## </Description> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be a good idea here to give an explicit example of how you might do this, and to specify that the absolute path of the file is required also. |
||
| ## </ManSection> | ||
| ## | ||
| DeclareGlobalName( "PackagesLoaded" ); | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -286,7 +286,8 @@ end ); | |||||
| ## In earlier versions, this function had an argument; now we ignore it. | ||||||
| ## | ||||||
| InstallGlobalFunction( InitializePackagesInfoRecords, function( arg ) | ||||||
| local pkgdirs, pkgdir, pkgdirstrs, ignore, name, file, files, record, r; | ||||||
| local pkgdirs, pkgdir, pkgdirstrs, ignore, name, file, files, record, r, | ||||||
| exact; | ||||||
|
|
||||||
| if IsBound( GAPInfo.PackagesInfoInitialized ) and | ||||||
| GAPInfo.PackagesInfoInitialized = true then | ||||||
|
|
@@ -372,6 +373,19 @@ InstallGlobalFunction( InitializePackagesInfoRecords, function( arg ) | |||||
| fi; | ||||||
| od; | ||||||
|
|
||||||
| # If exact version numbers are prescribed then ignore all package | ||||||
| # versions that do not fit to the list. | ||||||
| exact:= PrescribedPackageVersions( | ||||||
| UserPreference( "PrescribedPackageVersions" ) ); | ||||||
| if exact <> fail then | ||||||
| # Store the list of prescribed package version, | ||||||
| # including the informtion about ordering and 'OnlyNeeded' option. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| GAPInfo.PrescribedPackageVersions:= exact; | ||||||
| exact:= List( exact, x -> x{ [ 1, 2 ] } ); | ||||||
| GAPInfo.PackagesInfo:= Filtered( GAPInfo.PackagesInfo, | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens here if the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I should have read further, I see this is resolved below. |
||||||
| r -> [ LowercaseString( r.PackageName ), r.Version ] in exact ); | ||||||
| fi; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Semi-relatedly, shouldn't there be some sort of warning or something if there's a mismatch between the initial value of |
||||||
|
|
||||||
| # Sort the available info records by their version numbers. | ||||||
| # (Sort stably in order to make sure that an instance from the first | ||||||
| # possible root path gets chosen if the same version of a package | ||||||
|
|
@@ -1987,8 +2001,66 @@ The level can be changed in a running session using \ | |||||
| multi:= false, | ||||||
| ) ); | ||||||
|
|
||||||
| # And a preference for prescribing explicit package versions. | ||||||
| BindGlobal( "PrescribedPackageVersions", function( filename ) | ||||||
| local exact, len, l; | ||||||
|
|
||||||
| if IsString( filename ) and filename <> "" then | ||||||
| filename:= UserHomeExpand( filename ); | ||||||
| if IsReadableFile( filename ) then | ||||||
| # Check the contents; see 'PackagesLoaded' for the format. | ||||||
| exact:= List( SplitString( StringFile( filename ), "\n" ), | ||||||
| line -> SplitString( line, ",", " ," ) ); | ||||||
| if ForAll( exact, | ||||||
| x -> Length( x ) in [ 2, 4 ] and | ||||||
| Length( x[2] ) > 2 and | ||||||
| x[2][1] = '\"' and Last( x[2] ) = '\"' and | ||||||
| ( Length( x ) = 2 or | ||||||
| ( ForAll( x[3], IsDigitChar ) and | ||||||
| x[4] in [ "true", "false" ] ) ) ) then | ||||||
| len:= Length( exact ); | ||||||
| for l in exact do | ||||||
| l[1]:= ReplacedString( l[1], "\"", "" ); | ||||||
| l[2]:= ReplacedString( l[2], "\"", "" ); | ||||||
| if Length( l ) = 2 then | ||||||
| l[3]:= len; | ||||||
| else | ||||||
| l[3]:= Int( l[3] ); | ||||||
| l[4]:= ( l[4] = "true" ); | ||||||
| fi; | ||||||
| od; | ||||||
| SortBy( exact, x -> x[3] ); | ||||||
| return exact; | ||||||
| fi; | ||||||
| fi; | ||||||
| fi; | ||||||
| return fail; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Related to the comments above would it be possible to maybe give an info warning or error in the case that the file exists but fails the parsing above, to indicate what's wrong? |
||||||
| end ); | ||||||
|
|
||||||
| DeclareUserPreference( rec( | ||||||
| name:= "PrescribedPackageVersions", | ||||||
| description:= [ | ||||||
| "If the value is a nonempty string then it is assumed to be the name \ | ||||||
| of a file that consists of lines of the form <C>name = \"version\"</C>, \ | ||||||
| where <C>name</C> is the (case insensitive) name of a package \ | ||||||
| and <C>version</C> is the exact version of the package <C>name</C> \ | ||||||
| that shall be loaded. \ | ||||||
| In this case, &GAP;'s automatic package loading mechanism will try to load \ | ||||||
| exactly these package versions, all other available packages (in particular \ | ||||||
| suggested packages that are not listed in the file) will be ignored, \ | ||||||
| and an error will occur if not all of the given packages can be loaded \ | ||||||
| in the prescribed versions. \ | ||||||
| This preference overrides the preferences <C>\"PackagesToLoad\"</C>, \ | ||||||
| <C>\"ExcludeFromAutoload\"</C>, <C>\"PackagesToIgnore\"</C>, \ | ||||||
| and the command line option <C>-A</C>." | ||||||
| ], | ||||||
| default:= "", | ||||||
| check:= filename -> PrescribedPackageVersions( filename ) <> fail, | ||||||
| ) ); | ||||||
|
|
||||||
| InstallGlobalFunction( AutoloadPackages, function() | ||||||
| local msg, pair, excludedpackages, name, record, neededPackages; | ||||||
| local msg, pair, excludedpackages, name, record, neededPackages, | ||||||
| prescribed; | ||||||
|
|
||||||
| SetInfoLevel( InfoPackageLoading, | ||||||
| UserPreference( "InfoPackageLoadingLevel" ) ); | ||||||
|
|
@@ -2005,9 +2077,16 @@ InstallGlobalFunction( AutoloadPackages, function() | |||||
| GAPInfo.PackagesInfoInitialized:= false; | ||||||
| InitializePackagesInfoRecords(); | ||||||
|
|
||||||
| # If --bare is specified, load no packages | ||||||
| if GAPInfo.CommandLineOptions.bare then | ||||||
| # If '--bare' is specified, load no packages | ||||||
| neededPackages := []; | ||||||
| elif IsBound( GAPInfo.PrescribedPackageVersions ) then | ||||||
| # A list of packages with exact version numbers is prescribed, | ||||||
| # load these packages but no other packages. | ||||||
| # We assume that 'InitializePackagesInfoRecords' has removed all | ||||||
| # other package versions from the global data about available packages. | ||||||
| neededPackages := List( GAPInfo.PrescribedPackageVersions, | ||||||
| x -> x{ [ 1, 2 ] } ); | ||||||
| else | ||||||
| neededPackages := GAPInfo.Dependencies.NeededOtherPackages; | ||||||
| fi; | ||||||
|
|
@@ -2021,20 +2100,41 @@ InstallGlobalFunction( AutoloadPackages, function() | |||||
| List( neededPackages, | ||||||
| pair -> Concatenation( pair[1], " (", pair[2], ")" ) ) ), | ||||||
| "GAP" ); | ||||||
| if GAPInfo.CommandLineOptions.A then | ||||||
| # If the '-A' option is given, load the needed packages | ||||||
| # but not their suggested packages. | ||||||
| # Note that 'PrescribedPackageVersions' overrides the '-A' option. | ||||||
| if GAPInfo.CommandLineOptions.A and | ||||||
| not IsBound( GAPInfo.PrescribedPackageVersions ) then | ||||||
| PushOptions( rec( OnlyNeeded:= true ) ); | ||||||
| fi; | ||||||
| for pair in neededPackages do | ||||||
| # Set 'OnlyNeeded' for this package | ||||||
| # iff 'PrescribedPackageVersions' forces it. | ||||||
| if IsBound( GAPInfo.PrescribedPackageVersions ) then | ||||||
| prescribed:= First( GAPInfo.PrescribedPackageVersions, | ||||||
| l -> LowercaseString( pair[1] ) = l[1] ); | ||||||
| if Length( prescribed ) = 4 then | ||||||
| PushOptions( rec( OnlyNeeded:= prescribed[4] ) ); | ||||||
| fi; | ||||||
| fi; | ||||||
|
|
||||||
| # Load the package. | ||||||
| if LoadPackage( pair[1], pair[2], false ) <> true then | ||||||
| LogPackageLoadingMessage( PACKAGE_ERROR, Concatenation( | ||||||
| "needed package ", pair[1], " cannot be loaded" ), "GAP" ); | ||||||
| Error( "failed to load needed package `", pair[1], | ||||||
| "' (version ", pair[2], ")" ); | ||||||
| fi; | ||||||
|
|
||||||
| if IsBound( GAPInfo.PrescribedPackageVersions ) and | ||||||
| Length( prescribed ) = 4 then | ||||||
| PopOptions(); | ||||||
| fi; | ||||||
| od; | ||||||
| LogPackageLoadingMessage( PACKAGE_DEBUG, "needed packages loaded", | ||||||
| "GAP" ); | ||||||
| if GAPInfo.CommandLineOptions.A then | ||||||
| if GAPInfo.CommandLineOptions.A and | ||||||
| not IsBound( GAPInfo.PrescribedPackageVersions ) then | ||||||
| PopOptions(); | ||||||
| fi; | ||||||
| fi; | ||||||
|
|
@@ -2044,6 +2144,10 @@ InstallGlobalFunction( AutoloadPackages, function() | |||||
| LogPackageLoadingMessage( PACKAGE_DEBUG, | ||||||
| "omitting packages suggested via \"PackagesToLoad\" (-A option)", | ||||||
| "GAP" ); | ||||||
| elif IsBound( GAPInfo.PrescribedPackageVersions ) then | ||||||
| LogPackageLoadingMessage( PACKAGE_DEBUG, | ||||||
| "omitting packages suggested via \"PackagesToLoad\" (PrescribedPackageVersions)", | ||||||
| "GAP" ); | ||||||
| elif ValueOption( "OnlyNeeded" ) = true then | ||||||
| LogPackageLoadingMessage( PACKAGE_DEBUG, | ||||||
| [ "omitting packages suggested via \"PackagesToLoad\"", | ||||||
|
|
@@ -2084,6 +2188,9 @@ InstallGlobalFunction( AutoloadPackages, function() | |||||
| LogPackageLoadingMessage( PACKAGE_DEBUG, | ||||||
| "suggested packages loaded", "GAP" ); | ||||||
| fi; | ||||||
| if IsBound( GAPInfo.PrescribedPackageVersions ) then | ||||||
| PopOptions(); | ||||||
| fi; | ||||||
|
|
||||||
| # Load the documentation for not yet loaded packages. | ||||||
| LogPackageLoadingMessage( PACKAGE_DEBUG, | ||||||
|
|
@@ -3585,3 +3692,79 @@ InstallGlobalFunction( ShowPackageVariables, function( arg ) | |||||
| Print( result ); | ||||||
| fi; | ||||||
| end ); | ||||||
|
|
||||||
|
|
||||||
| ############################################################################# | ||||||
| ## | ||||||
| #F PackagesLoaded() | ||||||
| ## | ||||||
| ## <ManSection> | ||||||
| ## <Func Name="PackagesLoaded" Arg=''/> | ||||||
| ## | ||||||
| ## <Returns> | ||||||
| ## a string that describes the names of all currently loaded &GAP; packages | ||||||
| ## and their version numbers. | ||||||
| ## </Returns> | ||||||
| ## | ||||||
| ## <Description> | ||||||
| ## The result consists of <C>\n</C> separated lines of the form | ||||||
| ## <C>"name", "version"</C> or <C>"name", "version", pos, flag</C>, | ||||||
| ## where <C>name</C> is the lowercase name of a loaded &GAP; package, | ||||||
| ## <C>version</C> is its version number, | ||||||
| ## <C>pos</C>, if given, indicates that this package has been loaded | ||||||
| ## in the <C>pos</C>-th call of <Ref Func="LoadPackage"/>, | ||||||
| ## and <C>flag</C> is <K>false</K> or <K>true</K>, meaning that this package | ||||||
| ## and its indirectly loaded dependencies were loaded including suggested | ||||||
| ## packages or without suggested packages, respectively (the value of the | ||||||
| ## option <C>OnlyNeeded</C> during the <Ref Func="LoadPackage"/> call). | ||||||
| ## <P/> | ||||||
| ## One can print this string to a file and set the user preference | ||||||
| ## <C>"PrescribedPackageVersions"</C> to the name of this file, | ||||||
| ## Then starting &GAP; anew will try to load exactly the same packages, | ||||||
| ## in exactly the same order as in the current session, | ||||||
| ## and signal an error if this is not possible. | ||||||
| ## </Description> | ||||||
| ## </ManSection> | ||||||
| ## | ||||||
| BindGlobal( "PackagesLoaded", function() | ||||||
| local loaded, loadmsg, i, msg, nextmsg, old, l, pos; | ||||||
|
|
||||||
| # the names of the currently loaded packages, and their version numbers | ||||||
| loaded:= List( RecNames( GAPInfo.PackagesLoaded ), | ||||||
| x -> GAPInfo.PackagesLoaded.( x ){ [ 3, 2 ] } ); | ||||||
|
|
||||||
| # the packages for which 'LoadPackage' has been called in the current | ||||||
| # session, in the right order; | ||||||
| # note that there is only one explicit 'LoadPackage' call for each set | ||||||
| # of packages which depend on each other | ||||||
| loadmsg:= []; | ||||||
| for i in [ 1 .. Length( GAPInfo.PackageLoadingMessages ) - 1 ] do | ||||||
| msg:= GAPInfo.PackageLoadingMessages[i]; | ||||||
| nextmsg:= GAPInfo.PackageLoadingMessages[i+1]; | ||||||
| if StartsWith( msg[3][1], "entering LoadPackage" ) and | ||||||
| not StartsWith( nextmsg[3][1], | ||||||
| "return from LoadPackage, package was already loaded" ) then | ||||||
| Add( loadmsg, msg ); | ||||||
| fi; | ||||||
| od; | ||||||
| old:= List( loadmsg, | ||||||
| x -> [ x[1], PositionSublist( x[3][1], | ||||||
| "(omitting suggested packages)" ) <> fail ] ); | ||||||
|
|
||||||
| # store in which order the packages will have to be loaded. | ||||||
| for l in loaded do | ||||||
| pos:= PositionProperty( old, x -> l[1] = x[1] ); | ||||||
| if pos <> fail then | ||||||
| l[3]:= Concatenation( ", ", String( pos ), ", ", | ||||||
| String( old[ pos ][2] ) ); | ||||||
| else | ||||||
| l[3]:= ""; | ||||||
| fi; | ||||||
| od; | ||||||
|
|
||||||
| return JoinStringsWithSeparator( | ||||||
| Set( loaded, | ||||||
| x -> Concatenation( "\"", LowercaseString( x[1] ), | ||||||
| "\", \"", x[2], "\"", x[3] ) ), | ||||||
| "\n" ); | ||||||
| end ); | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.