Rewrite core-packages: byte-compile & autoload generation now module-aware

This commit is contained in:
Henrik Lissner 2017-01-28 02:02:16 -05:00
parent 80eafe71cb
commit 0007c246eb

View file

@ -1,14 +1,20 @@
;;; core-packages.el ;;; core-packages.el
;; Emacs has always been opinionated about package management. Unfortunately, so ;; Emacs is opinionated about package management. Unfortunately, so am I. So I
;; have I. I used to use Cask, but found it very unreliable, so the result is ;; combined use-package, quelpa and package.el to manage my plugins.
;; this: a mini-package manager I've written by combining the functionality of
;; package.el, quelpa and use-package.
;; ;;
;; Why all the trouble? Because I want to be able to call an ;; Why all the trouble? Because:
;; 'update-all-packages' function from a shell script and the like. I want to be ;; 1. Scriptability: I want my plugins managable from the command line (as well
;; able to manage my Emacs' packages from the command line, because I have tools ;; as an 'update-all-packages' command within emacs to update my plugins
;; in my dotfiles to help me auto-update everything with a one-liner. ;; automatically, rather than through package.el's clunky interface).
;; 2. Flexibility: I want to install packages from sources other than ELPA
;; repositories. Such as github or the Emacs wiki. Some plugins are out of
;; date through official channels, have changed hands unofficially, or simply
;; haven't been submitted to an ELPA repo yet.
;; 3. Stability: I don't want to be scared that every time I use my package
;; management something may go wrong. This was the case with Cask, which I
;; used previously. package.el and quelpa are much more stable.
;; 4. No external dependencies (e.g. Cask) for plugin management.
(defvar doom-init nil (defvar doom-init nil
"Whether doom's package system has been initialized or not. It may not be if "Whether doom's package system has been initialized or not. It may not be if
@ -20,9 +26,6 @@ you have byte-compiled your configuration (as intended).")
(defvar doom-modules nil (defvar doom-modules nil
"List of installed modules.") "List of installed modules.")
(defvar doom-packages-auto-p (not noninteractive)
"")
(defvar doom--load-path load-path (defvar doom--load-path load-path
"A backup of `load-path' before it was initialized.") "A backup of `load-path' before it was initialized.")
@ -35,49 +38,48 @@ you have byte-compiled your configuration (as intended).")
("melpa" . "http://melpa.org/packages/") ("melpa" . "http://melpa.org/packages/")
("org" . "http://orgmode.org/elpa/")) ("org" . "http://orgmode.org/elpa/"))
use-package-always-ensure t
use-package-always-defer t use-package-always-defer t
use-package-always-ensure nil
use-package-debug doom-debug-mode
quelpa-checkout-melpa-p nil quelpa-checkout-melpa-p nil
quelpa-update-melpa-p nil quelpa-update-melpa-p nil
quelpa-use-package-inhibit-loading-quelpa t
quelpa-dir (expand-file-name "quelpa" doom-packages-dir)) quelpa-dir (expand-file-name "quelpa" doom-packages-dir))
;; ;;
;; Bootstrap ;; Library
;; ;;
(autoload 'use-package "use-package")
(defun doom-package-init (&optional force-p) (defun doom-package-init (&optional force-p)
"Initialize DOOM, its essential packages and package.el. This must be used on "Initialize DOOM, its essential packages and package.el. This must be used on
first run. If you byte compile core/core.el, this file is avoided to speed up first run. If you byte compile core/core.el, this file is avoided to speed up
startup." startup. Returns `load-path'."
(when (or (not doom-init) force-p) (when (or (not doom-init) force-p)
(package-initialize) (package-initialize)
(unless (file-exists-p package-user-dir) (when (or (not (file-exists-p package-user-dir)) force-p)
(package-refresh-contents)) (package-refresh-contents))
(unless (package-installed-p 'quelpa-use-package) (unless (package-installed-p 'quelpa-use-package)
(package-install 'quelpa-use-package t)) (package-install 'quelpa-use-package t))
(require 'quelpa)
(require 'use-package)
(when doom-packages-auto-p
(setq use-package-always-ensure t)
(require 'quelpa-use-package) (require 'quelpa-use-package)
(quelpa-use-package-activate-advice)) (setq use-package-always-ensure t)
(quelpa-use-package-activate-advice)
(add-to-list 'load-path doom-local-dir)
(add-to-list 'load-path doom-modules-dir) (add-to-list 'load-path doom-modules-dir)
(add-to-list 'load-path doom-private-dir)
(add-to-list 'load-path doom-core-dir) (add-to-list 'load-path doom-core-dir)
(setq doom-init t))) (setq doom-init t)))
(defmacro package! (name &rest rest) (defmacro package! (name &rest rest)
"Declare a package. Wraps around `use-package', and takes the same arguments "Declare a package. Wraps around `use-package', and takes the same arguments
that it does." that it does. NOTE: Packages are deferred by default."
(declare (indent defun)) (declare (indent defun))
(add-to-list 'doom-packages name) (add-to-list 'doom-packages name)
(unless doom-packages-auto-p ;; If `use-package-always-ensure' is nil, then remove any possibility of an
;; installation by package.el or quelpa.
(unless use-package-always-ensure
(when (and (plist-member rest :ensure) (when (and (plist-member rest :ensure)
(plist-get rest :ensure)) (plist-get rest :ensure))
(setq rest (plist-put rest :ensure nil))) (setq rest (plist-put rest :ensure nil)))
@ -85,24 +87,41 @@ that it does."
(use-package-plist-delete rest :quelpa))) (use-package-plist-delete rest :quelpa)))
(macroexpand-all `(use-package ,name ,@rest))) (macroexpand-all `(use-package ,name ,@rest)))
(defmacro load-internal! (module package) (defmacro load! (file-or-module-sym &optional submodule noerror)
"Load a module from `doom-modules-dir'. Plays the same role as
`load-relative', but is specific to DOOM emacs modules and submodules.
) Examples:
(load! :lang emacs-lisp) loads modules/lang/emacs-lisp/{packages,config}.el
(load! +local-module) if called from ./config.el, loads ./+local-module.el
Note: requires that config.el be loaded with `load!'"
(let* ((module-name (symbol-name file-or-module-sym))
(module (if (and submodule (string-prefix-p ":" module-name)) (substring module-name 1) module-name)))
(if submodule
(let ((path (concat doom-modules-dir module "/" (symbol-name submodule) "/")))
(macroexp-progn
(mapcar (lambda (file)
(when (file-exists-p (concat path file ".el"))
(doom--load path file (not doom-debug-mode))))
(append (list "packages")
(unless noninteractive (list "config"))))))
(let ((path (concat (f-dirname load-file-name) "/")))
(doom--load path module (not doom-debug-mode))))))
(defmacro load! (plugin) (defvar __DIR__ nil "The directory of the currently loaded file (with `load!')")
(defvar __FILE__ nil "The full path of the currently loaded file (with `load!')")
) (defun doom--load (path file &optional noerror)
`(let ((__FILE__ ,(concat path file (if noninteractive ".el")))
(__DIR__ ,path))
(load __FILE__ nil ,noerror noninteractive noninteractive)))
(defun doom-package-outdated-p (package &optional inhibit-refresh-p)
;; "Determine whether PACKAGE (a symbol) is outdated or not. If INHIBIT-REFRESH-P
;; Commands is non-nil, don't run `package-refresh-contents' (which is slow, but useful if
;; you intend to use this method for batch processing -- be sure to run
`package-refresh-contents' beforehand however)."
(defun doom-package-outdated-p (package &optional inhibit-refresh) (unless inhibit-refresh-p
"Determine whether PACKAGE (a symbol) is outdated or not. If INHIBIT-REFRESH
is non-nil, don't run `package-refresh-contents' (which is slow. Use for batch
processing, and run `package-refresh-contents' once, beforehand)."
(unless inhibit-refresh
(package-refresh-contents)) (package-refresh-contents))
(when (and (package-installed-p package) (when (and (package-installed-p package)
(cadr (assq package package-archive-contents))) (cadr (assq package package-archive-contents)))
@ -114,28 +133,20 @@ processing, and run `package-refresh-contents' once, beforehand)."
(not (version-list-<= newest-version installed-version))))) (not (version-list-<= newest-version installed-version)))))
(defun doom/packages-reload () (defun doom/packages-reload ()
"Reload DOOM Emacs. This includes the `load-path'" "Reload `load-path' by scanning all packages. Run this if you ran make update
or make clean outside of Emacs."
(interactive) (interactive)
(setq load-path doom--load-path) (setq load-path doom--load-path)
(doom-package-init t) (doom-package-init t)
(when (called-interactively-p 'interactive) (when (called-interactively-p 'interactive)
(message "Reloaded %s packages" (length package-alist)))) (message "Reloaded %s packages" (length package-alist))))
(defun doom/packages-install ()
"Activate `doom-packages-auto-p' and evaluation your emacs configuration
again, in order to auto-install all packages that are missing."
(interactive)
(setq doom-packages-auto-p t)
(doom-package-init t)
(load (expand-file-name "init.el" doom-emacs-dir) nil nil t))
(defun doom/packages-update () (defun doom/packages-update ()
"Update all installed packages. This includes quelpa itself, quelpa-installed "Update outdated packages. This includes quelpa itself, quelpa-installed
packages, and ELPA packages." packages, and ELPA packages. This will delete old versions of packages as well."
(interactive) (interactive)
(doom-package-init t) (doom-package-init t)
(quelpa-upgrade) ; upgrade quelpa + quelpa-installed packages (quelpa-upgrade) ; upgrade quelpa + quelpa-installed packages
(package-refresh-contents) ; ...then packages.el
(mapc (lambda (package) (mapc (lambda (package)
(condition-case ex (condition-case ex
(let ((desc (cadr (assq package package-alist)))) (let ((desc (cadr (assq package package-alist))))
@ -147,7 +158,7 @@ packages, and ELPA packages."
(package--find-non-dependencies))))) (package--find-non-dependencies)))))
(defun doom/packages-clean () (defun doom/packages-clean ()
"Delete unused packages." "Delete packages that are no longer used or referred to."
(interactive) (interactive)
(doom-package-init t) (doom-package-init t)
(let* ((package-selected-packages (-intersection (package--find-non-dependencies) doom-packages)) (let* ((package-selected-packages (-intersection (package--find-non-dependencies) doom-packages))
@ -171,41 +182,56 @@ packages, and ELPA packages."
(when quelpa-modified-p (when quelpa-modified-p
(quelpa-save-cache)))))) (quelpa-save-cache))))))
(defun doom/byte-compile () (defun doom/byte-compile (&optional comprehensive-p)
"Byte (re)compile the important files in your emacs configuration. No more no "Byte (re)compile the important files in your emacs configuration. DOOM Emacs
less." was designed to benefit a lot from this. If COMPREHENSIVE-P is non-nil, compile
config.el and autoload.el files as well -- the performance benefit from this is
minor and may take a while.
No need to recompile any of these files so long as `auto-compile-mode' is on in
`emacs-lisp-mode', which, if you're using the provided emacs-lisp module, should
be the case."
(interactive) (interactive)
(let (use-package-always-ensure)
(doom-package-init) (doom-package-init)
(mapc 'byte-compile-file (mapc 'byte-compile-file
(append (list (expand-file-name "init.el" doom-emacs-dir) (append (list (expand-file-name "init.el" doom-emacs-dir)
(expand-file-name "core.el" doom-core-dir)) (expand-file-name "core.el" doom-core-dir))
(reverse (reverse
(file-expand-wildcards (f-glob "core-*.el" doom-core-dir))
(expand-file-name "core*.el" doom-core-dir))) (f-glob "*/*/packages.el" doom-modules-dir)
(file-expand-wildcards (when comprehensive-p
(expand-file-name "*/*/packages.el" doom-modules-dir))))) (f-glob "*/*/config.el" doom-modules-dir))
(when comprehensive-p
(f-glob "*/*/autoload.el" doom-modules-dir))))))
(defun doom/refresh-autoloads (&optional inhibit-require) (defun doom/refresh-autoloads ()
"Refreshes your emacs config's autoloads file. Use this if you modify an "Refreshes the autoloads.el file, which tells Emacs where to find all the
autoload.el file in any module." autoloaded functions in the modules you use or among the core libraries.
Rerun this whever you modify your init.el (or use `make autoloads` from the
command line)."
(interactive) (interactive)
(let ((generated-autoload-file (concat doom-modules-dir "autoloads.el")) (let ((generated-autoload-file (concat doom-local-dir "autoloads.el"))
(interactive-p (called-interactively-p 'interactive)) (interactive-p (called-interactively-p 'interactive))
(autoload-files (autoload-files
(file-expand-wildcards (append (-filter 'file-exists-p
(expand-file-name "*/*/autoload.el" doom-modules-dir)))) (mapcar (lambda (m)
(f-expand
(format "%s/%s/autoload.el" (substring (symbol-name (car m)) 1) (cdr m))
doom-modules-dir))
doom-modules))
(f-glob "autoload/*.el" doom-core-dir))))
(when (file-exists-p generated-autoload-file) (when (file-exists-p generated-autoload-file)
(delete-file generated-autoload-file) (delete-file generated-autoload-file)
(when interactive-p (message "Deleted old autoloads.el"))) (when interactive-p (message "Deleted old autoloads.el")))
(dolist (file autoload-files) (dolist (file autoload-files)
(update-file-autoloads file t) (update-file-autoloads file t)
(when interactive-p (unless interactive-p
(message "Detected: %s" (message "Detected: %s" (f-relative file doom-emacs-dir))))
(file-relative-name (directory-file-name parent)
doom-emacs-dir))))
(when interactive-p (message "Done!")) (when interactive-p (message "Done!"))
(with-demoted-errors "WARNING: %s" (with-demoted-errors "WARNING: %s"
(load "autoloads")))) (load generated-autoload-file nil t))))
(provide 'core-packages) (provide 'core-packages)
;;; core-packages.el ends here ;;; core-packages.el ends here