Directories in Lisp

Here’s the translation of the Go code to Lisp, formatted in Markdown for Hugo:

Our first program demonstrates working with directories in the file system. Here’s the full source code:

(defpackage :directories-example
  (:use :cl :uiop))

(in-package :directories-example)

(defun check (condition)
  (unless condition
    (error "An error occurred")))

(defun create-empty-file (name)
  (with-open-file (stream name :direction :output :if-exists :supersede)
    (write-string "" stream)))

(defun main ()
  ;; Create a new sub-directory in the current working directory.
  (ensure-directories-exist "subdir/")

  ;; When creating temporary directories, it's good practice to clean them up afterwards.
  ;; Here we use UIOP:DELETE-DIRECTORY-TREE which is similar to `rm -rf`.
  (unwind-protect
       (progn
         (create-empty-file "subdir/file1")

         ;; We can create a hierarchy of directories, including parents.
         ;; This is similar to the command-line `mkdir -p`.
         (ensure-directories-exist "subdir/parent/child/")

         (create-empty-file "subdir/parent/file2")
         (create-empty-file "subdir/parent/file3")
         (create-empty-file "subdir/parent/child/file4")

         ;; LIST-DIRECTORY lists directory contents.
         (format t "Listing subdir/parent~%")
         (dolist (entry (uiop:directory-files "subdir/parent/"))
           (format t "  ~A ~A~%" 
                   (file-namestring entry) 
                   (uiop:directory-pathname-p entry)))

         ;; CHDIR lets us change the current working directory.
         (uiop:chdir "subdir/parent/child")

         ;; Now we'll see the contents of `subdir/parent/child` when listing the current directory.
         (format t "Listing subdir/parent/child~%")
         (dolist (entry (uiop:directory-files "./"))
           (format t "  ~A ~A~%" 
                   (file-namestring entry) 
                   (uiop:directory-pathname-p entry)))

         ;; Change back to where we started.
         (uiop:chdir "../../..")

         ;; We can also visit a directory recursively, including all its sub-directories.
         (format t "Visiting subdir~%")
         (walk-directory "subdir"))
    ;; Clean up the directory we created
    (uiop:delete-directory-tree "subdir/" :validate t :if-does-not-exist :ignore)))

(defun walk-directory (directory)
  (uiop:collect-sub-directories 
   directory 
   (lambda (dir)
     (format t "  ~A ~A~%" dir (uiop:directory-pathname-p dir))
     (dolist (file (uiop:directory-files dir))
       (format t "  ~A ~A~%" file (uiop:directory-pathname-p file))))))

(main)

This Lisp program demonstrates various operations on directories:

  1. We use ensure-directories-exist to create directories, which is similar to os.MkdirAll in Go.

  2. uiop:delete-directory-tree is used for recursive directory deletion, similar to os.RemoveAll.

  3. uiop:directory-files is used to list directory contents, analogous to os.ReadDir.

  4. uiop:chdir changes the current working directory, just like os.Chdir.

  5. We implement a walk-directory function that recursively visits all subdirectories and files, similar to filepath.WalkDir in Go.

  6. The unwind-protect macro is used to ensure cleanup of the created directory, similar to Go’s defer.

To run this program, save it as directories.lisp and use your Lisp implementation. For example, with SBCL:

$ sbcl --script directories.lisp
Listing subdir/parent
  child T
  file2 NIL
  file3 NIL
Listing subdir/parent/child
  file4 NIL
Visiting subdir
  /path/to/subdir/ T
  /path/to/subdir/file1 NIL
  /path/to/subdir/parent/ T
  /path/to/subdir/parent/child/ T
  /path/to/subdir/parent/child/file4 NIL
  /path/to/subdir/parent/file2 NIL
  /path/to/subdir/parent/file3 NIL

Note that the exact output might vary depending on your Lisp implementation and operating system.