2

Is there a way to temporarily create a new directory, then remove it when the body of the code has finished?

(with-temp-directory path
   (write-test-files-into path)
   (other-test-functions path))
;; path is now deleted!

Similar to the Python function tempfile.TemporaryDirectory by a similar name:

# create a temporary directory using the context manager
with tempfile.TemporaryDirectory() as tmpdirname:
    print('created temporary directory', tmpdirname)

2 Answers 2

6

make-temp-file can be used to make a directory instead of a file, this example simply calls make-temp-file, then removes the directory afterwards.

(let ((temp-dir (make-temp-file "foo" t)))
  (unwind-protect
      (progn
        ;; do stuff
        )
    (delete-directory temp-dir t)))

This same functionality as a macro:

(defmacro with-temp-dir (temp-dir &rest body)
  `(let ((,temp-dir (make-temp-file "" t)))
    (unwind-protect
      (progn
        ,@body)
      (delete-directory ,temp-dir t))))
3
  • 2
    Welcome to Emacs.SE! Could you please add some text to explain what your code does?
    – Dan
    Jan 21, 2020 at 10:13
  • Ah, the DIR-FLAG is what I was missing, I assumed make-temp-files was only for files :/
    – ideasman42
    Jan 21, 2020 at 13:55
  • This would be nice as a macro (with-temp-dir var ...)
    – ideasman42
    Jan 21, 2020 at 13:56
3
;; Inspired from `dired-create-directory` code.
(defun with-temp-dir (dir)
  "..."
  (let* ((expanded  (directory-file-name (expand-file-name dir)))
         (try       expanded)
         new)
    (unwind-protect
        (progn
          (when (file-exists-p expanded)
            (error "Cannot create directory %s: file exists" expanded))
          ;; Find the topmost nonexistent parent dir (variable `new')
          (while (and try  (not (file-exists-p try))  (not (equal new try)))
            (setq new  try
                  try  (directory-file-name (file-name-directory try))))
          (make-directory expanded t)
          (write-test-files expanded)
          (other-test-functions expanded))
      (delete-directory new t))))

Or if you want to do arbitrary things in the directory, not just write-test-files and other-test-functions, use a macro:

(defmacro with-temp-dir (dir &rest body)
  "..."
  `(let* ((expanded  (directory-file-name (expand-file-name ',dir)))
          (try       expanded)
          new)
     (unwind-protect
         (progn
           (when (file-exists-p expanded)
             (error "Cannot create directory %s: file exists" expanded))
           ;; Find the topmost nonexistent parent dir (variable `new')
           (while (and try  (not (file-exists-p try))  (not (equal new try)))
             (setq new  try
                   try  (directory-file-name (file-name-directory try))))
           (make-directory expanded t)
           ,@body)
       (delete-directory new t))))

Then you would do, e.g.:

(with-temp-dir "/your/temp/dir" (write-test-files ...) (other-test-functions ...))
14
  • Does Emacs have something like mkdtemp to create a new name?
    – ideasman42
    Jan 20, 2020 at 15:17
  • I don't understand your comment question. Create what new name?
    – Drew
    Jan 20, 2020 at 15:26
  • Are you going to morph this question too into one or two or... other questions? Bad habit.
    – Drew
    Jan 20, 2020 at 15:39
  • Ah, I should have stated this in the question, I don't wanted to make a temporary directory that could potentially collide with an existing path. If this is different enough from you answer, I might be best to ask a separate question.
    – ideasman42
    Jan 20, 2020 at 15:44
  • 1
    OP: Your questions are often unclear, and then there is a long series of comments or changes to the question and answers, as you find your way and clarify things. We end up often with a still unclear question and answers to other questions than what you really wanted. It would really help everyone, including you, if you made more of an effort to figure out what you want to ask, at the outset.
    – Drew
    Jan 21, 2020 at 17:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.