Mercurial > public > mercurial-scm > hg
comparison mercurial/commands.py @ 2509:6350b01d173f
merge with wsgi changes.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Tue, 27 Jun 2006 00:10:41 -0700 |
parents | 158d3d2ae070 |
children | cbff06469488 |
comparison
equal
deleted
inserted
replaced
2508:ab460a3f0e3a | 2509:6350b01d173f |
---|---|
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): |
834 commit(ui, repo, **commit_opts) | 834 commit(ui, repo, **commit_opts) |
835 def nice(node): | 835 def nice(node): |
836 return '%d:%s' % (repo.changelog.rev(node), short(node)) | 836 return '%d:%s' % (repo.changelog.rev(node), short(node)) |
837 ui.status(_('changeset %s backs out changeset %s\n') % | 837 ui.status(_('changeset %s backs out changeset %s\n') % |
838 (nice(repo.changelog.tip()), nice(node))) | 838 (nice(repo.changelog.tip()), nice(node))) |
839 if opts['merge'] and op1 != node: | 839 if op1 != node: |
840 ui.status(_('merging with changeset %s\n') % nice(op1)) | 840 if opts['merge']: |
841 doupdate(ui, repo, hex(op1), **opts) | 841 ui.status(_('merging with changeset %s\n') % nice(op1)) |
842 | 842 doupdate(ui, repo, hex(op1), **opts) |
843 def bundle(ui, repo, fname, dest="default-push", **opts): | 843 else: |
844 ui.status(_('the backout changeset is a new head - ' | |
845 'do not forget to merge\n')) | |
846 ui.status(_('(use "backout -m" if you want to auto-merge)\n')) | |
847 | |
848 def bundle(ui, repo, fname, dest=None, **opts): | |
844 """create a changegroup file | 849 """create a changegroup file |
845 | 850 |
846 Generate a compressed changegroup file collecting all changesets | 851 Generate a compressed changegroup file collecting all changesets |
847 not found in the other repository. | 852 not found in the other repository. |
848 | 853 |
853 extension is ".hg". | 858 extension is ".hg". |
854 | 859 |
855 Unlike import/export, this exactly preserves all changeset | 860 Unlike import/export, this exactly preserves all changeset |
856 contents including permissions, rename data, and revision history. | 861 contents including permissions, rename data, and revision history. |
857 """ | 862 """ |
858 dest = ui.expandpath(dest) | 863 dest = ui.expandpath(dest or 'default-push', dest or 'default') |
859 other = hg.repository(ui, dest) | 864 other = hg.repository(ui, dest) |
860 o = repo.findoutgoing(other, force=opts['force']) | 865 o = repo.findoutgoing(other, force=opts['force']) |
861 cg = repo.changegroup(o, 'bundle') | 866 cg = repo.changegroup(o, 'bundle') |
862 write_bundle(cg, fname) | 867 write_bundle(cg, fname) |
863 | 868 |
1712 Import a list of patches and commit them individually. | 1717 Import a list of patches and commit them individually. |
1713 | 1718 |
1714 If there are outstanding changes in the working directory, import | 1719 If there are outstanding changes in the working directory, import |
1715 will abort unless given the -f flag. | 1720 will abort unless given the -f flag. |
1716 | 1721 |
1717 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 |
1718 "From " or looks like an RFC822 header), it will not be applied | 1723 as attachments work (body part must be type text/plain or |
1719 unless the -f option is used. The importer neither parses nor | 1724 text/x-patch to be used). Sender and subject line of email |
1720 discards mail headers, so use -f only to override the "mailness" | 1725 message are used as default committer and commit message. Any |
1721 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. | |
1722 | 1731 |
1723 To read a patch from standard input, use patch name "-". | 1732 To read a patch from standard input, use patch name "-". |
1724 """ | 1733 """ |
1725 patches = (patch1,) + patches | 1734 patches = (patch1,) + patches |
1726 | 1735 |
1732 | 1741 |
1733 mailre = re.compile(r'(?:From |[\w-]+:)') | 1742 mailre = re.compile(r'(?:From |[\w-]+:)') |
1734 | 1743 |
1735 # attempt to detect the start of a patch | 1744 # attempt to detect the start of a patch |
1736 # (this heuristic is borrowed from quilt) | 1745 # (this heuristic is borrowed from quilt) |
1737 diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' + | 1746 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' + |
1738 'retrieving revision [0-9]+(\.[0-9]+)*$|' + | 1747 'retrieving revision [0-9]+(\.[0-9]+)*$|' + |
1739 '(---|\*\*\*)[ \t])') | 1748 '(---|\*\*\*)[ \t])', re.MULTILINE) |
1740 | 1749 |
1741 for patch in patches: | 1750 for patch in patches: |
1742 pf = os.path.join(d, patch) | 1751 pf = os.path.join(d, patch) |
1743 | 1752 |
1744 message = [] | 1753 message = None |
1745 user = None | 1754 user = None |
1746 date = None | 1755 date = None |
1747 hgpatch = False | 1756 hgpatch = False |
1757 | |
1758 p = email.Parser.Parser() | |
1748 if pf == '-': | 1759 if pf == '-': |
1749 f = sys.stdin | 1760 msg = p.parse(sys.stdin) |
1750 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-') | |
1751 pf = tmpname | |
1752 tmpfp = os.fdopen(fd, 'w') | |
1753 ui.status(_("applying patch from stdin\n")) | 1761 ui.status(_("applying patch from stdin\n")) |
1754 else: | 1762 else: |
1755 f = open(pf) | 1763 msg = p.parse(file(pf)) |
1756 tmpfp, tmpname = None, None | |
1757 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') | |
1758 try: | 1768 try: |
1759 while True: | 1769 message = msg['Subject'] |
1760 line = f.readline() | 1770 if message: |
1761 if not line: break | 1771 message = message.replace('\n\t', ' ') |
1762 if tmpfp: tmpfp.write(line) | 1772 ui.debug('Subject: %s\n' % message) |
1763 line = line.rstrip() | 1773 user = msg['From'] |
1764 if (not message and not hgpatch and | 1774 if user: |
1765 mailre.match(line) and not opts['force']): | 1775 ui.debug('From: %s\n' % user) |
1766 if len(line) > 35: | 1776 diffs_seen = 0 |
1767 line = line[:32] + '...' | 1777 ok_types = ('text/plain', 'text/x-patch') |
1768 raise util.Abort(_('first line looks like a ' | 1778 for part in msg.walk(): |
1769 'mail header: ') + line) | 1779 content_type = part.get_content_type() |
1770 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 | |
1771 if tmpfp: | 1805 if tmpfp: |
1772 for chunk in util.filechunkiter(f): | 1806 tmpfp.write(payload) |
1773 tmpfp.write(chunk) | 1807 if not payload.endswith('\n'): |
1774 break | 1808 tmpfp.write('\n') |
1775 elif hgpatch: | 1809 elif not diffs_seen and message and content_type == 'text/plain': |
1776 # parse values when importing the result of an hg export | 1810 message += '\n' + payload |
1777 if line.startswith("# User "): | |
1778 user = line[7:] | |
1779 ui.debug(_('User: %s\n') % user) | |
1780 elif line.startswith("# Date "): | |
1781 date = line[7:] | |
1782 elif not line.startswith("# ") and line: | |
1783 message.append(line) | |
1784 hgpatch = False | |
1785 elif line == '# HG changeset patch': | |
1786 hgpatch = True | |
1787 message = [] # We may have collected garbage | |
1788 elif message or line: | |
1789 message.append(line) | |
1790 | 1811 |
1791 if opts['message']: | 1812 if opts['message']: |
1792 # pickup the cmdline msg | 1813 # pickup the cmdline msg |
1793 message = opts['message'] | 1814 message = opts['message'] |
1794 elif message: | 1815 elif message: |
1795 # pickup the patch msg | 1816 # pickup the patch msg |
1796 message = '\n'.join(message).rstrip() | 1817 message = message.strip() |
1797 else: | 1818 else: |
1798 # launch the editor | 1819 # launch the editor |
1799 message = None | 1820 message = None |
1800 ui.debug(_('message:\n%s\n') % message) | 1821 ui.debug(_('message:\n%s\n') % message) |
1801 | 1822 |
1802 if tmpfp: tmpfp.close() | 1823 tmpfp.close() |
1803 files = util.patch(strip, pf, ui) | 1824 if not diffs_seen: |
1804 | 1825 raise util.Abort(_('no diffs found')) |
1826 | |
1827 files = util.patch(strip, tmpname, ui) | |
1805 if len(files) > 0: | 1828 if len(files) > 0: |
1806 addremove_lock(ui, repo, files, {}) | 1829 addremove_lock(ui, repo, files, {}) |
1807 repo.commit(files, message, user, date) | 1830 repo.commit(files, message, user, date) |
1808 finally: | 1831 finally: |
1809 if tmpname: os.unlink(tmpname) | 1832 os.unlink(tmpname) |
1810 | 1833 |
1811 def incoming(ui, repo, source="default", **opts): | 1834 def incoming(ui, repo, source="default", **opts): |
1812 """show new changesets found in source | 1835 """show new changesets found in source |
1813 | 1836 |
1814 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 |
2040 marked as changed for the next commit and a commit must be | 2063 marked as changed for the next commit and a commit must be |
2041 performed before any further updates are allowed. | 2064 performed before any further updates are allowed. |
2042 """ | 2065 """ |
2043 return doupdate(ui, repo, node=node, merge=True, **opts) | 2066 return doupdate(ui, repo, node=node, merge=True, **opts) |
2044 | 2067 |
2045 def outgoing(ui, repo, dest="default-push", **opts): | 2068 def outgoing(ui, repo, dest=None, **opts): |
2046 """show changesets not found in destination | 2069 """show changesets not found in destination |
2047 | 2070 |
2048 Show changesets not found in the specified destination repository or | 2071 Show changesets not found in the specified destination repository or |
2049 the default push location. These are the changesets that would be pushed | 2072 the default push location. These are the changesets that would be pushed |
2050 if a push was requested. | 2073 if a push was requested. |
2051 | 2074 |
2052 See pull for valid destination format details. | 2075 See pull for valid destination format details. |
2053 """ | 2076 """ |
2054 dest = ui.expandpath(dest) | 2077 dest = ui.expandpath(dest or 'default-push', dest or 'default') |
2055 if opts['ssh']: | 2078 if opts['ssh']: |
2056 ui.setconfig("ui", "ssh", opts['ssh']) | 2079 ui.setconfig("ui", "ssh", opts['ssh']) |
2057 if opts['remotecmd']: | 2080 if opts['remotecmd']: |
2058 ui.setconfig("ui", "remotecmd", opts['remotecmd']) | 2081 ui.setconfig("ui", "remotecmd", opts['remotecmd']) |
2059 | 2082 |
2172 elif opts['rev']: | 2195 elif opts['rev']: |
2173 revs = [other.lookup(rev) for rev in opts['rev']] | 2196 revs = [other.lookup(rev) for rev in opts['rev']] |
2174 modheads = repo.pull(other, heads=revs, force=opts['force']) | 2197 modheads = repo.pull(other, heads=revs, force=opts['force']) |
2175 return postincoming(ui, repo, modheads, opts['update']) | 2198 return postincoming(ui, repo, modheads, opts['update']) |
2176 | 2199 |
2177 def push(ui, repo, dest="default-push", **opts): | 2200 def push(ui, repo, dest=None, **opts): |
2178 """push changes to the specified destination | 2201 """push changes to the specified destination |
2179 | 2202 |
2180 Push changes from the local repository to the given destination. | 2203 Push changes from the local repository to the given destination. |
2181 | 2204 |
2182 This is the symmetrical operation for pull. It helps to move | 2205 This is the symmetrical operation for pull. It helps to move |
2194 ssh://[user@]host[:port][/path] | 2217 ssh://[user@]host[:port][/path] |
2195 | 2218 |
2196 Look at the help text for the pull command for important details | 2219 Look at the help text for the pull command for important details |
2197 about ssh:// URLs. | 2220 about ssh:// URLs. |
2198 """ | 2221 """ |
2199 dest = ui.expandpath(dest) | 2222 dest = ui.expandpath(dest or 'default-push', dest or 'default') |
2200 | 2223 |
2201 if opts['ssh']: | 2224 if opts['ssh']: |
2202 ui.setconfig("ui", "ssh", opts['ssh']) | 2225 ui.setconfig("ui", "ssh", opts['ssh']) |
2203 if opts['remotecmd']: | 2226 if opts['remotecmd']: |
2204 ui.setconfig("ui", "remotecmd", opts['remotecmd']) | 2227 ui.setconfig("ui", "remotecmd", opts['remotecmd']) |