Skip to content

WIP: Handle symbolic links

Elias Pipping requested to merge epipping/asdf:handle-symbolic-links into master

Bug 1205653 and Bug 1205555 are just the tip of the iceberg. The behaviour of uiop:directory-files and uiop:subdirectories is unfortunately very far from consistent. Whether a symlink in ~/common-lisp/asdf is picked up by cl-launch e.g. is equally inconsistent and potentially related.

So far, I've gotten subdirectories into a state where it always resolves symlinks and gives me the right answer on the 9 platforms I've tested on. The sample directory I'm working with:

$ find /home/pipping/test -exec ls -ldF {} + | awk '{ for (i=9; i<=NF; ++i) { printf "%s ", $i }; print ""; }'
/home/pipping/test/ 
/home/pipping/test/broken-link -> does-not-exist 
/home/pipping/test/dir/ 
/home/pipping/test/dir/dir-in-dir/ 
/home/pipping/test/dir/file-in-dir 
/home/pipping/test/dir/secret-dir-in-dir/ 
/home/pipping/test/.dot-dir/ 
/home/pipping/test/file 
/home/pipping/test/link-to-dir -> dir// 
/home/pipping/test/link-to-dir-in-dir -> dir/dir-in-dir// 
/home/pipping/test/link-to-file -> file 
/home/pipping/test/link-to-file-in-dir -> dir/file-in-dir 
$

(the secret-dir-in-dir directory is the sole physical directory that doesn't have a link pointing to it. It should thus only ever show up in recursive listings of test/, or regular listings of (symlinks to) test/dir/)

The consistent output I now get (consistent up to the fact that some are truenames and others are not but I think that shouldn't be "fixed")

===== abcl =====
(/home/pipping/test/dir/dir-in-dir/ /home/pipping/test/dir/ /home/pipping/test/dir/ /home/pipping/test/.dot-dir/)
===== allegro =====
(/home/pipping/test/link-to-dir-in-dir/ /home/pipping/test/link-to-dir/ /home/pipping/test/dir/ /home/pipping/test/.dot-dir/)
===== ccl =====
(/home/pipping/test/.dot-dir/ /home/pipping/test/dir/ /home/pipping/test/link-to-dir /home/pipping/test/link-to-dir-in-dir)
===== clisp =====
(/home/pipping/test/.dot-dir/ /home/pipping/test/dir/ /home/pipping/test/dir/ /home/pipping/test/dir/dir-in-dir/)
===== cmucl =====
(/home/pipping/test/.dot-dir/ /home/pipping/test/dir/ /home/pipping/test/link-to-dir/ /home/pipping/test/link-to-dir-in-dir/)
===== ecl =====
(/home/pipping/test/.dot-dir/ /home/pipping/test/dir/ /home/pipping/test/dir/ /home/pipping/test/dir/dir-in-dir/)
===== lispworks =====
(/home/pipping/test/link-to-dir-in-dir/ /home/pipping/test/link-to-dir/ /home/pipping/test/dir/ /home/pipping/test/.dot-dir/)
===== mkcl =====
(/home/pipping/test/.dot-dir/ /home/pipping/test/dir/ /home/pipping/test/dir/  /home/pipping/test/dir/dir-in-dir/)
===== sbcl =====
(/home/pipping/test/.dot-dir/ /home/pipping/test/dir/ /home/pipping/test/link-to-dir-in-dir/ /home/pipping/test/link-to-dir/)

Next, I'd like to get an option to work that never resolves symlinks, for reasons of efficiency. Progress so far: The following appears to work (that's 5/9 platforms):

  • CCL: (uiop:directory* (uiop:merge-pathnames* uiop:*wild-directory* "/home/pipping/test/"))
  • ACL, MKCL: (remove-if-not #'uiop:directory-pathname-p (uiop:directory* (uiop:merge-pathnames* "*.*" "/home/pipping/test/")))
  • ECL: (uiop:directory* (uiop:merge-pathnames* uiop:*wild-directory* "/home/pipping/test/") :resolve-symlinks nil)
  • CMU CL (>=21b): (remove-if-not #'uiop:directory-pathname-p (uiop:directory* (uiop:merge-pathnames* "*.*" "/home/pipping/test/") :follow-links nil))

If SBCL were to apply https://bugs.launchpad.net/sbcl/+bug/1114689 then we could do

(uiop:directory* (uiop:merge-pathnames* uiop:*wild-directory* "/home/pipping/test/") :resolve-symlinks nil)

This leaves the following platforms for tackling: ABCL, CLISP, LispWorks.

Notes

These do things very different from what I would expect (in particular, not at all portable):

  • (uiop:directory* (uiop:merge-pathnames* uiop:*wild-directory* "/home/pipping/test/"))
  • (uiop:directory* (uiop:merge-pathnames* "*.*" "/home/pipping/test/"))
  • (mapcar #'uiop:directory-pathname-p (uiop:directory* (uiop:merge-pathnames* "*.*" "/home/pipping/test/")))
  • (uiop:directory* (uiop:wilden "/home/pipping/test/"))

Merge request reports