unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: "Michalis V." <mvar.40k@gmail.com>
To: Marco Centurion - URI <mcenturion@fing.edu.uy>
Cc: 47058@debbugs.gnu.org, Arthur Miller <arthur.miller@live.com>
Subject: bug#47058: 28.0.50; Dired Z: insert-directory: Reading directory: No such file or directory, CrossLine_linux_x86
Date: Tue, 21 Sep 2021 01:12:10 +0300	[thread overview]
Message-ID: <875yuuq4lh.fsf@gmail.com> (raw)
In-Reply-To: <pk635qoflck.fsf@crusher.fing.edu.uy> (Marco Centurion's message of "Wed, 01 Sep 2021 10:59:07 -0300")

[-- Attachment #1: Type: text/plain, Size: 3950 bytes --]

Marco Centurion - URI <mcenturion@fing.edu.uy> writes:

> Arthur Miller <arthur.miller@live.com> writes:
>
>> Marco Centurion <mcenturion@fing.edu.uy> writes:
>>
>>> I can confirm that this bug is present and pretty easy to reproduce.
>>> Steps to reproduce:
>>>
>>> ----
>>> $ touch test1
>>> $ tar czf test.tar.gz test1
>>> $ rm test1
>>>
>>> In dired, press Z (`dired-do-compress`) when the point is on test.tar.gz
>>> ----
>> I just did all those steps in emacs -Q, and I can not confirm any errors. I
>> named files exactly as you show there, and decompressed file is correctly named
>> 'test1'.
>>
>> I tested in two different directories, you three shell commands from terminal
>> (st in my case), and Z from dired created correctly test1.
>>
>
> Yes, the file is correctly decompressed.  The original report is about
> an error message that shows up in the minibuffer "Reading directory: No
> such file or directory, test".  And that's what I was able to reproduce
> without having to download the file linked in the report, something that
> I guess a lot of people wouldn't want to do.
>
>> Press 'g'.
>
> I do that, I just thought that it's a bit of a weird behaviour that
> sometimes after pressing Z the dired buffer is consistent with what's
> actually in the directory and sometimes it's not.  That is all.
> Personally I wouldn't be opposed to reverting the buffer after every
> operation that modifies files, but I'm sure most would and with good
> reason.


hi,

i've had a look into this some weeks ago and only just now managed to
assemble something presentable. As Marco correctly noted, the
problem is not with just a single file - any .tar.[gz|xz|zst|bz2] that
contains just files (no directories) will give the reported error.
The culprit is what 'dired-compress' expects: it assumes that the
uncompression result will produce just a single file or directory.

For example a test-file.gz will produce test-file, emacs-27.2.tar.gz
will give emacs-27.2/ etc. A special case is with formats that support
output directory like zip: boing.zip will be extracted to boing/
no-questions-asked. But for tars like this:

for i in a b c;do touch $i;done
tar cvzf abc.tar.gz a b c

doing Z on abc.tar.gz causes 'dired-compress' to expect abc but the
result is 3 new files a b c (and thus the error is shown). I tried to
think of some way to fix this and i've ended up with the attached
patch. What it does is to basically ask the user where to extract the
contents of the archive (even for zip files, so that the Z behavior is
somehow similar). To make this work for tar files i've added the -C
parameter in 'dired-compress-file-suffixes/. I've also added a missing
.tar.bz2 suffix (until now .tar.bz2 would just be decompressed & not
extracted).

The main work is done on a new function 'dired-uncompress-file' which
contains part of the code of 'dired-compress-file' (which handles both
compress/uncompress actions).
I thought it would be cleaner to have separate functions for these two
(and perhaps the latter function should be renamed to something better)
i've also added some new tests for .tar.gz and .zip formats.

the big downside of this patch is that it adds another prompt when
pressing Z: User must now enter the extraction directory (for file
/tmp/test.tar.gz the suggested default will be /tmp/test/). And that
behavior change might step on some people's toes so i'm a bit reserved
if this is the correct approach to solving the particular problem.

finally there's a corner case that is not solved: in the above scenario
with abc.tar.gz when you uncompress you still need to hit 'g' to refresh
the dired buffer (but there's no error anymore so at least that's
something). A fix for this would require some refactoring on what
'dired-compress' expects, perhaps make it expect a list of
files/directories and not just a single one, plus some more thinking into
the 'dired-compress-file' compression part.

thanks,
Michalis


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: dired-aux.patch --]
[-- Type: text/x-diff, Size: 7420 bytes --]

diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el
index c728642917..2d4269daed 100644
--- a/lisp/dired-aux.el
+++ b/lisp/dired-aux.el
@@ -1134,9 +1134,10 @@ dired-compress-file-suffixes
     ;; "tar -zxf" isn't used because it's not available on the
     ;; Solaris 10 version of tar (obsolete in 2024?).
     ;; Same thing on AIX 7.1 (obsolete 2023?) and 7.2 (obsolete 2022?).
-    ("\\.tar\\.gz\\'" "" "gzip -dc %i | tar -xf -")
-    ("\\.tar\\.xz\\'" "" "xz -dc %i | tar -xf -")
-    ("\\.tgz\\'" "" "gzip -dc %i | tar -xf -")
+    ("\\.tar\\.gz\\'" "" "gzip -dc %i | tar -xf - -C %c")
+    ("\\.tar\\.xz\\'" "" "xz -dc %i | tar -xf - -C %c")
+    ("\\.tgz\\'" "" "gzip -dc %i | tar -xf - -C %c")
+    ("\\.tar\\.bz2\\'" "" "bunzip2 -c %i | tar -xf - -C %c")
     ("\\.gz\\'" "" "gzip -d")
     ("\\.lz\\'" "" "lzip -d")
     ("\\.Z\\'" "" "uncompress")
@@ -1148,8 +1149,8 @@ dired-compress-file-suffixes
     ("\\.bz2\\'" "" "bunzip2")
     ("\\.xz\\'" "" "unxz")
     ("\\.zip\\'" "" "unzip -o -d %o %i")
-    ("\\.tar\\.zst\\'" "" "unzstd -c %i | tar -xf -")
-    ("\\.tzst\\'" "" "unzstd -c %i | tar -xf -")
+    ("\\.tar\\.zst\\'" "" "unzstd -c %i | tar -xf - -C %c")
+    ("\\.tzst\\'" "" "unzstd -c %i | tar -xf - -C %c")
     ("\\.zst\\'" "" "unzstd --rm")
     ("\\.7z\\'" "" "7z x -aoa -o%o %i")
     ;; This item controls naming for compression.
@@ -1253,6 +1254,42 @@ dired-do-compress-to
                       (length in-files)
                       (file-name-nondirectory out-file)))))))
 
+;;;###autoload
+(defun dired-uncompress-file (file dirname command)
+  "Uncompress FILE using COMMAND. If file is a tar archive or some other
+format that supports output directory in its parameters, ask user the
+target directory to extract it (defaults to DIRNAME). Returns the
+directory or filename produced after the uncompress operation."
+  (if (string-match "%[ioc]" command)
+      (let ((extractdir (expand-file-name
+                         (read-file-name
+                          (format "Extract file to (default %s): " dirname)
+                          dirname))))
+        (prog1 (file-name-as-directory extractdir)
+          (when (not (file-directory-p extractdir))
+            (dired-create-directory extractdir))
+          (dired-shell-command
+           (replace-regexp-in-string
+            "%[oc]" (shell-quote-argument extractdir)
+            (replace-regexp-in-string
+             "%i" (shell-quote-argument file)
+             command
+             nil t)
+            nil t))))
+    ;; We found an uncompression rule without output dir argument
+    (let ((match (string-search " " command))
+          (msg (concat "Uncompressing " file)))
+      (unless (if match
+                  (dired-check-process
+                   msg
+                   (substring command 0 match)
+                   (substring command (1+ match))
+                   file)
+                (dired-check-process msg
+                                     command
+                                     file))
+        dirname))))
+
 ;;;###autoload
 (defun dired-compress-file (file)
   "Compress or uncompress FILE.
@@ -1277,28 +1314,7 @@ dired-compress-file
           ((file-symlink-p file)
            nil)
           ((and suffix (setq command (nth 2 suffix)))
-           (if (string-match "%[io]" command)
-               (prog1 (setq newname (file-name-as-directory newname))
-                 (dired-shell-command
-                  (replace-regexp-in-string
-                   "%o" (shell-quote-argument newname)
-                   (replace-regexp-in-string
-                    "%i" (shell-quote-argument file)
-                    command
-                    nil t)
-                   nil t)))
-             ;; We found an uncompression rule.
-             (let ((match (string-search " " command))
-                   (msg (concat "Uncompressing " file)))
-               (unless (if match
-                           (dired-check-process msg
-                                                (substring command 0 match)
-                                                (substring command (1+ match))
-                                                file)
-                         (dired-check-process msg
-                                              command
-                                              file))
-                 newname))))
+           (dired-uncompress-file file newname command))
           (t
            ;; We don't recognize the file as compressed, so compress it.
            ;; Try gzip; if we don't have that, use compress.
diff --git a/test/lisp/dired-aux-tests.el b/test/lisp/dired-aux-tests.el
index 7f1743f88d..5888f4cd99 100644
--- a/test/lisp/dired-aux-tests.el
+++ b/test/lisp/dired-aux-tests.el
@@ -158,5 +158,59 @@ dired-test-highlight-metachar
     (should (string-match (regexp-quote command) (nth 0 lines)))
     (dired-test--check-highlighting (nth 0 lines) '(8))))
 
+(ert-deftest dired-test-bug47058-tar ()
+  "test for https://debbugs.gnu.org/47058 ."
+  (dired-test-bug47058-fn "tar -cf - %i | gzip -c9 > %o"
+                           "gzip -dc %i | tar -xf - -C %c"
+                           ".tar.gz"))
+
+(ert-deftest dired-test-bug47058-zip ()
+  "test for https://debbugs.gnu.org/47058 ."
+  (dired-test-bug47058-fn "zip %o -r --filesync %i"
+                           "unzip -o -d %o %i"
+                           ".zip"))
+
+(defun dired-test-bug47058-fn (compress-cmd uncompress-cmd extension)
+  "helper fn for testing https://debbugs.gnu.org/47058 ."
+  (let* ((base-file (make-temp-file "dired-test-47058-"))
+         (archive-file (concat base-file extension))
+         (file1 (make-temp-file "a"))
+         (file2 (make-temp-file "b"))
+         (file3 (make-temp-file "c"))
+         (filelist (list file1 file2 file3))
+         (comprcmd (replace-regexp-in-string
+                  "%c" (shell-quote-argument temporary-file-directory)
+                  (replace-regexp-in-string
+                   "%i" (mapconcat 'identity filelist " ")
+                   (replace-regexp-in-string
+                    "%o" (shell-quote-argument archive-file)
+                    compress-cmd)))))
+    (cl-letf (((symbol-function 'read-file-name)
+               (lambda (&rest _) base-file)))
+      (dired-delete-file base-file)
+      (should-not (file-exists-p base-file))
+      (should-not (file-exists-p archive-file))
+      (dired-shell-command comprcmd)
+      (should (file-exists-p archive-file))
+      (mapcar (lambda (f) (should (file-exists-p f)))
+              filelist)
+      (mapcar (lambda (f) (delete-file f))
+              filelist)
+      (mapcar (lambda (f) (should-not (file-exists-p f)))
+              filelist)
+      (should (string-equal
+               (dired-uncompress-file archive-file
+                                      base-file
+                                      uncompress-cmd)
+               (file-name-as-directory base-file)))
+      (mapcar (lambda (f)
+                (should (file-exists-p
+                         (concat (file-name-as-directory base-file) f))))
+              filelist)
+      (dired-delete-file base-file 'always' nil)
+      (dired-delete-file archive-file 'always' nil)
+      (should-not (file-exists-p base-file))
+      (should-not (file-exists-p archive-file)))))
+
 (provide 'dired-aux-tests)
 ;; dired-aux-tests.el ends here

  parent reply	other threads:[~2021-09-20 22:12 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-10 20:26 bug#47058: 28.0.50; Dired Z: insert-directory: Reading directory: No such file or directory, CrossLine_linux_x86 Jean Louis
2021-08-31 21:33 ` Marco Centurion
2021-08-31 22:12   ` Arthur Miller
2021-09-01 13:59     ` Marco Centurion - URI
2021-09-01 16:06       ` Arthur Miller
2021-09-20 22:12       ` Michalis V. [this message]
2021-09-21  4:32         ` Lars Ingebrigtsen
2021-09-21  8:24           ` Eli Zaretskii
2021-09-21  9:18             ` Michalis V.
2021-09-21  9:32               ` Eli Zaretskii
2021-09-21 17:10                 ` Lars Ingebrigtsen
     [not found]                   ` <83a6k5yfrb.fsf@gnu.org>
2021-09-21 17:58                     ` Lars Ingebrigtsen
2021-09-21 18:38                   ` Gregory Heytings
2021-09-21 18:43                     ` Eli Zaretskii
2021-09-21 19:19                       ` Gregory Heytings
2021-09-21 20:11                         ` Michalis V.
2021-09-21 20:48                         ` Gregory Heytings
2021-09-22  5:40                         ` Eli Zaretskii
2021-09-22  7:15                           ` Gregory Heytings
2021-09-22  7:54                             ` Eli Zaretskii
2021-09-22  8:07                               ` Gregory Heytings
2021-09-21 17:07             ` Lars Ingebrigtsen
2021-09-21 20:43               ` Michalis V.
2021-09-22  6:00                 ` Eli Zaretskii
2021-09-21  8:25         ` Michael Albinus
2021-09-21  9:24           ` Michalis V.
2021-09-21 12:06             ` Michael Albinus
2022-03-11  8:29               ` Michael Albinus

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=875yuuq4lh.fsf@gmail.com \
    --to=mvar.40k@gmail.com \
    --cc=47058@debbugs.gnu.org \
    --cc=arthur.miller@live.com \
    --cc=mcenturion@fing.edu.uy \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).