Commit 426c6d26 authored by Ryan C. Thompson's avatar Ryan C. Thompson

Added "el-get-merge-updatable-properties" with test

This is the first step on the way to fixing #659.
parent c32bd0ac
......@@ -133,8 +133,10 @@ returning a list that contains it (and only it)."
(defun el-get-source-name (source)
"Return the package name (stringp) given an `el-get-sources'
entry."
(if (symbolp source) (symbol-name source)
(format "%s" (plist-get source :name))))
(if (listp source)
(format "%s" (or (plist-get source :name)
(error "Source does not have a :name property: %S" source)))
(symbol-name source)))
;;
......
......@@ -48,11 +48,13 @@
package-name
(intern (format ":%s" package-name))))
(defun el-get-save-package-status (package status)
(defun el-get-save-package-status (package status &optional recipe)
"Save given package status"
(let* ((package (el-get-as-symbol package))
(recipe (when (string= status "installed")
(el-get-package-def package)))
(recipe
(or recipe
(when (string= status "installed")
(el-get-package-def package)))
(package-status-alist
(assq-delete-all package (el-get-read-status-file)))
(new-package-status-alist
......@@ -162,4 +164,87 @@
(put 'el-get-with-status-recipes 'lisp-indent-function
(get 'progn 'lisp-indent-function))
(defvar el-get-status-recipe-updatable-properties
'(:load-path
:info
:load
:features
:library
:before
:after
:lazy)
"Whitelist of properties that may be updated in cached recipes.
If you any have these properties set on a package in your
`el-get-sources', then the values from `el-get-sources' can be
used to replace the cached values without reinstalling or
updating the package..")
(defun el-get-merge-updatable-properties (package-or-source
&optional ignore-non-updatable)
"Merge updatable properties from package source into status file.
This function takes either a package name or a full package
source. The named package must already be installed. If given a
package name, the source is retrieved from `el-get-sources'. The
given source is compared to the cached source for the same
package. If it differs only in updatable properties (see
`el-get-status-recipe-updatable-properties'), then the updated
values from the given source will be saved to the recipe in the
status file, overwriting the old values stored there.
If any non-updatable properties differ, then an error is raised,
unless the optional second argument is non-nil, in which case
only a message is issued and the non-updatable properties are
simply ignored."
(let* ((source
(if (listp package-or-source)
(or package-or-source
(error "package-or-source cannot be nil"))
;; Not using `el-get-package-def' here, because we only
;; want what is listed in `el-get-sources', not what is in
;; the recipe file.
(loop for src in el-get-sources
when (string= package-or-source (el-get-source-name src))
if (symbolp src) (list :name src)
else src)))
(pkg (el-get-as-symbol (el-get-source-name source)))
(cached-recipe (el-get-read-package-status-recipe pkg))
;; Subset of properties that cannot be updated without a
;; package update or reinstall. If this is non-nil, then we
;; will abort with an error message.
(noupdate-plist
(loop for (k v) on source by 'cddr
unless (eq k :name)
unless (memq k el-get-status-recipe-updatable-properties)
;; We only care about non-updatable properties if they
;; don't match the cached value
unless (equal v (plist-get cached-recipe k))
append (list k v)))
;; Subset of properties that are updatable. If this is nil,
;; then there's nothing to update.
(update-plist
(loop for (k v) on source by 'cddr
when (memq k el-get-status-recipe-updatable-properties)
append (list k v))))
(unless (el-get-package-is-installed pkg)
(error "Package %s is not installed. Cannot update recipe." pkg))
(when noupdate-plist
(funcall
(if ignore-non-updatable
'el-get-verbose-message
'error)
"Cannot update the following properties on package %s:\n%s\n(Maybe you should use `el-get-update' or `el-get-reinstall' instead?)"
pkg (pp-to-string noupdate-plist)))
(if update-plist
(progn
(el-get-verbose-message
"Updating the following properties on package %s:\n%s"
pkg (pp-to-string update-plist))
(let ((updated-recipe (el-get-read-package-status-recipe pkg)))
(loop for (k v) on update-plist by 'cddr
do (plist-put updated-recipe k v))
(el-get-save-package-status pkg "installed" updated-recipe)))
(el-get-verbose-message "No properties to update on package %s" pkg))))
(provide 'el-get-status)
;; https://github.com/dimitri/el-get/issues/659
;;
;; Updatable properties in cached recipes
(require 'cl)
(require 'pp)
(el-get-register-method-alias :test :builtin)
(let ((el-get-default-process-sync t)
(el-get-verbose t)
(el-get-sources
`((:name a
:type test
:compile "."
:features a
:build (("sh" "-c"
,(format "echo %s > a.el"
(shell-quote-argument
(mapconcat
#'pp-to-string
'((provide 'a))
"\n")))))
:prepare (message "Preparing A")
:post-init (message "Post-init A")
:lazy nil)))
(update-source
'(:name a
:before (message "Before A")
:after (message "After A")
:features nil
:load "a"
:library "a"
;; This should not cause an error because it matches the
;; cached value.
:prepare (message "Preparing A")
:lazy t))
(invalid-update-source
'(:name a
:post-init (message "New post-init A"))))
;; Install a and b
(el-get-install 'a)
(assert (featurep 'a) nil
"Package A should be installed and loaded")
(el-get-merge-updatable-properties update-source)
(assert (plist-get (el-get-read-package-status-recipe 'a) :lazy) nil
"New values should be merged into cached recipe")
(condition-case err
(progn
(el-get-merge-updatable-properties invalid-update-source)
(signal 'test-failure "Failed to raise error when trying to update non-updatable property."))
(error (message "Got error as expected. Error was:\n%S" err))))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment