branch: externals/async commit 7ca3b9f6279559558ab5f7e25e7e70ff6505943f Author: Przemysław Kryger <pkry...@gmail.com> Commit: Thierry Volpiatto <thie...@posteo.net>
Use temporary file for async byte compile log This is to avoid log file contention when multiple packages are compiled in rapid succession. Update the default value `async-byte-compile-log-file`. The `temporary-file-directory` (implicitly) is used as a location where to store temporary compilation logs. Update to the semantic is done with backward compatibility in mind, that is to respect the directory part should it be set by user. Add `async-bytecomp--comp-buffer-to-file` macro to be used (`macroexpand`ed) in `async-byte-recompile-directory` and `async-byte-compile-file`. Pass value returned from expanded macro execution in child processes to `async-bytecomp--file-to-comp-buffer` call-back. --- async-bytecomp.el | 83 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 29 deletions(-) diff --git a/async-bytecomp.el b/async-bytecomp.el index eadb5df66e..bf12265604 100644 --- a/async-bytecomp.el +++ b/async-bytecomp.el @@ -59,27 +59,32 @@ all packages are always compiled asynchronously." (const :tag "All packages" all) (repeat symbol))) -(defvar async-byte-compile-log-file - (concat user-emacs-directory "async-bytecomp.log")) +(defvar async-byte-compile-log-file "async-bytecomp.log" + "Prefix for a file used to pass errors from async process to the caller. +The `file-name-nondirectory' part of the value is passed to +`make-temp-file' as a prefix. When the value is an absolute +path, then the `file-name-directory' part of it is expanded in +the calling process (with `expand-file-name') and used as a value +of variable `temporary-file-directory' in async processes.") (defvar async-bytecomp-load-variable-regexp "\\`load-path\\'" "The variable used by `async-inject-variables' when (re)compiling async.") -(defun async-bytecomp--file-to-comp-buffer (file-or-dir &optional quiet type) - (let ((bn (file-name-nondirectory (directory-file-name file-or-dir))) +(defun async-bytecomp--file-to-comp-buffer (file-or-dir &optional quiet type log-file) + (let ((bn (file-name-nondirectory file-or-dir)) (action-name (pcase type ('file "File") ('directory "Directory")))) - (if (file-exists-p async-byte-compile-log-file) + (if (and log-file (file-exists-p log-file)) (let ((buf (get-buffer-create byte-compile-log-buffer)) (n 0)) (with-current-buffer buf (goto-char (point-max)) (let ((inhibit-read-only t)) - (insert-file-contents async-byte-compile-log-file) + (insert-file-contents log-file) (compilation-mode)) (display-buffer buf) - (delete-file async-byte-compile-log-file) + (delete-file log-file) (unless quiet (save-excursion (goto-char (point-min)) @@ -92,6 +97,40 @@ all packages are always compiled asynchronously." (unless quiet (message "%s `%s' compiled asynchronously with success" action-name bn))))) +(defmacro async-bytecomp--comp-buffer-to-file () + "Write contents of `byte-compile-log-buffer' to a log file. +The log file is a temporary file that name is determined by +`async-byte-compile-log-file', which see. Return the actual log +file name, or nil if no log file has been created." + `(when (get-buffer byte-compile-log-buffer) + (let ((error-data (with-current-buffer byte-compile-log-buffer + (buffer-substring-no-properties (point-min) (point-max))))) + (unless (string= error-data "") + ;; The `async-byte-compile-log-file' used to be an absolute file name + ;; shared amongst all compilation async processes. For backward + ;; compatibility the directory part of it is used to create logs the same + ;; directory while the nondirectory part denotes the PREFIX for + ;; `make-temp-file' call. The `temporary-file-directory' is bound, such + ;; that the async process uses one set by the caller. + (let ((temporary-file-directory + ,(or (when (and async-byte-compile-log-file + (file-name-absolute-p + async-byte-compile-log-file)) + (expand-file-name (file-name-directory + async-byte-compile-log-file))) + temporary-file-directory)) + (log-file (make-temp-file ,(let ((log-file + (file-name-nondirectory + async-byte-compile-log-file))) + (format "%s%s" + log-file + (if (string-suffix-p "." log-file) + "" ".")))))) + (with-temp-file log-file + (erase-buffer) + (insert error-data)) + log-file))))) + ;;;###autoload (defun async-byte-recompile-directory (directory &optional quiet) "Compile all *.el files in DIRECTORY asynchronously. @@ -104,23 +143,16 @@ All *.elc files are systematically deleted before proceeding." ;; This happen when recompiling its own directory. (load "async") (let ((call-back - (lambda (&optional _ignore) - (async-bytecomp--file-to-comp-buffer directory quiet 'directory)))) + (lambda (&optional log-file) + (async-bytecomp--file-to-comp-buffer directory quiet 'directory log-file)))) (async-start `(lambda () (require 'bytecomp) ,(async-inject-variables async-bytecomp-load-variable-regexp) - (let ((default-directory (file-name-as-directory ,directory)) - error-data) + (let ((default-directory (file-name-as-directory ,directory))) (add-to-list 'load-path default-directory) (byte-recompile-directory ,directory 0 t) - (when (get-buffer byte-compile-log-buffer) - (setq error-data (with-current-buffer byte-compile-log-buffer - (buffer-substring-no-properties (point-min) (point-max)))) - (unless (string= error-data "") - (with-temp-file ,async-byte-compile-log-file - (erase-buffer) - (insert error-data)))))) + ,(macroexpand '(async-bytecomp--comp-buffer-to-file)))) call-back) (unless quiet (message "Started compiling asynchronously directory %s" directory)))) @@ -185,23 +217,16 @@ by default is async you don't need this." Same as `byte-compile-file' but asynchronous." (interactive "fFile: ") (let ((call-back - (lambda (&optional _ignore) - (async-bytecomp--file-to-comp-buffer file nil 'file)))) + (lambda (&optional log-file) + (async-bytecomp--file-to-comp-buffer file nil 'file log-file)))) (async-start `(lambda () (require 'bytecomp) ,(async-inject-variables async-bytecomp-load-variable-regexp) - (let ((default-directory ,(file-name-directory file)) - error-data) + (let ((default-directory ,(file-name-directory file))) (add-to-list 'load-path default-directory) (byte-compile-file ,file) - (when (get-buffer byte-compile-log-buffer) - (setq error-data (with-current-buffer byte-compile-log-buffer - (buffer-substring-no-properties (point-min) (point-max)))) - (unless (string= error-data "") - (with-temp-file ,async-byte-compile-log-file - (erase-buffer) - (insert error-data)))))) + ,(macroexpand '(async-bytecomp--comp-buffer-to-file)))) call-back))) (provide 'async-bytecomp)