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 |