forked from SystemCrafters/crafted-emacs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcrafted-updates-config.el
170 lines (133 loc) · 5.97 KB
/
crafted-updates-config.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
;;; crafted-updates-config.el --- Provides automatic update behavior for the configuration. -*- lexical-binding: t; -*-
;; Copyright (C) 2023
;; SPDX-License-Identifier: MIT
;; Author: System Crafters Community
;;; Commentary:
;; Checks for updates to the Crafted Emacs project. Provides a
;; function to show the updates before pulling changes.
;; This uses `crafted-emacs-home', which is set on load if it hasn't been
;; set by the user or by `crafted-init-config'. It expects that directory
;; to be a git directory that can be used to checking on updates from
;; upstream. Defensively would still need to check if that location
;; is `bound-and-true-p' before doing anything.
;;; Code:
;;; Find where Crafted Emacs is located
(unless (boundp 'crafted-emacs-home)
(setq crafted-emacs-home (project-root (project-current nil (file-name-directory (buffer-file-name)))))
(warn (format "crafted-emacs-home is not set. Attempting to use %s" crafted-emacs-home)))
(autoload 'vc-git--out-ok "vc-git")
;;; Public interface
;;;; Commands
(defun crafted-updates-check-for-latest ()
"Fetches the latest Crafted Emacs.
Get commits from GitHub and notify you if there are any updates."
(interactive)
(message "Checking for Crafted Emacs updates...")
(when (crafted-updates--call-git #' "fetch" "origin")
(crafted-updates--notify-of-updates)))
(defun crafted-updates-show-latest ()
"Get latest Crafted Emacs commits.
Shows a buffer containing a log of the latest commits to
Crafted Emacs."
(interactive)
(message "Fetching latest commit log for Crafted Emacs...")
(with-current-buffer (find-file-noselect (expand-file-name
"README.org"
crafted-emacs-home))
(vc-log-incoming)))
(defun crafted-updates-pull-latest (do-pull)
"Pull the latest Crafted Emacs version into the local repository.
If DO-PULL is nil then only the latest updates will be shown,
otherwise the local repository will get updated to the GitHub
version.
Interactively, the default if you just type RET is to show recent
changes as if you called `crafted-updates-show-latest'.
With a `\\[universal-argument]' prefix immediately pull changes
and don't prompt for confirmation."
(interactive
(list
(or current-prefix-arg
(pcase (completing-read "Crafted Update Action: " '("Show Log" "Update") nil t nil nil "Show Log")
("Show Log" nil)
("Update" t)))))
(if do-pull
(crafted-updates--pull-commits)
(crafted-updates-show-latest)))
;;;; Functions
(defun crafted-updates-status-message ()
"Status message indicating availble updates or not."
(let ((commit-count (crafted-updates--get-new-commit-count)))
(cond ((> commit-count 0) "Crafted Emacs updates are available!")
((= commit-count 0) "Crafted Emacs is up to date!")
((< commit-count 0) "Current branch is local only!"))))
;;; Customization options - See `M-x customize-group RET crafted-updates'
(defgroup crafted-updates '()
"Configuration for keeping Crafted Emacs up-to-date."
:tag "Crafted Updates"
:group 'crafted)
;; TODO: use a derived type to check that the value is something `run-at-time'
;; will accept
(defcustom crafted-updates-fetch-interval "24 hours"
"The interval at which `crafted-updates-mode' will check for updates.
The interval is scheduled with `run-at-time', so the value of
this variable must conform to a format accepted by
`run-at-time'."
:group 'crafted-updates)
;;; Private interface
;; These functions are not intended to be called directly.
(defun crafted-updates--call-git (&rest args)
"Call git with ARGS."
(let ((default-directory crafted-emacs-home))
(with-temp-buffer
(if (apply #'vc-git--out-ok args)
(buffer-string)
nil))))
(defun crafted-updates--pull-commits ()
"Pull commits from Crafted Emacs repo."
(message "Pulling latest commits to Crafted Emacs...")
(with-current-buffer (find-file-noselect
(expand-file-name "README.org"
crafted-emacs-home))
(vc-pull)))
(defun crafted-updates--get-new-commit-count ()
"Count new commits.
These are commits not currently pulled from the main repo."
(with-temp-buffer
(let* ((default-directory crafted-emacs-home)
(current-branch (car (vc-git-branches)))
(rev-list-path (concat current-branch "..origin/" current-branch))
(compare-remote (concat "origin/" current-branch)))
(if (member compare-remote (split-string (crafted-updates--call-git "branch" "-r")))
(string-to-number (crafted-updates--call-git "rev-list" "--count" rev-list-path))
-1))))
(defun crafted-updates--notify-of-updates ()
"Show a message in *Message* buffer."
(message (crafted-updates-status-message)))
(defun crafted-updates--poll-git-fetch-status (process)
"Check to see if the git PROCESS has completed."
(if (eql (process-status process) 'exit)
(when (eql (process-exit-status process) 0)
(message "crafted-updates: git fetch status completed successfully"))
(run-at-time 1 nil #'crafted-updates--poll-git-fetch-status process)))
(defun crafted-updates--schedule-fetch ()
"Schedule pulling Crafted Emacs updates."
(run-at-time crafted-updates-fetch-interval nil #'crafted-updates--do-automatic-fetch))
;;; Minor mode
(define-minor-mode crafted-updates-mode
"Crafted Emacs updates minor mode.
Provides an automatic update checking feature for Crafted
Emacs. When enabled, it will automatically check for updates at
the specified `crafted-updates-fetch-interval'."
:global t
:group 'crafted-updates
(when crafted-updates-mode
(crafted-updates--schedule-fetch)))
(defun crafted-updates--do-automatic-fetch ()
"Automatically fetch Crafted Emacs updates.
Only runs when `crafted-updates-mode' is active."
(when crafted-updates-mode
(crafted-updates-check-for-latest)
(crafted-updates--schedule-fetch)))
;;; _
(provide 'crafted-updates-config)
;;; crafted-updates-config.el ends here