WIP: Handle symbolic links
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/"))