def diff(self, ctx, ref=None): maxdiff = int(self.ui.config('notify', 'maxdiff', 300)) prev = ctx.p1().node() if ref: ref = ref.node() else: ref = ctx.node() chunks = patch.diff(self.repo, prev, ref, opts=patch.diffallopts(self.ui)) difflines = ''.join(chunks).splitlines() if self.ui.configbool('notify', 'diffstat', True): s = patch.diffstat(difflines) # s may be nil, don't include the header if it is if s: self.ui.write('\ndiffstat:\n\n%s' % s) if maxdiff == 0: return elif maxdiff > 0 and len(difflines) > maxdiff: msg = _('\ndiffs (truncated from %d to %d lines):\n\n') self.ui.write(msg % (len(difflines), maxdiff)) difflines = difflines[:maxdiff] elif difflines: self.ui.write(_('\ndiffs (%d lines):\n\n') % len(difflines)) self.ui.write("\n".join(difflines))
def _makeintro(repo, sender, patches, **opts): """make an introduction email, asking the user for content if needed email is returned as (subject, body, cumulative-diffstat)""" ui = repo.ui _charsets = mail._charsets(ui) tlen = len(str(len(patches))) flag = opts.get('flag') or '' if flag: flag = ' ' + ' '.join(flag) prefix = '[PATCH %0*d of %d%s]' % (tlen, 0, len(patches), flag) subj = (opts.get('subject') or prompt(ui, '(optional) Subject: ', rest=prefix, default='')) if not subj: return None # skip intro if the user doesn't bother subj = prefix + ' ' + subj body = '' if opts.get('diffstat'): # generate a cumulative diffstat of the whole patch series diffstat = patch.diffstat(sum(patches, [])) body = '\n' + diffstat else: diffstat = None body = _getdescription(repo, body, sender, **opts) msg = mail.mimeencode(ui, body, _charsets, opts.get('test')) msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test')) return (msg, subj, diffstat)
def makeintro(patches): tlen = len(str(len(patches))) flag = opts.get('flag') or '' if flag: flag = ' ' + ' '.join(flag) prefix = '[PATCH %0*d of %d%s]' % (tlen, 0, len(patches), flag) subj = (opts.get('subject') or prompt(ui, 'Subject: ', rest=prefix, default='')) if not subj: return None # skip intro if the user doesn't bother subj = prefix + ' ' + subj body = '' if opts.get('diffstat'): # generate a cumulative diffstat of the whole patch series diffstat = patch.diffstat(sum(patches, [])) body = '\n' + diffstat else: diffstat = None body = getdescription(body, sender) msg = mail.mimeencode(ui, body, _charsets, opts.get('test')) msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test')) return (msg, subj, diffstat)
def _makeintro(repo, sender, revs, patches, **opts): """make an introduction email, asking the user for content if needed email is returned as (subject, body, cumulative-diffstat)""" ui = repo.ui _charsets = mail._charsets(ui) # use the last revision which is likely to be a bookmarked head prefix = _formatprefix(ui, repo, revs.last(), opts.get('flag'), 0, len(patches), numbered=True) subj = (opts.get('subject') or prompt(ui, '(optional) Subject: ', rest=prefix, default='')) if not subj: return None # skip intro if the user doesn't bother subj = prefix + ' ' + subj body = '' if opts.get('diffstat'): # generate a cumulative diffstat of the whole patch series diffstat = patch.diffstat(sum(patches, [])) body = '\n' + diffstat else: diffstat = None body = _getdescription(repo, body, sender, **opts) msg = mail.mimeencode(ui, body, _charsets, opts.get('test')) msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test')) return (msg, subj, diffstat)
def cdiffstat(ui, summary, patchlines): s = patch.diffstat(patchlines) if summary: ui.write(summary, '\n') ui.write(s, '\n') ans = prompt(ui, _('does the diffstat above look okay?'), 'y') if not ans.lower().startswith('y'): raise util.Abort(_('diffstat rejected')) return s
def cdiffstat(summary, patchlines): s = patch.diffstat(patchlines) if s: if summary: ui.write(summary, '\n') ui.write(s, '\n') confirm(_('Does the diffstat above look okay'), _('diffstat rejected')) elif s is None: ui.warn(_('No diffstat information available.\n')) s = '' return s
def diffstat(self): class patchbuf(object): def __init__(self): self.lines = [] # diffstat is stupid self.name = 'cia' def write(self, data): self.lines.append(data) def close(self): pass n = self.ctx.node() pbuf = patchbuf() cmdutil.export(self.cia.repo, [n], fp=pbuf) return patch.diffstat(pbuf.lines) or ''
def diffstat(self): class patchbuf(object): def __init__(self): self.lines = [] # diffstat is stupid self.name = "cia" def write(self, data): self.lines += data.splitlines(True) def close(self): pass n = self.ctx.node() pbuf = patchbuf() cmdutil.export(self.cia.repo, [n], fp=pbuf) return patch.diffstat(pbuf.lines) or ""
def diffstat(ui, repo, **kwargs): '''Example usage: [hooks] commit.diffstat = python:/path/to/this/file.py:diffstat changegroup.diffstat = python:/path/to/this/file.py:diffstat ''' if kwargs.get('parent2'): return node = kwargs['node'] first = repo[node].p1().node() if 'url' in kwargs: last = repo['tip'].node() else: last = node diff = patch.diff(repo, first, last) ui.write(patch.diffstat(util.iterlines(diff)))
def diffstat(ui, repo, **kwargs): '''Example usage: [hooks] commit.diffstat = python:/path/to/this/file.py:diffstat changegroup.diffstat = python:/path/to/this/file.py:diffstat ''' if kwargs.get('parent2'): return node = kwargs['node'] first = repo[node].parents()[0].node() if 'url' in kwargs: last = repo['tip'].node() else: last = node diff = patch.diff(repo, first, last) ui.write(patch.diffstat(util.iterlines(diff)))
def diff(self, node, ref): maxdiff = int(self.ui.config('notify', 'maxdiff', 300)) prev = self.repo.changelog.parents(node)[0] self.ui.pushbuffer() patch.diff(self.repo, prev, ref) difflines = self.ui.popbuffer().splitlines(1) if self.ui.configbool('notify', 'diffstat', True): s = patch.diffstat(difflines) # s may be nil, don't include the header if it is if s: self.ui.write('\ndiffstat:\n\n%s' % s) if maxdiff == 0: return if maxdiff > 0 and len(difflines) > maxdiff: self.ui.write(_('\ndiffs (truncated from %d to %d lines):\n\n') % (len(difflines), maxdiff)) difflines = difflines[:maxdiff] elif difflines: self.ui.write(_('\ndiffs (%d lines):\n\n') % len(difflines)) self.ui.write(*difflines)
def diff(self, node, ref): maxdiff = int(self.ui.config('notify', 'maxdiff', 300)) prev = self.repo.changelog.parents(node)[0] self.ui.pushbuffer() patch.diff(self.repo, prev, ref, opts=patch.diffopts(self.ui)) difflines = self.ui.popbuffer().splitlines(1) if self.ui.configbool('notify', 'diffstat', True): s = patch.diffstat(difflines) # s may be nil, don't include the header if it is if s: self.ui.write('\ndiffstat:\n\n%s' % s) if maxdiff == 0: return if maxdiff > 0 and len(difflines) > maxdiff: self.ui.write( _('\ndiffs (truncated from %d to %d lines):\n\n') % (len(difflines), maxdiff)) difflines = difflines[:maxdiff] elif difflines: self.ui.write(_('\ndiffs (%d lines):\n\n') % len(difflines)) self.ui.write(*difflines)
def getpatchmsgs(patches, patchnames=None): jumbo = [] msgs = [] ui.write( _('This patch series consists of %d patches.\n\n') % len(patches)) name = None for i, p in enumerate(patches): jumbo.extend(p) if patchnames: name = patchnames[i] msg = makepatch(ui, repo, p, opts, _charsets, i + 1, len(patches), name) msgs.append(msg) if introneeded(opts, len(patches)): tlen = len(str(len(patches))) flag = ' '.join(opts.get('flag')) if flag: subj = '[PATCH %0*d of %d %s]' % (tlen, 0, len(patches), flag) else: subj = '[PATCH %0*d of %d]' % (tlen, 0, len(patches)) subj += ' ' + (opts.get('subject') or prompt(ui, 'Subject: ', rest=subj)) body = '' ds = patch.diffstat(jumbo) if ds and opts.get('diffstat'): body = '\n' + ds body = getdescription(body, sender) msg = mail.mimeencode(ui, body, _charsets, opts.get('test')) msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test')) msgs.insert(0, (msg, subj, ds)) return msgs
def getpatchmsgs(patches, patchnames=None): jumbo = [] msgs = [] ui.write(_('This patch series consists of %d patches.\n\n') % len(patches)) name = None for i, p in enumerate(patches): jumbo.extend(p) if patchnames: name = patchnames[i] msg = makepatch(ui, repo, p, opts, _charsets, i + 1, len(patches), name) msgs.append(msg) if introneeded(opts, len(patches)): tlen = len(str(len(patches))) flag = ' '.join(opts.get('flag')) if flag: subj = '[PATCH %0*d of %d %s]' % (tlen, 0, len(patches), flag) else: subj = '[PATCH %0*d of %d]' % (tlen, 0, len(patches)) subj += ' ' + (opts.get('subject') or prompt(ui, 'Subject: ', rest=subj)) body = '' ds = patch.diffstat(jumbo) if ds and opts.get('diffstat'): body = '\n' + ds body = getdescription(body, sender) msg = mail.mimeencode(ui, body, _charsets, opts.get('test')) msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test')) msgs.insert(0, (msg, subj, ds)) return msgs
def diff(self, ctx, ref=None): maxdiff = int(self.ui.config(b'notify', b'maxdiff')) prev = ctx.p1().node() if ref: ref = ref.node() else: ref = ctx.node() diffopts = patch.diffallopts(self.ui) diffopts.showfunc = self.showfunc chunks = patch.diff(self.repo, prev, ref, opts=diffopts) difflines = b''.join(chunks).splitlines() if self.ui.configbool(b'notify', b'diffstat'): maxdiffstat = int(self.ui.config(b'notify', b'maxdiffstat')) s = patch.diffstat(difflines) # s may be nil, don't include the header if it is if s: if maxdiffstat >= 0 and s.count(b"\n") > maxdiffstat + 1: s = s.split(b"\n") msg = _(b'\ndiffstat (truncated from %d to %d lines):\n\n') self.ui.write(msg % (len(s) - 2, maxdiffstat)) self.ui.write(b"\n".join(s[:maxdiffstat] + s[-2:])) else: self.ui.write(_(b'\ndiffstat:\n\n%s') % s) if maxdiff == 0: return elif maxdiff > 0 and len(difflines) > maxdiff: msg = _(b'\ndiffs (truncated from %d to %d lines):\n\n') self.ui.write(msg % (len(difflines), maxdiff)) difflines = difflines[:maxdiff] elif difflines: self.ui.write(_(b'\ndiffs (%d lines):\n\n') % len(difflines)) self.ui.write(b"\n".join(difflines))
def _incoming(ui, repo, **kwargs): # Ensure that no fancying of output is enabled (e.g. coloring) os.environ['TERM'] = 'dumb' ui.setconfig('ui', 'interactive', 'False') ui.setconfig('ui', 'formatted', 'False') try: colormod = sys.modules['hgext.color'] except KeyError: pass else: colormod._styles.clear() blacklisted = ui.config('mail', 'diff-blacklist', '').split() displayer = cmdutil.changeset_printer(ui, repo, False, False, True) ctx = repo[kwargs['node']] displayer.show(ctx) log = displayer.hunk[ctx.rev()] user = os.environ.get('HGPUSHER', 'local') path = '/'.join(repo.root.split('/')[4:]) body = [] #body += ['%s pushed %s to %s:' % (user, str(ctx), path), ''] body += [CSET_URL % (path, ctx)] body += [line for line in log.splitlines()[:-2] if line != 'tag: tip'] body += ['summary:\n ' + fromlocal(ctx.description())] # ctx.files() gives us misleading info on merges, we use a diffstat instead body += ['', 'files:'] diffopts = patch.diffopts(repo.ui, {'git': True, 'showfunc': True}) parents = ctx.parents() node1 = parents and parents[0].node() or nullid node2 = ctx.node() diffchunks = list(patch.diff(repo, node1, node2, opts=diffopts)) diffstat = patch.diffstat(iterlines(diffchunks), width=60, git=True) for line in iterlines([''.join(diffstat)]): body.append(' ' + line) body += ['', ''] diffchunks = strip_bin_diffs(diffchunks) diffchunks = strip_blacklisted_files(diffchunks, blacklisted) body.append(''.join(chunk for chunk in diffchunks)) body.append('-- ') body.append('Repository URL: %s%s' % (BASE, path)) to = ui.config('mail', 'notify', None) if to is None: print 'no email address configured' return False from_ = ui.config('mail', 'sender', None) if from_ is None: from_ = to sender = '%s <%s>' % (user, from_) prefixes = [path] if len(parents) == 2: b1, b2, b = parents[0].branch(), parents[1].branch(), ctx.branch() if b in (b1, b2): bp = b2 if b == b1 else b1 # normal case prefixes.append('(merge %s -> %s)' % (bp, b)) else: # XXX really?? prefixes.append('(merge %s + %s -> %s)' % (b1, b2, b)) else: branch = ctx.branch() if branch != 'default': prefixes.append('(%s)' % branch) desc = ctx.description().splitlines()[0] if len(desc) > 80: desc = desc[:80] if ' ' in desc: desc = desc.rsplit(' ', 1)[0] if prefixes: prefixes = ' '.join(prefixes) + ': ' else: prefixes = '' subj = prefixes + desc host = ui.config('smtp', 'host', '') port = int(ui.config('smtp', 'port', 0)) smtp = smtplib.SMTP(host, port) username = ui.config('smtp', 'username', '') if username: smtp.login(username, ui.config('smtp', 'password', '')) send(smtp, subj, sender, to, '\n'.join(body) + '\n') smtp.close() ui.status('notified %s of incoming changeset %s\n' % (to, ctx)) return False
def makepatch(ui, repo, patchlines, opts, _charsets, idx, total, numbered, patchname=None): desc = [] node = None body = '' for line in patchlines: if line.startswith('#'): if line.startswith('# Node ID'): node = line.split()[-1] continue if line.startswith('diff -r') or line.startswith('diff --git'): break desc.append(line) if not patchname and not node: raise ValueError if opts.get('attach') and not opts.get('body'): body = ('\n'.join(desc[1:]).strip() or 'Patch subject is complete summary.') body += '\n\n\n' if opts.get('plain'): while patchlines and patchlines[0].startswith('# '): patchlines.pop(0) if patchlines: patchlines.pop(0) while patchlines and not patchlines[0].strip(): patchlines.pop(0) ds = patch.diffstat(patchlines, git=opts.get('git')) if opts.get('diffstat'): body += ds + '\n\n' addattachment = opts.get('attach') or opts.get('inline') if not addattachment or opts.get('body'): body += '\n'.join(patchlines) if addattachment: msg = email.MIMEMultipart.MIMEMultipart() if body: msg.attach(mail.mimeencode(ui, body, _charsets, opts.get('test'))) p = mail.mimetextpatch('\n'.join(patchlines), 'x-patch', opts.get('test')) binnode = bin(node) # if node is mq patch, it will have the patch file's name as a tag if not patchname: patchtags = [t for t in repo.nodetags(binnode) if t.endswith('.patch') or t.endswith('.diff')] if patchtags: patchname = patchtags[0] elif total > 1: patchname = cmdutil.makefilename(repo, '%b-%n.patch', binnode, seqno=idx, total=total) else: patchname = cmdutil.makefilename(repo, '%b.patch', binnode) disposition = 'inline' if opts.get('attach'): disposition = 'attachment' p['Content-Disposition'] = disposition + '; filename=' + patchname msg.attach(p) else: msg = mail.mimetextpatch(body, display=opts.get('test')) flag = ' '.join(opts.get('flag')) if flag: flag = ' ' + flag subj = desc[0].strip().rstrip('. ') if not numbered: subj = '[PATCH%s] %s' % (flag, opts.get('subject') or subj) else: tlen = len(str(total)) subj = '[PATCH %0*d of %d%s] %s' % (tlen, idx, total, flag, subj) msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test')) msg['X-Mercurial-Node'] = node msg['X-Mercurial-Series-Index'] = '%i' % idx msg['X-Mercurial-Series-Total'] = '%i' % total return msg, subj, ds
def makepatch( ui, repo, rev, patchlines, opts, _charsets, idx, total, numbered, patchname=None, ): desc = [] node = None body = b'' for line in patchlines: if line.startswith(b'#'): if line.startswith(b'# Node ID'): node = line.split()[-1] continue if line.startswith(b'diff -r') or line.startswith(b'diff --git'): break desc.append(line) if not patchname and not node: raise ValueError if opts.get(b'attach') and not opts.get(b'body'): body = (b'\n'.join(desc[1:]).strip() or b'Patch subject is complete summary.') body += b'\n\n\n' if opts.get(b'plain'): while patchlines and patchlines[0].startswith(b'# '): patchlines.pop(0) if patchlines: patchlines.pop(0) while patchlines and not patchlines[0].strip(): patchlines.pop(0) ds = patch.diffstat(patchlines) if opts.get(b'diffstat'): body += ds + b'\n\n' addattachment = opts.get(b'attach') or opts.get(b'inline') if not addattachment or opts.get(b'body'): body += b'\n'.join(patchlines) if addattachment: msg = emimemultipart.MIMEMultipart() if body: msg.attach(mail.mimeencode(ui, body, _charsets, opts.get(b'test'))) p = mail.mimetextpatch(b'\n'.join(patchlines), 'x-patch', opts.get(b'test')) binnode = bin(node) # if node is mq patch, it will have the patch file's name as a tag if not patchname: patchtags = [ t for t in repo.nodetags(binnode) if t.endswith(b'.patch') or t.endswith(b'.diff') ] if patchtags: patchname = patchtags[0] elif total > 1: patchname = cmdutil.makefilename(repo[node], b'%b-%n.patch', seqno=idx, total=total) else: patchname = cmdutil.makefilename(repo[node], b'%b.patch') disposition = r'inline' if opts.get(b'attach'): disposition = r'attachment' p['Content-Disposition'] = (disposition + '; filename=' + encoding.strfromlocal(patchname)) msg.attach(p) else: msg = mail.mimetextpatch(body, display=opts.get(b'test')) prefix = _formatprefix(ui, repo, rev, opts.get(b'flag'), idx, total, numbered) subj = desc[0].strip().rstrip(b'. ') if not numbered: subj = b' '.join([prefix, opts.get(b'subject') or subj]) else: subj = b' '.join([prefix, subj]) msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get(b'test')) msg['X-Mercurial-Node'] = pycompat.sysstr(node) msg['X-Mercurial-Series-Index'] = '%i' % idx msg['X-Mercurial-Series-Total'] = '%i' % total return msg, subj, ds
def makepatch(ui, repo, patchlines, opts, _charsets, idx, total, numbered, patchname=None): desc = [] node = None body = '' for line in patchlines: if line.startswith('#'): if line.startswith('# Node ID'): node = line.split()[-1] continue if line.startswith('diff -r') or line.startswith('diff --git'): break desc.append(line) if not patchname and not node: raise ValueError if opts.get('attach'): body = ('\n'.join(desc[1:]).strip() or 'Patch subject is complete summary.') body += '\n\n\n' if opts.get('plain'): while patchlines and patchlines[0].startswith('# '): patchlines.pop(0) if patchlines: patchlines.pop(0) while patchlines and not patchlines[0].strip(): patchlines.pop(0) ds = patch.diffstat(patchlines, git=opts.get('git')) if opts.get('diffstat'): body += ds + '\n\n' if opts.get('attach') or opts.get('inline'): msg = email.MIMEMultipart.MIMEMultipart() if body: msg.attach(mail.mimeencode(ui, body, _charsets, opts.get('test'))) p = mail.mimetextpatch('\n'.join(patchlines), 'x-patch', opts.get('test')) binnode = bin(node) # if node is mq patch, it will have the patch file's name as a tag if not patchname: patchtags = [ t for t in repo.nodetags(binnode) if t.endswith('.patch') or t.endswith('.diff') ] if patchtags: patchname = patchtags[0] elif total > 1: patchname = cmdutil.makefilename(repo, '%b-%n.patch', binnode, seqno=idx, total=total) else: patchname = cmdutil.makefilename(repo, '%b.patch', binnode) disposition = 'inline' if opts.get('attach'): disposition = 'attachment' p['Content-Disposition'] = disposition + '; filename=' + patchname msg.attach(p) else: body += '\n'.join(patchlines) msg = mail.mimetextpatch(body, display=opts.get('test')) flag = ' '.join(opts.get('flag')) if flag: flag = ' ' + flag subj = desc[0].strip().rstrip('. ') if not numbered: subj = '[PATCH%s] %s' % (flag, opts.get('subject') or subj) else: tlen = len(str(total)) subj = '[PATCH %0*d of %d%s] %s' % (tlen, idx, total, flag, subj) msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test')) msg['X-Mercurial-Node'] = node return msg, subj, ds
def showdiffstat(repo, ctx, templ, **args): """String. Return diffstat-style summary of changes.""" width = repo.ui.termwidth() return patch.diffstat(util.iterlines(ctx.diff(noprefix=False)), width=width)