Mercurial > hg
view hgext/hooklib/changeset_obsoleted.py @ 51685:0eb515c7bec8
typing: add trivial type hints to the convert extension's common modules
This started as ensuring that the `encoding` and `orig_encoding` attributes has
a type other than `Any`, so pytype can catch problems where it needs to be str
for stdlib encoding and decoding. It turns out that adding the hint in
`mercurial.encoding` is what was needed, but I picked a bunch of low hanging
fruit while here. There's definitely more to do, and I see a problem where
`shlex.shlex` is being fed bytes instead of str, but there are not enough type
hints yet to make pytype notice.
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Thu, 11 Jul 2024 20:54:06 -0400 |
parents | 5392bf258049 |
children | f4733654f144 |
line wrap: on
line source
# Copyright 2020 Joerg Sonnenberger <joerg@bec.de> # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. """changeset_obsoleted is a hook to send a mail when an existing draft changeset is obsoleted by an obsmarker without successor. Correct message threading requires the same messageidseed to be used for both the original notification and the new mail. Usage: [notify] messageidseed = myseed [hooks] txnclose.changeset_obsoleted = \ python:hgext.hooklib.changeset_obsoleted.hook """ import email.errors as emailerrors import email.utils as emailutils from mercurial.i18n import _ from mercurial import ( encoding, error, formatter, logcmdutil, mail, obsutil, pycompat, registrar, ) from mercurial.utils import ( dateutil, stringutil, ) from .. import notify configtable = {} configitem = registrar.configitem(configtable) configitem( b'notify_obsoleted', b'domain', default=None, ) configitem( b'notify_obsoleted', b'messageidseed', default=None, ) configitem( b'notify_obsoleted', b'template', default=b'''Subject: changeset abandoned This changeset has been abandoned. ''', ) def _report_commit(ui, repo, ctx): domain = ui.config(b'notify_obsoleted', b'domain') or ui.config( b'notify', b'domain' ) messageidseed = ui.config( b'notify_obsoleted', b'messageidseed' ) or ui.config(b'notify', b'messageidseed') template = ui.config(b'notify_obsoleted', b'template') spec = formatter.literal_templatespec(template) templater = logcmdutil.changesettemplater(ui, repo, spec) ui.pushbuffer() n = notify.notifier(ui, repo, b'incoming') subs = set() for sub, spec in n.subs: if spec is None: subs.add(sub) continue revs = repo.revs(b'%r and %d:', spec, ctx.rev()) if len(revs): subs.add(sub) continue if len(subs) == 0: ui.debug( b'notify_obsoleted: no subscribers to selected repo and revset\n' ) return templater.show( ctx, changes=ctx.changeset(), baseurl=ui.config(b'web', b'baseurl'), root=repo.root, webroot=n.root, ) data = ui.popbuffer() try: msg = mail.parsebytes(data) except emailerrors.MessageParseError as inst: raise error.Abort(stringutil.forcebytestr(inst)) msg['In-reply-to'] = notify.messageid(ctx, domain, messageidseed) msg['Message-Id'] = notify.messageid( ctx, domain, messageidseed + b'-obsoleted' ) msg['Date'] = encoding.strfromlocal( dateutil.datestr(format=b"%a, %d %b %Y %H:%M:%S %1%2") ) if not msg['From']: sender = ui.config(b'email', b'from') or ui.username() if b'@' not in sender or b'@localhost' in sender: sender = n.fixmail(sender) msg['From'] = mail.addressencode(ui, sender, n.charsets, n.test) msg['To'] = ', '.join(sorted(subs)) msgtext = msg.as_bytes() if ui.configbool(b'notify', b'test'): ui.write(msgtext) if not msgtext.endswith(b'\n'): ui.write(b'\n') else: ui.status(_(b'notify_obsoleted: sending mail for %d\n') % ctx.rev()) mail.sendmail( ui, emailutils.parseaddr(msg['From'])[1], subs, msgtext, mbox=n.mbox ) def has_successor(repo, rev): return any( r for r in obsutil.allsuccessors(repo.obsstore, [rev]) if r != rev ) def hook(ui, repo, hooktype, node=None, **kwargs): if hooktype != b"txnclose": raise error.Abort( _(b'Unsupported hook type %r') % pycompat.bytestr(hooktype) ) for rev in obsutil.getobsoleted(repo, changes=kwargs['changes']): ctx = repo.unfiltered()[rev] if not has_successor(repo, ctx.node()): _report_commit(ui, repo, ctx)