Skip to content
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

Support several package instances with same version #3668

Merged
merged 2 commits into from
Oct 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 25 additions & 27 deletions lib/package.gd
Original file line number Diff line number Diff line change
Expand Up @@ -538,33 +538,31 @@ DeclareGlobalFunction( "DefaultPackageBannerString" );
##
## <Description>
## <Index Key="GAPInfo.Architecture"><C>GAPInfo.Architecture</C></Index>
## returns a list of the <C>bin/</C><A>architecture</A> subdirectories
## of all packages <A>name</A> where <A>architecture</A> is the architecture
## on which &GAP; has been compiled
## (this can be accessed as <C>GAPInfo.Architecture</C>,
## see <Ref Var="GAPInfo"/>)
## and the version of the installed package coincides with
## the version of the package <A>name</A> that is already loaded
## returns a list that is either empty or contains one directory object
## <C>dir</C>, say, that describes the place where external binaries of the
## &GAP; package <A>name</A> should be located.
## <P/>
## In the latter case,
## <C>dir</C> is the <C>bin/</C><A>architecture</A> subdirectory of a
## directory where the package <A>name</A> is installed,
## where <A>architecture</A> is the architecture on which &GAP; has been
## compiled (this can be accessed as <C>GAPInfo.Architecture</C>,
## see <Ref Var="GAPInfo"/>),
## and where the package directory belongs to the version of <A>name</A>
## that is already loaded
## or is currently going to be loaded
## or would be the first version &GAP; would try to load if no other version
## is explicitly prescribed.
## (If the package <A>name</A> is not yet loaded then we cannot guarantee
## that the returned directories belong to a version that really can be
## loaded.)
## that the directory belongs to a version that really can be loaded.)
## <P/>
## Note that <Ref Func="DirectoriesPackagePrograms"/> is likely to be called
## in the <C>AvailabilityTest</C> function in the package's
## <F>PackageInfo.g</F> file (see <Ref Sect="The PackageInfo.g File"/>).
## <P/>
## The directories returned by <Ref Func="DirectoriesPackagePrograms"/>
## are the place where external binaries of the &GAP; package <A>name</A>
## for the current package version and the current architecture
## should be located.
## <P/>
## <Log><![CDATA[
## gap> DirectoriesPackagePrograms( "nq" );
## [ dir("/home/gap/4.0/pkg/nq/bin/x86_64-unknown-linux-gnu-gcc/64-bit/"),
## dir("/home/gap/4.0/pkg/nq/bin/x86_64-unknown-linux-gnu-gcc/") ]
## [ dir("/home/gap/4.0/pkg/nq/bin/x86_64-pc-linux-gnu-default64-kv3/") ]
## ]]></Log>
## </Description>
## </ManSection>
Expand All @@ -583,21 +581,21 @@ DeclareGlobalFunction( "DirectoriesPackagePrograms" );
##
## <Description>
## takes the string <A>name</A>, a name of a &GAP; package,
## and returns a list of directory objects for those sub-directory/ies
## containing the library functions of this &GAP; package,
## for the version that is already loaded
## and returns a list that is either empty or contains one directory object
## <C>dir</C>, say, that describes the place where the library functions of
## this &GAP; package should be located.
## <P/>
## In the latter case,
## <C>dir</C> is the <A>path</A> subdirectory of a
## directory where the package <A>name</A> is installed,
## where the default for <A>path</A> is <C>"lib"</C>,
## and where the package directory belongs to the version of <A>name</A>
## that is already loaded
## or is currently going to be loaded
## or would be the first version &GAP; would try to load if no other version
## is explicitly prescribed.
## (If the package <A>name</A> is not yet loaded then we cannot guarantee
## that the returned directories belong to a version that really can be
## loaded.)
## <P/>
## The default is that the library functions are in the subdirectory
## <F>lib</F> of the &GAP; package's home directory.
## If this is not the case, then the second argument <A>path</A> needs to be
## present and must be a string that is a path name relative to the home
## directory of the &GAP; package with name <A>name</A>.
## that the directory belongs to a version that really can be loaded.)
## <P/>
## Note that <Ref Func="DirectoriesPackageLibrary"/> is likely to be called
## in the <C>AvailabilityTest</C> function in the package's
Expand Down
121 changes: 58 additions & 63 deletions lib/package.gi
Original file line number Diff line number Diff line change
Expand Up @@ -225,36 +225,30 @@ BindGlobal( "AddPackageInfos", function( files, pkgdir, ignore )
NormalizeWhitespace( pkgname );
version:= record.Version;

# If we have this version already then leave it out.
if ForAll( GAPInfo.PackagesInfo,
r -> r.PackageName <> record.PackageName
or r.Version <> version ) then
fingolfin marked this conversation as resolved.
Show resolved Hide resolved

# Check whether GAP wants to reset loadability.
if IsBound( GAPInfo.PackagesRestrictions.( pkgname ) )
and GAPInfo.PackagesRestrictions.( pkgname ).OnInitialization(
record ) = false then
Add( GAPInfo.PackagesInfoRefuseLoad, record );
elif pkgname in ignore then
LogPackageLoadingMessage( PACKAGE_DEBUG,
Concatenation( "ignore package ", record.PackageName,
" (user preference PackagesToIgnore)" ), "GAP" );
else
record.InstallationPath:= Filename( [ pkgdir ], file[2] );
if not IsBound( record.PackageDoc ) then
record.PackageDoc:= [];
elif IsRecord( record.PackageDoc ) then
record.PackageDoc:= [ record.PackageDoc ];
fi;
if IsHPCGAP then
# FIXME: we make the package info record immutable, to
# allow access from multiple threads; but that in turn
# can break packages, which rely on their package info
# record being readable (see issue #2568)
MakeImmutable(record);
fi;
Add( GAPInfo.PackagesInfo, record );
# Check whether GAP wants to reset loadability.
if IsBound( GAPInfo.PackagesRestrictions.( pkgname ) )
and GAPInfo.PackagesRestrictions.( pkgname ).OnInitialization(
record ) = false then
Add( GAPInfo.PackagesInfoRefuseLoad, record );
elif pkgname in ignore then
LogPackageLoadingMessage( PACKAGE_DEBUG,
Concatenation( "ignore package ", record.PackageName,
" (user preference PackagesToIgnore)" ), "GAP" );
else
record.InstallationPath:= Filename( [ pkgdir ], file[2] );
if not IsBound( record.PackageDoc ) then
record.PackageDoc:= [];
elif IsRecord( record.PackageDoc ) then
record.PackageDoc:= [ record.PackageDoc ];
fi;
if IsHPCGAP then
# FIXME: we make the package info record immutable, to
# allow access from multiple threads; but that in turn
# can break packages, which rely on their package info
# record being readable (see issue #2568)
MakeImmutable(record);
fi;
Add( GAPInfo.PackagesInfo, record );
fi;
fi;
od;
Expand Down Expand Up @@ -330,9 +324,14 @@ InstallGlobalFunction( InitializePackagesInfoRecords, function( arg )
od;

# Sort the available info records by their version numbers.
SortParallel( List( GAPInfo.PackagesInfo, r -> r.Version ),
# (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
# is available in several root paths.
# Note that 'CompareVersionNumbers' returns 'true'
# if the two arguments are equal.)
StableSortParallel( List( GAPInfo.PackagesInfo, r -> r.Version ),
GAPInfo.PackagesInfo,
CompareVersionNumbers );
{ a, b } -> a <> b and CompareVersionNumbers( a, b ) );

# Turn the lists into records.
record:= rec();
Expand Down Expand Up @@ -1190,30 +1189,27 @@ InstallGlobalFunction( DefaultPackageBannerString, function( inforec )
#F DirectoriesPackagePrograms( <name> )
##
InstallGlobalFunction( DirectoriesPackagePrograms, function( name )
local arch, dirs, info, version, r, path;
local info, installationpath;

arch := GAPInfo.Architecture;
dirs := [];
# We are not allowed to call
# `InstalledPackageVersion', `TestPackageAvailability' etc.
info:= PackageInfo( name );
if IsBound( GAPInfo.PackagesLoaded.( name ) ) then
# The package is already loaded.
version:= GAPInfo.PackagesLoaded.( name )[2];
installationpath:= GAPInfo.PackagesLoaded.( name )[1];
elif IsBound( GAPInfo.PackageCurrent ) then
# The package is currently going to be loaded.
version:= GAPInfo.PackageCurrent.Version;
installationpath:= GAPInfo.PackageCurrent.InstallationPath;
elif 0 < Length( info ) then
# Take the installed package with the highest version.
version:= info[1].Version;
# Take the installed package with the highest version
# that has been found first in the root paths.
installationpath:= info[1].InstallationPath;
else
# This package is not known.
return [];
fi;
for r in info do
if r.Version = version then
path:= Concatenation( r.InstallationPath, "/bin/", arch, "/" );
Add( dirs, Directory( path ) );
fi;
od;
return dirs;
return [ Directory( Concatenation( installationpath, "/bin/",
GAPInfo.Architecture, "/" ) ) ];
end );


Expand All @@ -1222,12 +1218,12 @@ end );
#F DirectoriesPackageLibrary( <name>[, <path>] )
##
InstallGlobalFunction( DirectoriesPackageLibrary, function( arg )
local name, path, dirs, info, version, r, tmp;
local name, path, info, installationpath, tmp;

if IsEmpty(arg) or 2 < Length(arg) then
Error( "usage: DirectoriesPackageLibrary( <name>[, <path>] )\n" );
Error( "usage: DirectoriesPackageLibrary( <name>[, <path>] )" );
elif not ForAll(arg, IsString) then
Error( "string argument(s) expected\n" );
Error( "string argument(s) expected" );
fi;

name:= LowercaseString( arg[1] );
Expand All @@ -1239,29 +1235,28 @@ InstallGlobalFunction( DirectoriesPackageLibrary, function( arg )
path := arg[2];
fi;

dirs := [];
# We are not allowed to call
# `InstalledPackageVersion', `TestPackageAvailability' etc.
info:= PackageInfo( name );
if IsBound( GAPInfo.PackagesLoaded.( name ) ) then
# The package is already loaded.
version:= GAPInfo.PackagesLoaded.( name )[2];
installationpath:= GAPInfo.PackagesLoaded.( name )[1];
elif IsBound( GAPInfo.PackageCurrent ) then
# The package is currently going to be loaded.
version:= GAPInfo.PackageCurrent.Version;
installationpath:= GAPInfo.PackageCurrent.InstallationPath;
elif 0 < Length( info ) then
# Take the installed package with the highest version.
version:= info[1].Version;
fi;
for r in info do
if r.Version = version then
tmp:= Concatenation( r.InstallationPath, "/", path );
if IsDirectoryPath( tmp ) = true then
Add( dirs, Directory( tmp ) );
fi;
fi;
od;
return dirs;
# Take the installed package with the highest version
# that has been found first in the root paths.
installationpath:= info[1].InstallationPath;
else
# This package is not known.
return [];
fi;
tmp:= Concatenation( installationpath, "/", path );
if IsDirectoryPath( tmp ) = true then
fingolfin marked this conversation as resolved.
Show resolved Hide resolved
return [ Directory( tmp ) ];
fi;
return [];
end );


Expand Down