diff --git a/gap/directories.gd b/gap/directories.gd index b2db6f0..e576570 100644 --- a/gap/directories.gd +++ b/gap/directories.gd @@ -1,4 +1,5 @@ DeclareGlobalFunction("PKGMAN_PackageDir"); +DeclareGlobalFunction("PKGMAN_RealPath"); DeclareGlobalFunction("PKGMAN_SetCustomPackageDir"); DeclareGlobalFunction("PKGMAN_CreateDirRecursively"); DeclareGlobalFunction("PKGMAN_InsertPackageDirectory"); diff --git a/gap/directories.gi b/gap/directories.gi index 782c8e0..be3e1d6 100644 --- a/gap/directories.gi +++ b/gap/directories.gi @@ -16,6 +16,22 @@ function() return dir; end); +# Resolve symlinks in where GAP supports it (4.15 or newer), else +# return unchanged. GAP 4.17 and newer store root and package +# directories with symlinks resolved (gap-system/gap#5930), so paths must be +# compared in this form (e.g. /var is /private/var on macOS). +InstallGlobalFunction(PKGMAN_RealPath, +function(path) + local res; + if IsBound(GAP_realpath) then + res := GAP_realpath(path); + if res <> fail then + return res; + fi; + fi; + return path; +end); + InstallGlobalFunction(PKGMAN_SetCustomPackageDir, function(dir) # Set the variable @@ -120,8 +136,11 @@ end); InstallGlobalFunction(PKGMAN_RemoveDir, function(dir) + local realdir, pkgdir; + realdir := PKGMAN_RealPath(dir); + pkgdir := PKGMAN_RealPath(PKGMAN_PackageDir()); # this 'if' statement is a paranoid check - it should always be true - if StartsWith(dir, PKGMAN_PackageDir()) and dir <> PKGMAN_PackageDir() then + if StartsWith(realdir, pkgdir) and realdir <> pkgdir then RemoveDirectoryRecursively(dir); Info(InfoPackageManager, 2, "Removed directory ", dir); PKGMAN_RefreshPackageInfo(); diff --git a/gap/packageinfo.gi b/gap/packageinfo.gi index dc5a106..7be724b 100644 --- a/gap/packageinfo.gi +++ b/gap/packageinfo.gi @@ -86,9 +86,10 @@ InstallGlobalFunction(PKGMAN_UserPackageInfo, function(name) local user_pkg_dir, allinfo, userinfo; - user_pkg_dir := PKGMAN_PackageDir(); + user_pkg_dir := PKGMAN_RealPath(PKGMAN_PackageDir()); allinfo := PackageInfo(name); - userinfo := Filtered(allinfo, i -> StartsWith(i.InstallationPath, user_pkg_dir)); + userinfo := Filtered(allinfo, + i -> StartsWith(PKGMAN_RealPath(i.InstallationPath), user_pkg_dir)); # Package not found if ValueOption("warnIfNone") = true and Length(userinfo) = 0 then diff --git a/tst/symlink.tst b/tst/symlink.tst new file mode 100644 index 0000000..cf2a10d --- /dev/null +++ b/tst/symlink.tst @@ -0,0 +1,19 @@ +# If the user package directory is given through a symlink, it must still +# match the resolved path GAP 4.17 and newer store (gap-system/gap#5930). +gap> olddir := PKGMAN_CustomPackageDir;; +gap> tmp := DirectoryTemporary();; +gap> CreateDir(Filename(tmp, "real")); +true +gap> PKGMAN_Exec(Filename(tmp, ""), "ln", "-s", "real", "link"); +rec( code := 0, output := "" ) +gap> PKGMAN_Exec(Filename(tmp, ""), "cp", "-r", +> Filename(DirectoriesPackageLibrary("PackageManager", "tst/data/new"), "pmdummy"), +> "real/"); +rec( code := 0, output := "" ) +gap> PKGMAN_InsertPackageDirectory(Filename(tmp, "real"));; +gap> PKGMAN_CustomPackageDir := Filename(tmp, "link");; +gap> Length(PKGMAN_UserPackageInfo("pmdummy")); +1 +gap> RemovePackage("pmdummy", false); +true +gap> PKGMAN_CustomPackageDir := olddir;; diff --git a/tst/testall.g b/tst/testall.g index c99cea9..79a95c4 100644 --- a/tst/testall.g +++ b/tst/testall.g @@ -26,6 +26,9 @@ fi; if not CompareVersionNumbers(version, ">=4.14") then Add(PKGMAN_ExcludeTestFiles, "RecentGapOnly.tst"); fi; +if not CompareVersionNumbers(version, ">=4.15") then + Add(PKGMAN_ExcludeTestFiles, "symlink.tst"); # needs GAP_realpath +fi; # Run tests TestDirectory(DirectoriesPackageLibrary("PackageManager", "tst"),