Create local Emacs package repository from installed packages so package upgrade never breaks.
Why
Package installation is fast. It takes only 15 seconds to install 115 packages
The package repository could be hosted on USB/Dropbox/GitHub
Tested with Emacs 27, 28, 29 on OSX/Cygwin/Windows10/Linux
Install CLI program "tar" is required. It's already installed on Windows10/Linux/macOS.
Download =elpa-mirror.el= to somewhere (say =~/.emacs.d/site-lisp/elpa-mirror/=)
Add below code into "~/.emacs",
(add-to-list 'load-path "~/.emacs.d/site-lisp/elpa-mirror") (require 'elpa-mirror)
Usage =M-x elpamr-create-mirror-for-installed= to create local repository.
To update existing local repository, run =M-x elpamr-create-mirror-for-installed= again.
BTW, =elpa-mirror.el= can run as an independent script,
mkdir -p ~/myelpa && emacs --batch -l ~/.emacs.d/init.el -l ~/any-directory-you-prefer/elpa-mirror.el --eval='(setq elpamr-default-output-directory "~/myelpa")' --eval='(elpamr-create-mirror-for-installed)'
To use the local repository =~/myelpa/=, insert below code into =~/.emacs=,
;; myelpa is the ONLY repository now, dont forget trailing slash in the directory (setq package-archives '(("myelpa" . "~/myelpa/")))
** Repository on Dropbox Insert below code into =~/.emacs=:
;; add-to-list will not override default elpa. ;; So now you have two repositories. ;; One is GNU elpa. Another is myelpa (add-to-list 'package-archives '("myelpa" . "https://dl.dropboxusercontent.com/u/858862/myelpa/"))
** Repository on GitHub My repository is [[https://github.com/redguardtoo/myelpa]].
Insert below code into =.emacs=:
;; add-to-list will not override default elpa. ;; So now you have two repositories. ;; One is GNU elpa. Another is myelpa (add-to-list 'package-archives '("myelpa" . "https://raw.githubusercontent.com/redguardtoo/myelpa/master/"))
=elpamr-exclude-patterns-filter-function= lets users define a filter function to exclude files and directories per package. The function returns the result to replace =elpamr-tar-command-exclude-patterns=.
Below setup adds directory "bin/" into package "vagrant-tramp".
(setq elpamr-exclude-patterns-filter-function (lambda (package-dir) (let ((patterns elpamr-tar-command-exclude-patterns)) (when (string-match "vagrant-tramp" package-dir) (setq patterns (remove "*/bin" patterns))) patterns)))
** Change output directory,
(setq elpamr-default-output-directory "~/myelpa")
Reproduce the bug, report it at [[https://github.com/redguardtoo/elpa-mirror]], and attach the contents of the buffer =elpa-mirror log=.