diff options
| author | Thierry Volpiatto | 2015-02-01 19:45:47 -0200 |
|---|---|---|
| committer | Artur Malabarba | 2015-02-01 20:17:51 -0200 |
| commit | e2f0f263df89a156ff5b4b05e3b3aae457eb38a9 (patch) | |
| tree | 80b4c9aea6e5fcd427200b54d88cb25640b9695b | |
| parent | 92a8dec54ed3314ca06f40cd0c226c4267a160e8 (diff) | |
| download | emacs-e2f0f263df89a156ff5b4b05e3b3aae457eb38a9.tar.gz emacs-e2f0f263df89a156ff5b4b05e3b3aae457eb38a9.zip | |
emacs-lisp/package.el: Don't allow deleting dependencies.
| -rw-r--r-- | lisp/ChangeLog | 26 | ||||
| -rw-r--r-- | lisp/emacs-lisp/package.el | 203 |
2 files changed, 192 insertions, 37 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 0a3c7c95929..742aced3a7c 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,29 @@ | |||
| 1 | 2015-02-01 Thierry Volpiatto <thierry.volpiatto@gmail.com> | ||
| 2 | |||
| 3 | * emacs-lisp/package.el: Don't allow deleting dependencies. | ||
| 4 | |||
| 5 | (package-used-elsewhere-p): New function. | ||
| 6 | (package-delete): Use it, return now an error when trying to | ||
| 7 | delete a package used as dependency by another package. | ||
| 8 | |||
| 9 | Add a reinstall package command. | ||
| 10 | (package-reinstall): New function. | ||
| 11 | |||
| 12 | Add a package-autoremove command. | ||
| 13 | (package-selected-packages): New user var. | ||
| 14 | (package-install): Add an optional arg to notify interactive use. | ||
| 15 | Fix docstring. Save installed package to | ||
| 16 | packages-installed-directly. | ||
| 17 | (package-install-from-buffer): Same. | ||
| 18 | (package-user-selected-packages-install): Allow installing all | ||
| 19 | packages in packages-installed-directly at once. | ||
| 20 | (package--get-deps): New function. | ||
| 21 | (package-autoremove): New function. | ||
| 22 | (package-install-button-action): Call package-install with | ||
| 23 | interactive arg. | ||
| 24 | (package-menu-execute): Same but only for only for not installed | ||
| 25 | packages. | ||
| 26 | |||
| 1 | 2015-01-31 Stefan Monnier <monnier@iro.umontreal.ca> | 27 | 2015-01-31 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 28 | ||
| 3 | * emacs-lisp/eieio.el (defclass): Use new eieio-make-class-predicate | 29 | * emacs-lisp/eieio.el (defclass): Use new eieio-make-class-predicate |
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index 88fc950ee21..db8d8685574 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el | |||
| @@ -333,6 +333,17 @@ contents of the archive." | |||
| 333 | :group 'package | 333 | :group 'package |
| 334 | :version "24.4") | 334 | :version "24.4") |
| 335 | 335 | ||
| 336 | (defcustom package-selected-packages nil | ||
| 337 | "Store here packages installed explicitely by user. | ||
| 338 | This variable will be feeded automatically by emacs, | ||
| 339 | when installing a new package. | ||
| 340 | This variable will be used by `package-autoremove' to decide | ||
| 341 | which packages are no more needed. | ||
| 342 | You can use it to (re)install packages on other machines | ||
| 343 | by running `package-user-selected-packages-install'." | ||
| 344 | :group 'package | ||
| 345 | :type '(repeat (choice symbol))) | ||
| 346 | |||
| 336 | (defvar package--default-summary "No description available.") | 347 | (defvar package--default-summary "No description available.") |
| 337 | 348 | ||
| 338 | (cl-defstruct (package-desc | 349 | (cl-defstruct (package-desc |
| @@ -1187,10 +1198,13 @@ using `package-compute-transaction'." | |||
| 1187 | (mapc #'package-install-from-archive packages)) | 1198 | (mapc #'package-install-from-archive packages)) |
| 1188 | 1199 | ||
| 1189 | ;;;###autoload | 1200 | ;;;###autoload |
| 1190 | (defun package-install (pkg) | 1201 | (defun package-install (pkg &optional arg) |
| 1191 | "Install the package PKG. | 1202 | "Install the package PKG. |
| 1192 | PKG can be a package-desc or the package name of one the available packages | 1203 | PKG can be a package-desc or the package name of one the available packages |
| 1193 | in an archive in `package-archives'. Interactively, prompt for its name." | 1204 | in an archive in `package-archives'. Interactively, prompt for its name |
| 1205 | and add PKG to `package-selected-packages'. | ||
| 1206 | When called from lisp you will have to use ARG if you want to | ||
| 1207 | simulate an interactive call to add PKG to `package-selected-packages'." | ||
| 1194 | (interactive | 1208 | (interactive |
| 1195 | (progn | 1209 | (progn |
| 1196 | ;; Initialize the package system to get the list of package | 1210 | ;; 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." | |||
| 1206 | (unless (package-installed-p (car elt)) | 1220 | (unless (package-installed-p (car elt)) |
| 1207 | (symbol-name (car elt)))) | 1221 | (symbol-name (car elt)))) |
| 1208 | package-archive-contents)) | 1222 | package-archive-contents)) |
| 1209 | nil t))))) | 1223 | nil t)) |
| 1224 | "\p"))) | ||
| 1225 | (when (and arg (not (memq pkg package-selected-packages))) | ||
| 1226 | (customize-save-variable 'package-selected-packages | ||
| 1227 | (cons pkg package-selected-packages))) | ||
| 1210 | (package-download-transaction | 1228 | (package-download-transaction |
| 1211 | (if (package-desc-p pkg) | 1229 | (if (package-desc-p pkg) |
| 1212 | (package-compute-transaction (list pkg) | 1230 | (package-compute-transaction (list pkg) |
| @@ -1214,6 +1232,16 @@ in an archive in `package-archives'. Interactively, prompt for its name." | |||
| 1214 | (package-compute-transaction () | 1232 | (package-compute-transaction () |
| 1215 | (list (list pkg)))))) | 1233 | (list (list pkg)))))) |
| 1216 | 1234 | ||
| 1235 | ;;;###autoload | ||
| 1236 | (defun package-reinstall (pkg) | ||
| 1237 | "Reinstall package PKG." | ||
| 1238 | (interactive (list (intern (completing-read | ||
| 1239 | "Reinstall package: " | ||
| 1240 | (mapcar 'symbol-name | ||
| 1241 | (mapcar 'car package-alist)))))) | ||
| 1242 | (package-delete (cadr (assq pkg package-alist)) t) | ||
| 1243 | (package-install pkg)) | ||
| 1244 | |||
| 1217 | (defun package-strip-rcs-id (str) | 1245 | (defun package-strip-rcs-id (str) |
| 1218 | "Strip RCS version ID from the version string STR. | 1246 | "Strip RCS version ID from the version string STR. |
| 1219 | If the result looks like a dotted numeric version, return it. | 1247 | 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. | |||
| 1354 | 1382 | ||
| 1355 | Downloads and installs required packages as needed." | 1383 | Downloads and installs required packages as needed." |
| 1356 | (interactive) | 1384 | (interactive) |
| 1357 | (let ((pkg-desc | 1385 | (let* ((pkg-desc |
| 1358 | (cond | 1386 | (cond |
| 1359 | ((derived-mode-p 'dired-mode) | 1387 | ((derived-mode-p 'dired-mode) |
| 1360 | ;; This is the only way a package-desc object with a `dir' | 1388 | ;; This is the only way a package-desc object with a `dir' |
| 1361 | ;; desc-kind can be created. Such packages can't be | 1389 | ;; desc-kind can be created. Such packages can't be |
| 1362 | ;; uploaded or installed from archives, they can only be | 1390 | ;; uploaded or installed from archives, they can only be |
| 1363 | ;; installed from local buffers or directories. | 1391 | ;; installed from local buffers or directories. |
| 1364 | (package-dir-info)) | 1392 | (package-dir-info)) |
| 1365 | ((derived-mode-p 'tar-mode) | 1393 | ((derived-mode-p 'tar-mode) |
| 1366 | (package-tar-file-info)) | 1394 | (package-tar-file-info)) |
| 1367 | (t | 1395 | (t |
| 1368 | (package-buffer-info))))) | 1396 | (package-buffer-info)))) |
| 1397 | (name (package-desc-name pkg-desc))) | ||
| 1369 | ;; Download and install the dependencies. | 1398 | ;; Download and install the dependencies. |
| 1370 | (let* ((requires (package-desc-reqs pkg-desc)) | 1399 | (let* ((requires (package-desc-reqs pkg-desc)) |
| 1371 | (transaction (package-compute-transaction nil requires))) | 1400 | (transaction (package-compute-transaction nil requires))) |
| 1372 | (package-download-transaction transaction)) | 1401 | (package-download-transaction transaction)) |
| 1373 | ;; Install the package itself. | 1402 | ;; Install the package itself. |
| 1374 | (package-unpack pkg-desc) | 1403 | (package-unpack pkg-desc) |
| 1404 | (unless (memq name package-selected-packages) | ||
| 1405 | (push name package-selected-packages) | ||
| 1406 | (customize-save-variable 'package-selected-packages | ||
| 1407 | package-selected-packages)) | ||
| 1375 | pkg-desc)) | 1408 | pkg-desc)) |
| 1376 | 1409 | ||
| 1377 | ;;;###autoload | 1410 | ;;;###autoload |
| @@ -1388,26 +1421,120 @@ The file can either be a tar file or an Emacs Lisp file." | |||
| 1388 | (when (string-match "\\.tar\\'" file) (tar-mode))) | 1421 | (when (string-match "\\.tar\\'" file) (tar-mode))) |
| 1389 | (package-install-from-buffer))) | 1422 | (package-install-from-buffer))) |
| 1390 | 1423 | ||
| 1391 | (defun package-delete (pkg-desc) | 1424 | (defun package--get-deps (pkg &optional only) |
| 1392 | (let ((dir (package-desc-dir pkg-desc))) | 1425 | (let* ((pkg-desc (cadr (assq pkg package-alist))) |
| 1393 | (if (not (string-prefix-p (file-name-as-directory | 1426 | (direct-deps (cl-loop for p in (package-desc-reqs pkg-desc) |
| 1394 | (expand-file-name package-user-dir)) | 1427 | for name = (car p) |
| 1395 | (expand-file-name dir))) | 1428 | when (assq name package-alist) |
| 1396 | ;; Don't delete "system" packages. | 1429 | collect name)) |
| 1397 | (error "Package `%s' is a system package, not deleting" | 1430 | (indirect-deps (unless (eq only 'direct) |
| 1398 | (package-desc-full-name pkg-desc)) | 1431 | (cl-loop for p in direct-deps |
| 1399 | (delete-directory dir t t) | 1432 | for dep = (cadr (assq p package-alist)) |
| 1400 | ;; Remove NAME-VERSION.signed file. | 1433 | when (and dep (assq p package-alist)) |
| 1401 | (let ((signed-file (concat dir ".signed"))) | 1434 | append (mapcar 'car |
| 1402 | (if (file-exists-p signed-file) | 1435 | (package-desc-reqs |
| 1403 | (delete-file signed-file))) | 1436 | dep)))))) |
| 1404 | ;; Update package-alist. | 1437 | (cl-case only |
| 1405 | (let* ((name (package-desc-name pkg-desc)) | 1438 | (direct direct-deps) |
| 1406 | (pkgs (assq name package-alist))) | 1439 | (separate (list direct-deps indirect-deps)) |
| 1407 | (delete pkg-desc pkgs) | 1440 | (indirect indirect-deps) |
| 1408 | (unless (cdr pkgs) | 1441 | (t (append direct-deps indirect-deps))))) |
| 1409 | (setq package-alist (delq pkgs package-alist)))) | 1442 | |
| 1410 | (message "Package `%s' deleted." (package-desc-full-name pkg-desc))))) | 1443 | ;;;###autoload |
| 1444 | (defun package-user-selected-packages-install () | ||
| 1445 | "Ensure packages in `package-selected-packages' are installed. | ||
| 1446 | If some packages are not installed propose to install them." | ||
| 1447 | (interactive) | ||
| 1448 | (cl-loop for p in package-selected-packages | ||
| 1449 | unless (package-installed-p p) | ||
| 1450 | collect p into lst | ||
| 1451 | finally | ||
| 1452 | (if lst | ||
| 1453 | (when (y-or-n-p | ||
| 1454 | (format "%s packages will be installed:\n%s, proceed?" | ||
| 1455 | (length lst) | ||
| 1456 | (mapconcat 'symbol-name lst ", "))) | ||
| 1457 | (mapc 'package-install lst)) | ||
| 1458 | (message "All your packages are already installed")))) | ||
| 1459 | |||
| 1460 | (defun package-used-elsewhere-p (pkg-desc &optional pkg-list) | ||
| 1461 | "Check in PKG-LIST if PKG-DESC is used elsewhere as dependency. | ||
| 1462 | |||
| 1463 | When not specified, PKG-LIST default to `package-alist' | ||
| 1464 | with PKG-DESC entry removed. | ||
| 1465 | Returns the first package found in PKG-LIST where PKG is used as dependency." | ||
| 1466 | (unless (string= (package-desc-status pkg-desc) "obsolete") | ||
| 1467 | (let ((pkg (package-desc-name pkg-desc))) | ||
| 1468 | (cl-loop with alist = (or pkg-list | ||
| 1469 | (remove (assq pkg package-alist) | ||
| 1470 | package-alist)) | ||
| 1471 | for p in alist thereis | ||
| 1472 | (and (memq pkg (mapcar 'car (package-desc-reqs (cadr p)))) | ||
| 1473 | (car p)))))) | ||
| 1474 | |||
| 1475 | (defun package-delete (pkg-desc &optional force) | ||
| 1476 | "Delete package PKG-DESC. | ||
| 1477 | |||
| 1478 | Argument PKG-DESC is a full description of package as vector. | ||
| 1479 | When package is used elsewhere as dependency of another package, | ||
| 1480 | refuse deleting it and return an error. | ||
| 1481 | If FORCE is non--nil package will be deleted even if it is used | ||
| 1482 | elsewhere." | ||
| 1483 | (let ((dir (package-desc-dir pkg-desc)) | ||
| 1484 | (name (package-desc-name pkg-desc)) | ||
| 1485 | pkg-used-elsewhere-by) | ||
| 1486 | (cond ((not (string-prefix-p (file-name-as-directory | ||
| 1487 | (expand-file-name package-user-dir)) | ||
| 1488 | (expand-file-name dir))) | ||
| 1489 | ;; Don't delete "system" packages. | ||
| 1490 | (error "Package `%s' is a system package, not deleting" | ||
| 1491 | (package-desc-full-name pkg-desc))) | ||
| 1492 | ((and (null force) | ||
| 1493 | (setq pkg-used-elsewhere-by | ||
| 1494 | (package-used-elsewhere-p pkg-desc))) | ||
| 1495 | ;; Don't delete packages used as dependency elsewhere. | ||
| 1496 | (error "Package `%s' is used by `%s' as dependency, not deleting" | ||
| 1497 | (package-desc-full-name pkg-desc) | ||
| 1498 | pkg-used-elsewhere-by)) | ||
| 1499 | (t | ||
| 1500 | (delete-directory dir t t) | ||
| 1501 | ;; Remove NAME-VERSION.signed file. | ||
| 1502 | (let ((signed-file (concat dir ".signed"))) | ||
| 1503 | (if (file-exists-p signed-file) | ||
| 1504 | (delete-file signed-file))) | ||
| 1505 | ;; Update package-alist. | ||
| 1506 | (let ((pkgs (assq name package-alist))) | ||
| 1507 | (delete pkg-desc pkgs) | ||
| 1508 | (unless (cdr pkgs) | ||
| 1509 | (setq package-alist (delq pkgs package-alist)))) | ||
| 1510 | (message "Package `%s' deleted." (package-desc-full-name pkg-desc)))))) | ||
| 1511 | |||
| 1512 | ;;;###autoload | ||
| 1513 | (defun package-autoremove () | ||
| 1514 | "Remove packages that are no more needed. | ||
| 1515 | |||
| 1516 | Packages that are no more needed by other packages in | ||
| 1517 | `package-selected-packages' and their dependencies | ||
| 1518 | will be deleted." | ||
| 1519 | (interactive) | ||
| 1520 | (let* (old-direct | ||
| 1521 | (needed (cl-loop for p in package-selected-packages | ||
| 1522 | if (assq p package-alist) | ||
| 1523 | append (package--get-deps p) into lst | ||
| 1524 | else do (push p old-direct) | ||
| 1525 | finally return lst))) | ||
| 1526 | (cl-loop for p in (mapcar 'car package-alist) | ||
| 1527 | unless (or (memq p needed) | ||
| 1528 | (memq p package-selected-packages)) | ||
| 1529 | collect p into lst | ||
| 1530 | finally (if lst | ||
| 1531 | (when (y-or-n-p (format "%s packages will be deleted:\n%s, proceed? " | ||
| 1532 | (length lst) | ||
| 1533 | (mapconcat 'symbol-name lst ", "))) | ||
| 1534 | (mapc (lambda (p) | ||
| 1535 | (package-delete (cadr (assq p package-alist)) t)) | ||
| 1536 | lst)) | ||
| 1537 | (message "Nothing to autoremove"))))) | ||
| 1411 | 1538 | ||
| 1412 | (defun package-archive-base (desc) | 1539 | (defun package-archive-base (desc) |
| 1413 | "Return the archive containing the package NAME." | 1540 | "Return the archive containing the package NAME." |
| @@ -1721,7 +1848,7 @@ If optional arg NO-ACTIVATE is non-nil, don't activate packages." | |||
| 1721 | (let ((pkg-desc (button-get button 'package-desc))) | 1848 | (let ((pkg-desc (button-get button 'package-desc))) |
| 1722 | (when (y-or-n-p (format "Install package `%s'? " | 1849 | (when (y-or-n-p (format "Install package `%s'? " |
| 1723 | (package-desc-full-name pkg-desc))) | 1850 | (package-desc-full-name pkg-desc))) |
| 1724 | (package-install pkg-desc) | 1851 | (package-install pkg-desc 1) |
| 1725 | (revert-buffer nil t) | 1852 | (revert-buffer nil t) |
| 1726 | (goto-char (point-min))))) | 1853 | (goto-char (point-min))))) |
| 1727 | 1854 | ||
| @@ -2178,7 +2305,9 @@ Optional argument NOQUERY non-nil means do not ask the user to confirm." | |||
| 2178 | (length install-list) | 2305 | (length install-list) |
| 2179 | (mapconcat #'package-desc-full-name | 2306 | (mapconcat #'package-desc-full-name |
| 2180 | install-list ", "))))) | 2307 | install-list ", "))))) |
| 2181 | (mapc 'package-install install-list))) | 2308 | (mapc (lambda (p) |
| 2309 | (package-install p (and (null (package-installed-p p)) 1))) | ||
| 2310 | install-list))) | ||
| 2182 | ;; Delete packages, prompting if necessary. | 2311 | ;; Delete packages, prompting if necessary. |
| 2183 | (when delete-list | 2312 | (when delete-list |
| 2184 | (if (or | 2313 | (if (or |