Polish package management system

This commit is contained in:
Henrik Lissner 2017-02-19 06:59:55 -05:00
parent b8f5d549ea
commit c68ae247b5
2 changed files with 215 additions and 162 deletions

View file

@ -1,22 +1,15 @@
;;; packages.el ;;; packages.el
(provide 'doom-lib-packages) (provide 'doom-lib-packages)
(defvar doom-packages-last-refresh nil
"A timestamp indicating the last time `package-refresh-contents' was run.")
;;;###autoload ;;;###autoload
(defun doom-refresh-packages () (defun doom-refresh-packages ()
"Refresh ELPA packages." "Refresh ELPA packages."
(doom-initialize) (doom-initialize)
(let ((refresh-cache (f-expand "last-pkg-refresh" doom-cache-dir))) (let ((last-refresh (persistent-soft-fetch 'last-pkg-refresh "emacs")))
(when (and (not doom-packages-last-refresh) (when (or (not last-refresh)
(f-exists-p refresh-cache)) (> (nth 1 (time-since last-refresh)) 600))
(setq doom-packages-last-refresh (read (f-read refresh-cache))))
(when (or (not doom-packages-last-refresh)
(> (nth 1 (time-since doom-packages-last-refresh)) 600))
(package-refresh-contents) (package-refresh-contents)
(setq doom-packages-last-refresh (current-time)) (persistent-soft-store 'last-pkg-refresh (current-time) "emacs"))))
(f-write (pp-to-string doom-packages-last-refresh) 'utf-8 refresh-cache))))
;;;###autoload ;;;###autoload
(defun doom-package-backend (name) (defun doom-package-backend (name)
@ -36,19 +29,20 @@ quelpa or nil (if not installed)."
"Determine whether NAME (a symbol) is outdated or not. If outdated, returns a "Determine whether NAME (a symbol) is outdated or not. If outdated, returns a
list, whose car is NAME, and cdr the current version list and latest version list, whose car is NAME, and cdr the current version list and latest version
list of the package." list of the package."
(doom-refresh-packages) (doom-initialize)
(-when-let (pkg (assq name package-alist)) (when-let (pkg (assq name package-alist))
(let* ((old-version (package-desc-version (cadr pkg))) (let* ((old-version (package-desc-version (cadr pkg)))
(new-version (new-version
(pcase (doom-package-backend name) (pcase (doom-package-backend name)
('quelpa ('quelpa
(let ((recipe (assq name quelpa-cache)) (let ((recipe (assq name quelpa-cache))
(dir (f-expand (symbol-name name) quelpa-build-dir)) (dir (expand-file-name (symbol-name name) quelpa-build-dir))
(inhibit-message t)) (inhibit-message t))
(-if-let (ver (and (quelpa-setup-p) (quelpa-checkout recipe dir))) (if-let (ver (and (quelpa-setup-p) (quelpa-checkout recipe dir)))
(version-to-list ver) (version-to-list ver)
old-version))) old-version)))
('elpa ('elpa
(doom-refresh-packages)
(let ((desc (cadr (assq name package-archive-contents)))) (let ((desc (cadr (assq name package-archive-contents))))
(when (package-desc-p desc) (when (package-desc-p desc)
(package-desc-version desc))))))) (package-desc-version desc)))))))
@ -63,15 +57,26 @@ Each element is a cons cell, whose car is the package symbol and whose cdr is
the quelpa recipe (if any). the quelpa recipe (if any).
BACKEND can be 'quelpa or 'elpa, and will instruct this function to return only BACKEND can be 'quelpa or 'elpa, and will instruct this function to return only
the packages relevant to that backend." the packages relevant to that backend.
Warning: this function is expensive; it re-evaluates all of doom's config files.
Be careful not to use it in a loop."
(doom-initialize-packages t) (doom-initialize-packages t)
(unless (quelpa-setup-p) (unless (quelpa-setup-p)
(error "Could not initialize quelpa")) (error "Could not initialize quelpa"))
(-non-nil (delete
(--map (or (assq it doom-packages) nil
(list (car (assq it package-alist)))) (mapcar (lambda (pkgsym)
(append doom-protected-packages (or (assq pkgsym doom-packages)
(mapcar 'car doom-packages))))) (list (car (assq pkgsym package-alist)))))
(append doom-protected-packages (mapcar 'car doom-packages)))))
;;;###autoload
(defun doom-get-dependencies-for (name)
"Return a list of packages that depend on the package named NAME."
(doom-initialize)
(when-let (desc (cadr (assq name package-alist)))
(mapcar 'package-desc-name (package--used-elsewhere-p desc nil t))))
;;;###autoload ;;;###autoload
(defun doom-get-outdated-packages () (defun doom-get-outdated-packages ()
@ -79,8 +84,7 @@ the packages relevant to that backend."
containing (PACKAGE-SYMBOL OLD-VERSION-LIST NEW-VERSION-LIST). containing (PACKAGE-SYMBOL OLD-VERSION-LIST NEW-VERSION-LIST).
Used by `doom/packages-update'." Used by `doom/packages-update'."
(-non-nil (--map (doom-package-outdated-p (car it)) (delq nil (mapcar 'doom-package-outdated-p (mapcar 'car (doom-get-packages)))))
(doom-get-packages))))
;;;###autoload ;;;###autoload
(defun doom-get-orphaned-packages () (defun doom-get-orphaned-packages ()
@ -89,30 +93,45 @@ depended on.
Used by `doom/packages-autoremove'." Used by `doom/packages-autoremove'."
(doom-initialize-packages t) (doom-initialize-packages t)
(let ((package-selected-packages (append (mapcar 'car doom-packages) doom-protected-packages))) (let ((package-selected-packages
(append (mapcar 'car doom-packages) doom-protected-packages)))
(package--removable-packages))) (package--removable-packages)))
;;;###autoload ;;;###autoload
(defun doom-get-missing-packages () (defun doom-get-missing-packages ()
"Return a list of packages that aren't installed, but need to be. Each element "Return a list of requested packages that aren't installed or built-in. Each
is a list whose CAR is the package symbol, and whose CDR is a plist taken from element is a list whose CAR is the package symbol, and whose CDR is a plist
that package's `@package' declaration. taken from that package's `@package' declaration.
Used by `doom/packages-install'." Used by `doom/packages-install'."
(--remove (assq (car it) package-alist) (doom-get-packages))) (cl-remove-if (lambda (pkgsym)
(or (assq (car pkgsym) package-alist)
(and (not (plist-get (assq (car pkgsym) doom-packages) :pin))
(assq (car pkgsym) package--builtins))))
(doom-get-packages)))
;;;###autoload ;;;###autoload
(defun doom*package-delete (name) (defun doom*package-delete (name &rest _)
"Update `quelpa-cache' upon a successful `package-delete'." "Update `quelpa-cache' upon a successful `package-delete'."
(when (and (not (package-installed-p name)) (when (and (not (package-installed-p name))
(quelpa-setup-p) (quelpa-setup-p)
(assq name quelpa-cache)) (assq name quelpa-cache))
(setq quelpa-cache (assq-delete-all name quelpa-cache)) (setq quelpa-cache (assq-delete-all name quelpa-cache))
(quelpa-save-cache) (quelpa-save-cache)
(let ((path (f-expand (symbol-name name) quelpa-build-dir))) (let ((path (expand-file-name (symbol-name name) quelpa-build-dir)))
(when (f-exists-p path) (when (file-exists-p path)
(delete-directory path t))))) (delete-directory path t)))))
;;; Private functions
(defsubst doom--version-list-str (vlist)
(concat (number-to-string (car vlist))
"."
(number-to-string (cadr vlist))))
(defsubst doom--sort-alpha (it other)
(string-lessp (symbol-name (car it))
(symbol-name (car other))))
;; ;;
;; Main functions ;; Main functions
@ -135,7 +154,7 @@ example; the package name can be omitted)."
(defun doom-update-package (name) (defun doom-update-package (name)
"Updates package NAME if it is out of date, using quelpa or package.el as "Updates package NAME if it is out of date, using quelpa or package.el as
appropriate." appropriate."
(doom-refresh-packages) (doom-initialize)
(unless (package-installed-p name) (unless (package-installed-p name)
(error "%s isn't installed" name)) (error "%s isn't installed" name))
(when (doom-package-outdated-p name) (when (doom-package-outdated-p name)
@ -157,13 +176,14 @@ appropriate."
(package-desc-version (cadr (assq name package-alist))) (package-desc-version (cadr (assq name package-alist)))
(package-desc-version (cadr (assq name package-archive-contents)))))) (package-desc-version (cadr (assq name package-archive-contents))))))
(defun doom-delete-package (name) (defun doom-delete-package (name &optional force-p)
"Uninstalls package NAME if it exists, and clears it from `quelpa-cache'." "Uninstalls package NAME if it exists, and clears it from `quelpa-cache'."
(doom-initialize) (doom-initialize)
(unless (package-installed-p name) (unless (package-installed-p name)
(error "%s isn't installed" name)) (error "%s isn't installed" name))
(let ((desc (cadr (assq name package-alist)))) (let ((desc (cadr (assq name package-alist)))
(package-delete desc)) (inhibit-message t))
(package-delete desc force-p))
(not (package-installed-p name))) (not (package-installed-p name)))
@ -179,76 +199,79 @@ appropriate."
(cond ((not packages) (cond ((not packages)
(message "No packages to install!")) (message "No packages to install!"))
((not (y-or-n-p ((not (or (getenv "YES")
(format "%s packages will be installed:\n\n%s\n\nProceed?" (y-or-n-p
(length packages) (format "%s packages will be installed:\n\n%s\n\nProceed?"
(mapconcat (lambda (pkg) (length packages)
(format "+ %s (%s)" (mapconcat (lambda (pkg)
(car pkg) (format "+ %s (%s)"
(if (plist-get (cdr pkg) :recipe) (car pkg)
"QUELPA" (if (plist-get (cdr pkg) :recipe)
"ELPA"))) "QUELPA"
(--sort (string-lessp (symbol-name (car it)) "ELPA")))
(symbol-name (car other))) (sort (cl-copy-list packages) 'doom--sort-alpha)
packages) "\n")))))
"\n"))))
(message "Aborted!")) (message "Aborted!"))
(t (t
(doom-message "Installing %s packages" (length packages)) (message "Installing %s packages" (length packages))
(dolist (pkg packages) (dolist (pkg packages)
(condition-case ex (condition-case ex
(doom-message "%s %s (%s)" (progn
(cond ((package-installed-p (car pkg)) (message "%s %s (%s)"
"Skipped (already installed)") (cond ((package-installed-p (car pkg))
((doom-install-package (car pkg) (cdr pkg)) "Skipped (already installed)")
"Installed") ((doom-install-package (car pkg) (cdr pkg))
(t "Failed to install")) "Installed")
(car pkg) (t "Failed to install"))
(cond ((cdr pkg) "QUELPA") (car pkg)
(t "ELPA"))) (cond ((cdr pkg) "QUELPA")
(t "ELPA"))))
(error (error
(doom-message "Error (%s): %s" (car pkg) ex)))) (message "Error (%s): %s" (car pkg) ex))))
(doom-message "Finished!"))))) (message "Finished!")))))
;;;###autoload ;;;###autoload
(defun doom/packages-update () (defun doom/packages-update ()
"Interactive command for updating packages." "Interactive command for updating packages."
(interactive) (interactive)
(let ((packages (doom-get-outdated-packages))) (let ((packages (cl-sort (doom-get-outdated-packages) 'doom--sort-alpha)))
(cond ((not packages) (cond ((not packages)
(message "Everything is up-to-date")) (message "Everything is up-to-date"))
((not (y-or-n-p ((not (or (getenv "YES")
(format "%s packages will be updated:\n\n%s\n\nProceed?" (y-or-n-p
(length packages) (format "%s packages will be updated:\n\n%s\n\nProceed?"
(let ((-max-len (or (-max (--map (length (symbol-name (car it))) packages)) 10))) (length packages)
(mapconcat (let ((max-len
(lambda (pkg) (or (car (sort (mapcar (lambda (it) (length (symbol-name (car it)))) packages)
(format "+ %s %s -> %s" (lambda (it other) (> it other))))
(s-pad-right (+ -max-len 2) " " (symbol-name (car pkg))) 10)))
(s-pad-right 14 " " (doom--version-list-str (cadr pkg))) (mapconcat
(doom--version-list-str (cl-caddr pkg)))) (lambda (pkg)
(--sort (string-lessp (symbol-name (car it)) (format "+ %s %s -> %s"
(symbol-name (car other))) (s-pad-right (+ max-len 2) " " (symbol-name (car pkg)))
packages) (s-pad-right 14 " " (doom--version-list-str (cadr pkg)))
"\n"))))) (doom--version-list-str (cl-caddr pkg))))
packages
"\n"))))))
(message "Aborted!")) (message "Aborted!"))
(t (t
(dolist (pkg packages) (dolist (pkg packages)
(condition-case ex (condition-case ex
(doom-message "%s %s" (progn
(if (doom-update-package (car pkg)) (message "%s %s"
"Updated" (if (doom-update-package (car pkg))
"Failed to update") "Updated"
(car pkg)) "Failed to update")
(car pkg)))
(error (error
(doom-message "Error installing %s: %s" (car pkg) ex)))) (message "Error installing %s: %s" (car pkg) ex))))
(doom-message "Finished!"))))) (message "Finished!")))))
;;;###autoload ;;;###autoload
(defun doom/packages-autoremove () (defun doom/packages-autoremove ()
@ -258,31 +281,27 @@ appropriate."
(cond ((not packages) (cond ((not packages)
(message "No unused packages to remove")) (message "No unused packages to remove"))
((not (y-or-n-p ((not (or (getenv "YES")
(format "%s packages will be deleted:\n\n%s\n\nProceed?" (y-or-n-p
(length packages) (format "%s packages will be deleted:\n\n%s\n\nProceed?"
(mapconcat (lambda (sym) (format "+ %s" (symbol-name sym))) (length packages)
(-sort 'string-lessp packages) (mapconcat (lambda (sym) (format "+ %s" (symbol-name sym)))
"\n")))) (sort (cl-copy-list packages) 'string-lessp)
"\n")))))
(message "Aborted!")) (message "Aborted!"))
(t (t
(dolist (pkg packages) (dolist (pkg packages)
(condition-case ex (condition-case ex
(doom-message "%s %s" (message "%s %s"
(if (doom-delete-package pkg) (if (doom-delete-package pkg t)
"Deleted" "Deleted"
"Failed to delete") "Failed to delete")
pkg) pkg)
(error (error
(doom-message "Error deleting %s: %s" pkg ex)))) (message "Error deleting %s: %s" pkg ex))))
(doom-message "Finished!"))))) (message "Finished!")))))
(defun doom--version-list-str (vlist)
(concat (number-to-string (car vlist))
"."
(number-to-string (cadr vlist))))
;;;###autoload ;;;###autoload
(defalias 'doom/install-package 'package-install) (defalias 'doom/install-package 'package-install)
@ -313,9 +332,9 @@ calls."
(let ((packages (doom-get-outdated-packages))) (let ((packages (doom-get-outdated-packages)))
(list (list
(if packages (if packages
(completing-read "Update package: " (--map (symbol-name (car it)) packages)) (completing-read "Update package: " (mapcar 'symbol-name (mapcar 'car packages)))
(user-error "All packages are up-to-date"))))) (user-error "All packages are up-to-date")))))
(-if-let (desc (doom-package-outdated-p (intern package))) (if-let (desc (doom-package-outdated-p (intern package)))
(if (y-or-n-p (format "%s will be updated from %s to %s. Update?" (if (y-or-n-p (format "%s will be updated from %s to %s. Update?"
(car desc) (car desc)
(doom--version-list-str (cadr desc)) (doom--version-list-str (cadr desc))

View file

@ -1,5 +1,6 @@
;;; core-packages.el ;;; core-packages.el
;; (defvar doom-start-time (current-time))
;; Emacs package management is opinionated. Unfortunately, so am I. So with the ;; Emacs package management is opinionated. Unfortunately, so am I. So with the
;; help of `use-package', `quelpa' and package.el, DOOM Emacs manages my ;; help of `use-package', `quelpa' and package.el, DOOM Emacs manages my
;; plugins and internal module dependency chains. ;; plugins and internal module dependency chains.
@ -55,7 +56,7 @@ package's name as a symbol, and whose CDR is the plist supplied to its
`@package' declaration.") `@package' declaration.")
(defvar doom-protected-packages (defvar doom-protected-packages
'(quelpa use-package dash f s) '(quelpa use-package)
"A list of packages that must be installed (and will be auto-installed if "A list of packages that must be installed (and will be auto-installed if
missing) and shouldn't be deleted.") missing) and shouldn't be deleted.")
@ -83,8 +84,11 @@ packages exist.")
use-package-debug nil use-package-debug nil
use-package-verbose doom-debug-mode use-package-verbose doom-debug-mode
;; Don't use MELPA, we'll use package.el for those
quelpa-checkout-melpa-p nil quelpa-checkout-melpa-p nil
quelpa-update-melpa-p nil quelpa-update-melpa-p nil
quelpa-melpa-recipe-stores nil
quelpa-self-upgrade-p nil
quelpa-dir (expand-file-name "quelpa" doom-packages-dir) quelpa-dir (expand-file-name "quelpa" doom-packages-dir)
byte-compile-dynamic t byte-compile-dynamic t
@ -160,20 +164,18 @@ even if they are."
('error (message "INIT-PACKAGES ERROR (%s): %s" file ex)))))) ('error (message "INIT-PACKAGES ERROR (%s): %s" file ex))))))
(when (or force-p (not doom-modules)) (when (or force-p (not doom-modules))
(setq doom-modules nil) (setq doom-modules nil)
(funcall load-fn (f-expand "init.el" doom-emacs-dir)) (funcall load-fn (expand-file-name "init.el" doom-emacs-dir))
(when load-p (when load-p
(mapc (lambda (file) (funcall load-fn file t)) (mapc (lambda (file) (funcall load-fn file t))
(append (reverse (f-glob "core*.el" doom-core-dir)) (append (reverse (file-expand-wildcards (concat doom-core-dir "core*.el")))
(f-glob "autoload/*.el" doom-core-dir) (file-expand-wildcards (concat doom-core-dir "autoload/*.el"))
(--map (doom-module-path (car it) (cdr it) "config.el") (doom--module-paths "config.el")))))
(doom--module-pairs))))))
(when (or force-p (not doom-packages)) (when (or force-p (not doom-packages))
(setq doom-packages nil) (setq doom-packages nil)
(funcall load-fn (f-expand "packages.el" doom-core-dir)) (funcall load-fn (expand-file-name "packages.el" doom-core-dir))
(mapc (lambda (file) (funcall load-fn file t)) (mapc (lambda (file) (funcall load-fn file t))
(--map (doom-module-path (car it) (cdr it) "packages.el") (doom--module-paths "packages.el")))))
(doom--module-pairs))))))
(defun doom-initialize-modules (modules) (defun doom-initialize-modules (modules)
"Adds MODULES to `doom-modules'. MODULES must be in mplist format. "Adds MODULES to `doom-modules'. MODULES must be in mplist format.
@ -188,11 +190,16 @@ even if they are."
((not mode) ((not mode)
(error "No namespace specified on `@doom' for %s" m)) (error "No namespace specified on `@doom' for %s" m))
((eq m '*) ((eq m '*)
(let ((mode-str (substring (symbol-name mode) 1))) (doom-initialize-modules
(doom-initialize-modules (cons mode
(cons mode (mapcar
(--map (intern (f-base it)) (lambda (dir) (intern (file-name-nondirectory dir)))
(f-directories (f-expand mode-str doom-modules-dir))))))) (cl-remove-if-not
'file-directory-p
(directory-files (expand-file-name
(substring (symbol-name mode) 1)
doom-modules-dir)
t "^\\w"))))))
(t (t
(doom--enable-module mode m)))))) (doom--enable-module mode m))))))
@ -205,8 +212,8 @@ even if they are."
(error "Expected a symbol, got %s" submodule)) (error "Expected a symbol, got %s" submodule))
(let ((module-name (substring (symbol-name module) 1)) (let ((module-name (substring (symbol-name module) 1))
(submodule-name (symbol-name submodule))) (submodule-name (symbol-name submodule)))
(f-expand (concat module-name "/" submodule-name "/" file) (expand-file-name (concat module-name "/" submodule-name "/" file)
doom-modules-dir))) doom-modules-dir)))
(defun doom-module-loaded-p (module submodule) (defun doom-module-loaded-p (module submodule)
"Returns t if MODULE->SUBMODULE is present in `doom-modules'." "Returns t if MODULE->SUBMODULE is present in `doom-modules'."
@ -221,6 +228,16 @@ is sorted by order of insertion."
doom-modules) doom-modules)
pairs)) pairs))
(defun doom--module-paths (&optional append-file)
"Returns a list of absolute file paths to modules, with APPEND-FILE added, if
the file exists."
(let (paths)
(dolist (pair (doom--module-pairs))
(let ((path (doom-module-path (car pair) (cdr pair) append-file)))
(when (file-exists-p path)
(push path paths))))
(reverse paths)))
(defun doom--enable-module (module submodule &optional force-p) (defun doom--enable-module (module submodule &optional force-p)
"Adds MODULE and SUBMODULE to `doom-modules', if it isn't already there (or if "Adds MODULE and SUBMODULE to `doom-modules', if it isn't already there (or if
FORCE-P is non-nil). MODULE is a keyword, SUBMODULE is a symbol. e.g. :lang FORCE-P is non-nil). MODULE is a keyword, SUBMODULE is a symbol. e.g. :lang
@ -230,6 +247,11 @@ Used by `@require' and `@depends-on'."
(unless (or force-p (doom-module-loaded-p module submodule)) (unless (or force-p (doom-module-loaded-p module submodule))
(puthash (cons module submodule) t doom-modules))) (puthash (cons module submodule) t doom-modules)))
(defun doom--display-benchmark ()
(message "Loaded %s packages in %.03fs"
(- (length load-path) (length doom--base-load-path))
(float-time (time-subtract nil doom-start-time))))
;; ;;
;; Macros ;; Macros
@ -241,10 +263,10 @@ Used by `@require' and `@depends-on'."
"DOOM Emacs bootstrap macro. List the modules to load. Benefits from "DOOM Emacs bootstrap macro. List the modules to load. Benefits from
byte-compilation." byte-compilation."
(doom-initialize-modules modules) (doom-initialize-modules modules)
(unless noninteractive `(let (file-name-handler-alist)
`(let (file-name-handler-alist) (setq doom-modules ',doom-modules)
(setq doom-modules ',doom-modules)
(unless noninteractive
,@(mapcar (lambda (module) `(@require ,(car module) ,(cdr module) t)) ,@(mapcar (lambda (module) `(@require ,(car module) ,(cdr module) t))
(doom--module-pairs)) (doom--module-pairs))
@ -254,35 +276,41 @@ byte-compilation."
(server-start))) (server-start)))
;; Benchmark ;; Benchmark
(format "Loaded %s packages in %s" (add-hook 'after-init-hook 'doom--display-benchmark t))))
(- (length load-path) (length doom--base-load-path))
(emacs-init-time)))))
(defalias '@def-package 'use-package (defmacro @def-package (name &rest plist)
"A `use-package' alias. It exists so DOOM configs adhere to the naming "Defines and configures a package using `use-package'. Packages are deferred
conventions of DOOM emacs. Note that packages are deferred by default.") by default. If the package isn't installed or loaded, `@def-package' is
ignored."
(when (or (featurep name)
(package-installed-p name))
`(use-package ,name ,@plist)))
(defmacro @load (filesym &optional path noerror) (defmacro @load (filesym &optional path noerror)
"Loads a file relative to the current module (or PATH). FILESYM is a file path "Loads a file relative to the current module (or PATH). FILESYM is a file path
as a symbol. PATH is a directory to prefix it with. If NOERROR is non-nil, don't as a symbol. PATH is a directory to prefix it with. If NOERROR is non-nil, don't
throw an error if the file doesn't exist. throw an error if the file doesn't exist."
(let ((path (or (and path
Sets `__FILE__' and `__DIR__' on the loaded file." (cond ((symbolp path) (symbol-value path))
(let ((path (or (and path (eval path)) (__DIR__)))) ((stringp path) path)
((listp path) (eval path))))
(and load-file-name (file-name-directory load-file-name))
(and buffer-file-name (file-name-directory buffer-file-name))
(and (bound-and-true-p byte-compile-current-file)
(file-name-directory byte-compile-current-file)))))
(unless path (unless path
(error "Could not find %s" filesym)) (error "Could not find %s" filesym))
(let ((file (f-expand (concat (symbol-name filesym) ".el") path))) (let ((file (expand-file-name (concat (symbol-name filesym) ".el") path)))
(if (f-exists-p file) (if (file-exists-p file)
`(let ((__FILE__ ,file) `(load ,(file-name-sans-extension file) ,noerror (not doom-debug-mode))
(__DIR__ ,path))
(load ,(f-no-ext file) ,noerror (not doom-debug-mode)))
(unless noerror (unless noerror
(error "Could not @load file %s" file)))))) (error "Could not @load file %s" file))))))
(defmacro @require (module submodule &optional reload-p) (defmacro @require (module submodule &optional reload-p)
"Like `require', but for doom modules. Will load a module's config.el file if "Like `require', but for doom modules. Will load a module's config.el file if
it hasn't already, and if it exists." it hasn't already, and if it exists."
(unless noninteractive (when (or (not noninteractive)
(bound-and-true-p byte-compile-current-file))
(let ((loaded-p (doom-module-loaded-p module submodule))) (let ((loaded-p (doom-module-loaded-p module submodule)))
(when (or reload-p (not loaded-p)) (when (or reload-p (not loaded-p))
(unless loaded-p (unless loaded-p
@ -353,22 +381,28 @@ the commandline."
(doom-initialize-packages noninteractive) (doom-initialize-packages noninteractive)
(let ((generated-autoload-file doom-autoload-file) (let ((generated-autoload-file doom-autoload-file)
(autoload-files (autoload-files
(append (-flatten (--map (let ((auto-dir (f-expand "autoload" it)) (file-expand-wildcards
(auto-file (f-expand "autoload.el" it))) (expand-file-name "autoload/*.el" doom-core-dir))))
(append (and (f-exists-p auto-file) (dolist (path (doom--module-paths))
(list auto-file)) (let ((auto-dir (expand-file-name "autoload" path))
(and (f-directory-p auto-dir) (auto-file (expand-file-name "autoload.el" path)))
(f-glob "*.el" auto-dir)))) (when (file-exists-p auto-file)
(--map (doom-module-path (car it) (cdr it)) (push auto-file autoload-files))
(doom--module-pairs)))) (when (file-directory-p auto-dir)
(f-glob "autoload/*.el" doom-core-dir)))) (mapc (lambda (file)
(when (f-exists-p generated-autoload-file) ;; Make evil.el autoload files a special case; don't load them
(f-delete generated-autoload-file) ;; unless evil is enabled.
(unless (and (equal (file-name-nondirectory file) "evil.el")
(not (@featurep :feature evil)))
(push file autoload-files)))
(file-expand-wildcards (expand-file-name "*.el" auto-dir) t)))))
(when (file-exists-p generated-autoload-file)
(delete-file generated-autoload-file)
(message "Deleted old autoloads.el")) (message "Deleted old autoloads.el"))
(dolist (file autoload-files) (dolist (file (reverse autoload-files))
(let ((inhibit-message t)) (let ((inhibit-message t))
(update-file-autoloads file)) (update-file-autoloads file))
(message "Scanned %s" (f-relative file doom-emacs-dir))) (message "Scanned %s" (file-relative-name file doom-emacs-dir)))
(condition-case ex (condition-case ex
(with-current-buffer (get-file-buffer generated-autoload-file) (with-current-buffer (get-file-buffer generated-autoload-file)
(save-buffer) (save-buffer)
@ -387,23 +421,23 @@ There should be a measurable benefit from this, but it may take a while."
;; eval-when-compile and require blocks scattered all over. ;; eval-when-compile and require blocks scattered all over.
(doom-initialize-packages t noninteractive) (doom-initialize-packages t noninteractive)
(let ((targets (let ((targets
(append (list (f-expand "init.el" doom-emacs-dir) (append (list (expand-file-name "init.el" doom-emacs-dir)
(f-expand "core.el" doom-core-dir)) (expand-file-name "core.el" doom-core-dir))
(f-glob "core-*.el" doom-core-dir) (file-expand-wildcards (expand-file-name "core-*.el" doom-core-dir))
(f-glob "autoload/*.el" doom-core-dir) (file-expand-wildcards (expand-file-name "autoload/*.el" doom-core-dir))))
(unless simple-p
(-flatten
(--map (f--entries (doom-module-path (car it) (cdr it))
(and (f-ext-p it "el")
(let ((fname (f-filename it)))
(or (string= fname "config.el")
(s-prefix-p "+" fname t))))
t)
(doom--module-pairs))))))
(n 0) (n 0)
results) results)
(unless simple-p
(dolist (path (doom--module-paths))
(nconc targets
(cl-remove-if (lambda (file)
(let ((fname (file-name-nondirectory file)))
(or (string= fname ".")
(string= fname ".."))))
(reverse
(directory-files-recursively path "\\.el$"))))))
(dolist (file targets) (dolist (file targets)
(push (cons (f-relative file doom-emacs-dir) (push (cons (file-relative-name file doom-emacs-dir)
(and (byte-recompile-file file nil 0) (and (byte-recompile-file file nil 0)
(setq n (1+ n)))) (setq n (1+ n))))
results)) results))