# HG changeset patch # User Brendan Cully # Date 1227391482 28800 # Node ID e71bda2d208764a8e8efa33d349c51da5a265cc3 # Parent 2cd1308cb5886c6234c9539486850e6e98286373 mq: create patch header class to abstract header manipulation diff -r 2cd1308cb588 -r e71bda2d2087 hgext/mq.py --- a/hgext/mq.py Sun Nov 23 00:44:31 2008 -0800 +++ b/hgext/mq.py Sat Nov 22 14:04:42 2008 -0800 @@ -56,6 +56,67 @@ def __str__(self): return self.rev + ':' + self.name +class patchheader(object): + def __init__(self, message, comments, user, date, haspatch): + self.message = message + self.comments = comments + self.user = user + self.date = date + self.haspatch = haspatch + + def setuser(self, user): + if not self.setheader(['From: ', '# User '], user): + try: + patchheaderat = self.comments.index('# HG changeset patch') + self.comments.insert(patchheaderat + 1,'# User ' + user) + except ValueError: + self.comments = ['From: ' + user, ''] + self.comments + self.user = user + + def setdate(self, date): + if self.setheader(['# Date '], date): + self.date = date + + def setmessage(self, message): + if self.comments: + self._delmsg() + self.message = [message] + self.comments += self.message + + def setheader(self, prefixes, new): + '''Update all references to a field in the patch header. + If none found, add it email style.''' + res = False + for prefix in prefixes: + for i in xrange(len(self.comments)): + if self.comments[i].startswith(prefix): + self.comments[i] = prefix + new + res = True + break + return res + + def __str__(self): + if not self.comments: + return '' + return '\n'.join(self.comments) + '\n\n' + + def _delmsg(self): + '''Remove existing message, keeping the rest of the comments fields. + If comments contains 'subject: ', message will prepend + the field and a blank line.''' + if self.message: + subj = 'subject: ' + self.message[0].lower() + for i in xrange(len(self.comments)): + if subj == self.comments[i].lower(): + del self.comments[i] + self.message = self.message[2:] + break + ci = 0 + for mi in xrange(len(self.message)): + while self.message[mi] != self.comments[ci]: + ci += 1 + del self.comments[ci] + class queue: def __init__(self, ui, path, patchdir=None): self.basepath = path @@ -307,7 +368,7 @@ if format and format.startswith("tag") and subject: message.insert(0, "") message.insert(0, subject) - return (message, comments, user, date, diffstart > 1) + return patchheader(message, comments, user, date, diffstart > 1) def removeundo(self, repo): undo = repo.sjoin('undo') @@ -351,13 +412,13 @@ if n == None: raise util.Abort(_("repo commit failed")) try: - message, comments, user, date, patchfound = mergeq.readheaders(patch) + ph = mergeq.readheaders(patch) except: raise util.Abort(_("unable to read %s") % patch) patchf = self.opener(patch, "w") + comments = str(ph) if comments: - comments = "\n".join(comments) + '\n\n' patchf.write(comments) self.printdiff(repo, head, n, fp=patchf) patchf.close() @@ -477,12 +538,13 @@ pf = os.path.join(patchdir, patchname) try: - message, comments, user, date, patchfound = self.readheaders(patchname) + ph = self.readheaders(patchname) except: self.ui.warn(_("Unable to read %s\n") % patchname) err = 1 break + message = ph.message if not message: message = _("imported patch %s\n") % patchname else: @@ -512,7 +574,7 @@ files = patch.updatedir(self.ui, repo, files) match = cmdutil.matchfiles(repo, files or []) - n = repo.commit(files, message, user, date, match=match, + n = repo.commit(files, message, ph.user, ph.date, match=match, force=True) if n == None: @@ -522,7 +584,7 @@ self.applied.append(statusentry(revlog.hex(n), patchname)) if patcherr: - if not patchfound: + if not ph.haspatch: self.ui.warn(_("patch %s is empty\n") % patchname) err = 0 else: @@ -1015,6 +1077,8 @@ if len(self.applied) == 0: self.ui.write(_("No patches applied\n")) return 1 + msg = opts.get('msg', '').rstrip() + newuser = opts.get('user') newdate = opts.get('date') if newdate: newdate = '%d %d' % util.parsedate(newdate) @@ -1027,7 +1091,7 @@ raise util.Abort(_("cannot refresh a revision with children")) cparents = repo.changelog.parents(top) patchparent = self.qparents(repo, top) - message, comments, user, date, patchfound = self.readheaders(patchfn) + ph = self.readheaders(patchfn) patchf = self.opener(patchfn, 'r+') @@ -1037,59 +1101,18 @@ self.diffopts().git = True break - msg = opts.get('msg', '').rstrip() - if msg and comments: - # Remove existing message, keeping the rest of the comments - # fields. - # If comments contains 'subject: ', message will prepend - # the field and a blank line. - if message: - subj = 'subject: ' + message[0].lower() - for i in xrange(len(comments)): - if subj == comments[i].lower(): - del comments[i] - message = message[2:] - break - ci = 0 - for mi in xrange(len(message)): - while message[mi] != comments[ci]: - ci += 1 - del comments[ci] - - def setheaderfield(comments, prefixes, new): - # Update all references to a field in the patch header. - # If none found, add it email style. - res = False - for prefix in prefixes: - for i in xrange(len(comments)): - if comments[i].startswith(prefix): - comments[i] = prefix + new - res = True - break - return res - - newuser = opts.get('user') + if msg: + ph.setmessage(msg) if newuser: - if not setheaderfield(comments, ['From: ', '# User '], newuser): - try: - patchheaderat = comments.index('# HG changeset patch') - comments.insert(patchheaderat + 1,'# User ' + newuser) - except ValueError: - comments = ['From: ' + newuser, ''] + comments - user = newuser - + ph.setuser(newuser) if newdate: - if setheaderfield(comments, ['# Date '], newdate): - date = newdate - - if msg: - comments.append(msg) + ph.setdate(newdate) patchf.seek(0) patchf.truncate() + comments = str(ph) if comments: - comments = "\n".join(comments) + '\n\n' patchf.write(comments) if opts.get('git'): @@ -1204,22 +1227,21 @@ repo.dirstate.forget(f) if not msg: - if not message: + if not ph.message: message = "[mq]: %s\n" % patchfn else: - message = "\n".join(message) + message = "\n".join(ph.message) else: message = msg - if not user: - user = changes[1] + user = ph.user or changes[1] self.applied.pop() self.applied_dirty = 1 self.strip(repo, top, update=False, backup='strip') - n = repo.commit(match.files(), message, user, date, match=match, - force=1) + n = repo.commit(match.files(), message, user, ph.date, + match=match, force=1) self.applied.append(statusentry(revlog.hex(n), patchfn)) self.removeundo(repo) else: @@ -1273,7 +1295,8 @@ summary=False): def displayname(patchname): if summary: - msg = self.readheaders(patchname)[0] + ph = self.readheaders(patchname) + msg = ph.message msg = msg and ': ' + msg[0] or ': ' else: msg = '' @@ -1828,8 +1851,8 @@ if message: raise util.Abort(_('option "-e" incompatible with "-m" or "-l"')) patch = q.applied[-1].name - (message, comment, user, date, hasdiff) = q.readheaders(patch) - message = ui.edit('\n'.join(message), user or ui.username()) + ph = q.readheaders(patch) + message = ui.edit('\n'.join(ph.message), ph.user or ui.username()) setupheaderopts(ui, opts) ret = q.refresh(repo, pats, msg=message, **opts) q.save_dirty() @@ -1887,7 +1910,8 @@ for p in patches: if not message: - messages.append(q.readheaders(p)[0]) + ph = q.readheaders(p) + messages.append(ph.message) pf = q.join(p) (patchsuccess, files, fuzz) = q.patch(repo, pf) if not patchsuccess: @@ -1895,7 +1919,8 @@ patch.updatedir(ui, repo, files) if not message: - message, comments, user = q.readheaders(parent)[0:3] + ph = q.readheaders(parent) + message, user = ph.message, ph.user for msg in messages: message.append('* * *') message.extend(msg) @@ -1978,9 +2003,9 @@ ui.write('No patches applied\n') return 1 patch = q.lookup('qtip') - message = repo.mq.readheaders(patch)[0] + ph = repo.mq.readheaders(patch) - ui.write('\n'.join(message) + '\n') + ui.write('\n'.join(ph.message) + '\n') def lastsavename(path): (directory, base) = os.path.split(path)