2018-09-07 21:49:49 -04:00
|
|
|
;; -*- no-byte-compile: t; -*-
|
|
|
|
;;; core/cli/packages.el
|
|
|
|
|
2019-07-21 15:39:45 +02:00
|
|
|
(defmacro doom--ensure-autoloads-while (&rest body)
|
|
|
|
`(progn
|
2019-09-20 01:23:58 -04:00
|
|
|
(straight-check-all)
|
2019-07-21 15:39:45 +02:00
|
|
|
(doom-reload-core-autoloads)
|
|
|
|
(when (progn ,@body)
|
|
|
|
(doom-reload-package-autoloads 'force-p))
|
|
|
|
t))
|
2018-09-07 21:49:49 -04:00
|
|
|
|
|
|
|
|
|
|
|
;;
|
2019-06-16 23:01:17 +02:00
|
|
|
;;; Dispatchers
|
|
|
|
|
2019-08-15 01:34:28 -04:00
|
|
|
(defcli! (update u) (&rest args)
|
2019-07-12 14:16:53 +02:00
|
|
|
"Updates packages.
|
|
|
|
|
2019-08-15 01:34:28 -04:00
|
|
|
This works by fetching all installed package repos and checking the distance
|
|
|
|
between HEAD and FETCH_HEAD. This can take a while.
|
|
|
|
|
2019-07-12 14:16:53 +02:00
|
|
|
This excludes packages whose `package!' declaration contains a non-nil :freeze
|
2019-09-12 17:22:17 -04:00
|
|
|
or :ignore property.
|
|
|
|
|
|
|
|
Switches:
|
|
|
|
-t/--timeout TTL Seconds until a thread is timed out (default: 45)
|
|
|
|
--threads N How many threads to use (default: 8)"
|
2019-07-21 15:39:45 +02:00
|
|
|
(doom--ensure-autoloads-while
|
2019-08-15 01:34:28 -04:00
|
|
|
(doom-packages-update
|
|
|
|
doom-auto-accept
|
2019-09-12 17:22:17 -04:00
|
|
|
(when-let (threads (cadr (member "--threads" args)))
|
|
|
|
(string-to-number threads))
|
2019-08-15 01:34:28 -04:00
|
|
|
(when-let (timeout (cadr (or (member "--timeout" args)
|
|
|
|
(member "-t" args))))
|
|
|
|
(string-to-number timeout)))))
|
2019-07-21 15:39:45 +02:00
|
|
|
|
2019-07-28 14:02:51 +02:00
|
|
|
(defcli! (rebuild build b) (&rest args)
|
2019-07-21 15:39:45 +02:00
|
|
|
"Rebuilds all installed packages.
|
|
|
|
|
|
|
|
This ensures that all needed files are symlinked from their package repo and
|
2019-09-12 17:24:04 -04:00
|
|
|
their elisp files are byte-compiled.
|
|
|
|
|
|
|
|
Switches:
|
|
|
|
-f Forcibly rebuild autoloads files, even if they're up-to-date"
|
2019-07-21 15:39:45 +02:00
|
|
|
(doom--ensure-autoloads-while
|
2019-07-25 19:42:01 +02:00
|
|
|
(doom-packages-rebuild doom-auto-accept (member "-f" args))))
|
2019-07-21 15:39:45 +02:00
|
|
|
|
2019-07-28 01:32:16 +02:00
|
|
|
(defcli! (purge p) (&rest args)
|
2019-07-29 03:47:12 +02:00
|
|
|
"Deletes any unused ELPA packages, straight builds, and (optionally) repos.
|
|
|
|
|
2019-09-09 19:21:39 -04:00
|
|
|
By default, this does not purge ELPA packages or repos. It is a good idea to run
|
|
|
|
'doom purge --all' once in a while, to stymy build-up of repos and ELPA
|
|
|
|
packages that could be taking up precious space.
|
2019-07-29 03:47:12 +02:00
|
|
|
|
2019-09-12 17:24:04 -04:00
|
|
|
Switches:
|
|
|
|
--no-builds Don't purge unneeded (built) packages
|
|
|
|
-e / --elpa Don't purge ELPA packages
|
|
|
|
-r / --repos Purge unused repos
|
|
|
|
--all Purge builds, elpa packages and repos"
|
2019-07-21 15:39:45 +02:00
|
|
|
(doom--ensure-autoloads-while
|
2019-09-09 19:21:39 -04:00
|
|
|
(doom-packages-purge (or (member "-e" args)
|
|
|
|
(member "--elpa" args)
|
|
|
|
(member "--all" args))
|
2019-07-29 03:47:12 +02:00
|
|
|
(not (member "--no-builds" args))
|
|
|
|
(or (member "-r" args)
|
2019-09-09 19:21:39 -04:00
|
|
|
(member "--repos" args)
|
|
|
|
(member "--all" args))
|
2019-07-25 19:42:01 +02:00
|
|
|
doom-auto-accept)))
|
2019-07-12 14:16:53 +02:00
|
|
|
|
2019-07-28 01:32:16 +02:00
|
|
|
;; (defcli! rollback () ; TODO rollback
|
2019-07-21 15:39:45 +02:00
|
|
|
;; "<Not implemented yet>"
|
|
|
|
;; (user-error "Not implemented yet, sorry!"))
|
2019-06-16 23:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
;;; Library
|
2018-09-07 21:49:49 -04:00
|
|
|
|
|
|
|
(defun doom-packages-install (&optional auto-accept-p)
|
2019-06-16 23:01:17 +02:00
|
|
|
"Installs missing packages.
|
|
|
|
|
|
|
|
This function will install any primary package (i.e. a package with a `package!'
|
|
|
|
declaration) or dependency thereof that hasn't already been.
|
|
|
|
|
|
|
|
Unless AUTO-ACCEPT-P is non-nil, this function will prompt for confirmation with
|
|
|
|
a list of packages that will be installed."
|
2019-07-21 15:39:45 +02:00
|
|
|
(print! "> Installing & building packages...")
|
|
|
|
(print-group!
|
|
|
|
(let ((n 0))
|
|
|
|
(dolist (package (hash-table-keys straight--recipe-cache))
|
|
|
|
(straight--with-plist (gethash package straight--recipe-cache)
|
|
|
|
(local-repo)
|
|
|
|
(let ((existed-p (file-directory-p (straight--repos-dir package))))
|
|
|
|
(condition-case-unless-debug e
|
|
|
|
(and (straight-use-package (intern package) nil nil " ")
|
|
|
|
(not existed-p)
|
|
|
|
(file-directory-p (straight--repos-dir package))
|
|
|
|
(cl-incf n))
|
|
|
|
(error
|
|
|
|
(signal 'doom-package-error
|
|
|
|
(list e (straight--process-get-output))))))))
|
|
|
|
(if (= n 0)
|
|
|
|
(ignore (print! (success "No packages need to be installed")))
|
|
|
|
(print! (success "Installed & built %d packages") n)
|
|
|
|
t))))
|
|
|
|
|
|
|
|
|
|
|
|
(defun doom-packages-rebuild (&optional auto-accept-p all)
|
|
|
|
"(Re)build all packages."
|
|
|
|
(print! (start "(Re)building %spackages...") (if all "all " ""))
|
|
|
|
(print-group!
|
|
|
|
(let ((n 0))
|
|
|
|
(if all
|
|
|
|
(let ((straight--packages-to-rebuild :all)
|
|
|
|
(straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
|
|
|
|
(dolist (package (hash-table-keys straight--recipe-cache))
|
|
|
|
(straight-use-package
|
|
|
|
(intern package) nil (lambda (_) (cl-incf n) nil) " ")))
|
2019-07-27 17:20:02 +02:00
|
|
|
(dolist (recipe (hash-table-values straight--recipe-cache))
|
|
|
|
(straight--with-plist recipe (package local-repo no-build)
|
|
|
|
(unless (or no-build (null local-repo))
|
|
|
|
;; REVIEW We do these modification checks manually because
|
|
|
|
;; Straight's checks seem to miss stale elc files. Need
|
|
|
|
;; more tests to confirm this.
|
|
|
|
(when (or (ignore-errors
|
|
|
|
(gethash package straight--packages-to-rebuild))
|
|
|
|
(gethash package straight--cached-package-modifications)
|
|
|
|
(not (file-directory-p (straight--build-dir package)))
|
|
|
|
(cl-loop for file
|
2019-07-26 20:04:53 +02:00
|
|
|
in (doom-files-in (straight--build-dir package)
|
|
|
|
:match "\\.el$"
|
|
|
|
:full t)
|
|
|
|
for elc-file = (byte-compile-dest-file file)
|
|
|
|
if (and (file-exists-p elc-file)
|
|
|
|
(file-newer-than-file-p file elc-file))
|
2019-07-27 17:20:02 +02:00
|
|
|
return t))
|
2019-07-29 20:59:52 +02:00
|
|
|
(let ((straight-use-package-pre-build-functions
|
|
|
|
straight-use-package-pre-build-functions))
|
|
|
|
(add-hook 'straight-use-package-pre-build-functions
|
|
|
|
(lambda (&rest _) (cl-incf n)))
|
|
|
|
(let ((straight--packages-to-rebuild :all)
|
|
|
|
(straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
|
2019-09-03 00:59:17 -04:00
|
|
|
(straight-use-package (intern package) nil nil " "))
|
2019-07-29 20:59:52 +02:00
|
|
|
(straight--byte-compile-package recipe)
|
|
|
|
(dolist (dep (straight--get-dependencies package))
|
|
|
|
(when-let (recipe (gethash dep straight--recipe-cache))
|
|
|
|
(straight--byte-compile-package recipe)))))))))
|
2019-07-21 15:39:45 +02:00
|
|
|
(if (= n 0)
|
|
|
|
(ignore (print! (success "No packages need rebuilding")))
|
2019-07-26 20:04:53 +02:00
|
|
|
(doom--finalize-straight)
|
2019-07-21 15:39:45 +02:00
|
|
|
(print! (success "Rebuilt %d package(s)" n))
|
|
|
|
t))))
|
|
|
|
|
2018-09-07 21:49:49 -04:00
|
|
|
|
2019-07-29 21:01:46 +02:00
|
|
|
(defun doom--packages-remove-outdated-f (packages)
|
|
|
|
(async-start
|
|
|
|
`(lambda ()
|
|
|
|
(setq load-path ',load-path
|
2019-08-08 11:48:13 -04:00
|
|
|
doom-modules ',doom-modules
|
|
|
|
user-emacs-directory ',user-emacs-directory)
|
2019-07-29 21:01:46 +02:00
|
|
|
(condition-case e
|
|
|
|
(let (packages errors)
|
|
|
|
(load ,(concat doom-core-dir "core.el"))
|
2019-09-03 00:45:32 -04:00
|
|
|
(doom-initialize 'force)
|
2019-07-29 21:01:46 +02:00
|
|
|
(dolist (recipe ',group)
|
2019-08-21 18:34:55 -04:00
|
|
|
(when (straight--repository-is-available-p recipe)
|
|
|
|
(straight-vc-git--destructure recipe
|
2019-09-03 00:45:32 -04:00
|
|
|
(package local-repo nonrecursive upstream-remote upstream-repo upstream-host branch)
|
2019-08-21 18:34:55 -04:00
|
|
|
(condition-case e
|
|
|
|
(let ((default-directory (straight--repos-dir local-repo)))
|
|
|
|
;; HACK We normalize packages to avoid certain scenarios
|
|
|
|
;; where `straight-fetch-package' will create an
|
|
|
|
;; interactive popup prompting for action (which will
|
|
|
|
;; cause this async process to block indefinitely). We
|
|
|
|
;; can't use `straight-normalize-package' because could
|
|
|
|
;; create popup prompts too, so we do it manually:
|
|
|
|
(shell-command-to-string "git merge --abort")
|
2019-09-03 00:45:32 -04:00
|
|
|
(straight--get-call "git" "reset" "--hard" branch)
|
2019-08-21 18:34:55 -04:00
|
|
|
(straight--get-call "git" "clean" "-ffd")
|
2019-08-22 13:02:24 -04:00
|
|
|
(unless nonrecursive
|
|
|
|
(shell-command-to-string "git submodule update --init --recursive"))
|
2019-08-21 18:34:55 -04:00
|
|
|
(when upstream-repo
|
|
|
|
(let ((desired-url (straight-vc-git--encode-url upstream-repo upstream-host))
|
|
|
|
(actual-url (condition-case nil
|
|
|
|
(straight--get-call "git" "remote" "get-url" upstream-remote)
|
|
|
|
(error nil))))
|
|
|
|
(unless (straight-vc-git--urls-compatible-p actual-url desired-url)
|
|
|
|
(straight--get-call "git" "remote" "remove" upstream-remote)
|
|
|
|
(straight--get-call "git" "remote" "add" upstream-remote desired-url)
|
|
|
|
(straight--get-call "git" "fetch" upstream-remote))))
|
|
|
|
(straight-fetch-package package)
|
|
|
|
;; REVIEW Is there no better way to get this information?
|
|
|
|
(let ((n (length
|
|
|
|
(split-string
|
|
|
|
(straight--get-call "git" "rev-list" "--left-right" "HEAD..@{u}")
|
|
|
|
"\n" t)))
|
|
|
|
(pretime
|
|
|
|
(string-to-number
|
|
|
|
(shell-command-to-string "git log -1 --format=%at HEAD")))
|
|
|
|
(time
|
|
|
|
(string-to-number
|
|
|
|
;; HACK `straight--get-call' has a higher failure
|
|
|
|
;; rate when querying FETCH_HEAD; not sure why.
|
|
|
|
;; Doing this manually, with
|
|
|
|
;; `shell-command-to-string' works fine.
|
|
|
|
(shell-command-to-string "git log -1 --format=%at FETCH_HEAD"))))
|
|
|
|
(with-current-buffer (straight--process-get-buffer)
|
|
|
|
(with-silent-modifications
|
|
|
|
(print! (debug (autofill "%s") (indent 2 (buffer-string))))
|
|
|
|
(erase-buffer)))
|
|
|
|
(when (> n 0)
|
|
|
|
(push (list n pretime time recipe)
|
|
|
|
packages))))
|
|
|
|
(error
|
|
|
|
(push (list package e (string-trim (or (straight--process-get-output) "")))
|
|
|
|
errors))))))
|
2019-07-29 21:01:46 +02:00
|
|
|
(if errors
|
|
|
|
(cons 'error errors)
|
|
|
|
(cons 'ok (nreverse packages))))
|
|
|
|
(error
|
|
|
|
(cons 'error e))))))
|
|
|
|
|
|
|
|
|
2019-09-12 17:22:17 -04:00
|
|
|
(defun doom-packages-update (&optional auto-accept-p threads timeout)
|
2019-06-16 23:01:17 +02:00
|
|
|
"Updates packages.
|
|
|
|
|
|
|
|
Unless AUTO-ACCEPT-P is non-nil, this function will prompt for confirmation with
|
|
|
|
a list of packages that will be updated."
|
2019-07-21 15:39:45 +02:00
|
|
|
(print! (start "Scanning for outdated packages (this may take a while)..."))
|
|
|
|
(print-group!
|
2019-08-15 01:34:28 -04:00
|
|
|
(when timeout
|
|
|
|
(print! (info "Using %S as timeout value" timeout)))
|
2019-09-12 17:22:17 -04:00
|
|
|
(when threads
|
|
|
|
(print! (info "Limiting to %d thread(s)" threads)))
|
2019-07-21 15:39:45 +02:00
|
|
|
;; REVIEW Does this fail gracefully enough? Is it error tolerant?
|
|
|
|
;; TODO Add version-lock checks; don't want to spend all this effort on
|
|
|
|
;; packages that shouldn't be updated
|
2019-08-07 21:07:43 -04:00
|
|
|
(let* ((futures
|
2019-09-12 17:22:17 -04:00
|
|
|
;; REVIEW We can do better "thread" management here
|
2019-08-07 21:07:43 -04:00
|
|
|
(or (cl-loop for group
|
|
|
|
in (seq-partition (hash-table-values straight--repo-cache)
|
|
|
|
(/ (hash-table-count straight--repo-cache)
|
2019-09-12 17:22:17 -04:00
|
|
|
(or threads 8)))
|
2019-08-07 21:07:43 -04:00
|
|
|
for future = (doom--packages-remove-outdated-f group)
|
|
|
|
if (processp future)
|
|
|
|
collect (cons future group)
|
|
|
|
else
|
|
|
|
do (print! (warn "Failed to create thread for:\n\n%s\n\nReason: %s"
|
|
|
|
group future)))
|
|
|
|
(error! "Failed to create any threads")))
|
|
|
|
(total (length futures))
|
2019-08-15 01:34:28 -04:00
|
|
|
(timeout (or timeout 45)))
|
2019-07-29 21:01:46 +02:00
|
|
|
(condition-case-unless-debug e
|
2019-08-07 21:07:43 -04:00
|
|
|
(let (specs)
|
2019-07-21 15:39:45 +02:00
|
|
|
(while futures
|
2019-07-28 15:02:02 +02:00
|
|
|
(print! ". %.0f%%" (* (/ (- total (length futures))
|
|
|
|
(float total))
|
|
|
|
100))
|
2019-08-07 21:07:43 -04:00
|
|
|
(let ((time 0))
|
|
|
|
(catch 'timeout
|
|
|
|
(while (not (async-ready (caar futures)))
|
|
|
|
(when (> time timeout)
|
2019-08-09 15:26:22 -04:00
|
|
|
(print! (warn "A thread has timed out. The following packages were skipped: %s"
|
2019-08-08 22:59:57 -04:00
|
|
|
(mapconcat (lambda (p) (plist-get p :package))
|
|
|
|
(cdar futures)
|
|
|
|
", ")))
|
2019-08-09 15:26:22 -04:00
|
|
|
(throw 'timeout (pop futures)))
|
2019-08-15 01:34:28 -04:00
|
|
|
(sleep-for 1)
|
|
|
|
(when (cl-evenp time)
|
|
|
|
(print! "."))
|
|
|
|
(cl-incf time))
|
2019-08-07 21:07:43 -04:00
|
|
|
(cl-destructuring-bind (status . result)
|
|
|
|
(or (async-get (car (pop futures)))
|
|
|
|
(cons nil nil))
|
|
|
|
(cond ((null status)
|
|
|
|
(error "Thread returned an invalid result: %S" errors))
|
|
|
|
((eq status 'error)
|
|
|
|
(error "There were errors:\n\n%s"
|
|
|
|
(cond ((and (listp result)
|
|
|
|
(symbolp (car result)))
|
|
|
|
(prin1-to-string result))
|
|
|
|
((stringp result)
|
|
|
|
result)
|
|
|
|
((mapconcat (lambda (e)
|
|
|
|
(format! " - %s: %s" (yellow (car e)) (cdr e)))
|
|
|
|
result
|
|
|
|
"\n")))))
|
|
|
|
((eq status 'ok)
|
|
|
|
(print! (debug "Appended %S to package list") (or result "nothing"))
|
|
|
|
(appendq! specs result))
|
|
|
|
((error "Thread returned a non-standard status: %s\n\n%s"
|
|
|
|
status result)))))))
|
2019-07-29 21:01:46 +02:00
|
|
|
(print! ". 100%%")
|
2019-07-21 15:39:45 +02:00
|
|
|
(terpri)
|
2019-07-29 21:01:46 +02:00
|
|
|
(if-let (specs (delq nil specs))
|
2019-07-22 21:35:27 +02:00
|
|
|
(if (not
|
|
|
|
(or auto-accept-p
|
|
|
|
(y-or-n-p
|
|
|
|
(format!
|
|
|
|
"%s\n\nThere %s %d package%s available to update. Update them?"
|
|
|
|
(mapconcat
|
|
|
|
(lambda (spec)
|
|
|
|
(cl-destructuring-bind (n pretime time recipe) spec
|
|
|
|
(straight--with-plist recipe (package)
|
|
|
|
(format! "+ %-33s %s commit(s) behind %s -> %s"
|
|
|
|
(yellow package) (yellow n)
|
|
|
|
(format-time-string "%Y%m%d" pretime)
|
|
|
|
(format-time-string "%Y%m%d" time)))))
|
|
|
|
specs
|
|
|
|
"\n")
|
|
|
|
(if (cdr specs) "are" "is")
|
|
|
|
(length specs)
|
|
|
|
(if (cdr specs) "s" "")))))
|
|
|
|
(ignore (print! (info "Aborted update")))
|
|
|
|
(terpri)
|
2019-07-25 17:18:20 +02:00
|
|
|
(straight--make-package-modifications-available)
|
2019-07-26 20:04:53 +02:00
|
|
|
(let ((straight--packages-to-rebuild (make-hash-table :test #'equal))
|
|
|
|
(straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
|
|
|
|
(dolist (spec specs)
|
|
|
|
(cl-destructuring-bind (n pretime time recipe) spec
|
|
|
|
(straight--with-plist recipe (local-repo package)
|
|
|
|
(let ((default-directory (straight--repos-dir local-repo)))
|
|
|
|
(print! (start "Updating %S") package)
|
|
|
|
(straight-merge-package package)
|
|
|
|
;; HACK `straight-rebuild-package' doesn't pick up that
|
|
|
|
;; this package has changed, so we do it manually. Is
|
|
|
|
;; there a better way?
|
|
|
|
(ignore-errors
|
|
|
|
(delete-directory (straight--build-dir package) 'recursive))
|
|
|
|
(puthash package t straight--packages-to-rebuild)
|
|
|
|
(cl-incf n))
|
|
|
|
(with-current-buffer (straight--process-get-buffer)
|
|
|
|
(with-silent-modifications
|
|
|
|
(print! (debug (autofill "%s") (indent 2 (buffer-string))))
|
|
|
|
(erase-buffer))))))
|
|
|
|
(doom--finalize-straight)
|
|
|
|
(doom-packages-rebuild auto-accept-p))
|
|
|
|
t)
|
2019-07-21 15:39:45 +02:00
|
|
|
(print! (success "No packages to update"))
|
2019-07-25 17:18:20 +02:00
|
|
|
nil))
|
|
|
|
(error
|
|
|
|
(message "Output:\n%s" (straight--process-get-output))
|
|
|
|
(signal (car e) (error-message-string e)))))))
|
2019-07-21 15:39:45 +02:00
|
|
|
|
|
|
|
|
2019-07-29 21:04:58 +02:00
|
|
|
;;; PURGE (for the emperor)
|
|
|
|
(defun doom--prompt-p (list-fn list preamble postamble)
|
|
|
|
(or (y-or-n-p (format "%s%s\n\n%s"
|
|
|
|
(if preamble (concat preamble "\n\n") "")
|
|
|
|
(mapconcat list-fn list "\n")
|
|
|
|
(or postamble "")))
|
|
|
|
(user-error! "Aborted")))
|
|
|
|
|
|
|
|
(defun doom--prompt-columns-p (row-fn list preamble postamble)
|
|
|
|
(doom--prompt-p (lambda (row)
|
|
|
|
(mapconcat row-fn row ""))
|
|
|
|
(seq-partition (cl-sort (copy-sequence list) #'string-lessp)
|
|
|
|
3)
|
|
|
|
preamble
|
|
|
|
postamble))
|
|
|
|
|
|
|
|
(defun doom--packages-purge-build (build)
|
|
|
|
(let ((build-dir (straight--build-dir build)))
|
|
|
|
(print! (start "Purging build/%s..." build))
|
2019-07-29 21:18:49 +02:00
|
|
|
(delete-directory build-dir 'recursive)
|
2019-07-29 21:04:58 +02:00
|
|
|
(if (file-directory-p build-dir)
|
|
|
|
(ignore (print! (error "Failed to purg build/%s" build)))
|
|
|
|
(print! (success "Purged build/%s" build))
|
|
|
|
t)))
|
|
|
|
|
|
|
|
(defun doom--packages-purge-builds (builds &optional auto-accept-p)
|
|
|
|
(if (not builds)
|
|
|
|
(progn (print! (info "No builds to purge"))
|
|
|
|
0)
|
|
|
|
(or auto-accept-p
|
|
|
|
(doom--prompt-columns-p
|
|
|
|
(lambda (p) (format " + %-20.20s" p)) builds nil
|
|
|
|
(format! "Found %d orphaned package builds. Purge them?"
|
|
|
|
(length builds))))
|
|
|
|
(length
|
|
|
|
(delq nil (mapcar #'doom--packages-purge-build builds)))))
|
|
|
|
|
|
|
|
(defun doom--packages-regraft-repo (repo)
|
|
|
|
(let ((default-directory (straight--repos-dir repo)))
|
|
|
|
(if (not (file-directory-p ".git"))
|
|
|
|
(ignore (print! (warn "repos/%s is not a git repo, skipping" repo)))
|
2019-07-29 21:29:43 +02:00
|
|
|
(print! (debug "Regrafting repos/%s..." repo))
|
2019-07-29 21:04:58 +02:00
|
|
|
(straight--call "git" "reset" "--hard")
|
|
|
|
(straight--call "git" "clean" "--ffd")
|
|
|
|
(straight--call "git" "replace" "--graft" "HEAD")
|
|
|
|
(straight--call "git" "gc")
|
|
|
|
(print! (debug "%s" (straight--process-get-output)))
|
|
|
|
(print! (success "Regrafted repos/%s" repo))
|
|
|
|
t)))
|
|
|
|
|
|
|
|
(defun doom--packages-regraft-repos (repos &optional auto-accept-p)
|
|
|
|
(if (not repos)
|
|
|
|
(progn (print! (info "No repos to regraft"))
|
|
|
|
0)
|
|
|
|
(or auto-accept-p
|
|
|
|
(y-or-n-p (format! "Preparing to regraft all %d repos. Continue?"
|
|
|
|
(length repos)))
|
|
|
|
(user-error! "Aborted!"))
|
|
|
|
(if (executable-find "du")
|
|
|
|
(cl-destructuring-bind (status . size)
|
|
|
|
(doom-sh "du" "-sh" (straight--repos-dir))
|
|
|
|
(prog1 (delq nil (mapcar #'doom--packages-regraft-repo repos))
|
|
|
|
(cl-destructuring-bind (status . newsize)
|
|
|
|
(doom-sh "du" "-sh" (straight--repos-dir))
|
|
|
|
(print! (success "Finshed regrafted. Size before: %s and after: %s"
|
|
|
|
(car (split-string size "\t"))
|
|
|
|
(car (split-string newsize "\t")))))))
|
|
|
|
(delq nil (mapcar #'doom--packages-regraft-repo repos)))))
|
|
|
|
|
|
|
|
(defun doom--packages-purge-repo (repo)
|
2019-07-29 21:29:43 +02:00
|
|
|
(print! (debug "Purging repos/%s..." repo))
|
2019-07-29 21:04:58 +02:00
|
|
|
(let ((repo-dir (straight--repos-dir repo)))
|
|
|
|
(delete-directory repo-dir 'recursive)
|
|
|
|
(ignore-errors
|
|
|
|
(delete-file (straight--modified-file repo)))
|
|
|
|
(if (file-directory-p repo-dir)
|
|
|
|
(ignore (print! (error "Failed to purge repos/%s" repo)))
|
|
|
|
(print! (success "Purged repos/%s" repo))
|
|
|
|
t)))
|
|
|
|
|
|
|
|
(defun doom--packages-purge-repos (repos &optional auto-accept-p)
|
|
|
|
(if (not repos)
|
|
|
|
(progn (print! (info "No repos to purge"))
|
|
|
|
0)
|
|
|
|
(or auto-accept-p
|
|
|
|
(doom--prompt-columns-p
|
|
|
|
(lambda (p) (format " + %-20.20s" p)) repos nil
|
|
|
|
(format! "Found %d orphaned repos. Purge them?"
|
|
|
|
(length repos))))
|
|
|
|
(length
|
|
|
|
(delq nil (mapcar #'doom--packages-purge-repo repos)))))
|
|
|
|
|
|
|
|
(defun doom--packages-purge-elpa (&optional auto-accept-p)
|
|
|
|
(unless (bound-and-true-p package--initialized)
|
|
|
|
(package-initialize))
|
2019-09-03 14:07:09 -04:00
|
|
|
(let ((packages (cl-loop for (package desc) in package-alist
|
2019-09-02 13:12:57 -04:00
|
|
|
for dir = (package-desc-dir desc)
|
2019-09-24 20:49:24 -04:00
|
|
|
if (file-in-directory-p dir package-user-dir)
|
2019-09-02 13:12:57 -04:00
|
|
|
collect (cons package dir))))
|
|
|
|
(if (not package-alist)
|
|
|
|
(progn (print! (info "No ELPA packages to purge"))
|
|
|
|
0)
|
|
|
|
(doom--prompt-columns-p
|
|
|
|
(lambda (p) (format " + %-20.20s" p))
|
|
|
|
(mapcar #'car packages) nil
|
|
|
|
(format! "Found %d orphaned ELPA packages. Purge them?"
|
|
|
|
(length package-alist)))
|
|
|
|
(mapc (doom-rpartial #'delete-directory 'recursive)
|
|
|
|
(mapcar #'cdr packages))
|
|
|
|
(length packages))))
|
2019-07-25 18:46:18 +02:00
|
|
|
|
|
|
|
(defun doom-packages-purge (&optional elpa-p builds-p repos-p auto-accept-p)
|
2019-07-21 15:39:45 +02:00
|
|
|
"Auto-removes orphaned packages and repos.
|
2019-06-16 23:01:17 +02:00
|
|
|
|
|
|
|
An orphaned package is a package that isn't a primary package (i.e. doesn't have
|
|
|
|
a `package!' declaration) or isn't depended on by another primary package.
|
|
|
|
|
2019-07-25 18:46:18 +02:00
|
|
|
If BUILDS-P, include straight package builds.
|
|
|
|
If REPOS-P, include straight repos.
|
|
|
|
If ELPA-P, include packages installed with package.el (M-x package-install).
|
|
|
|
|
2019-06-16 23:01:17 +02:00
|
|
|
Unless AUTO-ACCEPT-P is non-nil, this function will prompt for confirmation with
|
|
|
|
a list of packages that will be removed."
|
2019-07-29 21:04:58 +02:00
|
|
|
(print! (start "Searching for orphaned packages to purge (for the emperor)..."))
|
|
|
|
(cl-destructuring-bind (&optional builds-to-purge repos-to-purge repos-to-regraft)
|
2019-08-18 11:24:44 -04:00
|
|
|
(let ((rdirs (straight--directory-files (straight--repos-dir) nil nil 'sort))
|
|
|
|
(bdirs (straight--directory-files (straight--build-dir) nil nil 'sort)))
|
2019-08-22 16:12:22 -04:00
|
|
|
(list (cl-remove-if (doom-rpartial #'gethash straight--profile-cache)
|
2019-08-18 11:24:44 -04:00
|
|
|
bdirs)
|
2019-08-22 16:12:22 -04:00
|
|
|
(cl-remove-if (doom-rpartial #'straight--checkhash straight--repo-cache)
|
2019-08-18 11:24:44 -04:00
|
|
|
rdirs)
|
2019-08-22 16:12:22 -04:00
|
|
|
(cl-remove-if-not (doom-rpartial #'straight--checkhash straight--repo-cache)
|
2019-08-18 11:24:44 -04:00
|
|
|
rdirs)))
|
2019-07-26 13:59:14 +02:00
|
|
|
(let (success)
|
|
|
|
(print-group!
|
2019-07-29 21:04:58 +02:00
|
|
|
(if (not builds-p)
|
|
|
|
(print! (info "Skipping builds"))
|
|
|
|
(and (/= 0 (doom--packages-purge-builds builds-to-purge auto-accept-p))
|
|
|
|
(setq success t)
|
|
|
|
(straight-prune-build-cache)))
|
2019-07-26 13:59:14 +02:00
|
|
|
(if (not elpa-p)
|
|
|
|
(print! (info "Skipping elpa packages"))
|
2019-07-29 21:04:58 +02:00
|
|
|
(and (/= 0 (doom--packages-purge-elpa auto-accept-p))
|
|
|
|
(setq success t)))
|
|
|
|
(if (not repos-p)
|
|
|
|
(print! (info "Skipping repos"))
|
|
|
|
(and (/= 0 (doom--packages-purge-repos repos-to-purge auto-accept-p))
|
2019-07-26 13:59:14 +02:00
|
|
|
(setq success t))
|
2019-07-29 21:04:58 +02:00
|
|
|
(and (doom--packages-regraft-repos repos-to-regraft auto-accept-p)
|
|
|
|
(setq success t)))
|
2019-07-26 13:59:14 +02:00
|
|
|
(when success
|
|
|
|
(doom--finalize-straight)
|
|
|
|
t)))))
|