commands.import: refactor patch parsing into patch.extract.

This commit is contained in:
Vadim Gelfer 2006-08-12 13:16:48 -07:00
parent 2eab8e108e
commit beb26e5257
2 changed files with 91 additions and 72 deletions

View File

@ -12,7 +12,7 @@ demandload(globals(), "os re sys signal shutil imp urllib pdb")
demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
demandload(globals(), "fnmatch mdiff patch random signal tempfile time")
demandload(globals(), "traceback errno socket version struct atexit sets bz2")
demandload(globals(), "archival cStringIO changegroup email.Parser")
demandload(globals(), "archival cStringIO changegroup")
demandload(globals(), "hgweb.server sshserver")
class UnknownCommand(Exception):
@ -1814,84 +1814,23 @@ def import_(ui, repo, patch1, *patches, **opts):
d = opts["base"]
strip = opts["strip"]
mailre = re.compile(r'(?:From |[\w-]+:)')
# attempt to detect the start of a patch
# (this heuristic is borrowed from quilt)
diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
'retrieving revision [0-9]+(\.[0-9]+)*$|' +
'(---|\*\*\*)[ \t])', re.MULTILINE)
wlock = repo.wlock()
lock = repo.lock()
for p in patches:
pf = os.path.join(d, p)
message = None
user = None
date = None
hgpatch = False
parser = email.Parser.Parser()
if pf == '-':
msg = parser.parse(sys.stdin)
ui.status(_("applying patch from stdin\n"))
tmpname, message, user, date = patch.extract(ui, sys.stdin)
else:
msg = parser.parse(file(pf))
ui.status(_("applying %s\n") % p)
tmpname, message, user, date = patch.extract(ui, file(pf))
if tmpname is None:
raise util.Abort(_('no diffs found'))
fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
tmpfp = os.fdopen(fd, 'w')
try:
message = msg['Subject']
if message:
message = message.replace('\n\t', ' ')
ui.debug('Subject: %s\n' % message)
user = msg['From']
if user:
ui.debug('From: %s\n' % user)
diffs_seen = 0
ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
for part in msg.walk():
content_type = part.get_content_type()
ui.debug('Content-Type: %s\n' % content_type)
if content_type not in ok_types:
continue
payload = part.get_payload(decode=True)
m = diffre.search(payload)
if m:
ui.debug(_('found patch at byte %d\n') % m.start(0))
diffs_seen += 1
hgpatch = False
fp = cStringIO.StringIO()
if message:
fp.write(message)
fp.write('\n')
for line in payload[:m.start(0)].splitlines():
if line.startswith('# HG changeset patch'):
ui.debug(_('patch generated by hg export\n'))
hgpatch = True
# drop earlier commit message content
fp.seek(0)
fp.truncate()
elif hgpatch:
if line.startswith('# User '):
user = line[7:]
ui.debug('From: %s\n' % user)
elif line.startswith("# Date "):
date = line[7:]
if not line.startswith('# '):
fp.write(line)
fp.write('\n')
message = fp.getvalue()
if tmpfp:
tmpfp.write(payload)
if not payload.endswith('\n'):
tmpfp.write('\n')
elif not diffs_seen and message and content_type == 'text/plain':
message += '\n' + payload
if opts['message']:
# pickup the cmdline msg
message = opts['message']
@ -1903,10 +1842,6 @@ def import_(ui, repo, patch1, *patches, **opts):
message = None
ui.debug(_('message:\n%s\n') % message)
tmpfp.close()
if not diffs_seen:
raise util.Abort(_('no diffs found'))
files = patch.patch(strip, tmpname, ui, cwd=repo.root)
removes = []
if len(files) > 0:

View File

@ -6,8 +6,92 @@
# of the GNU General Public License, incorporated herein by reference.
from demandload import demandload
from i18n import gettext as _
demandload(globals(), "util")
demandload(globals(), "os re shutil tempfile")
demandload(globals(), "cStringIO email.Parser os re shutil tempfile")
def extract(ui, fileobj):
'''extract patch from data read from fileobj.
patch can be normal patch or contained in email message.
return tuple (filename, message, user, date). any item in returned
tuple can be None. if filename is None, fileobj did not contain
patch. caller must unlink filename when done.'''
# attempt to detect the start of a patch
# (this heuristic is borrowed from quilt)
diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
'retrieving revision [0-9]+(\.[0-9]+)*$|' +
'(---|\*\*\*)[ \t])', re.MULTILINE)
fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
tmpfp = os.fdopen(fd, 'w')
try:
hgpatch = False
msg = email.Parser.Parser().parse(fileobj)
message = msg['Subject']
user = msg['From']
# should try to parse msg['Date']
date = None
if message:
message = message.replace('\n\t', ' ')
ui.debug('Subject: %s\n' % message)
if user:
ui.debug('From: %s\n' % user)
diffs_seen = 0
ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
for part in msg.walk():
content_type = part.get_content_type()
ui.debug('Content-Type: %s\n' % content_type)
if content_type not in ok_types:
continue
payload = part.get_payload(decode=True)
m = diffre.search(payload)
if m:
ui.debug(_('found patch at byte %d\n') % m.start(0))
diffs_seen += 1
cfp = cStringIO.StringIO()
if message:
cfp.write(message)
cfp.write('\n')
for line in payload[:m.start(0)].splitlines():
if line.startswith('# HG changeset patch'):
ui.debug(_('patch generated by hg export\n'))
hgpatch = True
# drop earlier commit message content
cfp.seek(0)
cfp.truncate()
elif hgpatch:
if line.startswith('# User '):
user = line[7:]
ui.debug('From: %s\n' % user)
elif line.startswith("# Date "):
date = line[7:]
if not line.startswith('# '):
cfp.write(line)
cfp.write('\n')
message = cfp.getvalue()
if tmpfp:
tmpfp.write(payload)
if not payload.endswith('\n'):
tmpfp.write('\n')
elif not diffs_seen and message and content_type == 'text/plain':
message += '\n' + payload
except:
tmpfp.close()
os.unlink(tmpname)
raise
tmpfp.close()
if not diffs_seen:
os.unlink(tmpname)
return None, message, user, date
return tmpname, message, user, date
def readgitpatch(patchname):
"""extract git-style metadata about patches from <patchname>"""