dotfiles/.config/emacs/bootstrap/crafted-package-bootstrap.el

121 lines
5.0 KiB
EmacsLisp

;;;; crafted-package/package.el --- Configuration to use `package.el'. -*- lexical-binding: t; -*-
;; Copyright (C) 2022
;; SPDX-License-Identifier: MIT
;; Author: System Crafters Community
;;; Commentary:
;; Bootstrap `package.el' configuration. This is the default package
;; manager for Crafted Emacs. Code provided herein is intended for
;; internal use, the user is not expected to use the interface
;; provided here to manage their packages. In fact, should the user
;; prefer to use `use-package' in their configuration, that should
;; work seamlessly with this configuration. The user will need to
;; install `use-package', of course. That being said, the user is
;; welcome to use the macros presented here. They provide
;; `crafted-emacs' a standard way to install packages in the modules
;; provided as we can't predict if the user will choose to use
;; `package.el' or some other tool.
;;; Code:
;; package configuration
(require 'package)
(require 'time-date)
;; Emacs 27.x has gnu elpa as the default
;; Emacs 28.x adds the nongnu elpa to the list by default, so only
;; need to add nongnu when this isn't Emacs 28+
(when (version< emacs-version "28")
(add-to-list 'package-archives '("nongnu" . "https://elpa.nongnu.org/nongnu/")))
(add-to-list 'package-archives '("stable" . "https://stable.melpa.org/packages/"))
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(customize-set-variable 'package-archive-priorities
'(("gnu" . 99) ; prefer GNU packages
("nongnu" . 80) ; use non-gnu packages if
; not found in GNU elpa
("stable" . 70) ; prefer "released" versions
; from melpa
("melpa" . 0))) ; if all else fails, get it
; from melpa
(customize-set-variable 'package-user-dir
(expand-file-name "elpa/" crafted-config-path))
;; make sure the elpa/ folder exists after setting it above.
(unless (file-exists-p package-user-dir)
(mkdir package-user-dir t))
(defvar crafted-bootstrap-package-perform-stale-archive-check t
"Flag to allow the user to turn off checking if an archive is
stale on startup.")
(defvar crafted-bootstrap-package-update-days 1
"The number of days old a package archive must be before it is
considered stale.")
;;; package configuration
(defun crafted-package-archive-stale-p (archive)
"Return `t' if ARCHIVE is stale.
ARCHIVE is stale if the on-disk cache is older than
`crafted-bootstrap-package-update-days' old. If
`crafted-bootstrap-package-perform-stale-archive-check' is nil,
the check is skipped."
(let* ((today (decode-time nil nil t))
(archive-name (expand-file-name
(format "archives/%s/archive-contents" archive)
package-user-dir))
(last-update-time (decode-time (file-attribute-modification-time
(file-attributes archive-name))))
(delta (make-decoded-time :day crafted-bootstrap-package-update-days)))
(if crafted-bootstrap-package-perform-stale-archive-check
(time-less-p (encode-time (decoded-time-add last-update-time delta))
(encode-time today))
nil)))
(defun crafted-package-archives-stale-p ()
"Return `t' if any PACKAGE-ARHIVES cache is out of date.
Check each archive listed in PACKAGE-ARCHIVES, if the on-disk
cache is older than 1 day, return a non-nil value. Fails fast,
will return `t' for the first stale archive found or `nil' if
they are all up-to-date."
(interactive)
(cl-some #'crafted-package-archive-stale-p (mapcar #'car package-archives)))
(defmacro crafted-package-install-package (package)
"Only install the package if it is not already installed."
`(unless (package-installed-p ,package) (package-install ,package)))
(defmacro crafted-package-installed-p (package)
`(package-installed-p ,package))
(defun crafted-package-initialize ()
"Initialize the package system."
;; Only use package.el if it is enabled. The user may have turned it
;; off in their `early-config.el' file, so respect their wishes if so.
(when package-enable-at-startup
(package-initialize)
(require 'seq)
;; Only refresh package contents once per day on startup, or if the
;; `package-archive-contents' has not been initialized. If Emacs has
;; been running for a while, user will need to manually run
;; `package-refresh-contents' before calling `package-install'.
(cond ((seq-empty-p package-archive-contents)
(progn
(message "crafted-init: package archives empty, initializing")
(package-refresh-contents)))
((crafted-package-archives-stale-p)
(progn
(message "crafted-init: package archives stale, refreshing in the background")
(package-refresh-contents t))))
))
(provide 'crafted-package/package)
;;; crafted-package/package.el ends here