diff --git a/el-get-core.el b/el-get-core.el index 904ba244f..f0bc358f5 100644 --- a/el-get-core.el +++ b/el-get-core.el @@ -140,11 +140,13 @@ already-defined method DERIVED-FROM-NAME." ;; interface to write such structures as raw elisp. ;; ;;; "Fuzzy" data structure conversion utilities -(defun el-get-as-string (symbol-or-string) - "If STRING-OR-SYMBOL is already a string, return it. Otherwise -convert it to a string and return that." - (if (stringp symbol-or-string) symbol-or-string - (symbol-name symbol-or-string))) +(defun el-get-as-string (obj) + "Return OBJ as a string." + (cond + ((stringp obj) obj) + ((symbolp obj) (symbol-name obj)) + ((numberp obj) (number-to-string obj)) + (t (error "Can't convert %S to string." obj)))) (defun el-get-as-symbol (string-or-symbol) "If STRING-OR-SYMBOL is already a symbol, return it. Otherwise diff --git a/el-get-status.el b/el-get-status.el index d8196a430..0104cc88a 100644 --- a/el-get-status.el +++ b/el-get-status.el @@ -230,7 +230,7 @@ (progn ,@body))) -(defvar el-get-status-recipe-update-whitelist +(defconst el-get-status-init-whitelist '(:load-path :info :load @@ -243,13 +243,24 @@ :lazy :website :description) - "Properties that can be updated without `el-get-update'/`el-get-reinstall'. + "Properties that can be updated with only `el-get-init'. If any of these properties change on the recipe for an installed package, the changes may be merged into the cached version of that recipe in the el-get status file.") -(defun el-get-classify-new-properties (source newprops) +(defconst el-get-status-update-whitelist + `(:depends + :build + :build/system-type + :compile + :checksum + :checkout + :options + ,@el-get-status-init-whitelist) + "Properties than can be updated by `el-get-update'.") + +(defun el-get-classify-new-properties (operation source newprops) "Classify NEWPROPS into two groups: need update/disallowed. Return a list (UPDATE DISALLOWED). Both UPDATE and NEWPROPS are @@ -258,25 +269,34 @@ Elements in UPDATE are whitelisted whereas elements in DISALLOWED are not." (loop with update with disallowed - with whitelist = el-get-status-recipe-update-whitelist + with whitelist = (if (eq operation 'update) + el-get-status-update-whitelist + el-get-status-init-whitelist) for (k v) on newprops by 'cddr ;; Not a change, so ignore it if (equal v (plist-get source k)) do (ignore) ;; whitelisted - else if (memq k whitelist) do (setq update (plist-put update k v)) + else if + (or (memq k whitelist) ; whitelisted + (and (eq k :builtin) + ;; Check if `:builtin' change is safe. + (eq (version<= emacs-version (el-get-as-string v)) + (version<= emacs-version (el-get-as-string + (plist-get source k)))))) + do (setq update (plist-put update k v)) ;; Trying to change non-whitelisted property else do (setq disallowed (plist-put disallowed k v)) finally return (list update disallowed))) -(defun el-get-diagnosis-properties (old-source new-source) +(defun el-get-diagnosis-properties (operation old-source new-source) "Diagnosis difference between OLD-SOURCE and NEW-SOURCE. Return a list (UPDATE-P ADDED-DISALLOWED REMOVED-DISALLOWED). UPDATE-P is non-nil when OLD-SOURCE and NEW-SOURCE are different. ADDED-DISALLOWED and REMOVED-DISALLOWED are added and removed properties, respectively." - (let ((added (el-get-classify-new-properties old-source new-source)) - (removed (el-get-classify-new-properties new-source old-source))) + (let ((added (el-get-classify-new-properties operation old-source new-source)) + (removed (el-get-classify-new-properties operation new-source old-source))) (list (or (car added) (car removed)) (cadr added) (cadr removed)))) @@ -303,6 +323,7 @@ properties, respectively." package)))) (defun el-get-merge-properties-into-status (package-or-source + operation &rest keys) "Merge updatable properties for package into package status alist (or status file). @@ -323,6 +344,7 @@ t', this error is suppressed (but nothing is updated). \(fn PACKAGE-OR-SOURCE &key NOERROR)" (interactive (list (el-get-read-package-with-status "Update cached recipe" "installed") + 'init :noerror current-prefix-arg)) (let* ((noerror (cadr (memq :noerror keys))) (source (el-get-package-or-source package-or-source)) @@ -332,7 +354,7 @@ t', this error is suppressed (but nothing is updated). (unless (el-get-package-is-installed package) (error "Package %s is not installed. Cannot update recipe." package)) (destructuring-bind (update-p added-disallowed removed-disallowed) - (el-get-diagnosis-properties cached-recipe source) + (el-get-diagnosis-properties operation cached-recipe source) (if (or added-disallowed removed-disallowed) ;; Emit a verbose message if `noerror' is t (but still quit ;; the function). @@ -348,10 +370,11 @@ and remove non-whitelisted properties: into/from source: %s -Maybe you should use `el-get-update' or `el-get-reinstall' on %s instead?" +Maybe you should use %s`el-get-reinstall' on %s instead?" (if added-disallowed (pp-to-string added-disallowed) "()") (if removed-disallowed (pp-to-string removed-disallowed) "()") (pp-to-string cached-recipe) + (if (eq operation 'update) "" "`el-get-update' or") (el-get-source-name cached-recipe)) (when update-p (el-get-save-package-status package "installed" source)))))) diff --git a/el-get.el b/el-get.el index 2a150c20e..b28c15c8d 100644 --- a/el-get.el +++ b/el-get.el @@ -383,7 +383,7 @@ this warning either uninstall one of the el-get or package.el version of %s, or call `el-get' before `package-initialize' to prevent package.el from loading it." package package))) (when el-get-auto-update-cached-recipes - (el-get-merge-properties-into-status package () :noerror t)) + (el-get-merge-properties-into-status package 'init :noerror t)) (condition-case err (let* ((el-get-sources (el-get-package-status-recipes)) (source (el-get-read-package-status-recipe package)) @@ -641,6 +641,7 @@ PACKAGE may be either a string or the corresponding symbol." (defun el-get-post-update-build (package) "Function to call after building the package while updating it." ;; fix trailing failed installs + (el-get-merge-properties-into-status package 'update :noerror t) (when (string= (el-get-read-package-status package) "required") (el-get-save-package-status package "installed")) (el-get-invalidate-autoloads package)