Redesign Doom error handling

Another refactor, again to improve the locality of doom errors and make
the data that accompanies them more useful in determining the origin and
source of issues. Also, bin/doom is now a little more informative about
how to debug errors.
This commit is contained in:
Henrik Lissner 2018-06-20 02:07:12 +02:00
parent 84756b33a0
commit 151858a8dc
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
5 changed files with 89 additions and 64 deletions

View file

@ -85,5 +85,18 @@
((let ((default-directory emacs-dir))
(setq argv nil
noninteractive 'doom)
(doom-dispatch args)))))
(condition-case e (doom-dispatch args)
((debug error)
(message "--------------------------------------------------\n")
(message "There was an unexpected error:")
(message " %s (%s)" (get (car e) 'error-message) (car e))
(dolist (item (cdr e))
(message " %s" item))
(unless debug-on-error
(message
(concat "\nRun the command again with the -d (or --debug) option to enable debug\n"
"mode and, hopefully, generate a stack trace. If you decide to file a bug\n"
"report, please include it!\n\n"
"Emacs outputs to standard error, so you'll need to redirect stderr to\n"
"stdout to pipe this to a file or clipboard!\n\n"
" e.g. doom -d install 2>&1 | clipboard-program")))))))))

View file

@ -463,10 +463,22 @@ If NOERROR is non-nil, don't throw an error if the file doesn't exist."
(setq path (or (DIR!)
(error "Could not detect path to look for '%s' in"
filename))))
`(load ,(if path
`(expand-file-name ,filename ,path)
filename)
,noerror ,(not doom-debug-mode)))
(let ((file (if path `(expand-file-name ,filename ,path) filename)))
`(condition-case e
(load ,file ,noerror ,(not doom-debug-mode))
((debug doom-error) (signal (car e) (cdr e)))
((debug error)
(let* ((source (file-name-sans-extension ,file))
(err (cond ((file-in-directory-p source doom-core-dir)
(cons 'doom-error doom-core-dir))
((file-in-directory-p source doom-private-dir)
(cons 'doom-private-error doom-private-dir))
((cons 'doom-module-error doom-emacs-dir)))))
(signal (car err)
(list (file-relative-name
(concat source ".el")
(cdr err))
e)))))))
(provide 'core-lib)
;;; core-lib.el ends here

View file

@ -27,10 +27,6 @@ A warning will be put out if these deprecated modules are used.")
;; Bootstrap API
;;
;; Custom errors
(define-error 'doom-autoload-error "Error in your autoloads file(s)" 'doom-error)
(define-error 'doom-private-error "Error in your private config" 'doom-error)
(defun doom-initialize-modules (&optional force-p)
"Loads the init.el in `doom-private-dir' and sets up hooks for a healthy
session of Dooming. Will noop if used more than once, unless FORCE-P is
@ -43,8 +39,8 @@ non-nil."
(condition-case e
(load (expand-file-name "init" doom-private-dir)
'noerror 'nomessage)
((debug error)
(signal 'doom-private-error (list 'init e)))))))
((debug doom-error) (signal (car e) (cdr e)))
((debug error) (signal 'doom-private-error (list "init.el" e)))))))
;;
@ -285,11 +281,7 @@ to least)."
(let ((doom--stage 'config))
,@(nreverse config-forms)
(when doom-private-dir
(condition-case e
(load ,(expand-file-name "config" doom-private-dir)
t (not doom-debug-mode))
((debug error)
(signal 'doom-private-error (list 'config e))))))))))
(load! "config" doom-private-dir)))))))
(defvar doom-disabled-packages)
(defmacro def-package! (name &rest plist)

View file

@ -93,13 +93,11 @@ them."
;; the current session, but if you change an packages.el file in a module,
;; there's no non-trivial way to detect that, so we give you a way to
;; reload only doom-packages (by passing 'internal as FORCE-P).
;; `doom-packages'
(unless (eq force-p 'internal)
;; `package-alist'
(when (or force-p (not (bound-and-true-p package-alist)))
(setq load-path (cons doom-core-dir doom-site-load-path))
(doom-ensure-packages-initialized 'force))
;; `quelpa-cache'
(when (or force-p (not (bound-and-true-p quelpa-cache)))
;; ensure un-byte-compiled version of quelpa is loaded
@ -108,22 +106,32 @@ them."
(setq quelpa-initialized-p nil)
(or (quelpa-setup-p)
(error "Could not initialize quelpa"))))
;; `doom-packages'
(when (or force-p (not doom-packages))
(let ((doom-modules (doom-modules))
(doom--stage 'packages)
(noninteractive t))
(setq doom-packages nil)
(load (expand-file-name "packages.el" doom-core-dir) t t)
;; We load the private packages file twice to ensure disabled
;; packages are seen ASAP, and a second time to ensure privately
;; overridden packages are properly overwritten.
(let ((private-packages (expand-file-name "packages.el" doom-private-dir)))
(load private-packages t t)
(cl-loop for key being the hash-keys of doom-modules
for path = (doom-module-path (car key) (cdr key) "packages.el")
do (let ((doom--current-module key)) (load path t t)))
(load private-packages t t)))))))
(cl-flet
((_load
(lambda (file &optional noerror)
(condition-case e
(load file noerror t t)
((debug error)
(signal 'doom-package-error
(list (or (doom-module-from-path file)
'(:private . packages))
e)))))))
(let ((doom-modules (doom-modules))
(doom--stage 'packages)
(noninteractive t))
(setq doom-packages nil)
(_load (expand-file-name "packages.el" doom-core-dir))
;; We load the private packages file twice to ensure disabled
;; packages are seen ASAP, and a second time to ensure privately
;; overridden packages are properly overwritten.
(let ((private-packages (expand-file-name "packages.el" doom-private-dir)))
(_load private-packages t)
(cl-loop for key being the hash-keys of doom-modules
for path = (doom-module-path (car key) (cdr key) "packages.el")
do (let ((doom--current-module key)) (_load path t)))
(_load private-packages t))))))))
;;
@ -191,35 +199,31 @@ Returns t if package is successfully registered, and nil if it was disabled
elsewhere."
(declare (indent defun))
(doom--assert-stage-p 'packages #'package!)
(condition-case e
(let* ((old-plist (cdr (assq name doom-packages)))
(pkg-recipe (or (plist-get plist :recipe)
(and old-plist (plist-get old-plist :recipe))))
(pkg-pin (or (plist-get plist :pin)
(and old-plist (plist-get old-plist :pin))))
(pkg-disable (or (plist-get plist :disable)
(and old-plist (plist-get old-plist :disable)))))
(when pkg-disable
(add-to-list 'doom-disabled-packages name nil #'eq))
(when pkg-recipe
(when (= 0 (% (length pkg-recipe) 2))
(setq plist (plist-put plist :recipe (cons name pkg-recipe))))
(when pkg-pin
(setq plist (plist-put plist :pin nil))))
(dolist (prop '(:ignore :freeze))
(when-let* ((val (plist-get plist prop)))
(setq plist (plist-put plist prop (eval val)))))
(when (file-in-directory-p (or (bound-and-true-p byte-compile-current-file)
load-file-name)
doom-private-dir)
(setq plist (plist-put plist :private t)))
`(progn
,(if pkg-pin `(map-put package-pinned-packages ',name ,pkg-pin))
(map-put doom-packages ',name ',plist)
(not (memq ',name doom-disabled-packages))))
((debug error)
(signal 'doom-private-error
(list (list 'packages name) e)))))
(let* ((old-plist (cdr (assq name doom-packages)))
(pkg-recipe (or (plist-get plist :recipe)
(and old-plist (plist-get old-plist :recipe))))
(pkg-pin (or (plist-get plist :pin)
(and old-plist (plist-get old-plist :pin))))
(pkg-disable (or (plist-get plist :disable)
(and old-plist (plist-get old-plist :disable)))))
(when pkg-disable
(add-to-list 'doom-disabled-packages name nil #'eq))
(when pkg-recipe
(when (= 0 (% (length pkg-recipe) 2))
(setq plist (plist-put plist :recipe (cons name pkg-recipe))))
(when pkg-pin
(setq plist (plist-put plist :pin nil))))
(dolist (prop '(:ignore :freeze))
(when-let* ((val (plist-get plist prop)))
(setq plist (plist-put plist prop (eval val)))))
(when (file-in-directory-p (or (bound-and-true-p byte-compile-current-file)
load-file-name)
doom-private-dir)
(setq plist (plist-put plist :private t)))
`(progn
,(if pkg-pin `(map-put package-pinned-packages ',name ,pkg-pin))
(map-put doom-packages ',name ',plist)
(not (memq ',name doom-disabled-packages)))))
(defmacro packages! (&rest packages)
"A convenience macro like `package!', but allows you to declare multiple

View file

@ -119,8 +119,12 @@ else (except for `window-setup-hook').")
;; Custom error types
;;
(define-error 'doom-error "Doom Emacs error")
(define-error 'doom-error "Error in Doom Emacs core")
(define-error 'doom-hook-error "Error in a Doom startup hook" 'doom-error)
(define-error 'doom-autoload-error "Error in an autoloads file" 'doom-error)
(define-error 'doom-module-error "Error in a Doom module" 'doom-error)
(define-error 'doom-private-error "Error in private config" 'doom-error)
(define-error 'doom-package-error "Error with packages" 'doom-error)
;;