Skip to content

Commit

Permalink
Separate distro.* files
Browse files Browse the repository at this point in the history
  • Loading branch information
mtorpey committed Sep 3, 2024
1 parent 0512033 commit 9f2eb84
Show file tree
Hide file tree
Showing 8 changed files with 472 additions and 458 deletions.
43 changes: 0 additions & 43 deletions gap/PackageManager.gd
Original file line number Diff line number Diff line change
Expand Up @@ -122,23 +122,6 @@ DeclareGlobalFunction("UpdatePackage");
DeclareInfoClass("InfoPackageManager");
SetInfoLevel(InfoPackageManager, 3);

#! @Description
#! Attempts to download and install a package given only its name. Returns
#! <K>false</K> if something went wrong, and <K>true</K> otherwise.
#!
#! Certain decisions, such as installing newer versions of packages, will be
#! confirmed by the user via an interactive shell &ndash; to avoid this
#! interactivity and use sane defaults instead, the optional argument
#! <A>interactive</A> can be set to <K>false</K>.
#!
#! A required version can also be specified using the optional argument
#! <A>version</A>. It works as described in the <Ref Func="InstallPackage" />
#! function.
#! @Arguments name[, version][, interactive]
#! @Returns
#! <K>true</K> or <K>false</K>
DeclareGlobalFunction("InstallPackageFromName");

#! @Description
#! Attempts to download and install a package from a valid `PackageInfo.g`
#! file. The argument <A>info</A> should be either a valid package info
Expand All @@ -158,24 +141,6 @@ DeclareGlobalFunction("InstallPackageFromInfo");
#! <K>true</K> or <K>false</K>
DeclareGlobalFunction("InstallPackageFromArchive");

#! @Description
#! Attempts to download and install the latest versions of all packages
#! required for &GAP; to run. Currently these packages are
#! <Package>GAPDoc</Package>, <Package>primgrp</Package>,
#! <Package>SmallGrp</Package>, and <Package>transgrp</Package>.
#! Returns <K>false</K> if something went wrong, and
#! <K>true</K> otherwise.
#!
#! Clearly, since these packages are required for &GAP; to run, they must be
#! loaded before this function can be executed. However, this function
#! installs the packages in the `~/.gap/pkg` directory, so that they can be
#! managed by <Package>PackageManager</Package> in the future, and are
#! available for other &GAP; installations on the machine.
#! @Arguments
#! @Returns
#! <K>true</K> or <K>false</K>
DeclareGlobalFunction("InstallRequiredPackages");

#! @Section Removing packages

#! @Description
Expand All @@ -201,10 +166,7 @@ DeclareGlobalFunction("InstallRequiredPackages");
#! <K>true</K> or <K>false</K>
DeclareGlobalFunction("RemovePackage");

DeclareGlobalFunction("GetPackageURLs");

# Hidden functions
DeclareGlobalFunction("PKGMAN_InstallDependencies");
DeclareGlobalFunction("PKGMAN_CheckPackage");
DeclareGlobalFunction("PKGMAN_Exec");
DeclareGlobalFunction("PKGMAN_PackageDir");
Expand All @@ -221,18 +183,13 @@ DeclareGlobalFunction("PKGMAN_InfoWithIndent");

# Hidden variables
PKGMAN_CustomPackageDir := "";
PKGMAN_PackageInfoURLList :=
Concatenation("https://github.com/gap-system/PackageDistro/",
"releases/download/latest/pkglist.csv");
PKGMAN_ArchiveFormats := [".tar.gz", ".tar.bz2"];
PKGMAN_DownloadCmds := [ [ "wget", ["--quiet", "-O", "-"] ],
[ "curl", ["--silent", "-L", "--output", "-"] ] ];
PKGMAN_CurlIntReqVer :=
First(PackageInfo("PackageManager")[1].Dependencies.SuggestedOtherPackages,
item -> item[1] = "curlInterface")[2];
PKGMAN_Sysinfo := Filename(DirectoriesLibrary(""), "sysinfo.gap");
PKGMAN_InstallQueue := []; # Queue of dependencies to install
PKGMAN_MarkedForInstall := []; # Packages currently halfway through installing

# PackageInfo must at least contain the following to pass:
PKGMAN_RequiredPackageInfoFields := ["PackageName",
Expand Down
253 changes: 0 additions & 253 deletions gap/PackageManager.gi
Original file line number Diff line number Diff line change
Expand Up @@ -25,37 +25,6 @@ if not IsBound(ChangeDirectoryCurrent) then
end;
fi;

InstallGlobalFunction(GetPackageURLs,
function()
local get, urls, line, items;
# Get PackageInfo URLs from configurable list
get := PKGMAN_DownloadURL(PKGMAN_PackageInfoURLList);
urls := rec(success := false);
if not get.success then
Info(InfoPackageManager, 1,
"PackageManager: GetPackageURLs: could not contact server");
return urls;
fi;
for line in SplitString(get.result, "\n") do
# Format: <name> [MOVE] <URL>
items := SplitString(line, "", PKGMAN_WHITESPACE);
if Length(items) = 0 or items[1][1] = '#' then
continue;
elif Length(items) = 1 or Length(items) > 3
or (Length(items) = 3 and items[2] <> "MOVE") then
if Length(line) > 74 then # don't show too much
line := Concatenation(line{[1..71]}, "...");
fi;
Info(InfoPackageManager, 1,
"PackageManager: GetPackageURLs: bad line:\n#I ", line);
return urls;
fi;
urls.(LowercaseString(items[1])) := items[Length(items)];
od;
urls.success := true;
return urls;
end);

InstallGlobalFunction(InstallPackage,
function(string, args...)
local version, interactive;
Expand Down Expand Up @@ -98,117 +67,6 @@ function(string, args...)
return InstallPackageFromName(string, version, interactive);
end);

InstallGlobalFunction(InstallPackageFromName,
function(name, args...)
local version, interactive, urls, allinfo, info, current, dirs, vc, q, newest;

# Handle version condition and interactivity
version := true;
interactive := true;
if not IsString(name) then
ErrorNoReturn("PackageManager: InstallPackageFromName: ",
"<name> must be a string");
elif Length(args) > 2 then
ErrorNoReturn("PackageManager: InstallPackageFromName: ",
"requires 1 to 3 arguments (not ",
Length(args) + 1, ")");
elif Length(args) = 1 then
if IsString(args[1]) then
version := args[1];
elif args[1] = true or args[1] = false then
interactive := args[1];
else
ErrorNoReturn("PackageManager: InstallPackageFromName:\n",
"2nd argument must be true or false or a version string");
fi;
elif Length(args) = 2 then
version := args[1];
interactive := args[2];
fi;

# Check arguments
if not (IsString(version) or version = true) then
ErrorNoReturn("PackageManager: InstallPackageFromName:\n",
"if specified, <version> must be a version string");
elif not (interactive = true or interactive = false) then
ErrorNoReturn("PackageManager: InstallPackageFromName:\n",
"if specified, <interactive> must be true or false");
fi;

# Get package URL from name
name := LowercaseString(name);
Info(InfoPackageManager, 3, "Getting PackageInfo URLs...");
urls := GetPackageURLs();
if urls.success = false then
# An info message has already been printed.
return false;
elif not IsBound(urls.(name)) then
Info(InfoPackageManager, 1,
"Package \"", name, "\" not found in package list");
return false;
fi;

# Check for already-installed versions
allinfo := PackageInfo(name);
info := Filtered(allinfo,
x -> StartsWith(x.InstallationPath, PKGMAN_PackageDir()));
if not IsEmpty(info) then # Already installed
# Does the installed version already satisfy the prescribed version?
current := info[1]; # Highest-priority installation in user pkg directory
if version <> true and
CompareVersionNumbers(current.Version, version) then
Info(InfoPackageManager, 2, "Version ", current.Version,
" of package \"", name, "\" is already installed");
return PKGMAN_CheckPackage(current.InstallationPath);
fi;

# Any VC installations?
# (This step is not relevant in case of a prescribed version number.)
dirs := List(info, i -> ShallowCopy(i.InstallationPath));
for vc in ["git", "hg"] do
if Filename(List(dirs, Directory), Concatenation(".", vc)) <> fail then
q := Concatenation("Package \"", name, "\" already installed via ", vc,
". Update it?");
if interactive and PKGMAN_AskYesNoQuestion(q : default := false) then
return UpdatePackage(name, interactive);
fi;
fi;
od;

# Installed by archive only
newest := PKGMAN_DownloadPackageInfo(urls.(name));
if version <> true then
# Update or give up, but do not ask questions.
if CompareVersionNumbers( newest.Version, version ) then
# Updating to the newest version will satisfy the version condition.
return UpdatePackage(name, interactive);
else
Info(InfoPackageManager, 1, "Version \"", version, "\" of package \"",
name, "\" cannot be satisfied");
Info(InfoPackageManager, 2,
"The newest version available is ", newest.Version);
return false;
fi;
elif CompareVersionNumbers(newest.Version, current.Version, "equal") then
Info(InfoPackageManager, 2, "The newest version of package \"", name,
"\" is already installed");
return PKGMAN_CheckPackage(current.InstallationPath);
elif CompareVersionNumbers(newest.Version, current.Version) then
q := Concatenation("Package \"", name, "\" version ", current.Version,
" is installed, but ", newest.Version,
" is available. Install it?");
if interactive and PKGMAN_AskYesNoQuestion(q : default := false) then
return UpdatePackage(name, interactive);
else
return PKGMAN_CheckPackage(current.InstallationPath);
fi;
fi;
fi;

# Not installed yet
return InstallPackageFromInfo(urls.(name), version);
end);

InstallGlobalFunction(InstallPackageFromInfo,
function(info, version...)
local formats, format, url;
Expand Down Expand Up @@ -363,117 +221,6 @@ function(dir_or_stream)
return GAPInfo.PackageInfoCurrent;
end);

InstallGlobalFunction(PKGMAN_InstallDependencies,
function(dir)
local info, deps, to_install, dep, got, info_urls, dep_infos, current,
dep_info, i;
info := PKGMAN_GetPackageInfo(dir);
if IsBound(info.Dependencies) then
deps := info.Dependencies.NeededOtherPackages;
else
deps := [];
fi;
if IsEmpty(deps) then
return true;
fi;
# Mark this package as installing in case of circular dependencies
Add(PKGMAN_MarkedForInstall,
[LowercaseString(info.PackageName), info.Version]);
to_install := [];
Info(InfoPackageManager, 3,
"Checking dependencies for ", info.PackageName, "...");
for dep in deps do
# Do we already have it?
got := TestPackageAvailability(dep[1], dep[2]) <> fail or
PositionProperty(PKGMAN_MarkedForInstall,
x -> x[1] = dep[1]
and CompareVersionNumbers(x[2], dep[2]))
<> fail;
Info(InfoPackageManager, 3, " ", dep[1], " ", dep[2], ": ", got);
if not got then
Add(to_install, dep);
fi;
od;

info_urls := GetPackageURLs();
if info_urls.success = false then
# An info message has already been printed.
return false;
fi;
dep_infos := [];
for dep in to_install do
# Already installed, but needs recompiling?
current := Filtered(PackageInfo(dep[1]),
x -> StartsWith(x.InstallationPath,
PKGMAN_PackageDir()));
if not IsEmpty(current) then
current := current[1];
if CompareVersionNumbers(current.Version, dep[2]) then
Info(InfoPackageManager, 3, dep[1], "-", current.Version,
" installed but not loadable: trying to fix...");
if PKGMAN_CheckPackage(current.InstallationPath) then
continue; # package fixed!
fi;
fi;
fi;

# Otherwise, prepare to install a fresh version
if not IsBound(info_urls.(LowercaseString(dep[1]))) then
Info(InfoPackageManager, 1, "Required package ", dep[1], " unknown");
PKGMAN_InstallQueue := [];
PKGMAN_MarkedForInstall := [];
return false;
fi;
dep_info := PKGMAN_DownloadPackageInfo(info_urls.(LowercaseString(dep[1])));
if not CompareVersionNumbers(dep_info.Version, dep[2]) then
Info(InfoPackageManager, 1, "Package ", dep[1], " ", dep[2],
" unavailable: only version ", dep_info.Version, " was found");
PKGMAN_InstallQueue := [];
PKGMAN_MarkedForInstall := [];
return false;
fi;
Add(dep_infos, dep_info);

# If this is already marked for install later, unmark it
for i in [1 .. Length(PKGMAN_InstallQueue)] do
if PKGMAN_InstallQueue[i].PackageName = dep_info.PackageName
and PKGMAN_InstallQueue[i].Version = dep_info.Version then
Remove(PKGMAN_InstallQueue, i);
break;
fi;
od;
od;

# Add these new dependencies at the front of the queue
PKGMAN_InstallQueue := Concatenation(dep_infos, PKGMAN_InstallQueue);

# Do the installations (the whole global queue)
while not IsEmpty(PKGMAN_InstallQueue) do
dep_info := Remove(PKGMAN_InstallQueue, 1);
Info(InfoPackageManager, 3, "Installing dependency ",
dep_info.PackageName, " ", dep_info.Version, " ...");
if InstallPackageFromInfo(dep_info) <> true then
PKGMAN_InstallQueue := [];
PKGMAN_MarkedForInstall := [];
return false;
fi;
od;
PKGMAN_RefreshPackageInfo();
Remove(PKGMAN_MarkedForInstall); # this package
return true;
end);

InstallGlobalFunction(InstallRequiredPackages,
function()
local pkg;
for pkg in List(GAPInfo.Dependencies.NeededOtherPackages, l -> l[1]) do
if not InstallPackageFromName(pkg) then
return false;
fi;
od;
return true;
end);

InstallGlobalFunction(RemovePackage,
function(name, interactive...)
local user_pkg_dir, allinfo, info, dir;
Expand Down
Loading

0 comments on commit 9f2eb84

Please sign in to comment.