diff options
| author | Paul Eggert | 2022-12-17 12:15:30 -0800 |
|---|---|---|
| committer | Paul Eggert | 2022-12-17 14:24:16 -0800 |
| commit | bef1edc9cacb976120dff73b4d7bbdce6ade982b (patch) | |
| tree | dd1420a157c9ce01c4d7297a380b8e8dcb86cb09 | |
| parent | 8a9579ca29df951ace35125873949e905fd1af2b (diff) | |
| download | emacs-bef1edc9cacb976120dff73b4d7bbdce6ade982b.tar.gz emacs-bef1edc9cacb976120dff73b4d7bbdce6ade982b.zip | |
make-directory now returns t if dir already exists
This new feature will help fix a copy-directory bug (Bug#58919).
Its implementation does not rely on make-directory handlers
supporting the new feature, as it no longer uses a make-directory
handler H in any way other than (funcall H DIR), thus using
only the intersection of the old and new behavior for handlers.
This will give us time to fix handlers at our leisure.
* lisp/files.el (files--ensure-directory): New arg MKDIR.
All uses changed.
(files--ensure-directory, make-directory):
Return non-nil if DIR is already a directory. All uses changed.
* test/lisp/files-tests.el (files-tests-make-directory):
Test new return-value convention.
| -rw-r--r-- | doc/lispref/files.texi | 3 | ||||
| -rw-r--r-- | etc/NEWS | 5 | ||||
| -rw-r--r-- | lisp/files.el | 58 | ||||
| -rw-r--r-- | test/lisp/files-tests.el | 6 |
4 files changed, 41 insertions, 31 deletions
diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index b3f63b8f32a..a767f9c28d5 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi | |||
| @@ -3209,6 +3209,9 @@ This command creates a directory named @var{dirname}. If | |||
| 3209 | @var{parents} is non-@code{nil}, as is always the case in an | 3209 | @var{parents} is non-@code{nil}, as is always the case in an |
| 3210 | interactive call, that means to create the parent directories first, | 3210 | interactive call, that means to create the parent directories first, |
| 3211 | if they don't already exist. | 3211 | if they don't already exist. |
| 3212 | As a function, @code{make-directory} returns non-@code{nil} if @var{dirname} | ||
| 3213 | already exists as a directory and @var{parents} is non-@code{nil}, | ||
| 3214 | and returns @code{nil} if it successfully created @var{dirname}. | ||
| 3212 | @code{mkdir} is an alias for this. | 3215 | @code{mkdir} is an alias for this. |
| 3213 | @end deffn | 3216 | @end deffn |
| 3214 | 3217 | ||
| @@ -4486,6 +4486,11 @@ and cannot work with regular styles such as 'basic' or 'flex'. | |||
| 4486 | ** Magic file handlers for make-directory-internal are no longer needed. | 4486 | ** Magic file handlers for make-directory-internal are no longer needed. |
| 4487 | Instead, Emacs uses the already-existing make-directory handlers. | 4487 | Instead, Emacs uses the already-existing make-directory handlers. |
| 4488 | 4488 | ||
| 4489 | +++ | ||
| 4490 | ** (make-directory DIR t) returns non-nil if DIR already exists. | ||
| 4491 | This can let a caller know whether it created DIR. Formerly, | ||
| 4492 | make-directory's return value was unspecified. | ||
| 4493 | |||
| 4489 | 4494 | ||
| 4490 | * Changes in Emacs 29.1 on Non-Free Operating Systems | 4495 | * Changes in Emacs 29.1 on Non-Free Operating Systems |
| 4491 | 4496 | ||
diff --git a/lisp/files.el b/lisp/files.el index c74e7e808e4..235eacee704 100644 --- a/lisp/files.el +++ b/lisp/files.el | |||
| @@ -6193,18 +6193,17 @@ instance of such commands." | |||
| 6193 | (rename-buffer (generate-new-buffer-name base-name)) | 6193 | (rename-buffer (generate-new-buffer-name base-name)) |
| 6194 | (force-mode-line-update)))) | 6194 | (force-mode-line-update)))) |
| 6195 | 6195 | ||
| 6196 | (defun files--ensure-directory (dir) | 6196 | (defun files--ensure-directory (mkdir dir) |
| 6197 | "Make directory DIR if it is not already a directory. Return nil." | 6197 | "Use function MKDIR to make directory DIR if it is not already a directory. |
| 6198 | Return non-nil if DIR is already a directory." | ||
| 6198 | (condition-case err | 6199 | (condition-case err |
| 6199 | (make-directory-internal dir) | 6200 | (funcall mkdir dir) |
| 6200 | (error | 6201 | (error |
| 6201 | (unless (file-directory-p dir) | 6202 | (or (file-directory-p dir) |
| 6202 | (signal (car err) (cdr err)))))) | 6203 | (signal (car err) (cdr err)))))) |
| 6203 | 6204 | ||
| 6204 | (defun make-directory (dir &optional parents) | 6205 | (defun make-directory (dir &optional parents) |
| 6205 | "Create the directory DIR and optionally any nonexistent parent dirs. | 6206 | "Create the directory DIR and optionally any nonexistent parent dirs. |
| 6206 | If DIR already exists as a directory, signal an error, unless | ||
| 6207 | PARENTS is non-nil. | ||
| 6208 | 6207 | ||
| 6209 | Interactively, the default choice of directory to create is the | 6208 | Interactively, the default choice of directory to create is the |
| 6210 | current buffer's default directory. That is useful when you have | 6209 | current buffer's default directory. That is useful when you have |
| @@ -6214,8 +6213,9 @@ Noninteractively, the second (optional) argument PARENTS, if | |||
| 6214 | non-nil, says whether to create parent directories that don't | 6213 | non-nil, says whether to create parent directories that don't |
| 6215 | exist. Interactively, this happens by default. | 6214 | exist. Interactively, this happens by default. |
| 6216 | 6215 | ||
| 6217 | If creating the directory or directories fail, an error will be | 6216 | Return non-nil if PARENTS is non-nil and DIR already exists as a |
| 6218 | raised." | 6217 | directory, and nil if DIR did not already exist but was created. |
| 6218 | Signal an error if unsuccessful." | ||
| 6219 | (interactive | 6219 | (interactive |
| 6220 | (list (read-file-name "Make directory: " default-directory default-directory | 6220 | (list (read-file-name "Make directory: " default-directory default-directory |
| 6221 | nil nil) | 6221 | nil nil) |
| @@ -6223,25 +6223,27 @@ raised." | |||
| 6223 | ;; If default-directory is a remote directory, | 6223 | ;; If default-directory is a remote directory, |
| 6224 | ;; make sure we find its make-directory handler. | 6224 | ;; make sure we find its make-directory handler. |
| 6225 | (setq dir (expand-file-name dir)) | 6225 | (setq dir (expand-file-name dir)) |
| 6226 | (let ((handler (find-file-name-handler dir 'make-directory))) | 6226 | (let ((mkdir (if-let ((handler (find-file-name-handler dir 'make-directory))) |
| 6227 | (if handler | 6227 | #'(lambda (dir) (funcall handler 'make-directory dir)) |
| 6228 | (funcall handler 'make-directory dir parents) | 6228 | #'make-directory-internal))) |
| 6229 | (if (not parents) | 6229 | (if (not parents) |
| 6230 | (make-directory-internal dir) | 6230 | (funcall mkdir dir) |
| 6231 | (let ((dir (directory-file-name (expand-file-name dir))) | 6231 | (let ((dir (directory-file-name (expand-file-name dir))) |
| 6232 | create-list parent) | 6232 | already-dir create-list parent) |
| 6233 | (while (progn | 6233 | (while (progn |
| 6234 | (setq parent (directory-file-name | 6234 | (setq parent (directory-file-name |
| 6235 | (file-name-directory dir))) | 6235 | (file-name-directory dir))) |
| 6236 | (condition-case () | 6236 | (condition-case () |
| 6237 | (files--ensure-directory dir) | 6237 | (ignore (setq already-dir |
| 6238 | (file-missing | 6238 | (files--ensure-directory mkdir dir))) |
| 6239 | ;; Do not loop if root does not exist (Bug#2309). | 6239 | (error |
| 6240 | (not (string= dir parent))))) | 6240 | ;; Do not loop if root does not exist (Bug#2309). |
| 6241 | (setq create-list (cons dir create-list) | 6241 | (not (string= dir parent))))) |
| 6242 | dir parent)) | 6242 | (setq create-list (cons dir create-list) |
| 6243 | (dolist (dir create-list) | 6243 | dir parent)) |
| 6244 | (files--ensure-directory dir))))))) | 6244 | (dolist (dir create-list) |
| 6245 | (setq already-dir (files--ensure-directory mkdir dir))) | ||
| 6246 | already-dir)))) | ||
| 6245 | 6247 | ||
| 6246 | (defun make-empty-file (filename &optional parents) | 6248 | (defun make-empty-file (filename &optional parents) |
| 6247 | "Create an empty file FILENAME. | 6249 | "Create an empty file FILENAME. |
diff --git a/test/lisp/files-tests.el b/test/lisp/files-tests.el index efafb5583ac..b9fbeb8a4e0 100644 --- a/test/lisp/files-tests.el +++ b/test/lisp/files-tests.el | |||
| @@ -1261,11 +1261,11 @@ works as expected if the default directory is quoted." | |||
| 1261 | (a/b (concat dirname "a/b"))) | 1261 | (a/b (concat dirname "a/b"))) |
| 1262 | (write-region "" nil file) | 1262 | (write-region "" nil file) |
| 1263 | (should-error (make-directory "/")) | 1263 | (should-error (make-directory "/")) |
| 1264 | (should-not (make-directory "/" t)) | 1264 | (should (make-directory "/" t)) |
| 1265 | (should-error (make-directory dir)) | 1265 | (should-error (make-directory dir)) |
| 1266 | (should-not (make-directory dir t)) | 1266 | (should (make-directory dir t)) |
| 1267 | (should-error (make-directory dirname)) | 1267 | (should-error (make-directory dirname)) |
| 1268 | (should-not (make-directory dirname t)) | 1268 | (should (make-directory dirname t)) |
| 1269 | (should-error (make-directory file)) | 1269 | (should-error (make-directory file)) |
| 1270 | (should-error (make-directory file t)) | 1270 | (should-error (make-directory file t)) |
| 1271 | (should-not (make-directory subdir1)) | 1271 | (should-not (make-directory subdir1)) |