diff --git a/lib/package.gi b/lib/package.gi index b6998c00f9..5ed19406dd 100644 --- a/lib/package.gi +++ b/lib/package.gi @@ -304,7 +304,7 @@ InstallGlobalFunction( InitializePackagesInfoRecords, function( arg ) # the first time this is called, add the cmd line args to the list if IsEmpty(GAPInfo.PackageDirectories) then for pkgdirstrs in GAPInfo.CommandLineOptions.packagedirs do - pkgdirs:= List( SplitString( pkgdirstrs, ";" ), Directory ); + pkgdirs:= List( List( SplitString( pkgdirstrs, ";" ), GAP_realpath ), Directory ); for pkgdir in pkgdirs do if not pkgdir in GAPInfo.PackageDirectories then Add( GAPInfo.PackageDirectories, pkgdir ); @@ -1858,14 +1858,15 @@ InstallGlobalFunction( SetPackagePath, function( pkgname, pkgpath ) InstallGlobalFunction( ExtendRootDirectories, function( rootpaths ) local i; + rootpaths:= List( rootpaths, GAP_realpath ); + # 'DirectoriesLibrary' concatenates root paths with directory names. + for i in [ 1 .. Length( rootpaths ) ] do + if not EndsWith( rootpaths[i], "/" ) then + rootpaths[i]:= Concatenation( rootpaths[i], "/" ); + fi; + od; rootpaths:= Filtered( rootpaths, path -> not path in GAPInfo.RootPaths ); if not IsEmpty( rootpaths ) then - # 'DirectoriesLibrary' concatenates root paths with directory names. - for i in [ 1 .. Length( rootpaths ) ] do - if not EndsWith( rootpaths[i], "/" ) then - rootpaths[i]:= Concatenation( rootpaths[i], "/" ); - fi; - od; # Append the new root paths. GAPInfo.RootPaths:= Immutable( Concatenation( GAPInfo.RootPaths, rootpaths ) ); @@ -1889,11 +1890,12 @@ InstallGlobalFunction( ExtendPackageDirectories, function( paths_or_dirs ) local p, changed; changed:= false; for p in paths_or_dirs do - if IsString( p ) then - p:= Directory( p ); - elif not IsDirectory( p ) then + if IsDirectory( p ) then + p:= Filename( p, "" ); + elif not IsString( p ) then Error("input must be a list of path strings or directory objects"); fi; + p:= Directory( GAP_realpath( p ) ); if not p in GAPInfo.PackageDirectories then Add( GAPInfo.PackageDirectories, p ); changed:= true; diff --git a/src/streams.c b/src/streams.c index db5a23a2ac..48e2f5e8dc 100644 --- a/src/streams.c +++ b/src/streams.c @@ -1163,11 +1163,7 @@ static Obj FuncGAP_realpath(Obj self, Obj path) RequireStringRep(SELF_NAME, path); char resolved_path[GAP_PATH_MAX]; -#ifdef SYS_IS_MINGW - if (NULL == _fullpath(resolved_path, CONST_CSTR_STRING(path), sizeof(resolved_path))) { -#else - if (NULL == realpath(CONST_CSTR_STRING(path), resolved_path)) { -#endif + if (NULL == SyRealpath(CONST_CSTR_STRING(path), resolved_path)) { SySetErrorNo(); return Fail; } diff --git a/src/sysfiles.c b/src/sysfiles.c index b4c0221de7..1187e4b0ff 100644 --- a/src/sysfiles.c +++ b/src/sysfiles.c @@ -2912,6 +2912,20 @@ Int SyIsExistingFile ( const Char * name ) return res; } +/**************************************************************************** +** +*F SyRealpath( , ) . . . . . . . . . absolute canonical path +*/ +Char * SyRealpath(const Char * path, Char * buf) +{ +#ifdef SYS_IS_MINGW + return _fullpath(buf, path, GAP_PATH_MAX); +#else + return realpath(path, buf); +#endif +} + + /**************************************************************************** ** *F SyIsReadableFile( ) . . . . . . . . . . . is file readable diff --git a/src/sysfiles.h b/src/sysfiles.h index bca4cba689..3913a106da 100644 --- a/src/sysfiles.h +++ b/src/sysfiles.h @@ -350,6 +350,18 @@ void SySetErrorNo(void); Int SyIsExistingFile(const Char * name); +/**************************************************************************** +** +*F SyRealpath( , ) . . . . . . . . . absolute canonical path +** +** 'SyRealpath' stores the absolute path of with all symlinks +** resolved in , which must have room for 'GAP_PATH_MAX' characters, +** and returns . On failure, e.g. if does not exist, it returns +** NULL and sets 'errno'. +*/ +Char * SyRealpath(const Char * path, Char * buf); + + /**************************************************************************** ** *F SyIsReadableFile( ) . . . . . . . . . . . is file readable diff --git a/src/sysroots.c b/src/sysroots.c index 8b83b97902..39af197ab1 100644 --- a/src/sysroots.c +++ b/src/sysroots.c @@ -203,17 +203,27 @@ void SySetGapRootPath(const Char * string) // TODO; instead of iterating over all entries each time, just // do this for the new entries char * userhome = getenv("HOME"); - if (!userhome || !*userhome) - return; - const UInt userhomelen = strlen(userhome); + if (userhome && *userhome) { + const UInt userhomelen = strlen(userhome); + for (i = 0; i < MAX_GAP_DIRS && SyGapRootPaths[i][0]; i++) { + const UInt pathlen = strlen(SyGapRootPaths[i]); + if (SyGapRootPaths[i][0] == '~' && + userhomelen + pathlen < sizeof(SyGapRootPaths[i])) { + SyMemmove(SyGapRootPaths[i] + userhomelen, + // don't copy the ~ but the trailing '\0' + SyGapRootPaths[i] + 1, pathlen); + memcpy(SyGapRootPaths[i], userhome, userhomelen); + } + } + } + + // make all paths absolute; paths that do not exist are left as is for (i = 0; i < MAX_GAP_DIRS && SyGapRootPaths[i][0]; i++) { - const UInt pathlen = strlen(SyGapRootPaths[i]); - if (SyGapRootPaths[i][0] == '~' && - userhomelen + pathlen < sizeof(SyGapRootPaths[i])) { - SyMemmove(SyGapRootPaths[i] + userhomelen, - // don't copy the ~ but the trailing '\0' - SyGapRootPaths[i] + 1, pathlen); - memcpy(SyGapRootPaths[i], userhome, userhomelen); + char buf[GAP_PATH_MAX]; + if (SyRealpath(SyGapRootPaths[i], buf)) { + strxcpy(SyGapRootPaths[i], buf, sizeof(SyGapRootPaths[i])); + if (SyGapRootPaths[i][strlen(SyGapRootPaths[i]) - 1] != '/') + strxcat(SyGapRootPaths[i], "/", sizeof(SyGapRootPaths[i])); } } } diff --git a/src/sysroots.h b/src/sysroots.h index 4b9dfde11f..ecf83d54c1 100644 --- a/src/sysroots.h +++ b/src/sysroots.h @@ -49,7 +49,7 @@ void SySetGapRootPath(const Char * string); ** ** must point to a buffer of at least characters. This function ** then searches for a readable file with the name in the system -** area. If sich a file is found then its absolute path is copied into +** area. If such a file is found then its absolute path is copied into ** , and is returned. If no file is found or if is not big ** enough, then is set to an empty string and NULL is returned. */ diff --git a/tst/testinstall/package.tst b/tst/testinstall/package.tst index a2577c2519..10a1194161 100644 --- a/tst/testinstall/package.tst +++ b/tst/testinstall/package.tst @@ -690,6 +690,18 @@ gap> Last( GAPInfo.PackagesInfo.mockpkg ).InstallationPath = > GAPInfo.PackagesLoaded.mockpkg[1]; true +# paths are made absolute, so equivalent paths are not added again +gap> n:= Length( GAPInfo.PackageDirectories );; +gap> ExtendPackageDirectories( [ Concatenation( Filename( mockpkgpath, "" ), +> "../mockpkg" ) ] ); +gap> Length( GAPInfo.PackageDirectories ) = n; +true +gap> n:= Length( GAPInfo.RootPaths );; +gap> ExtendRootDirectories( List( Filtered( GAPInfo.RootPaths, IsDirectoryPath ), +> path -> Concatenation( path, "./" ) ) ); +gap> Length( GAPInfo.RootPaths ) = n; +true + # gap> SetPackagePath( "mockpkg", Filename( mockpkgpath, "" ) ); gap> SetPackagePath( "mockpkg", "/some/other/directory" );