[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master 9361417 041/187: Started work on a generalized async-file
From: |
Michael Albinus |
Subject: |
[elpa] master 9361417 041/187: Started work on a generalized async-file service |
Date: |
Wed, 30 Dec 2015 11:49:34 +0000 |
branch: master
commit 9361417b1f19b5baaa323d23286676854f03036a
Author: John Wiegley <address@hidden>
Commit: John Wiegley <address@hidden>
Started work on a generalized async-file service
---
async-file.el | 284 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 284 insertions(+), 0 deletions(-)
diff --git a/async-file.el b/async-file.el
new file mode 100644
index 0000000..10e8929
--- /dev/null
+++ b/async-file.el
@@ -0,0 +1,284 @@
+;;; async --- Asynchronous file operations
+
+;; Copyright (C) 2012 John Wiegley
+
+;; Author: John Wiegley <address@hidden>
+;; Created: 10 Jul 2012
+;; Version: 1.0
+;; Keywords: async
+;; X-URL: https://github.com/jwiegley/emacs-async
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; Provides asynchronous versions of the following operations:
+;;
+;; Function Command equivalent
+;; ----------------------- ---------------------------------
+;; copy-file cp
+;; copy-directory cp -R
+;; rename-file mv
+;; delete-file rm
+;; delete-directory rm -r
+;;
+;; Additional features:
+;;
+;; - If `async-file-use-native-commands' is non-nil, and none of the files
+;; involved are `file-remote-p', the native command equivalents are used
+;; above rather than spawning a child Emacs to call the related function.
+;;
+;; - Operations are queued, so that only one asynchronous operation is
+;; performed at one time. If an error occurs while processing the queue,
+;; the whole queue is aborted.
+
+;;; Code:
+
+(eval-when-compile
+ (require 'cl))
+
+(defgroup async-file nil
+ "Asynchronous file processing using async.el"
+ :group 'async)
+
+(defcustom async-file-use-native-commands nil
+ "If non-nil, use native cp/mv/rm commands for local-only files."
+ :type 'boolean
+ :group 'async-file)
+
+(defvar async-file-queue nil
+ "Queue of pending asynchronous file operations.
+Each operation that succeeds will start the next member of the queue. If an
+error occurs at any point, the rest of the queue is flushed.")
+(defvar async-file-queue-mutex nil)
+
+(defun* async-copy-file
+ (file newname
+ &optional ok-if-already-exists keep-time
+ preserve-uid-gid preserve-selinux-context
+ &key (callback 'ignore))
+ "Asynchronous version of `copy-file'.
+Accepts a key argument `:callback' which takes a lambda that
+receives the return value from `copy-file' (nil if Lisp was used,
+a process object otherwise) when the copy is done."
+ (if (and async-file-use-native-commands
+ (not (or (file-remote-p file)
+ (file-remote-p newname))))
+
+ (let ((args (list "-f" file newname)))
+ (if keep-time
+ (setq args (cons "-p" args)))
+ (unless ok-if-already-exists
+ (setq args (cons "-n" args)))
+ (apply #'async-start-process "cp" (executable-find "cp")
+ callback args))
+
+ (async-start (apply-partially #'copy-file
+ file newname ok-if-already-exists
+ keep-time preserve-uid-gid
+ preserve-selinux-context)
+ callback)))
+
+(defsubst async-file-contents (file)
+ "Return the contents of FILE, as a string."
+ (with-temp-buffer
+ (insert-file-contents file)
+ (buffer-string)))
+
+(defun* async-do-copy-file-test (ok-if-already-exists
+ keep-time preserve-uid-gid
+ preserve-selinux-context
+ &key use-native-commands
+ synchronously)
+ (let* ((temp-file (make-temp-file "async-do-copy-file-test"))
+ (temp-file2 (concat temp-file ".target")))
+ (unwind-protect
+ (progn
+ (with-temp-buffer
+ (insert "async-do-copy-file-test")
+ (write-region (point-min) (point-max) temp-file))
+
+ (let* ((async-file-use-native-commands use-native-commands)
+ (future (if synchronously
+ (copy-file temp-file temp-file2
+ ok-if-already-exists
+ keep-time
+ preserve-uid-gid
+ preserve-selinux-context)
+ (async-copy-file temp-file temp-file2
+ ok-if-already-exists
+ keep-time
+ preserve-uid-gid
+ preserve-selinux-context
+ :callback nil))))
+ (unless synchronously
+ (if use-native-commands
+ (let ((proc (async-get future)))
+ (should (processp proc))
+ (should (equal 'exit (process-status proc))))
+ (should (equal (async-get future) nil))))
+
+ (should (file-readable-p temp-file2))
+
+ (should (equal "async-do-copy-file-test"
+ (async-file-contents temp-file2)))))
+
+ (if (file-exists-p temp-file) (delete-file temp-file))
+ (if (file-exists-p temp-file2) (delete-file temp-file2)))))
+
+(ert-deftest async-copy-file-lisp-sync-1 ()
+ (async-do-copy-file-test t t t nil :synchronously t))
+(ert-deftest async-copy-file-lisp-1 ()
+ (async-do-copy-file-test t t t nil :use-native-commands nil))
+(ert-deftest async-copy-file-native-1 ()
+ (async-do-copy-file-test t t t nil :use-native-commands t))
+
+(defun* async-copy-directory
+ (directory newname
+ &optional keep-time parents copy-contents
+ &key (callback 'ignore))
+ "Asynchronous version of `copy-directory'.
+Accepts a key argument `:callback' which takes a lambda that
+receives the return value from `copy-directory' (always nil) when
+the copy is done."
+ (if (and async-file-use-native-commands
+ (not (or (file-remote-p directory)
+ (file-remote-p newname))))
+ (progn
+ (if parents
+ (let ((dest-dir (if copy-contents
+ (file-name-directory newname)
+ newname)))
+ (unless (file-directory-p dest-dir)
+ (message "Creating directory '%s'" dest-dir)
+ (make-directory dest-dir t))))
+
+ (if copy-contents
+ (let ((args (list "-r" (file-name-as-directory directory)
+ (file-name-as-directory newname))))
+ (if keep-time
+ (setq args (cons "-a" args)))
+ (apply #'async-start-process "rsync" (executable-find "rsync")
+ callback args))
+
+ (let ((args (list "-fR" directory newname)))
+ (if keep-time
+ (setq args (cons "-p" args)))
+ (apply #'async-start-process "cp" (executable-find "cp")
+ callback args))))
+
+ (async-start (apply-partially #'copy-directory
+ directory newname keep-time parents
+ copy-contents)
+ callback)))
+
+(defsubst async-file-make-temp-dir (prefix)
+ "Make a temporary directory using PREFIX.
+Return the name of the directory."
+ (let ((dir (make-temp-name
+ (expand-file-name prefix temporary-file-directory))))
+ (make-directory dir)
+ dir))
+
+(defsubst async-file-make-file (file contents)
+ "Create a new FILE with the given CONTENTS."
+ (with-temp-buffer
+ (insert contents)
+ (write-region (point-min) (point-max) file)))
+
+(defun* async-do-copy-directory-test (keep-time parents copy-contents
+ &key use-native-commands
+ synchronously)
+ (let* ((temp-dir (async-file-make-temp-dir "async-do-copy-directory-test"))
+ (temp-dir2 (concat temp-dir ".target")))
+ (unwind-protect
+ (progn
+ (async-file-make-file (expand-file-name "foo" temp-dir) "foo")
+ (async-file-make-file (expand-file-name "bar" temp-dir) "bar")
+
+ ;; Shouldn't the parents argument cause this to happen when needed?
+ ;; But if the following is wrapped with "unless parents", even
+ ;; `async-copy-directory-lisp-sync-2' fails.
+ (make-directory temp-dir2)
+
+ (let* ((async-file-use-native-commands use-native-commands)
+ (future (if synchronously
+ (copy-directory temp-dir temp-dir2
+ keep-time
+ parents
+ copy-contents)
+ (async-copy-directory temp-dir temp-dir2
+ keep-time
+ parents
+ copy-contents
+ :callback nil))))
+ (unless synchronously
+ (if use-native-commands
+ (let ((proc (async-get future)))
+ (should (processp proc))
+ (should (equal 'exit (process-status proc))))
+ ;; Ignore the return value from `copy-directory'
+ (async-get future)))
+
+ (if (and parents copy-contents)
+ (should (file-directory-p temp-dir2)))
+
+ (let* ((target (if copy-contents
+ temp-dir2
+ (expand-file-name (file-name-nondirectory
temp-dir)
+ temp-dir2)))
+ (foo-file (expand-file-name "foo" target))
+ (bar-file (expand-file-name "bar" target)))
+
+ (should (file-readable-p foo-file))
+ (should (file-readable-p bar-file))
+
+ (should (equal "foo" (async-file-contents foo-file)))
+ (should (equal "bar" (async-file-contents bar-file))))))
+
+ (if (file-directory-p temp-dir) (delete-directory temp-dir t))
+ (if (file-directory-p temp-dir2) (delete-directory temp-dir2 t)))))
+
+(ert-deftest async-copy-directory-lisp-sync-1 ()
+ (async-do-copy-directory-test t nil nil :synchronously t))
+(ert-deftest async-copy-directory-lisp-sync-2 ()
+ (async-do-copy-directory-test t t nil :synchronously t))
+(ert-deftest async-copy-directory-lisp-sync-3 ()
+ (async-do-copy-directory-test t nil t :synchronously t))
+(ert-deftest async-copy-directory-lisp-sync-4 ()
+ (async-do-copy-directory-test t t t :synchronously t))
+
+(ert-deftest async-copy-directory-lisp-1 ()
+ (async-do-copy-directory-test t nil nil :use-native-commands nil))
+(ert-deftest async-copy-directory-lisp-2 ()
+ (async-do-copy-directory-test t t nil :use-native-commands nil))
+(ert-deftest async-copy-directory-lisp-3 ()
+ (async-do-copy-directory-test t nil t :use-native-commands nil))
+(ert-deftest async-copy-directory-lisp-4 ()
+ (async-do-copy-directory-test t t t :use-native-commands nil))
+
+(ert-deftest async-copy-directory-native-1 ()
+ (async-do-copy-directory-test t nil nil :use-native-commands t))
+(ert-deftest async-copy-directory-native-2 ()
+ (async-do-copy-directory-test t t nil :use-native-commands t))
+(ert-deftest async-copy-directory-native-3 ()
+ (async-do-copy-directory-test t nil t :use-native-commands t))
+(ert-deftest async-copy-directory-native-4 ()
+ (async-do-copy-directory-test t t t :use-native-commands t))
+
+(provide 'async-file)
+
+;;; async-file.el ends here
- [elpa] master c472c4a 036/187: * helm-async.el Return file errors in child Emacs., (continued)
- [elpa] master c472c4a 036/187: * helm-async.el Return file errors in child Emacs., Michael Albinus, 2015/12/30
- [elpa] master eb26295 033/187: * helm-async.el: New, redefine dired-create-file to work with helm and dired., Michael Albinus, 2015/12/30
- [elpa] master c35324c 043/187: Async queue handling has to happen in dired-async, Michael Albinus, 2015/12/30
- [elpa] master ac1b896 040/187: Minor touches, Michael Albinus, 2015/12/30
- [elpa] master ad07ff3 039/187: Merge pull request #1 from thierryvolpiatto/master, Michael Albinus, 2015/12/30
- [elpa] master 6941276 046/187: * helm-async.el (helm-async-processes): use process-name., Michael Albinus, 2015/12/30
- [elpa] master 1647b97 047/187: * async.el (async-start): Use the possible true name of emacs executable., Michael Albinus, 2015/12/30
- [elpa] master 9779abc 044/187: Fix github issue 2, Michael Albinus, 2015/12/30
- [elpa] master 96cbe3a 048/187: Fix missing optional arguments when calling `async-copy-file' in `async-dired.el'., Michael Albinus, 2015/12/30
- [elpa] master 819b936 045/187: * helm-async.el: Turn off mode-line notification only when last process end., Michael Albinus, 2015/12/30
- [elpa] master 9361417 041/187: Started work on a generalized async-file service,
Michael Albinus <=
- [elpa] master 3cc71f3 051/187: * helm-async.el (helm-async-mode): ding when finish., Michael Albinus, 2015/12/30
- [elpa] master d9d68f7 049/187: Merge pull request #5 from mstrlu/fix-async-copy-call, Michael Albinus, 2015/12/30
- [elpa] master bd43f86 053/187: * helm-async.el (dired-create-files): Honor dired-overwrite-confirmed., Michael Albinus, 2015/12/30
- [elpa] master fba2cb9 052/187: Merge branch 'master' of github.com:jwiegley/emacs-async, Michael Albinus, 2015/12/30
- [elpa] master 42fba8d 050/187: * dired-async.el: Add a defvar for `dired-async-use-native-commands', Michael Albinus, 2015/12/30
- [elpa] master 0afa685 056/187: Merge pull request #11 from myuhe/pkg, Michael Albinus, 2015/12/30
- [elpa] master 34ee9c5 054/187: * helm-async.el (dired-create-file): Fix operation is executed even when replying no for overwriting., Michael Albinus, 2015/12/30
- [elpa] master a5ad866 057/187: Merge pull request #6 from mstrlu/fix-def-use-native-commands, Michael Albinus, 2015/12/30
- [elpa] master ee21700 060/187: * async.el: Issue #7 Apply sabof patch from github; Fix processing non--latin chars., Michael Albinus, 2015/12/30
- [elpa] master ef0e45c 055/187: add async-pkg.el, Michael Albinus, 2015/12/30