magit / emacsql

A high-level Emacs Lisp RDBMS front-end
The Unlicense
554 stars 41 forks source link

"apply: Selecting deleted buffer" when opening a magit buffer (with forge installed) #104

Closed winny- closed 1 year ago

winny- commented 2 years ago

what behavior you expected

Magit should able to carry on and open the buffer if there's a forge issue.

what behavior you observed

Visitng a file in a git repository, then running magit-status yields an error.

and how we can reproduce the issue.

Not sure, see the next section for my environment information. If I'm successful in reproducing in an easy-to-reproduce enviroment I'll follow up.

Environment

GNU Emacs 28.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.34, cairo version 1.16.0)

backtrace

Debugger entered--Lisp error: (error "Selecting deleted buffer")
  #f(compiled-function (connection) "Return true if the end of the buffer has a properly-formatted prompt." #<bytecode -0xc1bb28134296ed9>)(#<forge-database forge-database-fe5f0e>)
  apply(#f(compiled-function (connection) "Return true if the end of the buffer has a properly-formatted prompt." #<bytecode -0xc1bb28134296ed9>) #<forge-database forge-database-fe5f0e> nil)
  emacsql-waiting-p(#<forge-database forge-database-fe5f0e>)
  #f(compiled-function (connection &optional timeout) "Block until CONNECTION is waiting for further input." #<bytecode -0x1a666b92c4a6ef10>)(#<forge-database forge-database-fe5f0e>)
  apply(#f(compiled-function (connection &optional timeout) "Block until CONNECTION is waiting for further input." #<bytecode -0x1a666b92c4a6ef10>) #<forge-database forge-database-fe5f0e> nil)
  emacsql-wait(#<forge-database forge-database-fe5f0e>)
  #f(compiled-function (#<forge-database forge-database-fe5f0e> (:file "/home/winston/.emacs.d/forge-database.sqlite"))
  apply(#f(compiled-function 
  #f(compiled-function (&rest args) #<bytecode 0x24e89310fe0bc38>)(#<forge-database forge-database-fe5f0e> (:file "/home/winston/.emacs.d/forge-database.sqlite"))
  apply(#f(compiled-function (&rest args) #<bytecode 0x24e89310fe0bc38>) #<forge-database forge-database-fe5f0e> (:file "/home/winston/.emacs.d/forge-database.sqlite"))
  initialize-instance(#<forge-database forge-database-fe5f0e> (:file "/home/winston/.emacs.d/forge-database.sqlite"))
  #f(compiled-function (class &rest slots) "Default constructor for CLASS `eieio-default-superclass'.\nSLOTS are the initialization slots used by `initialize-instance'.\nThis static method is called when an object is constructed.\nIt allocates the vector used to represent an EIEIO object, and then\ncalls `initialize-instance' on that object." #<bytecode -0x1e7474630a623959>)(forge-database :file "/home/winston/.emacs.d/forge-database.sqlite")
  apply(#f(compiled-function (class &rest slots) "Default constructor for CLASS `eieio-default-superclass'.\nSLOTS are the initialization slots used by `initialize-instance'.\nThis static method is called when an object is constructed.\nIt allocates the vector used to represent an EIEIO object, and then\ncalls `initialize-instance' on that object." #<bytecode -0x1e7474630a623959>) forge-database (:file "/home/winston/.emacs.d/forge-database.sqlite"))
  make-instance(forge-database :file "/home/winston/.emacs.d/forge-database.sqlite")
  #f(compiled-function (class &optional variable file debug) #<bytecode 0x1c4ec0bcfc5a4e4f>)(forge-database forge--db-connection "/home/winston/.emacs.d/forge-database.sqlite" t)
  apply(#f(compiled-function (class &optional variable file debug) #<bytecode 0x1c4ec0bcfc5a4e4f>) forge-database (forge--db-connection "/home/winston/.emacs.d/forge-database.sqlite" t))
  closql-db(forge-database forge--db-connection "/home/winston/.emacs.d/forge-database.sqlite" t)
  forge-db()
  forge-sql([:select * :from repository :where (and (= forge $s1) (= owner $s2) (= name $s3))] "gitlab.com" "winny" "dotfiles")
  #f(compiled-function (&rest rest) "((host owner name) &optional remote demand)\n\nReturn the repository identified by HOST, OWNER and NAME." #<bytecode 0x1ca381fcf2cd580>)(("gitlab.com" "winny" "dotfiles") "origin" full)
  apply(#f(compiled-function (&rest rest) "((host owner name) &optional remote demand)\n\nReturn the repository identified by HOST, OWNER and NAME." #<bytecode 0x1ca381fcf2cd580>) ("gitlab.com" "winny" "dotfiles") ("origin" full))
  forge-get-repository(("gitlab.com" "winny" "dotfiles") "origin" full)
  #f(compiled-function (url &optional remote demand) "Return the repository at URL." #<bytecode -0x146129c3f134b01e>)("git@gitlab.com:winny/dotfiles.git" "origin" full)
  apply(#f(compiled-function (url &optional remote demand) "Return the repository at URL." #<bytecode -0x146129c3f134b01e>) "git@gitlab.com:winny/dotfiles.git" ("origin" full))
  forge-get-repository("git@gitlab.com:winny/dotfiles.git" "origin" full)
  #f(compiled-function (demand &optional remote) "Return the current forge repository.\n\nIf the `forge-buffer-repository' is non-nil, then return that.\nOtherwise if `forge-buffer-topic' is non-nil, then return the\nrepository for that.  Finally if both variables are nil, then\nreturn the forge repository corresponding to the current Git\nrepository, if any." #<bytecode 0x13b54082cfa1b5a5>)(full)
  apply(#f(compiled-function (demand &optional remote) "Return the current forge repository.\n\nIf the `forge-buffer-repository' is non-nil, then return that.\nOtherwise if `forge-buffer-topic' is non-nil, then return the\nrepository for that.  Finally if both variables are nil, then\nreturn the forge repository corresponding to the current Git\nrepository, if any." #<bytecode 0x13b54082cfa1b5a5>) full nil)
  forge-get-repository(full)
  forge-bug-reference-setup()
  run-hooks(change-major-mode-after-body-hook special-mode-hook magit-section-mode-hook magit-mode-hook magit-status-mode-hook)
  apply(run-hooks (change-major-mode-after-body-hook special-mode-hook magit-section-mode-hook magit-mode-hook magit-status-mode-hook))
  run-mode-hooks(magit-status-mode-hook)
  magit-status-mode()
  magit-setup-buffer-internal(magit-status-mode nil ((magit-buffer-diff-args ("--no-ext-diff")) (magit-buffer-diff-files nil) (magit-buffer-log-args ("-n256" "--decorate")) (magit-buffer-log-files nil)))
  magit-status-setup-buffer("~/p/dotfiles/.git/")
  magit-status(nil ((5 . 10) (("/home/winston/p/dotfiles/" "remote" "get-url" "origin") . "git@gitlab.com:winny/dotfiles.git") (("/home/winston/p/dotfiles/" . config) . #<hash-table equal 36/65 0xfe5a4d>) (("/home/winston/p/dotfiles/" . magit-toplevel) . "/home/winston/p/dotfiles/") (("/home/winston/p/dotfiles/" "rev-parse" "--show-cdup") . "") (("/home/winston/p/dotfiles/" "rev-parse" "--show-toplevel") . "/home/winston/p/dotfiles") (("~/p/dotfiles/.git/" . magit-toplevel) . "/home/winston/p/dotfiles/") (("/home/winston/p/dotfiles/.git/" "rev-parse" "--is-bare-repository") . "false\n") (("/home/winston/p/dotfiles/.git/" "rev-parse" "--git-dir") . ".") (("/home/winston/p/dotfiles/.git/" "rev-parse" "--show-toplevel"))))
  funcall-interactively(magit-status nil ((5 . 10) (("/home/winston/p/dotfiles/" "remote" "get-url" "origin") . "git@gitlab.com:winny/dotfiles.git") (("/home/winston/p/dotfiles/" . config) . #<hash-table equal 36/65 0xfe5a4d>) (("/home/winston/p/dotfiles/" . magit-toplevel) . "/home/winston/p/dotfiles/") (("/home/winston/p/dotfiles/" "rev-parse" "--show-cdup") . "") (("/home/winston/p/dotfiles/" "rev-parse" "--show-toplevel") . "/home/winston/p/dotfiles") (("~/p/dotfiles/.git/" . magit-toplevel) . "/home/winston/p/dotfiles/") (("/home/winston/p/dotfiles/.git/" "rev-parse" "--is-bare-repository") . "false\n") (("/home/winston/p/dotfiles/.git/" "rev-parse" "--git-dir") . ".") (("/home/winston/p/dotfiles/.git/" "rev-parse" "--show-toplevel"))))
  call-interactively(magit-status nil nil)
  command-execute(magit-status)

other issues with same error message (might be unrelated)

MassimoLauria commented 2 years ago

I have the same issue with Magit and disabling Forge temporarily fixed it. I only have the issue on MacOS, but I don't have it on Linux.

tarsius commented 2 years ago

I am guessing that there was some fatal error when running the executable. That causes the process sentinel to be run and that kills the process buffer unconditionally, which in this case is premature because emacsql-waiting-p will still try to access the buffer.

Changing that function to the following should address that:

(cl-defmethod emacsql-waiting-p ((connection emacsql-protocol-mixin))
  "Return t if the end of the buffer has a properly-formatted prompt.
Also return t if the process has terminated."
  (let ((buffer (emacsql-buffer connection)))
    (or (not (buffer-live-p buffer))
        (with-current-buffer buffer
          (and (>= (buffer-size) 2)
               (string= "#\n"
                        (buffer-substring (- (point-max) 2) (point-max))))))))

However, that won't show the error message about why the executable could not be run. (You probably will get an error about a timeout, but that probably isn't correct, given that you didn't mention a hang.) The process sentinel should probably be changed to raise an error itself, but I don't know what such an error would look like, so please also apply this patch:

diff --git a/emacsql-sqlite.el b/emacsql-sqlite.el
index b14d1ac..58f2f5a 100644
--- a/emacsql-sqlite.el
+++ b/emacsql-sqlite.el
@@ -96,7 +96,11 @@ (cl-defmethod initialize-instance :after
                    "emacsql-sqlite" buffer emacsql-sqlite-executable fullfile)))
     (setf (slot-value connection 'process) process)
     (setf (process-sentinel process)
-          (lambda (proc _) (kill-buffer (process-buffer proc))))
+          (lambda (proc str)
+            (let ((buf (process-buffer proc)))
+              (message "--- %s" str)
+              (message ">>>%s<<<" (with-current-buffer buf (buffer-string)))
+              (kill-buffer buf))))
     (emacsql-wait connection)
     (emacsql connection [:pragma (= busy-timeout $s1)]
              (/ (* emacsql-global-timeout 1000) 2))

and post the output.

hexmode commented 1 year ago

I just came across this using emacs HEAD (a06c13db9eee0487975177089b44198dd08206be) and saw some "Selecting deleted buffer" messages which led me to this bug. it does appear to be related to sqlite.

Emacs 28 (the version I can get easily from Debian) works without a problem.

My minimal init.el to reproduce this is:


(let ((bootstrap-file
        (expand-file-name "straight/repos/straight.el/bootstrap.el"
                user-emacs-directory))
       (bootstrap-version 5)
       (straight-url (concat "https://raw.githubusercontent.com/raxod502/"
                             "straight.el/develop/install.el")))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously straight-url
                'silent 'inhibit-cookies)
      (goto-char (point-max))
      (eval-print-last-sexp)))
  (message (concat "got " bootstrap-file))
  (load bootstrap-file nil 'nomessage))
(declare-function straight-use-package (expand-file-name "~/.emacs.d/straight/repos/straight.el/straight.el"))
(straight-use-package 'use-package)

(use-package magit
  :bind (("C-x v d" . magit-status))
  :ensure t
  :init
  (fset 'vc-dir 'magit-status)
  :custom
  (magit-diff-refine-hunk t)
  (magit-diff-refine-ignore-whitespace t)
  ; maybe change to a numger if this is too heavy
  (magit-diff-adjust-tab-width t))

(use-package forge
  :straight t
  :after magit)
tsdh commented 1 year ago

Bug report on the emacs side: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=60872

tarsius commented 1 year ago

Fixed. See https://github.com/magit/forge/issues/535#issuecomment-1387734805.