Polish package management system; no infinite recursion; smarter autoload refresh
This commit is contained in:
parent
70a1fb52cc
commit
e80df3c03c
4 changed files with 122 additions and 84 deletions
|
@ -58,7 +58,7 @@ the quelpa recipe (if any).
|
|||
|
||||
BACKEND can be 'quelpa or 'elpa, and will instruct this function to return only
|
||||
the packages relevant to that backend."
|
||||
(doom-initialize)
|
||||
(doom-reload)
|
||||
(unless (quelpa-setup-p)
|
||||
(error "Could not initialize quelpa"))
|
||||
(--map (cons it (assq it quelpa-cache))
|
||||
|
@ -76,18 +76,31 @@ be fed to `doom/packages-update'."
|
|||
(defun doom-get-orphaned-packages ()
|
||||
"Return a list of packages that are no longer needed or depended on. Can be
|
||||
fed to `doom/packages-delete'."
|
||||
(doom-initialize)
|
||||
(-difference (package--removable-packages)
|
||||
doom-protected-packages))
|
||||
(doom-reload)
|
||||
(let ((package-selected-packages
|
||||
(append (mapcar 'car doom-packages) doom-protected-packages)))
|
||||
(package--removable-packages)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-get-packages-to-install ()
|
||||
"Return a list of packages that aren't installed, but need to be. Used by
|
||||
`doom/packages-install'."
|
||||
(doom-refresh-self)
|
||||
(doom-reload)
|
||||
(--remove (assq (car it) package-alist)
|
||||
(append doom-packages (-map 'list doom-protected-packages))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom*package-delete (name)
|
||||
"Makes `package-delete' update `quelpa-cache'."
|
||||
(when (and (not (package-installed-p name))
|
||||
(quelpa-setup-p)
|
||||
(assq name quelpa-cache))
|
||||
(setq quelpa-cache (assq-delete-all name quelpa-cache))
|
||||
(quelpa-save-cache)
|
||||
(let ((path (f-expand (symbol-name name) quelpa-build-dir)))
|
||||
(when (f-exists-p path)
|
||||
(delete-directory path t)))))
|
||||
|
||||
|
||||
;;
|
||||
;; Main functions
|
||||
|
@ -133,15 +146,8 @@ appropriate."
|
|||
(doom-initialize)
|
||||
(unless (package-installed-p name)
|
||||
(error "%s isn't installed" name))
|
||||
(let ((desc (cadr (assq package package-alist))))
|
||||
(let ((desc (cadr (assq name package-alist))))
|
||||
(package-delete desc))
|
||||
(when (and (quelpa-setup-p)
|
||||
(assq name quelpa-cache))
|
||||
(setq quelpa-cache (delq name quelpa-cache))
|
||||
(let ((path (f-expand (symbol-name name) quelpa-build-dir)))
|
||||
(when (f-exists-p path)
|
||||
(delete-directory path t)))
|
||||
(quelpa-save-cache))
|
||||
(not (package-installed-p name)))
|
||||
|
||||
|
||||
|
@ -152,6 +158,7 @@ appropriate."
|
|||
|
||||
;;;###autoload
|
||||
(defun doom/packages-install ()
|
||||
"Interactive command for installing missing packages."
|
||||
(interactive)
|
||||
(let ((packages (doom-get-packages-to-install)))
|
||||
(cond ((not packages)
|
||||
|
@ -187,6 +194,7 @@ appropriate."
|
|||
|
||||
;;;###autoload
|
||||
(defun doom/packages-update ()
|
||||
"Interactive command for updating packages."
|
||||
(interactive)
|
||||
(let ((packages (doom-get-outdated-packages)))
|
||||
(cond ((not packages)
|
||||
|
@ -219,6 +227,7 @@ appropriate."
|
|||
|
||||
;;;###autoload
|
||||
(defun doom/packages-autoremove ()
|
||||
"Interactive command for auto-removing orphaned packages."
|
||||
(interactive)
|
||||
(let ((packages (doom-get-orphaned-packages)))
|
||||
(cond ((not packages)
|
||||
|
@ -243,7 +252,6 @@ appropriate."
|
|||
|
||||
(doom-message "Finished!")))))
|
||||
|
||||
|
||||
;;;###autoload
|
||||
(defalias 'doom/package-install 'package-install)
|
||||
|
||||
|
|
|
@ -60,14 +60,15 @@ If HOOK is omitted, then default to `__PACKAGE__' to determine HOOK."
|
|||
(-list hook)))))
|
||||
funcs))))
|
||||
|
||||
(defmacro associate! (mode &rest rest)
|
||||
(defmacro associate! (&rest rest)
|
||||
"Associate a major or minor mode to certain patterns and project files."
|
||||
(declare (indent 1))
|
||||
(let ((minor (plist-get rest :minor))
|
||||
(in (plist-get rest :in))
|
||||
(match (plist-get rest :match))
|
||||
(files (plist-get rest :files))
|
||||
(pred (plist-get rest :when)))
|
||||
(let* ((mode (if (keywordp (car rest)) __PACKAGE__ (pop rest)))
|
||||
(minor (plist-get rest :minor))
|
||||
(in (plist-get rest :in))
|
||||
(match (plist-get rest :match))
|
||||
(files (plist-get rest :files))
|
||||
(pred (plist-get rest :when)))
|
||||
(cond ((or files in pred)
|
||||
(when (and files (not (or (listp files) (stringp files))))
|
||||
(user-error "associate! :files expects a string or list of strings"))
|
||||
|
|
|
@ -37,6 +37,10 @@ if you have byte-compiled your configuration (as intended).")
|
|||
anything, just track what should be loaded. Useful for scanning packages and
|
||||
loaded modules.")
|
||||
|
||||
(defvar doom-reloading-p nil
|
||||
"If non-nil, DOOM is reloading itself. Use this to determine to prevent
|
||||
infinite recursion.")
|
||||
|
||||
(defvar doom-prefer-el-p noninteractive
|
||||
"If non-nil, load uncompiled .el config files.")
|
||||
|
||||
|
@ -62,7 +66,6 @@ loaded modules.")
|
|||
use-package-verbose doom-debug-mode
|
||||
quelpa-checkout-melpa-p nil
|
||||
quelpa-update-melpa-p nil
|
||||
quelpa-use-package-inhibit-loading-quelpa t
|
||||
quelpa-dir (expand-file-name "quelpa" doom-packages-dir)
|
||||
;; ssh, no tears. Only compiling.
|
||||
byte-compile-warnings
|
||||
|
@ -107,7 +110,13 @@ avoided to speed up startup."
|
|||
(unless (or doom-init-p force-p)
|
||||
(setq load-path doom--base-load-path
|
||||
package-activated-list nil)
|
||||
(package-initialize)
|
||||
(package-initialize t)
|
||||
;; Sure, package-initialize fills the load-path, but it will error out on
|
||||
;; missing packages. UNACCEPTAABBLLLE!
|
||||
(setq load-path
|
||||
(append load-path
|
||||
(directory-files package-user-dir t "^[a-zA-Z0-9]" t)))
|
||||
|
||||
(unless (and (file-exists-p doom-packages-dir)
|
||||
(require 'use-package nil t)
|
||||
(require 'quelpa nil t))
|
||||
|
@ -125,7 +134,7 @@ avoided to speed up startup."
|
|||
|
||||
(require 'quelpa)
|
||||
(require 'use-package)
|
||||
(advice-add 'package-delete :around 'doom*package-delete)
|
||||
(advice-add 'package-delete :after 'doom*package-delete)
|
||||
;; Remove package management keywords, I'll deal with the myself
|
||||
(mapc (lambda (keyword) (setq use-package-keywords (delq keyword use-package-keywords)))
|
||||
'(:ensure :pin))
|
||||
|
@ -134,12 +143,21 @@ avoided to speed up startup."
|
|||
(defun doom-reload ()
|
||||
"Rereads the Emacs config, reloading `doom-packages' and
|
||||
`doom-enabled-modules'."
|
||||
(doom-initialize)
|
||||
(let ((doom-prefer-el-p t)
|
||||
(doom-dont-load-p t))
|
||||
(setq doom-modules nil
|
||||
doom-packages nil)
|
||||
(load (concat doom-emacs-dir "init.el") :noerror (not doom-debug-mode) :nosuffix)))
|
||||
(unless doom-reloading-p
|
||||
(doom-initialize)
|
||||
(let ((doom-prefer-el-p t)
|
||||
(doom-dont-load-p t)
|
||||
(doom-reloading-p t)
|
||||
noninteractive)
|
||||
(setq doom-enabled-modules nil
|
||||
doom-packages nil)
|
||||
(let ((load-fn (lambda (file) (load file :noerror (not doom-debug-mode) :nosuffix))))
|
||||
(mapc load-fn
|
||||
(list (f-expand "init.el" doom-emacs-dir)
|
||||
(f-expand "core.el" doom-core-dir)))
|
||||
(mapc load-fn
|
||||
(--map (doom-module-path (car it) (cdr it) "packages.el")
|
||||
doom-enabled-modules))))))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -155,43 +173,48 @@ avoided to speed up startup."
|
|||
conventions of DOOM emacs, as well as let-bind `__PACKAGE__' for the containing
|
||||
forms. This is helpful for macros like `set!' and `add-hook!'. Note that
|
||||
packages are deferred by default."
|
||||
(declare (indent defun))
|
||||
`(let ((__PACKAGE__ ',name))
|
||||
(use-package ,name ,@plist)))
|
||||
|
||||
(defmacro package! (name &rest plist)
|
||||
"Wraps around `use-package' (with `quelpa-use-package') and takes the same
|
||||
arguments. Ensures the package named NAME is installed and available. If
|
||||
`doom--auto-install-p' is nil, then strip out :ensure and :quelpa properties,
|
||||
which is the case if you've byte-compiled DOOM Emacs.
|
||||
|
||||
Note that packages are deferred by default."
|
||||
"Wraps around `use-package' to declare a deferred package (unless otherwise
|
||||
indicated), takes the same arguments, but adds the :recipe property, which takes
|
||||
a MELPA recipe. Also binds `__PACKAGE__` for PLIST forms to optionally use."
|
||||
(declare (indent defun))
|
||||
(let ((recipe (cadr (memq :recipe plist)))
|
||||
(pin (cadr (memq :pin plist))))
|
||||
(when recipe
|
||||
(when (= 0 (mod (length recipe) 2))
|
||||
(push name recipe))
|
||||
(setq plist (use-package-plist-delete plist :recipe)))
|
||||
(pin (cadr (memq :pin plist)))
|
||||
(lpath (cadr (memq :load-path plist))))
|
||||
(when (and recipe (= 0 (mod (length recipe) 2)))
|
||||
(push name recipe))
|
||||
(if (not lpath)
|
||||
(cl-pushnew (cons name recipe) doom-packages :key 'car)
|
||||
(cl-pushnew lpath doom--base-load-path)
|
||||
(setq recipe nil
|
||||
pin nil))
|
||||
(when pin
|
||||
(add-to-list 'package-pinned-packages (cons package (plist-get plist :pin)))
|
||||
(setq plist (use-package-plist-delete plist :pin)))
|
||||
(pushnew (cons name recipe) doom-packages :key 'car)
|
||||
(cl-pushnew (cons package (plist-get plist :pin)) package-pinned-packages :key 'car))
|
||||
(setq plist (use-package-plist-delete plist :recipe))
|
||||
(setq plist (use-package-plist-delete plist :pin))
|
||||
(unless doom-dont-load-p
|
||||
`(use-package! ,name ,@plist))))
|
||||
|
||||
(defmacro require! (feature)
|
||||
"Like `require', but prefers uncompiled files when `doom-prefer-el-p' is
|
||||
non-nil or in a noninteractive session."
|
||||
"Like `require', but will prefer uncompiled files if `doom-prefer-el-p' is
|
||||
non-nil or this is a noninteractive session."
|
||||
(let ((prefer-el-p (or doom-prefer-el-p noninteractive)))
|
||||
`(require ',feature
|
||||
,(locate-file (concat (symbol-name feature) (if prefer-el-p ".el"))
|
||||
load-path))))
|
||||
|
||||
(defmacro load! (file-or-module-sym &optional submodule file)
|
||||
"Load a module from `doom-modules-dir'. Plays the same role as
|
||||
`load-relative', but is specific to DOOM emacs modules and submodules. If
|
||||
`doom-prefer-el-p' is non-nil or in an noninteractive session, prefer the
|
||||
un-compiled elisp file.
|
||||
(defmacro load! (module &optional submodule file)
|
||||
"Load a module from `doom-modules-dir' when both MODULE and SUBMODULE is
|
||||
provided (both symbols). If FILE is non-nil, append it to the resulting path. If
|
||||
SUBMODULE is nil, MODULE is loaded relative to the current file (see `__DIR__').
|
||||
When SUBMODULE is nil, FILE isn't used.
|
||||
|
||||
Will prefer uncompiled elisp sources if `doom-prefer-el-p' is non-nil or this is
|
||||
an noninteractive session.
|
||||
|
||||
Examples:
|
||||
(load! :lang emacs-lisp)
|
||||
|
@ -205,13 +228,13 @@ Examples:
|
|||
path file)
|
||||
(cond ((null submodule)
|
||||
(setq path __DIR__
|
||||
file (concat (symbol-name file-or-module-sym) ".el")))
|
||||
file (concat (symbol-name module) ".el")))
|
||||
(t
|
||||
(pushnew (cons file-or-module-sym submodule)
|
||||
doom-enabled-modules
|
||||
:test (lambda (x y) (and (eq (car x) (car y))
|
||||
(eq (cdr x) (cdr y)))))
|
||||
(setq path (doom-module-path file-or-module-sym submodule)
|
||||
(cl-pushnew (cons module submodule)
|
||||
doom-enabled-modules
|
||||
:test (lambda (x y) (and (eq (car x) (car y))
|
||||
(eq (cdr x) (cdr y)))))
|
||||
(setq path (doom-module-path module submodule)
|
||||
file (or file "config.el"))))
|
||||
(setq path (f-slash path)
|
||||
file (concat path file))
|
||||
|
@ -249,39 +272,42 @@ or make clean outside of Emacs."
|
|||
"Refreshes the autoloads.el file, which tells Emacs where to find all the
|
||||
autoloaded functions in the modules you use or among the core libraries.
|
||||
|
||||
In modules, checks for modules/*/autoload.el and modules/*/autoload/*.el.
|
||||
|
||||
Rerun this whenever you modify your init.el (or use `make autoloads` from the
|
||||
command line)."
|
||||
(interactive)
|
||||
(doom-reload)
|
||||
(let ((generated-autoload-file (concat doom-local-dir "autoloads.el"))
|
||||
(autoload-files
|
||||
(append (-flatten (mapcar (lambda (dir)
|
||||
(let ((auto-dir (f-expand "autoload" dir))
|
||||
(auto-file (f-expand "autoload.el" dir)))
|
||||
(cond ((f-directory-p auto-dir)
|
||||
(f-glob "*.el" auto-dir))
|
||||
((f-exists-p auto-file)
|
||||
auto-file))))
|
||||
(--map (doom-module-path (car it) (cdr it)) doom-enabled-modules)))
|
||||
(f-glob "autoload/*.el" doom-core-dir))))
|
||||
(when (f-exists-p generated-autoload-file)
|
||||
(f-delete generated-autoload-file)
|
||||
(message "Deleted old autoloads.el"))
|
||||
(dolist (file autoload-files)
|
||||
(update-file-autoloads file)
|
||||
(message "Detected: %s" (f-relative file doom-emacs-dir)))
|
||||
(with-current-buffer (get-file-buffer generated-autoload-file)
|
||||
(save-buffer))
|
||||
(load generated-autoload-file nil t t)
|
||||
(message "Done!")))
|
||||
(unless doom-reloading-p
|
||||
(doom-reload)
|
||||
(let ((generated-autoload-file (concat doom-local-dir "autoloads.el"))
|
||||
(autoload-files
|
||||
(append (-flatten (mapcar (lambda (dir)
|
||||
(let ((auto-dir (f-expand "autoload" dir))
|
||||
(auto-file (f-expand "autoload.el" dir)))
|
||||
(cond ((f-directory-p auto-dir)
|
||||
(f-glob "*.el" auto-dir))
|
||||
((f-exists-p auto-file)
|
||||
auto-file))))
|
||||
(--map (doom-module-path (car it) (cdr it)) doom-enabled-modules)))
|
||||
(f-glob "autoload/*.el" doom-core-dir))))
|
||||
(when (f-exists-p generated-autoload-file)
|
||||
(f-delete generated-autoload-file)
|
||||
(message "Deleted old autoloads.el"))
|
||||
(dolist (file autoload-files)
|
||||
(update-file-autoloads file)
|
||||
(message "Detected: %s" (f-relative file doom-emacs-dir)))
|
||||
(with-current-buffer (get-file-buffer generated-autoload-file)
|
||||
(save-buffer)
|
||||
(eval-buffer))
|
||||
(message "Done!"))))
|
||||
|
||||
(defun doom/byte-compile (&optional comprehensive-p)
|
||||
"Byte (re)compile the important files in your emacs configuration (i.e.
|
||||
init.el, core/*.el and modules/*/*/config.el) DOOM Emacs was designed to benefit
|
||||
a lot from this.
|
||||
|
||||
If COMPREHENSIVE-P or the envar ALL is non-nil, also compile all autoload files.
|
||||
The benefit from this is minimal and may take more time."
|
||||
If COMPREHENSIVE-P is non-nil, then compile modules/*/*/*.el (except for
|
||||
packages.el files). The benefit from this is minimal and may take more time."
|
||||
(interactive)
|
||||
(doom-reload)
|
||||
(let ((targets (append
|
||||
|
|
11
core/core.el
11
core/core.el
|
@ -133,9 +133,7 @@ enable multiple minor modes for the same regexp.")
|
|||
|
||||
;;; Let 'er rip
|
||||
(require 'core-lib)
|
||||
(unless (require 'autoloads (concat doom-local-dir "autoloads.el") t)
|
||||
(doom/refresh-autoloads))
|
||||
|
||||
(require 'autoloads (concat doom-local-dir "autoloads.el") t)
|
||||
(unless noninteractive
|
||||
(package! anaphora
|
||||
:commands (awhen aif acond awhile))
|
||||
|
@ -160,7 +158,12 @@ enable multiple minor modes for the same regexp.")
|
|||
(require! core-ui) ; draw me like one of your French editors
|
||||
(require! core-popups) ; taming sudden yet inevitable windows
|
||||
(require! core-editor) ; baseline configuration for text editing
|
||||
(require! core-projects))) ; making Emacs project-aware
|
||||
(require! core-projects) ; making Emacs project-aware
|
||||
|
||||
;; We check last as a promise that the core files won't use autoloaded
|
||||
;; functions. If they do, it shouldn't be autoloaded!
|
||||
(unless (featurep 'autoloads)
|
||||
(doom/refresh-autoloads))))
|
||||
|
||||
(provide 'core)
|
||||
;;; core.el ends here
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue