Subject: Fwd: bug#41000: 28.0.50; Package file(.el) is 0 bytes after downloading

From: Stefan Kangas <[email-masked]>
Date: Tue, 24 Aug 2021 16:29:18 +0200

It seems like the below was sent to me in private, without using
"Reply to all" so it never reached the bug tracker.  I am therefore
forwarding the full message here.

---------- Forwarded message ---------
Från: Compro Prasad <[email-masked]>
Date: mån 11 maj 2020 kl 09:00
Subject: Re: bug#41000: 28.0.50; Package file(.el) is 0 bytes after downloading
To: Stefan Kangas <[email-masked]>

On Sat, May 9, 2020 at 12:04 AM Stefan Kangas <[email-masked]> wrote:
>
> Compro Prasad <[email-masked]> writes:
>
> > There isn't a valid way to reproduce this issue. It mostly works fine. But
> > this has occured with me in the past too but thought it was already
> > reported.
>
> Could you tell us anything else regarding the circumstances when this
> happens, or is it completely random?
Its completely random and mostly rare. Network might be an issue. But am
not sure.
> How frequent is it?
Its rare.
> Also, could you please try using "emacs -Q" while installing and/or
> upgrading packages for a while to see if you can reproduce this issue
> there?
There isn't a valid way to reproduce this. It happens at random, maybe due
to network issues.
> > To be very specific I have mostly found the .el file having 0 bytes size.
> > Other files mostly had sizes greater than 0 bytes.
>
> Which other files are you referring to?  Do you mean other files inside
> a multi file package?
I am referring to the .el files of the package that I install using
package-install.

I have used an advice after package-install and also an after-init-hook
function that checks for any empty file which fixes this thing for now. Its
given below.

(defun compro/get-empty-pkgs ()
  "Get 0 bytes .el packages."
  (let ((default-directory package-user-dir))
    (seq-reduce
     (lambda (value-list file)
       (if (= (file-attribute-size (file-attributes file)) 0)
           (cons file value-list)
         value-list))
     (seq-filter
      (apply-partially #'s-suffix-p ".el")
      (seq-reduce
       (lambda (value-list file)
         (if (and
              (not (s-prefix-p "." file))
              (file-accessible-directory-p file))
             (append
              (seq-map
               (apply-partially #'concat file "/")
               (directory-files file))
              value-list)
           value-list))
       (directory-files "")
       '()))
     '())))

(defun compro/redownload-empty-pkgs ()
  "Redownload empty packages."
  (interactive)
  (let* ((pkgs (compro/get-empty-pkgs))
         (default-directory package-user-dir)
         (choice-list (list
                       (cons (intern "Delete and re-download all") 1)
                       (cons (intern "Manually select for re-downloading") 2)
                       (cons (intern "Fix everything manually") 3)))
         (choice (if pkgs
                     (alist-get
                      (intern
                       (completing-read
                        (concat
                         "Some files were not properly downloaded namely "
                         (s-join ", " pkgs)
                         ". What action do you want to take?  ")
                        choice-list))
                      choice-list)
                   3)))
    (if (= choice 3)
        (when (null pkgs)
          (message "No empty packages were found"))
      (package-refresh-contents)
      (seq-each
       (lambda (file)
         (let* ((values (s-split "/" file))
                (dir-name (car values))
                (pkg-values (s-split "-" dir-name))
                (pkg-name (s-join "-" (butlast pkg-values 1)))
                (each-choice
                 (if (= choice 1)
                     t
                   (yes-or-no-p
                    (concat "Delete and re-download " dir-name "? ")))))
           (when each-choice
             (delete-directory dir-name t)
             (ignore-errors
               (package-reinstall (intern pkg-name))))))
       pkgs))))
(add-hook 'after-init-hook 'compro/redownload-empty-packages)

(defun re-download (pkg &optional arg)
  "Advice for package-install."
  (let* ((pkg-name (symbol-name (if (package-desc-p pkg)
                                    (package-desc-name pkg)
                                  pkg)))
         (file-name (car
                     (sort
                      (seq-filter
                       (apply-partially #'s-prefix-p pkg-name)
                       (compro/get-empty-pkgs))
                      #'string-greaterp)))
         (dir (when file-name (car (s-split "/" file-name)))))
    (when dir
      (delete-directory dir)
      (ignore-errors (package-reinstall pkg)))))
(advice-add 'package-install :after 're-download)

My elisp skills aren't great but the above fixes my issue for now.
Would be nice to have something concrete to handle this issue.

Regards,
Compro Prasad