summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyle Meyer <kyle@kyleam.com>2020-06-05 19:46:43 -0400
committerKyle Meyer <kyle@kyleam.com>2020-06-06 15:09:23 -0400
commit6a61ff58c159a8b46408b99825c3c2ff420a20e0 (patch)
treeda7d68cd142774cbdb0af59613b640d1f2e62f99
parent432230a18783fca060535698e087641a69ab1bf2 (diff)
downloadpiem-6a61ff58c159a8b46408b99825c3c2ff420a20e0.tar.gz
Extract reusable git-am logic from -b4
The end goal is to turn piem-am into a command that can work with patches extracted from the current buffer. Pull out the logic that can be reused for this.
-rw-r--r--piem-b4.el125
-rw-r--r--piem.el126
2 files changed, 128 insertions, 123 deletions
diff --git a/piem-b4.el b/piem-b4.el
index f8908f7..a5530e3 100644
--- a/piem-b4.el
+++ b/piem-b4.el
@@ -30,7 +30,6 @@
(require 'mail-extr)
(require 'message)
(require 'piem)
-(require 'subr-x)
(require 'transient)
@@ -45,108 +44,9 @@
"Which b4 executable to use."
:type 'string)
-
-
-(defcustom piem-b4-default-branch-function
- #'piem-b4-name-branch-who-what-v
- "Function that generates the default branch on completion.
-
-The function is called with one argument, a plist that contains
-the following information about the patch series:
-
- :date
- :from
- :subject
- The date, sender, and subject of the cover letter, if any, or of
- the first patch otherwise.
- :base-commit
- The reported base commit of the patch, if any."
- :type 'boolean)
-
;;;; Internals
-(defun piem-b4--series-info (cover patches)
- "Collect information for a patch series.
-COVER is an mbox with the cover letter, and PATCHES is an
-am-ready mbox. If the series does not have a cover letter (e.g.,
-a one-patch series), COVER may be nil."
- (with-temp-buffer
- (insert-file-contents (or cover patches))
- (let ((info (save-restriction
- (message-narrow-to-headers)
- (list :date (message-fetch-field "date")
- :from (message-fetch-field "from")
- :subject (message-fetch-field "subject")))))
- (when (re-search-forward (rx line-start "base-commit: "
- (group (>= 40 hex-digit))
- line-end)
- nil t)
- (plist-put info :base-commit (match-string 1)))
- info)))
-
-(defun piem-b4--shorten-subject (subject)
- (let ((words
- (mapcar #'downcase
- (split-string
- (thread-last subject
- (replace-regexp-in-string
- (rx (any "'\""))
- "")
- (replace-regexp-in-string
- (rx string-start (zero-or-more space) "["
- (zero-or-more (not (any "]" "\n")))
- "PATCH"
- (zero-or-more (not (any "]" "\n")))
- "]" (one-or-more space))
- ""))
- "\\W+" t)))
- (ignore-these (list "a" "an" "the"))
- (num-words 0)
- (num-chars 0)
- kept)
- (catch 'stop
- (dolist (word words)
- (when (not (member word ignore-these))
- (cl-incf num-words)
- (cl-incf num-chars (length word))
- (push word kept)
- (when (or (> num-words 5)
- (> num-chars 20))
- (throw 'stop nil)))))
- (mapconcat #'identity (reverse kept) "-")))
-
-(defun piem-b4-name-branch-who-what-v (info)
- "Construct a branch name like \"km/b4-short-subj__v3\".
-
-In the above example, \"k\" and \"m\" are the first letters of
-the first and second \"words\" in the \"From:\" field.
-\"b4-short-subj\" is a stripped down, truncated variant of
-\"Subject:\". And \"v3\" is the version of the patch series, as
-indicated in the subject.
-
-INFO is a plist with properties documented
-in `piem-b4-default-branch-function'."
- (when-let ((sender (car (mail-extract-address-components
- (plist-get info :from))))
- (subject (plist-get info :subject)))
- (let* ((subnames (split-string sender))
- (initials (mapconcat
- (lambda (subname)
- (and subname
- (downcase (substring subname nil 1))))
- (list (car subnames) (cadr subnames))
- ""))
- (version (and (string-match
- (rx "[" (zero-or-more (not (any "[" "\n")))
- "PATCH "
- (zero-or-one (group "v" (one-or-more digit))))
- subject)
- (match-string 1 subject))))
- (concat initials "/"
- (piem-b4--shorten-subject subject)
- (and version (concat "__" version))))))
-
;; In many cases, we don't really need b4 to download the mbox for us,
;; as we already have our own mbox to URL mapping. Perhaps we should
;; default to using that, but it should still be an option to use b4
@@ -221,30 +121,9 @@ in `piem-b4-default-branch-function'."
(read-directory-name "Git repository: ")))
(`(,cover ,mbox-file)
(piem-b4--get-am-files mid coderepo args))
- (info (piem-b4--series-info cover mbox-file))
+ (info (piem-series-info cover mbox-file))
(default-directory coderepo))
- ;; TODO: Optionally do more through Magit.
- (let ((new-branch (read-string
- "New branch (empty for detached): "
- (funcall piem-b4-default-branch-function info)))
- (base (completing-read
- "Base commit: "
- (let ((cands (and piem-use-magit
- (fboundp 'magit-list-local-branch-names)
- (magit-list-local-branch-names)))
- (base (plist-get info :base-commit)))
- (if base (cons base cands) cands)))))
- (apply #'piem-process-call nil piem-git-executable "checkout"
- (append (if (string-empty-p new-branch)
- (list "--detach")
- (list "-b" new-branch))
- (list base))))
- (piem-process-call nil piem-git-executable "am" "--scissors"
- mbox-file)
- (if (and piem-use-magit
- (fboundp 'magit-status-setup-buffer))
- (magit-status-setup-buffer)
- (dired "."))))
+ (piem-am mbox-file info coderepo)))
(define-infix-argument piem-b4-am:--outdir ()
:description "Output directory"
diff --git a/piem.el b/piem.el
index 6218e50..b764616 100644
--- a/piem.el
+++ b/piem.el
@@ -139,6 +139,22 @@ intended to be used by libraries implementing a function for
"Whether to use Magit where possible."
:type 'boolean)
+(defcustom piem-default-branch-function
+ #'piem-name-branch-who-what-v
+ "Function that generates the default branch on completion.
+
+The function is called with one argument, a plist that contains
+the following information about the patch series:
+
+ :date
+ :from
+ :subject
+ The date, sender, and subject of the cover letter, if any, or of
+ the first patch otherwise.
+ :base-commit
+ The reported base commit of the patch, if any."
+ :type 'boolean)
+
;;;; Subprocess handling
@@ -223,6 +239,116 @@ intended to be used by libraries implementing a function for
"Return the current buffer's message ID."
(run-hook-with-args-until-success 'piem-get-mid-functions))
+
+;;;; Patch handling
+
+(defun piem-series-info (cover patches)
+ "Collect information for a patch series.
+COVER is an mbox with the cover letter, and PATCHES is an
+am-ready mbox. If the series does not have a cover letter (e.g.,
+a one-patch series), COVER may be nil."
+ (with-temp-buffer
+ (insert-file-contents (or cover patches))
+ (let ((info (save-restriction
+ (message-narrow-to-headers)
+ (list :date (message-fetch-field "date")
+ :from (message-fetch-field "from")
+ :subject (message-fetch-field "subject")))))
+ (when (re-search-forward (rx line-start "base-commit: "
+ (group (>= 40 hex-digit))
+ line-end)
+ nil t)
+ (plist-put info :base-commit (match-string 1)))
+ info)))
+
+(defun piem--shorten-subject (subject)
+ (let ((words
+ (mapcar #'downcase
+ (split-string
+ (thread-last subject
+ (replace-regexp-in-string
+ (rx (any "'\""))
+ "")
+ (replace-regexp-in-string
+ (rx string-start (zero-or-more space) "["
+ (zero-or-more (not (any "]" "\n")))
+ "PATCH"
+ (zero-or-more (not (any "]" "\n")))
+ "]" (one-or-more space))
+ ""))
+ "\\W+" t)))
+ (ignore-these (list "a" "an" "the"))
+ (num-words 0)
+ (num-chars 0)
+ kept)
+ (catch 'stop
+ (dolist (word words)
+ (when (not (member word ignore-these))
+ (cl-incf num-words)
+ (cl-incf num-chars (length word))
+ (push word kept)
+ (when (or (> num-words 5)
+ (> num-chars 20))
+ (throw 'stop nil)))))
+ (mapconcat #'identity (reverse kept) "-")))
+
+(defun piem-name-branch-who-what-v (info)
+ "Construct a branch name like \"km/b4-short-subj__v3\".
+
+In the above example, \"k\" and \"m\" are the first letters of
+the first and second \"words\" in the \"From:\" field.
+\"b4-short-subj\" is a stripped down, truncated variant of
+\"Subject:\". And \"v3\" is the version of the patch series, as
+indicated in the subject.
+
+INFO is a plist with properties documented
+in `piem-default-branch-function'."
+ (when-let ((sender (car (mail-extract-address-components
+ (plist-get info :from))))
+ (subject (plist-get info :subject)))
+ (let* ((subnames (split-string sender))
+ (initials (mapconcat
+ (lambda (subname)
+ (and subname
+ (downcase (substring subname nil 1))))
+ (list (car subnames) (cadr subnames))
+ ""))
+ (version (and (string-match
+ (rx "[" (zero-or-more (not (any "[" "\n")))
+ "PATCH "
+ (zero-or-one (group "v" (one-or-more digit))))
+ subject)
+ (match-string 1 subject))))
+ (concat initials "/"
+ (piem--shorten-subject subject)
+ (and version (concat "__" version))))))
+
+(defun piem-am (mbox &optional info coderepo)
+ (let* ((default-directory (or coderepo default-directory)))
+ ;; TODO: Optionally do more through Magit.
+ (let ((new-branch (read-string
+ "New branch (empty for detached): "
+ (funcall piem-default-branch-function info)))
+ (base (completing-read
+ "Base commit: "
+ (let ((cands (and piem-use-magit
+ (fboundp 'magit-list-local-branch-names)
+ (magit-list-local-branch-names)))
+ (base (plist-get info :base-commit)))
+ (if base (cons base cands) cands)))))
+ (apply #'piem-process-call nil piem-git-executable "checkout"
+ (append (if (string-empty-p new-branch)
+ (list "--detach")
+ (list "-b" new-branch))
+ (list base))))
+ (piem-process-call nil piem-git-executable "am" "--scissors" mbox)
+ (if (and piem-use-magit
+ (fboundp 'magit-status-setup-buffer))
+ (magit-status-setup-buffer)
+ (dired "."))))
+
+
+
(defun piem-please ()
"How I wish I could intersect my emails, feeds, and repos")