From 60f5a3a0faa73b3efe86adfd029179e4aa510376 Mon Sep 17 00:00:00 2001 From: syl20bnr Date: Mon, 30 May 2016 22:58:59 -0400 Subject: [PATCH] New dotfile variable dotspacemacs-download-packages This new variable replace dotspacemacs-delete-orphan-packages It defines the behaviour of Spacemacs when downloading packages. Possible values are `used', `used-but-keep-unused' and `all'. - `used' will download only explicitly used packages and remove any unused packages as well as their dependencies. - `used-but-keep-unused' will download only the used packages but won't delete them if they become unused. - `all' will download all the packages regardless if they are used or not and packages won't be deleted by Spacemacs. Default value is `used`. --- core/core-configuration-layer.el | 61 ++++++++----- core/core-dotspacemacs.el | 18 ++-- core/templates/.spacemacs.template | 12 ++- doc/FAQ.org | 17 +++- tests/core/core-configuration-layer-utest.el | 92 ++++++++++++++++++++ 5 files changed, 163 insertions(+), 37 deletions(-) diff --git a/core/core-configuration-layer.el b/core/core-configuration-layer.el index 3e247da82..fdfd30f3d 100644 --- a/core/core-configuration-layer.el +++ b/core/core-configuration-layer.el @@ -320,20 +320,24 @@ If NO-INSTALL is non nil then install steps are skipped." (configuration-layer//configure-layers configuration-layer--layers) ;; pre-filter some packages to save some time later in the loading process (setq configuration-layer--used-distant-packages - (configuration-layer//get-distant-used-packages - configuration-layer--packages)) + (configuration-layer//get-distant-packages + configuration-layer--packages t)) ;; install/uninstall packages (configuration-layer/load-auto-layer-file) (unless no-install - (configuration-layer//install-packages - (configuration-layer/filter-objects - configuration-layer--used-distant-packages - (lambda (x) - (not (oref x :lazy-install))))) + (if (eq 'all dotspacemacs-download-packages) + (configuration-layer//install-packages + (configuration-layer//get-distant-packages + (configuration-layer/get-all-packages) nil)) + (configuration-layer//install-packages + (configuration-layer/filter-objects + configuration-layer--used-distant-packages + (lambda (x) + (not (oref x :lazy-install)))))) (configuration-layer//configure-packages configuration-layer--packages) (configuration-layer//load-layers-files configuration-layer--layers '("keybindings.el")) - (when (and dotspacemacs-delete-orphan-packages + (when (and (eq 'used-only dotspacemacs-download-packages) (not configuration-layer-distribution) (not configuration-layer-no-layer)) (configuration-layer/delete-orphan-packages @@ -699,6 +703,14 @@ If TOGGLEP is non nil then `:toggle' parameter is ignored." (push obj configuration-layer--packages)) (oset obj :excluded t))))) +(defun configuration-layer/get-all-packages () + "Return a list of _all_ packages." + (let (configuration-layer--packages) + (configuration-layer/get-packages + (mapcar 'configuration-layer/make-layer + (configuration-layer/get-layers-list))) + configuration-layer--packages)) + (defun configuration-layer//sort-packages (packages) "Return a sorted list of PACKAGES objects." (sort packages (lambda (x y) (string< (symbol-name (oref x :name)) @@ -721,8 +733,8 @@ If TOGGLEP is non nil then `:toggle' parameter is ignored." (or (not (eq layer-name (oref p :owner))) (null (package-installed-p (oref p :name))))) - (configuration-layer//get-distant-used-packages - packages)) + (configuration-layer//get-distant-packages + packages t)) :initial-value t))) (oset layer :lazy-install lazy) (dolist (pkg packages) @@ -752,15 +764,18 @@ If TOGGLEP is non nil then `:toggle' parameter is ignored." objects :initial-value nil))) -(defun configuration-layer//get-distant-used-packages (packages) - "Return the distant packages (ie to be intalled) that are effectively used." +(defun configuration-layer//get-distant-packages (packages usedp) + "Return the distant packages (ie to be intalled). +If USEDP is not nil then only return only the used packages, if it is nil then +return both used and unused packages." (configuration-layer/filter-objects packages (lambda (x) - (and (not (null (oref x :owner))) - (not (memq (oref x :location) '(built-in site local))) + (and (not (memq (oref x :location) '(built-in site local))) (not (stringp (oref x :location))) - (cfgl-package-enabledp x) - (not (oref x :excluded)))))) + (or (null usedp) + (and (not (null (oref x :owner))) + (cfgl-package-enabledp x) + (not (oref x :excluded)))))))) (defun configuration-layer//get-private-layer-dir (name) "Return an absolute path to the private configuration layer string NAME." @@ -1022,7 +1037,7 @@ path." (format "--> installing %s: %s%s... [%s/%s]" (if layer "package" "dependency") pkg-name (if layer (format "@%S" layer) "") - installed-count noinst-count) t) + installed-count not-inst-count) t) (spacemacs//redisplay) (unless (package-installed-p pkg-name) (condition-case-unless-debug err @@ -1088,23 +1103,23 @@ path." (interactive) ;; ensure we have quelpa available first (configuration-layer//install-quelpa) - (let* ((noinst-pkg-names + (let* ((not-inst-pkg-names (configuration-layer//get-uninstalled-packages (mapcar 'car (object-assoc-list :name packages)))) - (noinst-count (length noinst-pkg-names)) + (not-inst-count (length not-inst-pkg-names)) installed-count) ;; installation - (when noinst-pkg-names + (when not-inst-pkg-names (spacemacs-buffer/append (format "Found %s new package(s) to install...\n" - noinst-count)) + not-inst-count)) (configuration-layer/retrieve-package-archives) (setq installed-count 0) (spacemacs//redisplay) - (dolist (pkg-name noinst-pkg-names) + (dolist (pkg-name not-inst-pkg-names) (setq installed-count (1+ installed-count)) (configuration-layer//install-package - (object-assoc pkg-name :name configuration-layer--packages))) + (object-assoc pkg-name :name packages))) (spacemacs-buffer/append "\n")))) (defun configuration-layer//install-from-elpa (pkg-name) diff --git a/core/core-dotspacemacs.el b/core/core-dotspacemacs.el index 178e11b86..f19a52d63 100644 --- a/core/core-dotspacemacs.el +++ b/core/core-dotspacemacs.el @@ -65,6 +65,15 @@ environment, otherwise it is strongly recommended to let it set to t.") "List of additional paths where to look for configuration layers. Paths must have a trailing slash (ie. `~/.mycontribs/')") +(defvar dotspacemacs-download-packages 'used + "Defines the behaviour of Spacemacs when downloading packages. +Possible values are `used', `used-but-keep-unused' and `all'. `used' will +download only explicitly used packages and remove any unused packages as well as +their dependencies. `used-but-keep-unused' will download only the used packages +but won't delete them if they become unused. `all' will download all the +packages regardless if they are used or not and packages won't be deleted by +Spacemacs.") + (defvar dotspacemacs-enable-lazy-installation 'unused " Lazy installation of layers (i.e. layers are installed only when a file with a supported type is opened). Possible values are `all', `unused' and `nil'. @@ -280,11 +289,6 @@ to aggressively delete empty lines and long sequences of whitespace, `trailing' to delete only the whitespace at end of lines, `changed' to delete only whitespace for changed lines or `nil' to disable cleanup.") -(defvar dotspacemacs-delete-orphan-packages t - "If non-nil spacemacs will delete any orphan packages, i.e. packages that are -declared in a layer which is not a member of -`dotspacemacs-configuration-layers'") - (defvar dotspacemacs-search-tools '("ag" "pt" "ack" "grep") "List of search tool executable names. Spacemacs uses the first installed tool of the list. Supported tools are `ag', `pt', `ack' and `grep'.") @@ -523,7 +527,7 @@ error recovery." (defadvice dotspacemacs/layers (after error-recover-preserve-packages activate) (progn - (setq-default dotspacemacs-delete-orphan-packages nil) + (setq-default dotspacemacs-download-packages 'used-but-keep-unused) (ad-disable-advice 'dotspacemacs/layers 'after 'error-recover-preserve-packages) (ad-activate 'dotspacemacs/layers))) @@ -557,7 +561,7 @@ error recovery." ;; protect global values of these variables (let (dotspacemacs-configuration-layer-path dotspacemacs-configuration-layers dotspacemacs-additional-packages dotspacemacs-excluded-packages - dotspacemacs-delete-orphan-packages + dotspacemacs-download-packages (passed-tests 0) (total-tests 0)) (load dotspacemacs-filepath) (dotspacemacs/layers) diff --git a/core/templates/.spacemacs.template b/core/templates/.spacemacs.template index 9b8a1b3b7..f1e736c7c 100644 --- a/core/templates/.spacemacs.template +++ b/core/templates/.spacemacs.template @@ -57,10 +57,14 @@ values." dotspacemacs-additional-packages '() ;; A list of packages that will not be install and loaded. dotspacemacs-excluded-packages '() - ;; If non-nil spacemacs will delete any orphan packages, i.e. packages that - ;; are declared in a layer which is not a member of - ;; the list `dotspacemacs-configuration-layers'. (default t) - dotspacemacs-delete-orphan-packages t)) + ;; Defines the behaviour of Spacemacs when downloading packages. + ;; Possible values are `used', `used-but-keep-unused' and `all'. `used' will + ;; download only explicitly used packages and remove any unused packages as + ;; well as their dependencies. `used-but-keep-unused' will download only the + ;; used packages but won't delete them if they become unused. `all' will + ;; download all the packages regardless if they are used or not and packages + ;; won't be deleted by Spacemacs. (default is `used') + dotspacemacs-download-packages 'used)) (defun dotspacemacs/init () "Initialization function. diff --git a/doc/FAQ.org b/doc/FAQ.org index 8f10347af..95f36fcd8 100644 --- a/doc/FAQ.org +++ b/doc/FAQ.org @@ -58,9 +58,20 @@ may also just type ~SPC f e v~. As it is written, that is _space_ then _macs_. ** Why are packages installed with =package-install= automatically deleted by Spacemacs when it boots? -To declare new packages you have to create a new configuration layer or add the -package name to the variable =dotspacemacs-additonal-packages= of your dotfile, -see the [[file:QUICK_START.org][quick start guide]] for more info. +By default Spacemacs will keep only the packages that you use (i.e. the packages +belonging to a layer explicitly listed in the variable +=dotspacemacs-configuration-layers=). + +To install packages that does not belong to any Spacemacs layers, you can: + +- use the variable =dotspacemacs-additonal-packages=. +- or create a configuration layer configuring the package and add this layer to + =dotspacemacs-configuration-layers= +- or set the variable =dotspacemacs-download-packages= to =used-but-keep-unused= + which will prevent Spacemacs from removing the packages you installed + manually. + +To create a new configuration layer see the [[file:QUICK_START.org][quick start guide]] for more info. ** How to fix package download errors when installing Spacemacs ? Since 0.105.0 HTTPS protocol is used by default to download packages. If your diff --git a/tests/core/core-configuration-layer-utest.el b/tests/core/core-configuration-layer-utest.el index 19c4dd356..647516efc 100644 --- a/tests/core/core-configuration-layer-utest.el +++ b/tests/core/core-configuration-layer-utest.el @@ -281,6 +281,56 @@ (result (configuration-layer/make-package pkg obj))) (should (equal result expected)))) +;; --------------------------------------------------------------------------- +;; configuration-layer//get-distant-packages +;; --------------------------------------------------------------------------- + +(defvar test-get-distant-packages--test-data + `(,(cfgl-package "pkg18" :name 'pkg18 :owner nil) + ,(cfgl-package "pkg17" :name 'pkg17 :owner nil :location 'elpa) + ,(cfgl-package "pkg16" :name 'pkg16 :owner nil :toggle nil) + ,(cfgl-package "pkg15" :name 'pkg15 :owner nil :toggle t) + ,(cfgl-package "pkg14" :name 'pkg14 :owner nil :location '(recipe)) + ,(cfgl-package "pkg13" :name 'pkg13 :owner nil :location 'built-in) + ,(cfgl-package "pkg12" :name 'pkg12 :owner nil :location 'local) + ,(cfgl-package "pkg11" :name 'pkg11 :owner nil :location 'site) + ,(cfgl-package "pkg10" :name 'pkg10 :owner nil :location "/path") + ,(cfgl-package "pkg9" :name 'pkg9 :owner 'layer) + ,(cfgl-package "pkg8" :name 'pkg8 :owner 'layer :location 'elpa) + ,(cfgl-package "pkg7" :name 'pkg7 :owner 'layer :toggle nil) + ,(cfgl-package "pkg6" :name 'pkg6 :owner 'layer :toggle t) + ,(cfgl-package "pkg5" :name 'pkg5 :owner 'layer :location '(recipe)) + ,(cfgl-package "pkg4" :name 'pkg4 :owner 'layer :location 'built-in) + ,(cfgl-package "pkg3" :name 'pkg3 :owner 'layer :location 'local) + ,(cfgl-package "pkg2" :name 'pkg2 :owner 'layer :location 'site) + ,(cfgl-package "pkg1" :name 'pkg1 :owner 'layer :location "/path"))) + +(ert-deftest test-get-distant-packages--return-only-used-packages () + (let ((packages test-get-distant-packages--test-data)) + (should + (equal + `(,(cfgl-package "pkg9" :name 'pkg9 :owner 'layer) + ,(cfgl-package "pkg8" :name 'pkg8 :owner 'layer :location 'elpa) + ,(cfgl-package "pkg6" :name 'pkg6 :owner 'layer :toggle t) + ,(cfgl-package "pkg5" :name 'pkg5 :owner 'layer :location '(recipe))) + (configuration-layer//get-distant-packages packages t))))) + +(ert-deftest test-get-distant-packages--return-only-unused-packages () + (let ((packages test-get-distant-packages--test-data)) + (should + (equal + `(,(cfgl-package "pkg18" :name 'pkg18 :owner nil) + ,(cfgl-package "pkg17" :name 'pkg17 :owner nil :location 'elpa) + ,(cfgl-package "pkg16" :name 'pkg16 :owner nil :toggle nil) + ,(cfgl-package "pkg15" :name 'pkg15 :owner nil :toggle t) + ,(cfgl-package "pkg14" :name 'pkg14 :owner nil :location '(recipe)) + ,(cfgl-package "pkg9" :name 'pkg9 :owner 'layer) + ,(cfgl-package "pkg8" :name 'pkg8 :owner 'layer :location 'elpa) + ,(cfgl-package "pkg7" :name 'pkg7 :owner 'layer :toggle nil) + ,(cfgl-package "pkg6" :name 'pkg6 :owner 'layer :toggle t) + ,(cfgl-package "pkg5" :name 'pkg5 :owner 'layer :location '(recipe))) + (configuration-layer//get-distant-packages packages nil))))) + ;; --------------------------------------------------------------------------- ;; configuration-layer/get-packages ;; --------------------------------------------------------------------------- @@ -643,6 +693,48 @@ :toggle '(bar-toggle))) configuration-layer--packages)))))) +;; --------------------------------------------------------------------------- +;; configuration-layer/get-all-packages +;; --------------------------------------------------------------------------- + +(ert-deftest test-get-all-packages () + (let* ((configuration-layer-paths + #s(hash-table size 256 + test eql + rehash-size 1.5 + rehash-threshold 0.8 data + (layerall1 "/path/" layerall2 "/path/" + layerall3 "/path/" layerall4 "/path/" + layerall5 "/path/"))) + (layerall1-packages '(pkg1)) + (layerall2-packages '(pkg2 pkg6)) + (layerall3-packages '(pkg3)) + (layerall4-packages '(pkg4 pkg7 pkg8)) + (layerall5-packages '(pkg5 pkg9)) + (mocker-mock-default-record-cls 'mocker-stub-record)) + (defun layerall1/init-pkg1 nil) + (defun layerall2/init-pkg2 nil) + (defun layerall2/init-pkg6 nil) + (defun layerall3/init-pkg3 nil) + (defun layerall4/init-pkg4 nil) + (defun layerall4/init-pkg7 nil) + (defun layerall4/init-pkg8 nil) + (defun layerall5/init-pkg5 nil) + (defun layerall5/init-pkg9 nil) + (mocker-let + ((file-exists-p (f) ((:output t))) + (load (f) ((:output nil)))) + (should (equal (list (cfgl-package "pkg1" :name 'pkg1 :owner 'layerall1) + (cfgl-package "pkg6" :name 'pkg6 :owner 'layerall2) + (cfgl-package "pkg2" :name 'pkg2 :owner 'layerall2) + (cfgl-package "pkg3" :name 'pkg3 :owner 'layerall3) + (cfgl-package "pkg8" :name 'pkg8 :owner 'layerall4) + (cfgl-package "pkg7" :name 'pkg7 :owner 'layerall4) + (cfgl-package "pkg4" :name 'pkg4 :owner 'layerall4) + (cfgl-package "pkg9" :name 'pkg9 :owner 'layerall5) + (cfgl-package "pkg5" :name 'pkg5 :owner 'layerall5)) + (configuration-layer/get-all-packages)))))) + ;; --------------------------------------------------------------------------- ;; configuration-layer//configure-package ;; ---------------------------------------------------------------------------