From: Thierry Volpiatto <thierry.volpiatto@gmail.com>
To: bruce.connor.am@gmail.com
Cc: Stefan Monnier <monnier@iro.umontreal.ca>,
emacs-devel <emacs-devel@gnu.org>
Subject: Re: package.el dependencies
Date: Sun, 01 Feb 2015 08:02:29 +0100 [thread overview]
Message-ID: <87lhkiru62.fsf@gmail.com> (raw)
In-Reply-To: <CAAdUY-JqttUAE2car4aSozkAhL_cKU6ht1Eswd_Ban2BevJ16Q@mail.gmail.com>
Artur Malabarba <bruce.connor.am@gmail.com> writes:
>> While you're at it: if package-selected-packages (or whatever name you
>> end up using) is not yet set (e.g. still nil), you could guess an
>> initial value: take the list of packages that are installed and are not
>> required by other installed packages. I.e. choose as initial value of
>> package-selected-packages the smallest set of packages such that
>> package-autoremove won't have anything to remove.
>
> I'll work on this, and then I'll add it in once this patch is applied.
So here again my final patch:
- packages-installed-directly renamed to package-selected-packages
- remove customize call in package-autoremove.
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index 88fc950..74a441b 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -333,6 +333,17 @@ contents of the archive."
:group 'package
:version "24.4")
+(defcustom package-selected-packages nil
+ "Store here packages installed explicitely by user.
+This variable will be feeded automatically by emacs,
+when installing a new package.
+This variable will be used by `package-autoremove' to decide
+which packages are no more needed.
+You can use it to (re)install packages on other machines
+by running `package-user-selected-packages-install'."
+ :group 'package
+ :type '(repeat (choice symbol)))
+
(defvar package--default-summary "No description available.")
(cl-defstruct (package-desc
@@ -1187,10 +1198,13 @@ using `package-compute-transaction'."
(mapc #'package-install-from-archive packages))
;;;###autoload
-(defun package-install (pkg)
+(defun package-install (pkg &optional arg)
"Install the package PKG.
PKG can be a package-desc or the package name of one the available packages
-in an archive in `package-archives'. Interactively, prompt for its name."
+in an archive in `package-archives'. Interactively, prompt for its name
+and add PKG to `package-selected-packages'.
+When called from lisp you will have to use ARG if you want to
+simulate an interactive call to add PKG to `package-selected-packages'."
(interactive
(progn
;; Initialize the package system to get the list of package
@@ -1206,7 +1220,11 @@ in an archive in `package-archives'. Interactively, prompt for its name."
(unless (package-installed-p (car elt))
(symbol-name (car elt))))
package-archive-contents))
- nil t)))))
+ nil t))
+ "\p")))
+ (when (and arg (not (memq pkg package-selected-packages)))
+ (customize-save-variable 'package-selected-packages
+ (cons pkg package-selected-packages)))
(package-download-transaction
(if (package-desc-p pkg)
(package-compute-transaction (list pkg)
@@ -1214,6 +1232,16 @@ in an archive in `package-archives'. Interactively, prompt for its name."
(package-compute-transaction ()
(list (list pkg))))))
+;;;###autoload
+(defun package-reinstall (pkg)
+ "Reinstall package PKG."
+ (interactive (list (intern (completing-read
+ "Reinstall package: "
+ (mapcar 'symbol-name
+ (mapcar 'car package-alist))))))
+ (package-delete (cadr (assq pkg package-alist)) t)
+ (package-install pkg))
+
(defun package-strip-rcs-id (str)
"Strip RCS version ID from the version string STR.
If the result looks like a dotted numeric version, return it.
@@ -1354,24 +1382,29 @@ is derived from the main .el file in the directory.
Downloads and installs required packages as needed."
(interactive)
- (let ((pkg-desc
- (cond
- ((derived-mode-p 'dired-mode)
- ;; This is the only way a package-desc object with a `dir'
- ;; desc-kind can be created. Such packages can't be
- ;; uploaded or installed from archives, they can only be
- ;; installed from local buffers or directories.
- (package-dir-info))
- ((derived-mode-p 'tar-mode)
- (package-tar-file-info))
- (t
- (package-buffer-info)))))
+ (let* ((pkg-desc
+ (cond
+ ((derived-mode-p 'dired-mode)
+ ;; This is the only way a package-desc object with a `dir'
+ ;; desc-kind can be created. Such packages can't be
+ ;; uploaded or installed from archives, they can only be
+ ;; installed from local buffers or directories.
+ (package-dir-info))
+ ((derived-mode-p 'tar-mode)
+ (package-tar-file-info))
+ (t
+ (package-buffer-info))))
+ (name (package-desc-name pkg-desc)))
;; Download and install the dependencies.
(let* ((requires (package-desc-reqs pkg-desc))
(transaction (package-compute-transaction nil requires)))
(package-download-transaction transaction))
;; Install the package itself.
(package-unpack pkg-desc)
+ (unless (memq name package-selected-packages)
+ (push name package-selected-packages)
+ (customize-save-variable 'package-selected-packages
+ package-selected-packages))
pkg-desc))
;;;###autoload
@@ -1388,26 +1421,120 @@ The file can either be a tar file or an Emacs Lisp file."
(when (string-match "\\.tar\\'" file) (tar-mode)))
(package-install-from-buffer)))
-(defun package-delete (pkg-desc)
- (let ((dir (package-desc-dir pkg-desc)))
- (if (not (string-prefix-p (file-name-as-directory
- (expand-file-name package-user-dir))
- (expand-file-name dir)))
- ;; Don't delete "system" packages.
- (error "Package `%s' is a system package, not deleting"
- (package-desc-full-name pkg-desc))
- (delete-directory dir t t)
- ;; Remove NAME-VERSION.signed file.
- (let ((signed-file (concat dir ".signed")))
- (if (file-exists-p signed-file)
- (delete-file signed-file)))
- ;; Update package-alist.
- (let* ((name (package-desc-name pkg-desc))
- (pkgs (assq name package-alist)))
- (delete pkg-desc pkgs)
- (unless (cdr pkgs)
- (setq package-alist (delq pkgs package-alist))))
- (message "Package `%s' deleted." (package-desc-full-name pkg-desc)))))
+(defun package--get-deps (pkg &optional only)
+ (let* ((pkg-desc (cadr (assq pkg package-alist)))
+ (direct-deps (cl-loop for p in (package-desc-reqs pkg-desc)
+ for name = (car p)
+ when (assq name package-alist)
+ collect name))
+ (indirect-deps (unless (eq only 'direct)
+ (cl-loop for p in direct-deps
+ for dep = (cadr (assq p package-alist))
+ when (and dep (assq p package-alist))
+ append (mapcar 'car
+ (package-desc-reqs
+ dep))))))
+ (cl-case only
+ (direct direct-deps)
+ (separate (list direct-deps indirect-deps))
+ (indirect indirect-deps)
+ (t (append direct-deps indirect-deps)))))
+
+;;;###autoload
+(defun package-user-selected-packages-install ()
+ "Ensure packages in `package-selected-packages' are installed.
+If some packages are not installed propose to install them."
+ (interactive)
+ (cl-loop for p in package-selected-packages
+ unless (package-installed-p p)
+ collect p into lst
+ finally
+ (if lst
+ (when (y-or-n-p
+ (format "%s packages will be installed:\n%s, proceed?"
+ (length lst)
+ (mapconcat 'symbol-name lst ", ")))
+ (mapc 'package-install lst))
+ (message "All your packages are already installed"))))
+
+(defun package-used-elsewhere-p (pkg-desc &optional pkg-list)
+ "Check in PKG-LIST if PKG-DESC is used elsewhere as dependency.
+
+When not specified, PKG-LIST default to `package-alist'
+with PKG-DESC entry removed.
+Returns the first package found in PKG-LIST where PKG is used as dependency."
+ (unless (string= (package-desc-status pkg-desc) "obsolete")
+ (let ((pkg (package-desc-name pkg-desc)))
+ (cl-loop with alist = (or pkg-list
+ (remove (assq pkg package-alist)
+ package-alist))
+ for p in alist thereis
+ (and (memq pkg (mapcar 'car (package-desc-reqs (cadr p))))
+ (car p))))))
+
+(defun package-delete (pkg-desc &optional force)
+ "Delete package PKG-DESC.
+
+Argument PKG-DESC is a full description of package as vector.
+When package is used elsewhere as dependency of another package,
+refuse deleting it and return an error.
+If FORCE is non--nil package will be deleted even if it is used
+elsewhere."
+ (let ((dir (package-desc-dir pkg-desc))
+ (name (package-desc-name pkg-desc))
+ pkg-used-elsewhere-by)
+ (cond ((not (string-prefix-p (file-name-as-directory
+ (expand-file-name package-user-dir))
+ (expand-file-name dir)))
+ ;; Don't delete "system" packages.
+ (error "Package `%s' is a system package, not deleting"
+ (package-desc-full-name pkg-desc)))
+ ((and (null force)
+ (setq pkg-used-elsewhere-by
+ (package-used-elsewhere-p name)))
+ ;; Don't delete packages used as dependency elsewhere.
+ (error "Package `%s' is used by `%s' as dependency, not deleting"
+ (package-desc-full-name pkg-desc)
+ pkg-used-elsewhere-by))
+ (t
+ (delete-directory dir t t)
+ ;; Remove NAME-VERSION.signed file.
+ (let ((signed-file (concat dir ".signed")))
+ (if (file-exists-p signed-file)
+ (delete-file signed-file)))
+ ;; Update package-alist.
+ (let ((pkgs (assq name package-alist)))
+ (delete pkg-desc pkgs)
+ (unless (cdr pkgs)
+ (setq package-alist (delq pkgs package-alist))))
+ (message "Package `%s' deleted." (package-desc-full-name pkg-desc))))))
+
+;;;###autoload
+(defun package-autoremove ()
+ "Remove packages that are no more needed.
+
+Packages that are no more needed by other packages in
+`package-selected-packages' and their dependencies
+will be deleted."
+ (interactive)
+ (let* (old-direct
+ (needed (cl-loop for p in package-selected-packages
+ if (assq p package-alist)
+ append (package--get-deps p) into lst
+ else do (push p old-direct)
+ finally return lst)))
+ (cl-loop for p in (mapcar 'car package-alist)
+ unless (or (memq p needed)
+ (memq p package-selected-packages))
+ collect p into lst
+ finally (if lst
+ (when (y-or-n-p (format "%s packages will be deleted:\n%s, proceed? "
+ (length lst)
+ (mapconcat 'symbol-name lst ", ")))
+ (mapc (lambda (p)
+ (package-delete (cadr (assq p package-alist)) t))
+ lst))
+ (message "Nothing to autoremove")))))
(defun package-archive-base (desc)
"Return the archive containing the package NAME."
@@ -1721,7 +1848,7 @@ If optional arg NO-ACTIVATE is non-nil, don't activate packages."
(let ((pkg-desc (button-get button 'package-desc)))
(when (y-or-n-p (format "Install package `%s'? "
(package-desc-full-name pkg-desc)))
- (package-install pkg-desc)
+ (package-install pkg-desc 1)
(revert-buffer nil t)
(goto-char (point-min)))))
@@ -2178,7 +2305,9 @@ Optional argument NOQUERY non-nil means do not ask the user to confirm."
(length install-list)
(mapconcat #'package-desc-full-name
install-list ", ")))))
- (mapc 'package-install install-list)))
+ (mapc (lambda (p)
+ (package-install p (and (null (package-installed-p p)) 1)))
+ install-list)))
;; Delete packages, prompting if necessary.
(when delete-list
(if (or
--
Thierry
Get my Gnupg key:
gpg --keyserver pgp.mit.edu --recv-keys 59F29997
next prev parent reply other threads:[~2015-02-01 7:02 UTC|newest]
Thread overview: 79+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-01-23 13:37 package.el dependencies Thierry Volpiatto
2015-01-23 13:46 ` Dmitry Gutov
2015-01-23 14:12 ` Ivan Shmakov
2015-01-23 20:40 ` Stefan Monnier
2015-01-23 21:02 ` Thierry Volpiatto
2015-01-24 0:50 ` Artur Malabarba
2015-01-24 4:55 ` Stefan Monnier
2015-01-25 6:51 ` Thierry Volpiatto
2015-01-26 7:17 ` Thierry Volpiatto
2015-01-26 9:19 ` Artur Malabarba
2015-01-26 9:54 ` Thierry Volpiatto
2015-01-26 12:46 ` Artur Malabarba
2015-01-26 14:52 ` Stefan Monnier
2015-01-27 6:10 ` Thierry Volpiatto
2015-01-27 11:52 ` Artur Malabarba
2015-01-25 9:18 ` Thierry Volpiatto
2015-01-25 14:54 ` Stefan Monnier
2015-01-25 15:48 ` Thierry Volpiatto
2015-01-25 17:10 ` Dmitry Gutov
2015-01-25 18:32 ` Stephen Leake
2015-01-25 18:21 ` Artur Malabarba
2015-01-26 4:48 ` Thierry Volpiatto
2015-01-26 12:35 ` Artur Malabarba
2015-01-26 12:53 ` Artur Malabarba
2015-01-26 15:22 ` Thierry Volpiatto
2015-01-26 15:44 ` Stefan Monnier
2015-01-27 6:08 ` Thierry Volpiatto
2015-01-26 16:34 ` Artur Malabarba
2015-01-28 7:30 ` Thierry Volpiatto
2015-01-28 8:55 ` Thierry Volpiatto
2015-01-28 12:42 ` Thierry Volpiatto
2015-01-28 13:17 ` Artur Malabarba
2015-01-28 14:32 ` Thierry Volpiatto
2015-01-28 13:40 ` Dmitry Gutov
2015-01-28 10:47 ` Artur Malabarba
2015-01-28 11:58 ` Thierry Volpiatto
2015-01-28 19:33 ` Stefan Monnier
2015-01-28 19:50 ` Ivan Shmakov
2015-01-28 20:12 ` Artur Malabarba
2015-01-28 22:20 ` Stefan Monnier
2015-01-29 5:31 ` Thierry Volpiatto
2015-01-29 7:22 ` Thierry Volpiatto
2015-01-30 5:38 ` Thierry Volpiatto
2015-01-30 16:43 ` Artur Malabarba
2015-01-30 17:13 ` Thierry Volpiatto
2015-01-31 6:01 ` Thierry Volpiatto
2015-01-31 10:58 ` Artur Malabarba
2015-01-31 20:26 ` Stefan Monnier
[not found] ` <874mr67gjb.fsf@gmail.com>
[not found] ` <jwvvbjmnun4.fsf-monnier+emacs@gnu.org>
[not found] ` <87oapervqv.fsf@gmail.com>
[not found] ` <jwvk302nnmd.fsf-monnier+emacs@gnu.org>
[not found] ` <877fw2kp1y.fsf@gmail.com>
[not found] ` <jwvioflbrlg.fsf-monnier+emacs@gnu.org>
[not found] ` <87d25tps2q.fsf@gmail.com>
[not found] ` <jwvy4oggva5.fsf-monnier+emacs@gnu.org>
2015-02-02 20:35 ` Thierry Volpiatto
2015-02-02 21:37 ` Artur Malabarba
2015-02-03 4:53 ` Thierry Volpiatto
2015-02-03 5:13 ` Stefan Monnier
2015-02-03 10:04 ` Artur Malabarba
2015-02-03 14:06 ` Artur Malabarba
2015-02-03 5:45 ` Thierry Volpiatto
2015-02-03 10:05 ` Artur Malabarba
2015-02-03 10:18 ` Thierry Volpiatto
2015-02-03 11:39 ` Artur Malabarba
2015-02-02 21:19 ` Thierry Volpiatto
2015-02-02 21:22 ` Dmitry Gutov
2015-02-03 11:39 ` Artur Malabarba
2015-02-03 11:44 ` Dmitry Gutov
2015-01-31 6:51 ` Thierry Volpiatto
2015-01-31 20:30 ` Stefan Monnier
2015-01-31 22:10 ` Thierry Volpiatto
2015-01-31 23:26 ` Artur Malabarba
2015-02-01 6:29 ` Thierry Volpiatto
2015-02-01 7:02 ` Thierry Volpiatto [this message]
2015-02-01 15:55 ` Thierry Volpiatto
2015-02-01 23:47 ` Artur Malabarba
2015-02-02 12:00 ` Artur Malabarba
2015-02-02 13:14 ` Thierry Volpiatto
2015-02-02 14:14 ` Thierry Volpiatto
2015-02-02 14:56 ` Artur Malabarba
2015-02-02 15:19 ` Thierry Volpiatto
2015-02-02 15:33 ` Thierry Volpiatto
2015-02-02 15:50 ` Artur Malabarba
2015-02-02 16:07 ` Thierry Volpiatto
2015-02-02 21:23 ` Thierry Volpiatto
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87lhkiru62.fsf@gmail.com \
--to=thierry.volpiatto@gmail.com \
--cc=bruce.connor.am@gmail.com \
--cc=emacs-devel@gnu.org \
--cc=monnier@iro.umontreal.ca \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.