;;; core/upgrade.el --- Upgrade packages  -*- lexical-binding: t; -*-

;;; Commentary:
;;
;; Command use to upgrade Emacs packages,
;;
;;   $ eask upgrade [names..]
;;
;;
;;  Positionals:
;;
;;    [names..]     package to upgrade; else we upgrade all packages
;;

;;; Code:

(let ((dir (file-name-directory (nth 1 (member "-scriptload" command-line-args)))))
  (load (expand-file-name "_prepare.el"
                          (locate-dominating-file dir "_prepare.el"))
        nil t))

(defun eask-upgrade--package-version-string (pkg-desc)
  "Get package version string with color from PKG-DESC."
  (let ((version (package-desc-version pkg-desc)))
    (ansi-yellow (package-version-join version))))

(defun eask-upgrade--package (pkg-desc)
  "Upgrade package using PKG-DESC."
  (let* ((name (package-desc-name pkg-desc))
         (pkg-string (ansi-green (eask-2str name)))
         (version-new (eask-upgrade--package-version-string pkg-desc))
         (old-pkg-desc (eask-package-desc name t))
         (version-old (eask-upgrade--package-version-string old-pkg-desc)))
    (eask-with-progress
      (format "  - Upgrading %s (%s) -> (%s)..." pkg-string version-old version-new)
      (eask-with-verbosity 'debug
        (when (eask-force-p) (package-delete old-pkg-desc))
        (package-install pkg-desc)
        (unless (eask-force-p) (package-delete old-pkg-desc)))
      "done ✓")))

(defun eask-package--upgradable-p (pkg)
  "Return non-nil if PKG can be upgraded."
  (let ((current (eask-package--version pkg t))
        (latest (eask-package--version pkg nil)))
    (version-list-< current latest)))

(defun eask-package--upgrades ()
  "Return a list of upgradable package description."
  (let (upgrades)
    (eask-with-progress
      (ansi-green "Collecting information for upgradable packages...")
      (dolist (pkg (mapcar #'car package-alist))
        (when (eask-package--upgradable-p pkg)
          (push (cadr (assq pkg package-archive-contents)) upgrades)))
      (ansi-green "done ✓"))
    upgrades))

(defun eask-upgrade--package-all ()
  "Upgrade for archive packages."
  (if-let* ((upgrades (eask-package--upgrades)))
      (progn
        (mapc #'eask-upgrade--package upgrades)
        (eask-msg "")
        (eask-info "(Done upgrading all packages)"))
    (eask-msg "")
    (eask-info "(All packages are up to date)")))

(eask-start
  (eask-pkg-init)
  (if-let* ((names (eask-args)))
      (dolist (name names)
        (setq name (intern name))
        (if (package-installed-p name)
            (if (or (eask-package--upgradable-p name) (eask-force-p))
                (eask-upgrade--package (cadr (assq name package-archive-contents)))
              (eask-warn "Package `%s` is already up to date" name))
          (eask-error "Package does not exists `%s`, you need to install before upgrade" name)))
    (eask-upgrade--package-all)))

;;; core/upgrade.el ends here
