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() patch.export(self.cia.repo, [n], fp=pbuf) return patch.diffstat(pbuf.lines) or ''
def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False, opts=None): ''' export changesets as hg patches. Mercurial moved patch.export to cmdutil.export after version 1.5 (change e764f24a45ee in mercurial). ''' try: return cmdutil.export(repo, revs, template, fp, switch_parent, opts) except AttributeError: from mercurial import patch return patch.export(repo, revs, template, fp, switch_parent, opts)
def bzexport(ui, repo, *args, **opts): """ Export changesets to bugzilla attachments. The -e option may be used to bring up an editor that will allow editing all fields of the attachment and bug (if creating one). The --new option may be used to create a new bug rather than using an existing bug. See the newbug command for details. The -u (--update) option is equivalent to setting both 'update-patch' and 'rename-patch' to True in the [bzexport] section of your config file. """ auth, api_server, bugzilla = bugzilla_info(ui, opts.get('ffprofile')) rev, bug = infer_arguments(ui, repo, args, opts) if not opts['new']: for o in ('cc', 'depends', 'blocks'): if opts[o]: ui.write("Warning: ignoring --%s option when not creating a bug\n" % o) contents = StringIO() diffopts = patch.diffopts(ui, opts) context = ui.config("bzexport", "unified", ui.config("diff", "unified", None)) if context: diffopts.context = int(context) if rev in repo: description_from_patch = repo[rev].description().decode('utf-8') if hasattr(cmdutil, "export"): cmdutil.export(repo, [rev], fp=contents, opts=diffopts) else: # Support older hg versions patch.export(repo, [rev], fp=contents, opts=diffopts) else: q = repo.mq contents = q.opener(q.lookup(rev), "r") description_from_patch = '\n'.join(mq.patchheader(q.join(rev), q.plainmode).message) # Just always use the rev name as the patch name. Doesn't matter much, # unless you want to avoid obsoleting existing patches when uploading a # version that doesn't include whitespace changes. filename = rev if opts['ignore_all_space']: filename += "_ws" patch_comment = None reviewers = [] orig_desc = opts['description'] or description_from_patch if not orig_desc or orig_desc.startswith('[mq]'): desc = '<required>' else: # Lightly reformat changeset messages into attachment descriptions. # Only use the first line of the provided description for our actual # description - use the rest for the patch/bug comment. parts = orig_desc.split('\n', 1) firstline = parts[0] if len(parts) == 2: patch_comment = parts[1].strip() # Attempt to split the firstline into a bug number, and strip()ed # description with that bug number string removed. desc_bug_number, desc = extract_bug_num_and_desc(firstline) # Failing that try looking in the commit description for a bug number, # since orig_desc could have come from the command line instead. if not desc_bug_number: commit_firstline = description_from_patch.split('\n', 1)[0] desc_bug_number, __ = extract_bug_num_and_desc(commit_firstline) if desc_bug_number: if bug and bug != desc_bug_number: ui.warn("Warning: Bug number %s from commandline doesn't match " "bug number %s from changeset description\n" % (bug, desc_bug_number)) else: bug = desc_bug_number # Strip any remaining leading separator and whitespace, # if the original was something like "bug NNN - " if desc[0] in ['-', ':', '.']: desc = desc[1:].lstrip() # Next strip off review and approval annotations, grabbing the # reviewers from the patch comments only if -r auto was given def grab_reviewer(m): if opts['review'] == 'auto': reviewers.append(m.group(1)) return '' desc = review_re.sub(grab_reviewer, desc).rstrip() # Strip any trailing separators, if the original was something like: # "Desc; r=foo" or "Desc. r=foo" if desc and desc[-1] in (';', '.'): desc = desc[:-1].rstrip() if len(reviewers) > 0: opts['review'] = '' attachment_comment = opts['comment'] bug_comment = opts['bug_description'] if not attachment_comment: # New bugs get first shot at the patch comment if not opts['new'] or bug_comment: attachment_comment = patch_comment if not bug_comment and opts['new']: bug_comment = patch_comment if opts["review"]: search_strings = opts["review"].split(",") valid_users = validate_users(ui, api_server, auth, search_strings, multi_user_prompt, 'reviewer') reviewers = select_users(valid_users, search_strings) elif len(reviewers) > 0: # Pulled reviewers out of commit message valid_users = validate_users(ui, api_server, auth, reviewers, multi_user_prompt, 'reviewer') reviewers = select_users(valid_users, reviewers) if reviewers is None: raise util.Abort(_("Invalid reviewers")) feedback = [] if opts["feedback"]: search_strings = opts["feedback"].split(",") valid_users = validate_users(ui, api_server, auth, search_strings, multi_user_prompt, 'feedback from') feedback = select_users(valid_users, search_strings) values = {'BUGNUM': bug, 'ATTACHMENT_FILENAME': filename, 'ATTACHMENT_DESCRIPTION': desc, 'ATTACHCOMMENT': attachment_comment, 'REVIEWERS': reviewers, 'FEEDBACK': feedback, } cc = [] depends = opts["depends"].split(",") blocks = opts["blocks"].split(",") if opts['new']: if opts["cc"]: search_strings = opts["cc"].split(",") valid_users = validate_users(ui, api_server, auth, search_strings, multi_user_prompt, 'CC') cc = select_users(valid_users, search_strings) values['BUGTITLE'] = opts['title'] or desc values['PRODUCT'] = opts.get('product', '') or ui.config("bzexport", "product", '<choose-from-menu>') values['COMPONENT'] = opts.get('component', '') or ui.config("bzexport", "component", '<choose-from-menu>') values['PRODVERSION'] = opts.get('prodversion', '') or ui.config("bzexport", "prodversion", '<default>') values['BUGCOMMENT0'] = bug_comment values['CC'] = cc values['BLOCKS'] = blocks values['DEPENDS'] = depends values = fill_values(values, ui, api_server, finalize=False) if opts['edit']: if opts['new']: values = edit_form(ui, repo, values, 'new_both_template') else: values = edit_form(ui, repo, values, 'existing_bug_template') bug = values['BUGNUM'] search_strings = [] for key in ('REVIEWERS', 'CC', 'FEEDBACK'): # TODO: Handle <choose-from-menu> search_strings.extend(values.get(key, [])) users = validate_users(ui, api_server, auth, search_strings, multi_user_prompt, 'reviewer') if users is None: raise util.Abort("Invalid users") if 'REVIEWERS' in values: # Always true reviewers = select_users(users, values['REVIEWERS']) if 'CC' in values: # Only when opts['new'] cc = select_users(users, values['CC']) if 'BLOCKS' in values: # Only when opts['new'] blocks = values['BLOCKS'] if 'DEPENDS' in values: # Only when opts['new'] depends = values['DEPENDS'] if 'FEEDBACK' in values: # Always true feedback = select_users(users, values['FEEDBACK']) if 'ATTACHMENT_FILENAME' in values: filename = values['ATTACHMENT_FILENAME'] values = fill_values(values, ui, api_server, finalize=True) if opts["new"]: if bug is not None: raise util.Abort("Bug %s given but creation of new bug requested!" % bug) if opts['interactive'] and ui.prompt(_("Create bug in '%s' :: '%s' (y/n)?") % (values['PRODUCT'], values['COMPONENT'])) != 'y': ui.write(_("Exiting without creating bug\n")) return try: create_opts = {} if not opts['no_take_bug']: create_opts['assign_to'] = auth.username(api_server) result = bz.create_bug(auth, product=values['PRODUCT'], component=values['COMPONENT'], version=values['PRODVERSION'], title=values['BUGTITLE'], description=values['BUGCOMMENT0'], cc=cc, depends=depends, blocks=blocks, **create_opts) bug = result['id'] ui.write("Created bug %s at %sshow_bug.cgi?id=%s\n" % (bug, bugzilla, bug)) except Exception, e: raise util.Abort(_("Error creating bug: %s\n" % str(e)))
def getpatches(revs): for r in cmdutil.revrange(repo, revs): output = cStringIO.StringIO() patch.export(repo, [r], fp=output, opts=patch.diffopts(ui, opts)) yield output.getvalue().split('\n')
def bzexport(ui, repo, *args, **opts): """ Export changesets to bugzilla attachments. The -e option may be used to bring up an editor that will allow editing all fields of the attachment and bug (if creating one). The --new option may be used to create a new bug rather than using an existing bug. See the newbug command for details. The -u (--update) option is equivalent to setting both 'update-patch' and 'rename-patch' to True in the [bzexport] section of your config file. """ auth, api_server, bugzilla = bugzilla_info(ui, opts.get('ffprofile')) rev, bug = infer_arguments(ui, repo, args, opts) if not opts['new']: for o in ('cc', 'depends', 'blocks'): if opts[o]: ui.write( "Warning: ignoring --%s option when not creating a bug\n" % o) contents = StringIO() diffopts = patch.diffopts(ui, opts) context = ui.config("bzexport", "unified", ui.config("diff", "unified", None)) if context: diffopts.context = int(context) if rev in repo: description_from_patch = repo[rev].description().decode('utf-8') if hasattr(cmdutil, "export"): cmdutil.export(repo, [rev], fp=contents, opts=diffopts) else: # Support older hg versions patch.export(repo, [rev], fp=contents, opts=diffopts) else: q = repo.mq contents = q.opener(q.lookup(rev), "r") description_from_patch = '\n'.join( mq.patchheader(q.join(rev), q.plainmode).message) # Just always use the rev name as the patch name. Doesn't matter much, # unless you want to avoid obsoleting existing patches when uploading a # version that doesn't include whitespace changes. filename = rev if opts['ignore_all_space']: filename += "_ws" patch_comment = None reviewers = [] orig_desc = opts['description'] or description_from_patch if not orig_desc or orig_desc.startswith('[mq]'): desc = '<required>' else: # Lightly reformat changeset messages into attachment descriptions. # Only use the first line of the provided description for our actual # description - use the rest for the patch/bug comment. parts = orig_desc.split('\n', 1) firstline = parts[0] if len(parts) == 2: patch_comment = parts[1].strip() # Attempt to split the firstline into a bug number, and strip()ed # description with that bug number string removed. desc_bug_number, desc = extract_bug_num_and_desc(firstline) # Failing that try looking in the commit description for a bug number, # since orig_desc could have come from the command line instead. if not desc_bug_number: commit_firstline = description_from_patch.split('\n', 1)[0] desc_bug_number, __ = extract_bug_num_and_desc(commit_firstline) if desc_bug_number: if bug and bug != desc_bug_number: ui.warn( "Warning: Bug number %s from commandline doesn't match " "bug number %s from changeset description\n" % (bug, desc_bug_number)) else: bug = desc_bug_number # Strip any remaining leading separator and whitespace, # if the original was something like "bug NNN - " if desc[0] in ['-', ':', '.']: desc = desc[1:].lstrip() # Next strip off review and approval annotations, grabbing the # reviewers from the patch comments only if -r auto was given def grab_reviewer(m): if opts['review'] == 'auto': reviewers.append(m.group(1)) return '' desc = review_re.sub(grab_reviewer, desc).rstrip() # Strip any trailing separators, if the original was something like: # "Desc; r=foo" or "Desc. r=foo" if desc and desc[-1] in (';', '.'): desc = desc[:-1].rstrip() if len(reviewers) > 0: opts['review'] = '' attachment_comment = opts['comment'] bug_comment = opts['bug_description'] if not attachment_comment: # New bugs get first shot at the patch comment if not opts['new'] or bug_comment: attachment_comment = patch_comment if not bug_comment and opts['new']: bug_comment = patch_comment if opts["review"]: search_strings = opts["review"].split(",") valid_users = validate_users(ui, api_server, auth, search_strings, multi_user_prompt, 'reviewer') reviewers = select_users(valid_users, search_strings) elif len(reviewers) > 0: # Pulled reviewers out of commit message valid_users = validate_users(ui, api_server, auth, reviewers, multi_user_prompt, 'reviewer') reviewers = select_users(valid_users, reviewers) if reviewers is None: raise util.Abort(_("Invalid reviewers")) feedback = [] if opts["feedback"]: search_strings = opts["feedback"].split(",") valid_users = validate_users(ui, api_server, auth, search_strings, multi_user_prompt, 'feedback from') feedback = select_users(valid_users, search_strings) values = { 'BUGNUM': bug, 'ATTACHMENT_FILENAME': filename, 'ATTACHMENT_DESCRIPTION': desc, 'ATTACHCOMMENT': attachment_comment, 'REVIEWERS': reviewers, 'FEEDBACK': feedback, } cc = [] depends = opts["depends"].split(",") blocks = opts["blocks"].split(",") if opts['new']: if opts["cc"]: search_strings = opts["cc"].split(",") valid_users = validate_users(ui, api_server, auth, search_strings, multi_user_prompt, 'CC') cc = select_users(valid_users, search_strings) values['BUGTITLE'] = opts['title'] or desc values['PRODUCT'] = opts.get('product', '') or ui.config( "bzexport", "product", '<choose-from-menu>') values['COMPONENT'] = opts.get('component', '') or ui.config( "bzexport", "component", '<choose-from-menu>') values['PRODVERSION'] = opts.get('prodversion', '') or ui.config( "bzexport", "prodversion", '<default>') values['BUGCOMMENT0'] = bug_comment values['CC'] = cc values['BLOCKS'] = blocks values['DEPENDS'] = depends values = fill_values(values, ui, api_server, finalize=False) if opts['edit']: if opts['new']: values = edit_form(ui, repo, values, 'new_both_template') else: values = edit_form(ui, repo, values, 'existing_bug_template') bug = values['BUGNUM'] search_strings = [] for key in ('REVIEWERS', 'CC', 'FEEDBACK'): # TODO: Handle <choose-from-menu> search_strings.extend(values.get(key, [])) users = validate_users(ui, api_server, auth, search_strings, multi_user_prompt, 'reviewer') if users is None: raise util.Abort("Invalid users") if 'REVIEWERS' in values: # Always true reviewers = select_users(users, values['REVIEWERS']) if 'CC' in values: # Only when opts['new'] cc = select_users(users, values['CC']) if 'BLOCKS' in values: # Only when opts['new'] blocks = values['BLOCKS'] if 'DEPENDS' in values: # Only when opts['new'] depends = values['DEPENDS'] if 'FEEDBACK' in values: # Always true feedback = select_users(users, values['FEEDBACK']) if 'ATTACHMENT_FILENAME' in values: filename = values['ATTACHMENT_FILENAME'] values = fill_values(values, ui, api_server, finalize=True) if opts["new"]: if bug is not None: raise util.Abort( "Bug %s given but creation of new bug requested!" % bug) if opts['interactive'] and ui.prompt( _("Create bug in '%s' :: '%s' (y/n)?") % (values['PRODUCT'], values['COMPONENT'])) != 'y': ui.write(_("Exiting without creating bug\n")) return try: create_opts = {} if not opts['no_take_bug']: create_opts['assign_to'] = auth.username(api_server) result = bz.create_bug(auth, product=values['PRODUCT'], component=values['COMPONENT'], version=values['PRODVERSION'], title=values['BUGTITLE'], description=values['BUGCOMMENT0'], cc=cc, depends=depends, blocks=blocks, **create_opts) bug = result['id'] ui.write("Created bug %s at %sshow_bug.cgi?id=%s\n" % (bug, bugzilla, bug)) except Exception, e: raise util.Abort(_("Error creating bug: %s\n" % str(e)))