branch: externals/plz
commit f1a89a8816f56c1560044bfd54ca3d56824ef2f8
Author: Adam Porter <[email protected]>
Commit: Adam Porter <[email protected]>
Add: Download :as file
---
README.org | 2 ++
plz.el | 39 +++++++++++++++++++++++++++++++++++++++
tests/test-plz.el | 30 ++++++++++++++++++++++++++++++
3 files changed, 71 insertions(+)
diff --git a/README.org b/README.org
index 9d9f8c259a..f96317c442 100644
--- a/README.org
+++ b/README.org
@@ -115,6 +115,8 @@ Synchronously download a JPEG file, then create an Emacs
image object from the d
- ~string~ to pass the response body as a decoded string.
- ~response~ to pass a ~plz-response~ struct.
- A function, to pass its return value; it is called in the response
buffer, which is narrowed to the response body (suitable for, e.g. ~json-read~).
+ - ~file~ to pass a temporary filename to which the response body has been
saved without decoding.
+ - ~(file FILENAME)~ to pass ~FILENAME~ after having saved the response
body to it without decoding. ~FILENAME~ must be a non-existent file; if it
exists, it will not be overwritten, and an error will be signaled.
If ~DECODE~ is non-nil, the response body is decoded automatically. For
binary content, it should be nil. When ~AS~ is ~binary~, ~DECODE~ is
automatically set to nil.
diff --git a/plz.el b/plz.el
index 86a9a270b5..81c2112d84 100644
--- a/plz.el
+++ b/plz.el
@@ -231,9 +231,21 @@ THEN, or the kind of result to return for synchronous
requests.
It may be:
- `buffer' to pass the response buffer.
+
- `binary' to pass the response body as an undecoded string.
+
- `string' to pass the response body as a decoded string.
+
- `response' to pass a `plz-response' struct.
+
+- `file' to pass a temporary filename to which the response body
+ has been saved without decoding.
+
+- `(file FILENAME)' to pass FILENAME after having saved the
+ response body to it without decoding. FILENAME must be a
+ non-existent file; if it exists, it will not be overwritten,
+ and an error will be signaled.
+
- A function, which is called in the response buffer with it
narrowed to the response body (suitable for, e.g. `json-read').
@@ -330,6 +342,33 @@ NOQUERY is passed to `make-process', which see."
(funcall then (current-buffer))))
('response (lambda ()
(funcall then (plz--response :decode-p
decode))))
+ ('file (lambda ()
+ (set-buffer-multibyte nil)
+ (plz--narrow-to-body)
+ (let ((filename (make-temp-file "plz-")))
+ (condition-case err
+ (write-region (point-min) (point-max)
filename)
+ ;; In case of an error writing to the file,
delete the temp file
+ ;; and signal the error. Ignore any errors
encountered while
+ ;; deleting the file, which would obscure the
original error.
+ (error (ignore-errors
+ (delete-file filename))
+ (signal (car err) (cdr err))))
+ (funcall then filename))))
+ (`(file ,(and (pred stringp) filename))
+ (lambda ()
+ (set-buffer-multibyte nil)
+ (plz--narrow-to-body)
+ (condition-case err
+ (write-region (point-min) (point-max) filename nil
nil nil 'excl)
+ ;; Since we are creating the file, it seems sensible
to delete it in case of an
+ ;; error while writing to it (e.g. a disk-full
error). And we ignore any errors
+ ;; encountered while deleting the file, which would
obscure the original error.
+ (error (ignore-errors
+ (when (file-exists-p filename)
+ (delete-file filename)))
+ (signal (car err) (cdr err))))
+ (funcall then filename)))
((pred functionp) (lambda ()
(let ((coding-system (or
(plz--coding-system) 'utf-8)))
(plz--narrow-to-body)
diff --git a/tests/test-plz.el b/tests/test-plz.el
index 6cc3f3397f..49fd0271df 100644
--- a/tests/test-plz.el
+++ b/tests/test-plz.el
@@ -346,6 +346,36 @@
:as 'binary :then 'sync)))
(should (equal 'jpeg (image-type-from-data jpeg)))))
+;;;;; Downloading to files
+
+(ert-deftest plz-get-temp-file ()
+ (let ((filename (plz 'get "https://httpbin.org/image/jpeg"
+ :as 'file :then 'sync)))
+ (unwind-protect
+ (let ((jpeg-data (with-temp-buffer
+ (insert-file-contents filename)
+ (buffer-string))))
+ (should (equal 'jpeg (image-type-from-data jpeg-data))))
+ ;; It's a temp file, so it should always be deleted.
+ (delete-file filename))))
+
+(ert-deftest plz-get-named-file ()
+ (let ((filename (make-temp-file "plz-")))
+ ;; HACK: Delete the temp file and reuse its name, because
+ ;; `make-temp-name' is less convenient to use.
+ (delete-file filename)
+ (unwind-protect
+ (progn
+ (plz 'get "https://httpbin.org/image/jpeg"
+ :as `(file ,filename) :then 'sync)
+ (let ((jpeg-data (with-temp-buffer
+ (insert-file-contents filename)
+ (buffer-string))))
+ (should (equal 'jpeg (image-type-from-data jpeg-data)))))
+ ;; It's a temp file, so it should always be deleted.
+ (when (file-exists-p filename)
+ (delete-file filename)))))
+
;;;; Footer
(provide 'test-plz)