From 4078a6e49cd0f10ccc0a1b48d791730ed92cd87a Mon Sep 17 00:00:00 2001 From: Kyle Meyer Date: Tue, 21 Apr 2020 00:14:33 -0400 Subject: Add a barely useful interface to b4-am Aside from switching the 'b4 am' process to an asynchronous one, the am-ready commands may not need a lot of work. The more interesting variant, piem-b4-am-from-mid, can find an associated code repository and am the patch, but there's a lot that needs to be fleshed out. --- .gitignore | 1 + Makefile | 9 ++- piem-b4.el | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ piem.texi | 4 ++ 4 files changed, 217 insertions(+), 2 deletions(-) create mode 100644 piem-b4.el diff --git a/.gitignore b/.gitignore index f02607a..8171c92 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.elc *.info +config.mk diff --git a/Makefile b/Makefile index 8b04a53..50c87d2 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,12 @@ -BATCH = emacs -Q --batch +-include config.mk -all: piem.elc piem.info +TRANSIENT_DIR ?= /dev/null + +LOAD_PATH = -L . -L $(TRANSIENT_DIR) +BATCH = emacs -Q --batch $(LOAD_PATH) + +all: piem.elc piem-b4.elc piem.info .PHONY: clean clean: diff --git a/piem-b4.el b/piem-b4.el new file mode 100644 index 0000000..957994e --- /dev/null +++ b/piem-b4.el @@ -0,0 +1,205 @@ +;;; piem-b4.el --- Emacs interface to the b4 tool -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Kyle Meyer + +;; Author: Kyle Meyer +;; Keywords: vc, tools +;; Version: 0.0.0 +;; Package-Requires: ((emacs "26.3") (transient "0.2.0")) + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; + +;;; Code: + +(require 'cl-lib) +(require 'piem) +(require 'subr-x) +(require 'transient) + + +;;; Options + +(defgroup piem-b4 nil + "Control the b4 tool from Emacs." + :link '(info-link "(piem)b4 integration") + :group 'piem) + +(defcustom piem-b4-b4-executable "b4" + "Which b4 executable to use." + :type 'string) + +(defcustom piem-b4-git-executable + (or (and (boundp 'magit-git-executable) magit-git-executable) + "git") + "Which git executable to use." + :type 'string) + +(defcustom piem-b4-use-magit (featurep 'magit) + "Whether to use Magit where possible." + :type 'boolean) + + +;;; Internals + +(define-error 'piem-b4-error "b4 error") + +(defconst piem-b4-output-buffer "*piem-b4-output*") + +;; TODO: Use an asynchronous process. +(defun piem-b4--call-b4 (&rest args) + (unless piem-b4-b4-executable + (user-error "piem-b4-b4-executable must be non-nil")) + (let ((temp-buffer-show-function (lambda (_)))) + (with-output-to-temp-buffer piem-b4-output-buffer + (unless (= 0 (apply #'call-process piem-b4-b4-executable + nil standard-output nil + (remq nil args))) + (display-buffer piem-b4-output-buffer) + (signal 'piem-b4-error + (list (format "b4 call in %s failed" default-directory))))))) + +;; 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 +;; so that we honor its customization/URL resolution. +(defun piem-b4--get-mbox-file (mid coderepo args) + (let* ((mbox-name (format "%s.mbx" mid)) + (outdir (file-name-as-directory + (make-temp-file "piem-b4-" t))) + (mbox-am (concat outdir mbox-name)) + (mbox-thread (concat mbox-am "-thread")) + (custom-p nil)) + (when-let ((fn (run-hook-with-args-until-success + 'piem-mid-to-thread-functions mid))) + (with-temp-file mbox-thread + (funcall fn) + (unless (= (point-max) 1) + (setq custom-p t)))) + ;; Move to the coderepo so that we pick up any b4 configuration + ;; from there. + (let ((default-directory coderepo)) + (apply #'piem-b4--call-b4 "am" + (and custom-p + (concat "--use-local-mbox=" mbox-thread)) + (concat "--outdir=" outdir) + (concat "--mbox-name=" mbox-name) + (append args (list mid)))) + (unless (file-exists-p mbox-am) + (error "Expected mbox file does not exist: %s" mbox-am)) + mbox-am)) + + +;;; Commands + +;;;###autoload +(defun piem-b4-am-ready-from-mbox (mbox &optional args) + (interactive (list (read-file-name "mbox: ") + (transient-args 'piem-b4-am))) + (apply #'piem-b4--call-b4 "am" + (cons (concat "--use-local-mbox=" mbox) args)) + (display-buffer piem-b4-output-buffer)) + +;;;###autoload +(defun piem-b4-am-ready-from-mid (mid &optional args) + (interactive (list (read-string "Message ID: " nil nil (piem-mid)) + (transient-args 'piem-b4-am))) + (apply #'piem-b4--call-b4 "am" (append args (list mid))) + (display-buffer piem-b4-output-buffer)) + +;;;###autoload +(defun piem-b4-am-from-mid (mid &optional args) + (interactive (list (or (piem-mid) + (read-string "Message ID: ")) + (transient-args 'piem-b4-am))) + (when-let ((badopt (cl-some + (lambda (arg) + (and (string-match + (rx string-start + (group (or "--outdir" "--mbox-name")) "=") + arg) + (match-string 1 arg))) + args))) + (user-error "%s is incompatible with this command" badopt)) + (let* ((coderepo (or (piem-inbox-coderepo) + (and (fboundp 'projectile-relevant-known-projects) + (completing-read + "Project: " + (projectile-relevant-known-projects))) + (and piem-b4-use-magit + (fboundp 'magit-read-repository) + (magit-read-repository)) + (read-directory-name "Git repository: "))) + (mbox-file (piem-b4--get-mbox-file mid coderepo args)) + (default-directory coderepo)) + ;; TODO: From the mbox file (1) search for base commit and (2) + ;; gather information to suggest default branch name. + + ;; TODO: Add branch call. Without base, will need to ask branch + ;; name and starting point. Detached head could be signaled with + ;; empty string. + + ;; TODO: Optionally do more through Magit. + (call-process piem-b4-git-executable + mbox-file nil nil "am" "--scissors") + (if (and piem-b4-use-magit + (fboundp 'magit-status-setup-buffer)) + (magit-status-setup-buffer) + (dired ".")))) + +(define-infix-argument piem-b4-am:--outdir () + :description "Output directory" + :class 'transient-option + :shortarg "-o" + :argument "--outdir=" + :reader #'transient-read-existing-directory) + +(define-infix-argument piem-b4-am:--mbox-name () + :description "Base file name for mbox" + :class 'transient-option + :shortarg "-n" + :argument "--mbox-name=" + :reader #'read-string) + +(define-infix-argument piem-b4-am:--use-version () + :description "Desired version of patch series" + :class 'transient-option + :shortarg "-v" + :argument "--use-version=" + :reader #'transient-read-number-N+) + +;;;###autoload (autoload 'piem-b4-am "b4" nil t) +(define-transient-command piem-b4-am () + "Filter mbox to patches and feed to git-am" + ["General options" + ("-c" "Check newer versions" "--check-newer-revisions") + ("-C" "Don't use local cache" "--no-cache") + ("-s" "Add my signed-off-by" "--add-my-sob") + ("-S" "Apply trailers without checking email addresses" "--sloppy-trailers") + ("-t" "Apply cover letter trailers" "--apply-cover-trailers") + ("-T" "Do not add trailers" "--no-add-trailers") + (piem-b4-am:--use-version)] + ["Options for creating am-ready mboxes" + (piem-b4-am:--outdir) + (piem-b4-am:--mbox-name)] + ["Actions" + [("a" "Message ID -> mbox -> git-am" piem-b4-am-from-mid)] + [("b" "Local mbox -> am-ready mbox" piem-b4-am-ready-from-mbox) + ("i" "Message ID -> am-ready mbox" piem-b4-am-ready-from-mid)]]) + +;;; piem-b4.el ends here +(provide 'piem-b4) diff --git a/piem.texi b/piem.texi index 15b0e2e..137a7cb 100644 --- a/piem.texi +++ b/piem.texi @@ -45,6 +45,7 @@ This manual is for piem version @value{VERSION}. @menu * Overview:: +* b4 interface:: * Related tools:: * Contributing:: @@ -64,6 +65,9 @@ Indices @node public-inbox @section public-inbox +@node b4 interface +@chapter b4 interface + @node Related tools @chapter Related tools -- cgit v1.2.3