mercurial/commands.py
changeset 2504 158d3d2ae070
parent 2494 73ac95671788
child 2510 cbff06469488
equal deleted inserted replaced
2502:18cf95ad3666 2504:158d3d2ae070
    10 from i18n import gettext as _
    10 from i18n import gettext as _
    11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
    11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
    12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
    12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
    13 demandload(globals(), "fnmatch mdiff random signal tempfile time")
    13 demandload(globals(), "fnmatch mdiff random signal tempfile time")
    14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
    14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
    15 demandload(globals(), "archival changegroup")
    15 demandload(globals(), "archival cStringIO changegroup email.Parser")
    16 demandload(globals(), "hgweb.server sshserver")
    16 demandload(globals(), "hgweb.server sshserver")
    17 
    17 
    18 class UnknownCommand(Exception):
    18 class UnknownCommand(Exception):
    19     """Exception raised if command is not in the command table."""
    19     """Exception raised if command is not in the command table."""
    20 class AmbiguousCommand(Exception):
    20 class AmbiguousCommand(Exception):
  1717     Import a list of patches and commit them individually.
  1717     Import a list of patches and commit them individually.
  1718 
  1718 
  1719     If there are outstanding changes in the working directory, import
  1719     If there are outstanding changes in the working directory, import
  1720     will abort unless given the -f flag.
  1720     will abort unless given the -f flag.
  1721 
  1721 
  1722     If a patch looks like a mail message (its first line starts with
  1722     You can import a patch straight from a mail message.  Even patches
  1723     "From " or looks like an RFC822 header), it will not be applied
  1723     as attachments work (body part must be type text/plain or
  1724     unless the -f option is used.  The importer neither parses nor
  1724     text/x-patch to be used).  Sender and subject line of email
  1725     discards mail headers, so use -f only to override the "mailness"
  1725     message are used as default committer and commit message.  Any
  1726     safety check, not to import a real mail message.
  1726     text/plain body part before first diff is added to commit message.
       
  1727 
       
  1728     If imported patch was generated by hg export, user and description
       
  1729     from patch override values from message headers and body.  Values
       
  1730     given on command line with -m and -u override these.
  1727 
  1731 
  1728     To read a patch from standard input, use patch name "-".
  1732     To read a patch from standard input, use patch name "-".
  1729     """
  1733     """
  1730     patches = (patch1,) + patches
  1734     patches = (patch1,) + patches
  1731 
  1735 
  1737 
  1741 
  1738     mailre = re.compile(r'(?:From |[\w-]+:)')
  1742     mailre = re.compile(r'(?:From |[\w-]+:)')
  1739 
  1743 
  1740     # attempt to detect the start of a patch
  1744     # attempt to detect the start of a patch
  1741     # (this heuristic is borrowed from quilt)
  1745     # (this heuristic is borrowed from quilt)
  1742     diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' +
  1746     diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
  1743                         'retrieving revision [0-9]+(\.[0-9]+)*$|' +
  1747                         'retrieving revision [0-9]+(\.[0-9]+)*$|' +
  1744                         '(---|\*\*\*)[ \t])')
  1748                         '(---|\*\*\*)[ \t])', re.MULTILINE)
  1745 
  1749 
  1746     for patch in patches:
  1750     for patch in patches:
  1747         pf = os.path.join(d, patch)
  1751         pf = os.path.join(d, patch)
  1748 
  1752 
  1749         message = []
  1753         message = None
  1750         user = None
  1754         user = None
  1751         date = None
  1755         date = None
  1752         hgpatch = False
  1756         hgpatch = False
       
  1757 
       
  1758         p = email.Parser.Parser()
  1753         if pf == '-':
  1759         if pf == '-':
  1754             f = sys.stdin
  1760             msg = p.parse(sys.stdin)
  1755             fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
       
  1756             pf = tmpname
       
  1757             tmpfp = os.fdopen(fd, 'w')
       
  1758             ui.status(_("applying patch from stdin\n"))
  1761             ui.status(_("applying patch from stdin\n"))
  1759         else:
  1762         else:
  1760             f = open(pf)
  1763             msg = p.parse(file(pf))
  1761             tmpfp, tmpname = None, None
       
  1762             ui.status(_("applying %s\n") % patch)
  1764             ui.status(_("applying %s\n") % patch)
       
  1765 
       
  1766         fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
       
  1767         tmpfp = os.fdopen(fd, 'w')
  1763         try:
  1768         try:
  1764             while True:
  1769             message = msg['Subject']
  1765                 line = f.readline()
  1770             if message:
  1766                 if not line: break
  1771                 message = message.replace('\n\t', ' ')
  1767                 if tmpfp: tmpfp.write(line)
  1772                 ui.debug('Subject: %s\n' % message)
  1768                 line = line.rstrip()
  1773             user = msg['From']
  1769                 if (not message and not hgpatch and
  1774             if user:
  1770                        mailre.match(line) and not opts['force']):
  1775                 ui.debug('From: %s\n' % user)
  1771                     if len(line) > 35:
  1776             diffs_seen = 0
  1772                         line = line[:32] + '...'
  1777             ok_types = ('text/plain', 'text/x-patch')
  1773                     raise util.Abort(_('first line looks like a '
  1778             for part in msg.walk():
  1774                                        'mail header: ') + line)
  1779                 content_type = part.get_content_type()
  1775                 if diffre.match(line):
  1780                 ui.debug('Content-Type: %s\n' % content_type)
       
  1781                 if content_type not in ok_types:
       
  1782                     continue
       
  1783                 payload = part.get_payload(decode=True)
       
  1784                 m = diffre.search(payload)
       
  1785                 if m:
       
  1786                     ui.debug(_('found patch at byte %d\n') % m.start(0))
       
  1787                     diffs_seen += 1
       
  1788                     hgpatch = False
       
  1789                     fp = cStringIO.StringIO()
       
  1790                     for line in payload[:m.start(0)].splitlines():
       
  1791                         if line.startswith('# HG changeset patch'):
       
  1792                             ui.debug(_('patch generated by hg export\n'))
       
  1793                             hgpatch = True
       
  1794                         elif hgpatch:
       
  1795                             if line.startswith('# User '):
       
  1796                                 user = line[7:]
       
  1797                                 ui.debug('From: %s\n' % user)
       
  1798                             elif line.startswith("# Date "):
       
  1799                                 date = line[7:]
       
  1800                         if not line.startswith('# '):
       
  1801                             fp.write(line)
       
  1802                             fp.write('\n')
       
  1803                             hgpatch = False
       
  1804                     message = fp.getvalue() or message
  1776                     if tmpfp:
  1805                     if tmpfp:
  1777                         for chunk in util.filechunkiter(f):
  1806                         tmpfp.write(payload)
  1778                             tmpfp.write(chunk)
  1807                         if not payload.endswith('\n'):
  1779                     break
  1808                             tmpfp.write('\n')
  1780                 elif hgpatch:
  1809                 elif not diffs_seen and message and content_type == 'text/plain':
  1781                     # parse values when importing the result of an hg export
  1810                     message += '\n' + payload
  1782                     if line.startswith("# User "):
       
  1783                         user = line[7:]
       
  1784                         ui.debug(_('User: %s\n') % user)
       
  1785                     elif line.startswith("# Date "):
       
  1786                         date = line[7:]
       
  1787                     elif not line.startswith("# ") and line:
       
  1788                         message.append(line)
       
  1789                         hgpatch = False
       
  1790                 elif line == '# HG changeset patch':
       
  1791                     hgpatch = True
       
  1792                     message = []       # We may have collected garbage
       
  1793                 elif message or line:
       
  1794                     message.append(line)
       
  1795 
  1811 
  1796             if opts['message']:
  1812             if opts['message']:
  1797                 # pickup the cmdline msg
  1813                 # pickup the cmdline msg
  1798                 message = opts['message']
  1814                 message = opts['message']
  1799             elif message:
  1815             elif message:
  1800                 # pickup the patch msg
  1816                 # pickup the patch msg
  1801                 message = '\n'.join(message).rstrip()
  1817                 message = message.strip()
  1802             else:
  1818             else:
  1803                 # launch the editor
  1819                 # launch the editor
  1804                 message = None
  1820                 message = None
  1805             ui.debug(_('message:\n%s\n') % message)
  1821             ui.debug(_('message:\n%s\n') % message)
  1806 
  1822 
  1807             if tmpfp: tmpfp.close()
  1823             tmpfp.close()
  1808             files = util.patch(strip, pf, ui)
  1824             if not diffs_seen:
  1809 
  1825                 raise util.Abort(_('no diffs found'))
       
  1826 
       
  1827             files = util.patch(strip, tmpname, ui)
  1810             if len(files) > 0:
  1828             if len(files) > 0:
  1811                 addremove_lock(ui, repo, files, {})
  1829                 addremove_lock(ui, repo, files, {})
  1812             repo.commit(files, message, user, date)
  1830             repo.commit(files, message, user, date)
  1813         finally:
  1831         finally:
  1814             if tmpname: os.unlink(tmpname)
  1832             os.unlink(tmpname)
  1815 
  1833 
  1816 def incoming(ui, repo, source="default", **opts):
  1834 def incoming(ui, repo, source="default", **opts):
  1817     """show new changesets found in source
  1835     """show new changesets found in source
  1818 
  1836 
  1819     Show new changesets found in the specified path/URL or the default
  1837     Show new changesets found in the specified path/URL or the default