Skip to content

Commit

Permalink
core: implement :depends for package declarations
Browse files Browse the repository at this point in the history
This replaces the older pattern
:toggle (configuration-layer/package-usedp ..)

This implementation ensures that :disabled-for honors dependent packages, i.e.
if package a depends on package b, which is owned by layer c, and layer c is
disabled for layer d, then neither package a nor b will be configured for layer
d. Previously, this was only true for package a, but not b.

This commit also fixes:

- configuration-layer/describe-package now shows which post-init and pre-init
  functions are disabled, if any
- Does not recreate all layer objects unconditionally when calling
  configuration-layer/discover-layers. Previously, this led to all layers being
  recreated after e.g. `SPC h SPC`, without any of the dotfile information.
  Since this information is now necessary for
  configuration-layer/describe-package, it’s important that we don’t clear the
  indexed layers when invoking this function.
  • Loading branch information
TheBB committed Jun 22, 2017
1 parent a38d717 commit 08561d8
Show file tree
Hide file tree
Showing 41 changed files with 320 additions and 92 deletions.
119 changes: 94 additions & 25 deletions core/core-configuration-layer.el
Expand Up @@ -163,9 +163,9 @@ If PROPS is non-nil then return packages as lists with their properties"
:type list
:documentation "List of layers with a pre-init function.")
(post-layers :initarg :post-layers
:initform '()
:type list
:documentation "List of layers with a post-init function.")
:initform '()
:type list
:documentation "List of layers with a post-init function.")
(location :initarg :location
:initform elpa
:type (satisfies (lambda (x)
Expand Down Expand Up @@ -196,16 +196,42 @@ If PROPS is non-nil then return packages as lists with their properties"
:initform nil
:type boolean
:documentation
"If non-nil this package is excluded from all layers.")))

(defmethod cfgl-package-enabledp ((pkg cfgl-package) &optional inhibit-messages)
"If non-nil this package is excluded from all layers.")
(depends :initarg :depends
:initform nil
:type list
:documentation
"Packages that must be enabled for this package to be enabled.")))

(defmethod cfgl-package-toggled-p ((pkg cfgl-package) &optional inhibit-messages)
"Evaluate the `toggle' slot of passed PKG.
If INHIBIT-MESSAGES is non nil then any message emitted by the toggle evaluation
is ignored."
(let ((message-log-max (unless inhibit-messages message-log-max))
(toggle (oref pkg :toggle)))
(eval toggle)))

(defmethod cfgl-package-deps-satisfied-p ((pkg cfgl-package) &optional inhibit-messages)
"Check if dependencies of a package are all enabled.
If INHIBIT-MESSAGES is non nil then any message emitted by the toggle evaluation
is ignored."
(not (memq nil (mapcar
(lambda (dep-pkg)
(let ((pkg-obj (configuration-layer/get-package dep-pkg)))
(when pkg-obj
(cfgl-package-enabled-p pkg-obj inhibit-messages))))
(oref pkg :depends)))))

(defmethod cfgl-package-enabled-p ((pkg cfgl-package) &optional inhibit-messages)
"Check if a package is enabled.
This checks the excluded property, evaluates the toggle, if any, and recursively
checks whether dependent packages are also enabled.
If INHIBIT-MESSAGES is non nil then any message emitted by the toggle evaluation
is ignored."
(and (or (oref pkg :protected) (not (oref pkg :excluded)))
(cfgl-package-deps-satisfied-p pkg inhibit-messages)
(cfgl-package-toggled-p pkg inhibit-messages)))

(defmethod cfgl-package-get-safe-owner ((pkg cfgl-package))
"Safe method to return the name of the layer which owns PKG."
;; The owner of a package is the first *used* layer in `:owners' slot.
Expand Down Expand Up @@ -421,12 +447,12 @@ If NO-INSTALL is non nil then install steps are skipped."
(spacemacs-buffer//inject-version))
;; declare used layers then packages as soon as possible to resolve
;; usage and ownership
(configuration-layer/discover-layers)
(configuration-layer/discover-layers 'refresh-index)
(configuration-layer//declare-used-layers dotspacemacs-configuration-layers)
(configuration-layer//declare-used-packages configuration-layer--used-layers)
;; then load the functions and finally configure the layers
(configuration-layer//load-layers-files configuration-layer--used-layers
'("funcs.el"))
'("funcs.el"))
(configuration-layer//configure-layers configuration-layer--used-layers)
;; pre-filter some packages to save some time later in the loading process
(setq configuration-layer--used-distant-packages
Expand Down Expand Up @@ -469,7 +495,7 @@ If NO-INSTALL is non nil then install steps are skipped."
;; configure used packages
(configuration-layer//configure-packages configuration-layer--used-packages)
(configuration-layer//load-layers-files configuration-layer--used-layers
'("keybindings.el"))
'("keybindings.el"))
(run-hooks 'configuration-layer-post-sync-hook))

(defun configuration-layer/load-auto-layer-file ()
Expand Down Expand Up @@ -606,6 +632,8 @@ If TOGGLEP is nil then `:toggle' parameter is ignored."
(min-version (when (listp pkg) (plist-get (cdr pkg) :min-version)))
(step (when (listp pkg) (plist-get (cdr pkg) :step)))
(toggle (when (listp pkg) (plist-get (cdr pkg) :toggle)))
(depends (when (listp pkg) (plist-get (cdr pkg) :depends)))
(depends (if (listp depends) depends (list depends)))
(excluded (when (listp pkg) (plist-get (cdr pkg) :excluded)))
(location (when (listp pkg) (plist-get (cdr pkg) :location)))
(protected (when (listp pkg) (plist-get (cdr pkg) :protected)))
Expand All @@ -623,7 +651,10 @@ If TOGGLEP is nil then `:toggle' parameter is ignored."
(when min-version
(cfgl-package-set-property obj :min-version (version-to-list min-version)))
(when step (cfgl-package-set-property obj :step step))
(when toggle (cfgl-package-set-property obj :toggle toggle))
(when toggle
(cfgl-package-set-property obj :toggle toggle))
(when (and ownerp depends)
(cfgl-package-set-property obj :depends depends))
(cfgl-package-set-property obj :excluded
(and (configuration-layer/layer-usedp layer-name)
(or excluded (oref obj :excluded))))
Expand Down Expand Up @@ -682,6 +713,12 @@ If TOGGLEP is nil then `:toggle' parameter is ignored."
(format (concat "Ignoring :toggle for package %s because "
"layer %S does not own it.")
pkg-name layer-name)))
;; check if depends can be applied
(when (and (not ownerp) depends)
(configuration-layer//warning
(format (concat "Ignoring :depends for package %s because "
"layer %S does not own it.")
pkg-name layer-name)))
(when (fboundp pre-init-func)
(object-add-to-list obj :pre-layers layer-name))
(when (fboundp post-init-func)
Expand All @@ -704,6 +741,12 @@ If TOGGLEP is nil then `:toggle' parameter is ignored."
(purecopy (concat "mouse-2, RET: "
"visit the Spacemacs dotfile where variable is defined.")))

(define-button-type 'help-describe-package
:supertype 'help-xref
'help-function 'configuration-layer/describe-package
'help-echo
(purecopy (concat "mouse-2, RET: show a description of this package.")))

(defun configuration-layer/describe-package (pkg-symbol
&optional layer-list pkg-list)
"Describe a package in the context of the configuration layer system."
Expand Down Expand Up @@ -754,11 +797,22 @@ If TOGGLEP is nil then `:toggle' parameter is ignored."
;; toggle
(unless (or (oref pkg :excluded) (eq t (oref pkg :toggle)))
(princ "\nA toggle is defined for this package, it is currently ")
(princ (if (cfgl-package-enabledp pkg t) "on" "off"))
(princ (if (cfgl-package-toggled-p pkg t) "on" "off"))
(princ " because the following expression evaluates to ")
(princ (if (cfgl-package-enabledp pkg t) "t:\n" "nil:\n"))
(princ (if (cfgl-package-toggled-p pkg t) "t:\n" "nil:\n"))
(princ (oref pkg :toggle))
(princ "\n"))
(when (oref pkg :depends)
(princ "\nThis package depends on the following packages: ")
(dolist (dep-pkg (oref pkg :depends))
(princ (concat "`" (symbol-name dep-pkg) "' "))
(with-current-buffer standard-output
(save-excursion
(re-search-backward "`\\([^`']+\\)'" nil t)
(help-xref-button 1 'help-describe-package dep-pkg))))
(princ "\nThese dependencies are currently ")
(princ (if (cfgl-package-deps-satisfied-p pkg t) "" "not "))
(princ "satisfied.\n"))
(unless (oref pkg :excluded)
;; usage and installation
(if (not (configuration-layer/package-usedp pkg-symbol))
Expand Down Expand Up @@ -838,7 +892,9 @@ If TOGGLEP is nil then `:toggle' parameter is ignored."
(help-xref-button
1 'help-function-def
(intern (format "%S/pre-init-%S" layer-sym pkg-symbol))
path))))
path)))
(unless (configuration-layer//package-enabled-p pkg layer-sym)
(princ " (disabled)")))
(princ " "))
(princ "\n"))
(when (oref pkg post-layers)
Expand All @@ -853,7 +909,9 @@ If TOGGLEP is nil then `:toggle' parameter is ignored."
(help-xref-button
1 'help-function-def
(intern (format "%S/post-init-%S" layer-sym pkg-symbol))
path))))
path)))
(unless (configuration-layer//package-enabled-p pkg layer-sym)
(princ " (disabled)")))
(princ " "))
(princ "\n"))))
(princ (concat "\nClick [here] to display an Emacs description "
Expand Down Expand Up @@ -1048,7 +1106,7 @@ return both used and unused packages."
(or (null usedp)
(and (not (null (oref pkg :owners)))
(not (oref pkg :excluded))
(cfgl-package-enabledp pkg t))))))))
(cfgl-package-enabled-p pkg t))))))))

(defun configuration-layer//get-private-layer-dir (name)
"Return an absolute path to the private configuration layer string NAME."
Expand Down Expand Up @@ -1114,12 +1172,15 @@ Returns nil if the directory is not a category."
(when (string-match "^+" dirname)
(intern (substring dirname 1))))))

(defun configuration-layer/discover-layers ()
"Initialize `configuration-layer--indexed-layers' with layer directories."
(defun configuration-layer/discover-layers (&optional refresh-index)
"Initialize `configuration-layer--indexed-layers' with layer directories.
If REFRESH-INDEX is non-nil, the layer index is cleared before
discovery."
;; load private layers at the end on purpose we asume that the user layers
;; must have the final word on configuration choices. Let
;; `dotspacemacs-directory' override the private directory if it exists.
(setq configuration-layer--indexed-layers (make-hash-table :size 1024))
(when refresh-index
(setq configuration-layer--indexed-layers (make-hash-table :size 1024)))
(spacemacs-buffer/set-mode-line "Indexing layers...")
(spacemacs//redisplay)
(let ((search-paths (append
Expand Down Expand Up @@ -1186,8 +1247,10 @@ Returns nil if the directory is not a category."
"-> Discovered configuration layer: %s" layer-name-str)
(let ((configuration-layer--load-packages-files nil))
(configuration-layer//add-layer
(configuration-layer/make-layer layer-name
nil nil sub))))))
(configuration-layer/make-layer
layer-name
(configuration-layer/get-layer layer-name)
nil sub))))))
(t
;; layer not found, add it to search path
(setq search-paths (cons sub search-paths)))))))))))
Expand Down Expand Up @@ -1575,8 +1638,8 @@ wether the declared layer is an used one or not."
((null (oref pkg :owners))
(spacemacs-buffer/message
(format "%S ignored since it has no owner layer." pkg-name)))
((not (cfgl-package-enabledp pkg))
(spacemacs-buffer/message (format "%S is toggled off." pkg-name)))
((not (cfgl-package-enabled-p pkg))
(spacemacs-buffer/message (format "%S is disabled." pkg-name)))
(t
;; load-path
(let ((dir (configuration-layer/get-location-directory
Expand Down Expand Up @@ -1622,9 +1685,15 @@ LAYER must not be the owner of PKG."
(let* ((owner (configuration-layer/get-layer (car (oref pkg :owners))))
(disabled (oref owner :disabled-for))
(enabled (oref owner :enabled-for)))
(if (not (eq 'unspecified enabled))
(memq layer enabled)
(not (memq layer disabled)))))
(and (not (memq nil (mapcar
(lambda (dep-pkg)
(let ((pkg-obj (configuration-layer/get-package dep-pkg)))
(when pkg-obj
(configuration-layer//package-enabled-p pkg-obj layer))))
(oref pkg :depends))))
(if (not (eq 'unspecified enabled))
(memq layer enabled)
(not (memq layer disabled))))))

(defun configuration-layer//configure-package (pkg)
"Configure PKG object."
Expand Down
10 changes: 5 additions & 5 deletions core/core-dotspacemacs.el
Expand Up @@ -791,7 +791,7 @@ error recovery."
"Test settings in dotfile for correctness.
Return non-nil if all the tests passed."
(interactive)
(configuration-layer/discover-layers)
(configuration-layer/discover-layers 'refresh-index)
(let ((min-version "0.0"))
;; dotspacemacs-version not implemented yet
;; (if (version< dotspacemacs-version min-version)
Expand All @@ -815,10 +815,10 @@ error recovery."
(prog1
;; execute all tests no matter what
(cl-reduce (lambda (x y)
(and (funcall y) x))
'(dotspacemacs//test-dotspacemacs/layers
dotspacemacs//test-dotspacemacs/init)
:initial-value t)
(and (funcall y) x))
'(dotspacemacs//test-dotspacemacs/layers
dotspacemacs//test-dotspacemacs/init)
:initial-value t)
(goto-char (point-min))))))))

(provide 'core-dotspacemacs)
2 changes: 1 addition & 1 deletion layers/+chat/rcirc/packages.el
Expand Up @@ -5,7 +5,7 @@
emoji-cheat-sheet-plus
flyspell
(helm-rcirc :location local
:toggle (configuration-layer/package-usedp 'helm))
:depends helm)
persp-mode
rcirc
rcirc-color
Expand Down
4 changes: 2 additions & 2 deletions layers/+completion/auto-completion/packages.el
Expand Up @@ -17,8 +17,8 @@
(company-quickhelp :toggle auto-completion-enable-help-tooltip)
company-statistics
fuzzy
(helm-company :toggle (configuration-layer/package-usedp 'helm))
(helm-c-yasnippet :toggle (configuration-layer/package-usedp 'helm))
(helm-company :depends helm)
(helm-c-yasnippet :depends helm)
hippie-exp
yasnippet
auto-yasnippet
Expand Down
2 changes: 1 addition & 1 deletion layers/+completion/ivy/packages.el
Expand Up @@ -14,7 +14,7 @@
auto-highlight-symbol
bookmark
counsel
(counsel-projectile :toggle (configuration-layer/package-usedp 'projectile))
(counsel-projectile :depends projectile)
evil
flx
helm-make
Expand Down
2 changes: 1 addition & 1 deletion layers/+emacs/org/packages.el
Expand Up @@ -30,7 +30,7 @@
(org-mime :location built-in)
org-pomodoro
org-present
(org-projectile :toggle (configuration-layer/package-usedp 'projectile))
(org-projectile :depends projectile)
(ox-twbs :toggle org-enable-bootstrap-support)
;; use a for of ox-gfm to fix index generation
(ox-gfm :location (recipe :fetcher github :repo "syl20bnr/ox-gfm")
Expand Down
2 changes: 1 addition & 1 deletion layers/+fun/emoji/packages.el
Expand Up @@ -13,7 +13,7 @@
'(
emoji-cheat-sheet-plus
emojify
(company-emoji :toggle (configuration-layer/package-usedp 'company))
(company-emoji :depends company)
))

(defun emoji/init-emoji-cheat-sheet-plus ()
Expand Down
2 changes: 1 addition & 1 deletion layers/+fun/games/packages.el
Expand Up @@ -13,7 +13,7 @@
'(
2048-game
(helm-games :location local
:toggle (configuration-layer/package-usedp 'helm))
:depends helm)
pacmacs
(tetris :location built-in)
sudoku
Expand Down
2 changes: 1 addition & 1 deletion layers/+lang/c-c++/packages.el
Expand Up @@ -16,7 +16,7 @@
clang-format
cmake-mode
company
(company-c-headers :toggle (configuration-layer/package-usedp 'company))
(company-c-headers :depends company)
company-ycmd
flycheck
gdb-mi
Expand Down
5 changes: 3 additions & 2 deletions layers/+lang/common-lisp/packages.el
Expand Up @@ -11,14 +11,15 @@

(setq common-lisp-packages
'(auto-highlight-symbol
(common-lisp-snippets :toggle (configuration-layer/package-usedp 'yasnippet))
(common-lisp-snippets :depends yasnippet)
evil
ggtags
helm
helm-gtags
parinfer
slime
(slime-company :toggle (configuration-layer/package-usedp 'company))))
(slime-company :depends company)
))

(defun common-lisp/post-init-auto-highlight-symbol ()
(with-eval-after-load 'auto-highlight-symbol
Expand Down
2 changes: 1 addition & 1 deletion layers/+lang/coq/packages.el
Expand Up @@ -11,7 +11,7 @@

(setq coq-packages
'(
(company-coq :toggle (configuration-layer/package-usedp 'company))
(company-coq :depends company)
(proof-general :location (recipe
:fetcher github
:repo "ProofGeneral/PG"
Expand Down
4 changes: 2 additions & 2 deletions layers/+lang/d/packages.el
Expand Up @@ -14,10 +14,10 @@
(setq d-packages
'(
company
(company-dcd :toggle (configuration-layer/package-usedp 'company))
(company-dcd :depends company)
d-mode
flycheck
(flycheck-dmd-dub :toggle (configuration-layer/package-usedp 'flycheck))
(flycheck-dmd-dub :depends flycheck)
ggtags
helm-gtags
))
Expand Down
2 changes: 1 addition & 1 deletion layers/+lang/elm/packages.el
Expand Up @@ -14,7 +14,7 @@
company
elm-mode
flycheck
(flycheck-elm :toggle (configuration-layer/package-usedp 'flycheck))
(flycheck-elm :depends flycheck)
popwin
smartparens
))
Expand Down
2 changes: 1 addition & 1 deletion layers/+lang/go/packages.el
Expand Up @@ -11,7 +11,7 @@

(setq go-packages
'(
(company-go :toggle (configuration-layer/package-usedp 'company))
(company-go :depends company)
flycheck
(flycheck-gometalinter :toggle (and go-use-gometalinter
(configuration-layer/package-usedp
Expand Down

0 comments on commit 08561d8

Please sign in to comment.