aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--b4/command.py4
-rw-r--r--b4/ez.py102
-rw-r--r--docs/contributor/prep.rst5
-rw-r--r--man/b4.55
-rw-r--r--man/b4.5.rst3
5 files changed, 86 insertions, 33 deletions
diff --git a/b4/command.py b/b4/command.py
index 245bfd0..b16043e 100644
--- a/b4/command.py
+++ b/b4/command.py
@@ -266,6 +266,8 @@ def cmd():
help='Show current series revision number')
spp_g.add_argument('--force-revision', metavar='N', type=int,
help='Force revision to be this number instead')
+ spp_g.add_argument('--compare-to', metavar='vN',
+ help='Display a range-diff to previously sent revision N')
spp_g.add_argument('--manual-reroll', dest='reroll', default=None, metavar='COVER_MSGID',
help='Mark current revision as sent and reroll (requires cover letter msgid)')
ag_prepn = sp_prep.add_argument_group('Create new branch', 'Create a new branch for working on patch series')
@@ -308,7 +310,7 @@ def cmd():
sp_send.add_argument('--cc', nargs='+', help='Addresses to add to the Cc: list')
sp_send.add_argument('--not-me-too', action='store_true', default=False,
help='Remove yourself from the To: or Cc: list')
- sp_send.add_argument('--resend', default=None,
+ sp_send.add_argument('--resend', metavar='vN', default=None,
help='Resend a previously sent version of the series')
sp_send.add_argument('--no-sign', action='store_true', default=False,
help='Do not add the cryptographic attestation signature header')
diff --git a/b4/ez.py b/b4/ez.py
index 58564fa..07c5b98 100644
--- a/b4/ez.py
+++ b/b4/ez.py
@@ -26,7 +26,7 @@ import gzip
import io
import copy
-from typing import Optional, Tuple, List
+from typing import Optional, Tuple, List, Union
from email import utils
from string import Template
@@ -45,6 +45,8 @@ except ModuleNotFoundError:
logger = b4.logger
MAGIC_MARKER = '--- b4-submit-tracking ---'
+# Make this configurable?
+SENT_TAG_PREFIX = 'sent/'
DEFAULT_COVER_TEMPLATE = """
${cover}
@@ -907,10 +909,7 @@ def print_pretty_addrs(addrs: list, hdrname: str) -> None:
logger.info(' %s', b4.format_addrs([addr]))
-def get_sent_tag_as_patches(tagname: str, revision: Optional[str] = None,
- prefixes: Optional[List[str]] = None,
- hide_cover_to_cc: bool = False
- ) -> Tuple[List, List, List[Tuple[str, email.message.Message]]]:
+def get_base_changeid_from_tag(tagname: str) -> Tuple[str, str, str]:
gitargs = ['cat-file', '-p', tagname]
ecode, tagmsg = b4.git_run_command(None, gitargs)
if ecode > 0:
@@ -926,12 +925,13 @@ def get_sent_tag_as_patches(tagname: str, revision: Optional[str] = None,
if not matches:
raise RuntimeError('Tag %s does not contain change-id info' % tagname)
change_id = matches.groups()[0]
- if revision is None:
- matches = re.search(r'.*-v(\d+)$', tagname, flags=re.I | re.M)
- if not matches:
- raise RuntimeError('Could not grok revision number from %s' % tagname)
- revision = matches.groups()[0]
+ return cover, base_commit, change_id
+
+def get_sent_tag_as_patches(tagname: str, revision: int, prefixes: Optional[List[str]] = None,
+ hide_cover_to_cc: bool = False
+ ) -> Tuple[List, List, List[Tuple[str, email.message.Message]]]:
+ cover, base_commit, change_id = get_base_changeid_from_tag(tagname)
# First line is the subject
csubject, cbody = cover.split('\n', maxsplit=1)
cbody = cbody.strip() + '\n-- \n' + b4.get_email_signature()
@@ -949,7 +949,7 @@ def get_sent_tag_as_patches(tagname: str, revision: Optional[str] = None,
if revision != 1:
prefixes.append(f'v{revision}')
seriests = int(time.time())
- msgid_tpt = make_msgid_tpt(change_id, revision)
+ msgid_tpt = make_msgid_tpt(change_id, str(revision))
usercfg = b4.get_user_config()
mailfrom = (usercfg.get('name'), usercfg.get('email'))
@@ -1102,8 +1102,6 @@ def cmd_send(cmdargs: argparse.Namespace) -> None:
auth_verify(cmdargs)
return
- # Should we make the sent/ prefix configurable?
- tagprefix = 'sent/'
mybranch = b4.git_get_current_branch()
prefixes = cmdargs.prefixes
if cmdargs.prefixes is None:
@@ -1114,17 +1112,11 @@ def cmd_send(cmdargs: argparse.Namespace) -> None:
cmdargs.hide_cover_to_cc = True
if cmdargs.resend:
- # We accept both a full tag name and just a vN short form
- matches = re.search(r'^v(\d+)$', cmdargs.resend)
- if matches:
- revision = matches.groups()[0]
- if mybranch.startswith('b4/'):
- tagname = f'{tagprefix}{mybranch[3:]}-v{revision}'
- else:
- tagname = f'{tagprefix}{mybranch}-v{revision}'
- else:
- revision = None
- tagname = cmdargs.resend
+ tagname, revision = get_sent_tagname(mybranch, SENT_TAG_PREFIX, cmdargs.resend)
+
+ if revision is None:
+ logger.critical('Could not figure out revision from %s', cmdargs.resend)
+ sys.exit(1)
prefixes.append('RESEND')
try:
@@ -1316,7 +1308,26 @@ def cmd_send(cmdargs: argparse.Namespace) -> None:
reroll(mybranch, cover_msg)
-def reroll(mybranch: str, cover_msg: email.message.Message, tagprefix: str = 'sent/'):
+def get_sent_tagname(branch: str, tagprefix: str, revstr: Union[str, int]) -> Tuple[str, Optional[int]]:
+ revision = None
+ try:
+ revision = int(revstr)
+ except ValueError:
+ matches = re.search(r'^v(\d+)$', revstr)
+ if not matches:
+ # assume we got a full tag name, so try to find the revision there
+ matches = re.search(r'v(\d+)$', revstr)
+ if matches:
+ revision = int(matches.groups()[0])
+ return revstr.replace('refs/tags/', ''), revision
+ revision = int(matches.groups()[0])
+
+ if branch.startswith('b4/'):
+ return f'{tagprefix}{branch[3:]}-v{revision}', revision
+ return f'{tagprefix}{branch}-v{revision}', revision
+
+
+def reroll(mybranch: str, cover_msg: email.message.Message, tagprefix: str = SENT_TAG_PREFIX):
# Prepare annotated tag body from the cover letter
lsubject = b4.LoreSubject(cover_msg.get('subject'))
cbody = cover_msg.get_payload()
@@ -1328,11 +1339,7 @@ def reroll(mybranch: str, cover_msg: email.message.Message, tagprefix: str = 'se
cover, tracking = load_cover(strip_comments=True)
revision = tracking['series']['revision']
- if mybranch.startswith('b4/'):
- tagname = f'{tagprefix}{mybranch[3:]}-v{revision}'
- else:
- tagname = f'{tagprefix}{mybranch}-v{revision}'
-
+ tagname, revision = get_sent_tagname(mybranch, tagprefix, revision)
logger.debug('checking if we already have %s', tagname)
gitargs = ['rev-parse', f'refs/tags/{tagname}']
ecode, out = b4.git_run_command(None, gitargs)
@@ -1458,6 +1465,38 @@ def force_revision(forceto: int) -> None:
store_cover(cover, tracking)
+def compare(compareto: str) -> None:
+ mybranch = b4.git_get_current_branch(None)
+ tagname, revision = get_sent_tagname(mybranch, SENT_TAG_PREFIX, compareto)
+ gitargs = ['rev-parse', tagname]
+ lines = b4.git_get_command_lines(None, gitargs)
+ if not lines:
+ logger.critical('CRITICAL: Could not rev-parse %s', tagname)
+ sys.exit(1)
+ prev_end = lines[0]
+ try:
+ cover, base_commit, change_id = get_base_changeid_from_tag(tagname)
+ except RuntimeError as ex:
+ logger.critical('CRITICAL: %s', str(ex))
+ sys.exit(1)
+ prev_start = base_commit
+ curr_start = get_series_start()
+ strategy = get_cover_strategy()
+ if strategy == 'tip-commit':
+ cover_commit = find_cover_commit()
+ series_end = f'{cover_commit}~1'
+ else:
+ series_end = 'HEAD'
+
+ gitargs = ['rev-parse', series_end]
+ lines = b4.git_get_command_lines(None, gitargs)
+ curr_end = lines[0]
+ grdcmd = ['git', 'range-diff', '%.12s..%.12s' % (prev_start, prev_end), '%.12s..%.12s' % (curr_start, curr_end)]
+ # We exec range-diff and let it take over
+ logger.debug('Running %s', ' '.join(grdcmd))
+ os.execvp(grdcmd[0], grdcmd)
+
+
def auto_to_cc() -> None:
tocmdstr = None
cccmdstr = None
@@ -1589,6 +1628,9 @@ def cmd_prep(cmdargs: argparse.Namespace) -> None:
if cmdargs.format_patch:
return format_patch(cmdargs.format_patch)
+ if cmdargs.compare_to:
+ return compare(cmdargs.compare_to)
+
if is_prep_branch():
logger.critical('CRITICAL: This appears to already be a b4-prep managed branch.')
sys.exit(1)
diff --git a/docs/contributor/prep.rst b/docs/contributor/prep.rst
index 61133d7..2a9f753 100644
--- a/docs/contributor/prep.rst
+++ b/docs/contributor/prep.rst
@@ -239,6 +239,11 @@ or modifying defaults for some of these flags.
Forces the revision to a different integer number. This modifies your
cover letter and tracking information and makes this change permanent.
+``--compare-to vN`` **(v0.11+)**
+ This executes a ``git range-diff`` command that lets you compare the
+ previously sent version of the series to what is currently in your
+ working branch.
+
``--manual-reroll MSGID``
Normally, your patch series will be automatically rerolled to the next
version after a successful ``b4 send`` (see :doc:`send`). However, if
diff --git a/man/b4.5 b/man/b4.5
index 56c13ac..198c4fc 100644
--- a/man/b4.5
+++ b/man/b4.5
@@ -523,7 +523,7 @@ Show all developer keys from the thread
.INDENT 0.0
.TP
.B usage:
-b4 prep [\-h] [\-c | \-p OUTPUT_DIR | \-\-edit\-cover | \-\-show\-revision | \-\-force\-revision N | \-\-manual\-reroll COVER_MSGID] [\-n NEW_SERIES_NAME] [\-f FORK_POINT] [\-F MSGID] [\-e ENROLL_BASE]
+b4 prep [\-h] [\-c | \-p OUTPUT_DIR | \-\-edit\-cover | \-\-show\-revision | \-\-force\-revision N | \-\-compare\-to vN | \-\-manual\-reroll COVER_MSGID] [\-n NEW_SERIES_NAME] [\-f FORK_POINT] [\-F MSGID] [\-e ENROLL_BASE]
.TP
.B options:
.INDENT 7.0
@@ -546,6 +546,9 @@ Show current series revision number
.BI \-\-force\-revision \ N
Force revision to be this number instead
.TP
+.BI \-\-compare\-to \ vN
+Display a range\-diff to previously sent revision N
+.TP
.BI \-\-manual\-reroll \ COVER_MSGID
Mark current revision as sent and reroll (requires cover letter msgid)
.UNINDENT
diff --git a/man/b4.5.rst b/man/b4.5.rst
index 072c107..073f32a 100644
--- a/man/b4.5.rst
+++ b/man/b4.5.rst
@@ -342,7 +342,7 @@ optional arguments:
b4 prep
~~~~~~~
usage:
- b4 prep [-h] [-c | -p OUTPUT_DIR | --edit-cover | --show-revision | --force-revision N | --manual-reroll COVER_MSGID] [-n NEW_SERIES_NAME] [-f FORK_POINT] [-F MSGID] [-e ENROLL_BASE]
+ b4 prep [-h] [-c | -p OUTPUT_DIR | --edit-cover | --show-revision | --force-revision N | --compare-to vN | --manual-reroll COVER_MSGID] [-n NEW_SERIES_NAME] [-f FORK_POINT] [-F MSGID] [-e ENROLL_BASE]
options:
-h, --help show this help message and exit
@@ -352,6 +352,7 @@ options:
--edit-cover Edit the cover letter in your defined $EDITOR (or core.editor)
--show-revision Show current series revision number
--force-revision N Force revision to be this number instead
+ --compare-to vN Display a range-diff to previously sent revision N
--manual-reroll COVER_MSGID
Mark current revision as sent and reroll (requires cover letter msgid)