Skip to content

Commit c94a364

Browse files
committed
Improve IsPackageLoaded
First off, it now aborts immediately if the package is not loaded, and doesn't call the package's `AvailabilityTest` function (fixes #2862). This was achieved by not using `TestPackageAvailability` anymore, but rather `IsPackageMarkedForLoading`. The main difference to the latter now is this: We now record whether a package fully completed loading (in particular, we record whether its `init.g` and `read.g` executed without an error). This information is then used by `IsPackageLoaded` after `IsPackageMarkedForLoading` returned `true`, to determine the final result.
1 parent aff1860 commit c94a364

File tree

4 files changed

+112
-17
lines changed

4 files changed

+112
-17
lines changed

lib/package.gd

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@
4343
## <Ref Var="GAPInfo.PackagesLoaded"/> is a mutable record,
4444
## its component names are the names of those &GAP; packages that are
4545
## already loaded.
46-
## The component for each package is a list of length three, the entries
46+
## The component for each package is a list of length four, the entries
4747
## being the path to the &GAP; root directory that contains the package,
48-
## the package version, and the package name.
48+
## the package version, the package name, and a boolean indicating whether
49+
## the package finished loading.
4950
## For each package, the value gets bound in the <Ref Func="LoadPackage"/>
5051
## call.
5152
## <P/>
@@ -353,16 +354,22 @@ DeclareGlobalFunction( "TestPackageAvailability" );
353354

354355
#############################################################################
355356
##
356-
#F IsPackageLoaded( <name>[, <version>][, <checkall>] )
357+
#F IsPackageLoaded( <name>[, <version>] )
357358
##
358359
## <#GAPDoc Label="IsPackageLoaded">
359360
## <ManSection>
360-
## <Func Name="IsPackageLoaded" Arg='name[, version][, checkall]'/>
361+
## <Func Name="IsPackageLoaded" Arg='name[, version]'/>
361362
##
362363
## <Description>
363-
## This function return <K>true</K> if the given package is loaded, and
364-
## <K>false</K> otherwise. For details on the meaning of the arguments,
365-
## see <Ref Func="TestPackageAvailability"/>.
364+
## For strings <A>name</A> and <A>version</A>, this function tests
365+
## whether the &GAP; package <A>name</A> is already loaded in a
366+
## version that is at least <A>version</A>, or equal to <A>version</A>
367+
## if the first character of <A>version</A> is <C>=</C>
368+
## (see <Ref Func="CompareVersionNumbers"/> for further
369+
## details about version numbers).
370+
## <P/>
371+
## The result is <K>true</K> if the package is already loaded,
372+
## <K>false</K> otherwise.
366373
## </Description>
367374
## </ManSection>
368375
## <#/GAPDoc>

lib/package.gi

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -888,7 +888,7 @@ InstallGlobalFunction( PackageAvailabilityInfo,
888888
record.InstallationPaths:= record_local.InstallationPaths;
889889
Add( record.InstallationPaths,
890890
[ name, [ inforec.InstallationPath, inforec.Version,
891-
inforec.PackageName ] ] );
891+
inforec.PackageName, false ] ] );
892892
record.Dependencies:= record_local.Dependencies;
893893
record.StrongDependencies:= record_local.StrongDependencies;
894894
record.AlreadyHandled:= record_local.AlreadyHandled;
@@ -1005,13 +1005,20 @@ InstallGlobalFunction( TestPackageAvailability, function( arg )
10051005

10061006
#############################################################################
10071007
##
1008-
#F IsPackageLoaded( <name>[, <version>][, <checkall>] )
1008+
#F IsPackageLoaded( <name>[, <version>] )
10091009
##
1010-
InstallGlobalFunction( IsPackageLoaded, function( arg )
1010+
InstallGlobalFunction( IsPackageLoaded, function( name, version... )
10111011
local result;
10121012

1013-
result := CallFuncList( TestPackageAvailability, arg );
1014-
return result = true;
1013+
if Length(version) > 0 then
1014+
version := version[1];
1015+
fi;
1016+
result := IsPackageMarkedForLoading( name, version );
1017+
if result then
1018+
# check if the package actually completed loading
1019+
result := GAPInfo.PackagesLoaded.( name )[4];
1020+
fi;
1021+
return result;
10151022
end );
10161023

10171024

@@ -1319,10 +1326,10 @@ BindGlobal( "LoadPackage_ReadImplementationParts",
13191326
local pair, info, bannerstring, fun, u, pkgname, namespace;
13201327

13211328
for pair in secondrun do
1329+
namespace := pair[1].PackageName;
1330+
pkgname := LowercaseString( namespace );
13221331
if pair[2] <> fail then
13231332
GAPInfo.PackageCurrent:= pair[1];
1324-
namespace := pair[1].PackageName;
1325-
pkgname := LowercaseString( namespace );
13261333
LogPackageLoadingMessage( PACKAGE_DEBUG,
13271334
"start reading file 'read.g'",
13281335
namespace );
@@ -1334,6 +1341,9 @@ BindGlobal( "LoadPackage_ReadImplementationParts",
13341341
"finish reading file 'read.g'",
13351342
namespace );
13361343
fi;
1344+
# mark the package as completely loaded
1345+
GAPInfo.PackagesLoaded.(pkgname)[4] := true;
1346+
MakeImmutable( GAPInfo.PackagesLoaded.(pkgname) );
13371347
od;
13381348

13391349
# Show the banners.
@@ -1560,7 +1570,8 @@ InstallGlobalFunction( LoadPackage, function( arg )
15601570
# inside the package code causes the files to be read more than once.
15611571
for pkgname in cycle do
15621572
pos:= PositionSorted( paths[1], pkgname );
1563-
GAPInfo.PackagesLoaded.( pkgname ):= MakeImmutable(paths[2][ pos ]);
1573+
# the following entry is made immutable in LoadPackage_ReadImplementationParts
1574+
GAPInfo.PackagesLoaded.( pkgname ):= paths[2][ pos ];
15641575
od;
15651576

15661577
# If the weight is 1 and the GAP library is not yet loaded

tst/mockpkg/PackageInfo.g

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,10 @@ Dependencies := rec(
8585
ExternalConditions := [ ],
8686
),
8787

88-
AvailabilityTest := ReturnTrue,
88+
AvailabilityTest := function()
89+
Print("oops, should not print here\n");
90+
return true;
91+
end,
8992

9093
# use an empty banner string, so that we get identical output regardless
9194
# of whether GAP is started with -q or -b, or not.

tst/testinstall/package.tst

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,47 @@ true
182182

183183
#
184184
# Deal with mock package
185+
#
186+
187+
# first, force "unload" it (this is a very bad idea in general,
188+
# but for this mock package, it is OK because we control everything)
189+
gap> Unbind(GAPInfo.PackagesInfo.mockpkg);
190+
gap> Unbind(GAPInfo.PackagesLoaded.mockpkg);
191+
gap> for n in [ "mockpkg_GlobalFunction", "mockpkg_Operation", "mockpkg_Attribute", "mockpkg_Property" ] do
192+
> if IsBoundGlobal(n) then
193+
> MakeReadWriteGlobal(n);
194+
> UnbindGlobal(n);
195+
> fi;
196+
> od;
197+
198+
#
199+
gap> TestPackageAvailability("non-existing-package");
200+
fail
201+
gap> TestPackageAvailability("mockpkg");
202+
fail
203+
gap> TestPackageAvailability("mockpkg", "=0.1");
204+
fail
205+
gap> TestPackageAvailability("mockpkg", ">=0.1");
206+
fail
207+
gap> TestPackageAvailability("mockpkg", "=2.0");
208+
fail
209+
gap> TestPackageAvailability("mockpkg", ">=2.0");
210+
fail
211+
212+
#
213+
gap> IsPackageLoaded("non-existing-package");
214+
false
215+
gap> IsPackageLoaded("mockpkg");
216+
false
217+
gap> IsPackageLoaded("mockpkg", "=0.1");
218+
false
219+
gap> IsPackageLoaded("mockpkg", ">=0.1");
220+
false
221+
gap> IsPackageLoaded("mockpkg", "=2.0");
222+
false
223+
gap> IsPackageLoaded("mockpkg", ">=2.0");
224+
false
225+
185226
#
186227
gap> mockpkgpath := DirectoriesLibrary("tst/mockpkg")[1];;
187228
gap> ValidatePackageInfo(Filename(mockpkgpath, "PackageInfo.g"));
@@ -196,12 +237,45 @@ gap> GetPackageNameForPrefix("mock");
196237
# point GAP at mockpkg
197238
gap> SetPackagePath("mockpkg", mockpkgpath);
198239

199-
# ... now it "knows" it
240+
# ... now GAP "knows" the package
200241
gap> GetPackageNameForPrefix("mock");
201242
"mockpkg"
202243

244+
#
245+
gap> TestPackageAvailability("non-existing-package");
246+
fail
247+
gap> TestPackageAvailability("mockpkg") = Filename(mockpkgpath, "");
248+
oops, should not print here
249+
true
250+
gap> TestPackageAvailability("mockpkg", "=0.1") = Filename(mockpkgpath, "");
251+
oops, should not print here
252+
true
253+
gap> TestPackageAvailability("mockpkg", ">=0.1") = Filename(mockpkgpath, "");
254+
oops, should not print here
255+
true
256+
gap> TestPackageAvailability("mockpkg", "=2.0");
257+
fail
258+
gap> TestPackageAvailability("mockpkg", ">=2.0");
259+
fail
260+
261+
#
262+
gap> IsPackageLoaded("non-existing-package");
263+
false
264+
gap> IsPackageLoaded("mockpkg");
265+
false
266+
gap> IsPackageLoaded("mockpkg", "=0.1");
267+
false
268+
gap> IsPackageLoaded("mockpkg", ">=0.1");
269+
false
270+
gap> IsPackageLoaded("mockpkg", "=2.0");
271+
false
272+
gap> IsPackageLoaded("mockpkg", ">=2.0");
273+
false
274+
203275
# instruct GAP to load the package, and record all its declarations
204276
gap> PackageVariablesInfo("mockpkg", "0.1");;
277+
oops, should not print here
278+
oops, should not print here
205279
gap> ShowPackageVariables("mockpkg");
206280
new global functions:
207281
mockpkg_GlobalFunction( )*

0 commit comments

Comments
 (0)