Show More
@@ -1833,9 +1833,82 b' def import_(ui, repo, patch1, *patches, ' | |||||
1833 | d = opts["base"] |
|
1833 | d = opts["base"] | |
1834 | strip = opts["strip"] |
|
1834 | strip = opts["strip"] | |
1835 | wlock = lock = None |
|
1835 | wlock = lock = None | |
|
1836 | ||||
|
1837 | def tryone(ui, hunk): | |||
|
1838 | tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, hunk) | |||
|
1839 | ||||
|
1840 | if not tmpname: | |||
|
1841 | return None | |||
|
1842 | commitid = _('to working directory') | |||
|
1843 | ||||
|
1844 | try: | |||
|
1845 | cmdline_message = cmdutil.logmessage(opts) | |||
|
1846 | if cmdline_message: | |||
|
1847 | # pickup the cmdline msg | |||
|
1848 | message = cmdline_message | |||
|
1849 | elif message: | |||
|
1850 | # pickup the patch msg | |||
|
1851 | message = message.strip() | |||
|
1852 | else: | |||
|
1853 | # launch the editor | |||
|
1854 | message = None | |||
|
1855 | ui.debug('message:\n%s\n' % message) | |||
|
1856 | ||||
|
1857 | wp = repo.parents() | |||
|
1858 | if opts.get('exact'): | |||
|
1859 | if not nodeid or not p1: | |||
|
1860 | raise util.Abort(_('not a Mercurial patch')) | |||
|
1861 | p1 = repo.lookup(p1) | |||
|
1862 | p2 = repo.lookup(p2 or hex(nullid)) | |||
|
1863 | ||||
|
1864 | if p1 != wp[0].node(): | |||
|
1865 | hg.clean(repo, p1) | |||
|
1866 | repo.dirstate.setparents(p1, p2) | |||
|
1867 | elif p2: | |||
|
1868 | try: | |||
|
1869 | p1 = repo.lookup(p1) | |||
|
1870 | p2 = repo.lookup(p2) | |||
|
1871 | if p1 == wp[0].node(): | |||
|
1872 | repo.dirstate.setparents(p1, p2) | |||
|
1873 | except error.RepoError: | |||
|
1874 | pass | |||
|
1875 | if opts.get('exact') or opts.get('import_branch'): | |||
|
1876 | repo.dirstate.setbranch(branch or 'default') | |||
|
1877 | ||||
|
1878 | files = {} | |||
|
1879 | try: | |||
|
1880 | patch.patch(tmpname, ui, strip=strip, cwd=repo.root, | |||
|
1881 | files=files, eolmode=None) | |||
|
1882 | finally: | |||
|
1883 | files = patch.updatedir(ui, repo, files, | |||
|
1884 | similarity=sim / 100.0) | |||
|
1885 | if not opts.get('no_commit'): | |||
|
1886 | if opts.get('exact'): | |||
|
1887 | m = None | |||
|
1888 | else: | |||
|
1889 | m = cmdutil.matchfiles(repo, files or []) | |||
|
1890 | n = repo.commit(message, opts.get('user') or user, | |||
|
1891 | opts.get('date') or date, match=m, | |||
|
1892 | editor=cmdutil.commiteditor) | |||
|
1893 | if opts.get('exact'): | |||
|
1894 | if hex(n) != nodeid: | |||
|
1895 | repo.rollback() | |||
|
1896 | raise util.Abort(_('patch is damaged' | |||
|
1897 | ' or loses information')) | |||
|
1898 | # Force a dirstate write so that the next transaction | |||
|
1899 | # backups an up-do-date file. | |||
|
1900 | repo.dirstate.write() | |||
|
1901 | if n: | |||
|
1902 | commitid = short(n) | |||
|
1903 | ||||
|
1904 | return commitid | |||
|
1905 | finally: | |||
|
1906 | os.unlink(tmpname) | |||
|
1907 | ||||
1836 | try: |
|
1908 | try: | |
1837 | wlock = repo.wlock() |
|
1909 | wlock = repo.wlock() | |
1838 | lock = repo.lock() |
|
1910 | lock = repo.lock() | |
|
1911 | lastcommit = None | |||
1839 | for p in patches: |
|
1912 | for p in patches: | |
1840 | pf = os.path.join(d, p) |
|
1913 | pf = os.path.join(d, p) | |
1841 |
|
1914 | |||
@@ -1845,68 +1918,19 b' def import_(ui, repo, patch1, *patches, ' | |||||
1845 | else: |
|
1918 | else: | |
1846 | ui.status(_("applying %s\n") % p) |
|
1919 | ui.status(_("applying %s\n") % p) | |
1847 | pf = url.open(ui, pf) |
|
1920 | pf = url.open(ui, pf) | |
1848 | data = patch.extract(ui, pf) |
|
1921 | ||
1849 | tmpname, message, user, date, branch, nodeid, p1, p2 = data |
|
1922 | haspatch = False | |
1850 |
|
1923 | for hunk in patch.split(pf): | ||
1851 | if tmpname is None: |
|
1924 | commitid = tryone(ui, hunk) | |
|
1925 | if commitid: | |||
|
1926 | haspatch = True | |||
|
1927 | if lastcommit: | |||
|
1928 | ui.status(_('applied %s\n') % lastcommit) | |||
|
1929 | lastcommit = commitid | |||
|
1930 | ||||
|
1931 | if not haspatch: | |||
1852 | raise util.Abort(_('no diffs found')) |
|
1932 | raise util.Abort(_('no diffs found')) | |
1853 |
|
1933 | |||
1854 | try: |
|
|||
1855 | cmdline_message = cmdutil.logmessage(opts) |
|
|||
1856 | if cmdline_message: |
|
|||
1857 | # pickup the cmdline msg |
|
|||
1858 | message = cmdline_message |
|
|||
1859 | elif message: |
|
|||
1860 | # pickup the patch msg |
|
|||
1861 | message = message.strip() |
|
|||
1862 | else: |
|
|||
1863 | # launch the editor |
|
|||
1864 | message = None |
|
|||
1865 | ui.debug('message:\n%s\n' % message) |
|
|||
1866 |
|
||||
1867 | wp = repo.parents() |
|
|||
1868 | if opts.get('exact'): |
|
|||
1869 | if not nodeid or not p1: |
|
|||
1870 | raise util.Abort(_('not a Mercurial patch')) |
|
|||
1871 | p1 = repo.lookup(p1) |
|
|||
1872 | p2 = repo.lookup(p2 or hex(nullid)) |
|
|||
1873 |
|
||||
1874 | if p1 != wp[0].node(): |
|
|||
1875 | hg.clean(repo, p1) |
|
|||
1876 | repo.dirstate.setparents(p1, p2) |
|
|||
1877 | elif p2: |
|
|||
1878 | try: |
|
|||
1879 | p1 = repo.lookup(p1) |
|
|||
1880 | p2 = repo.lookup(p2) |
|
|||
1881 | if p1 == wp[0].node(): |
|
|||
1882 | repo.dirstate.setparents(p1, p2) |
|
|||
1883 | except error.RepoError: |
|
|||
1884 | pass |
|
|||
1885 | if opts.get('exact') or opts.get('import_branch'): |
|
|||
1886 | repo.dirstate.setbranch(branch or 'default') |
|
|||
1887 |
|
||||
1888 | files = {} |
|
|||
1889 | try: |
|
|||
1890 | patch.patch(tmpname, ui, strip=strip, cwd=repo.root, |
|
|||
1891 | files=files, eolmode=None) |
|
|||
1892 | finally: |
|
|||
1893 | files = patch.updatedir(ui, repo, files, |
|
|||
1894 | similarity=sim / 100.0) |
|
|||
1895 | if not opts.get('no_commit'): |
|
|||
1896 | m = cmdutil.matchfiles(repo, files or []) |
|
|||
1897 | n = repo.commit(message, opts.get('user') or user, |
|
|||
1898 | opts.get('date') or date, match=m, |
|
|||
1899 | editor=cmdutil.commiteditor) |
|
|||
1900 | if opts.get('exact'): |
|
|||
1901 | if hex(n) != nodeid: |
|
|||
1902 | repo.rollback() |
|
|||
1903 | raise util.Abort(_('patch is damaged' |
|
|||
1904 | ' or loses information')) |
|
|||
1905 | # Force a dirstate write so that the next transaction |
|
|||
1906 | # backups an up-do-date file. |
|
|||
1907 | repo.dirstate.write() |
|
|||
1908 | finally: |
|
|||
1909 | os.unlink(tmpname) |
|
|||
1910 | finally: |
|
1934 | finally: | |
1911 | release(lock, wlock) |
|
1935 | release(lock, wlock) | |
1912 |
|
1936 |
@@ -41,6 +41,130 b' def copyfile(src, dst, basedir):' | |||||
41 |
|
41 | |||
42 | # public functions |
|
42 | # public functions | |
43 |
|
43 | |||
|
44 | def split(stream): | |||
|
45 | '''return an iterator of individual patches from a stream''' | |||
|
46 | def isheader(line, inheader): | |||
|
47 | if inheader and line[0] in (' ', '\t'): | |||
|
48 | # continuation | |||
|
49 | return True | |||
|
50 | l = line.split(': ', 1) | |||
|
51 | return len(l) == 2 and ' ' not in l[0] | |||
|
52 | ||||
|
53 | def chunk(lines): | |||
|
54 | return cStringIO.StringIO(''.join(lines)) | |||
|
55 | ||||
|
56 | def hgsplit(stream, cur): | |||
|
57 | inheader = True | |||
|
58 | ||||
|
59 | for line in stream: | |||
|
60 | if not line.strip(): | |||
|
61 | inheader = False | |||
|
62 | if not inheader and line.startswith('# HG changeset patch'): | |||
|
63 | yield chunk(cur) | |||
|
64 | cur = [] | |||
|
65 | inheader = True | |||
|
66 | ||||
|
67 | cur.append(line) | |||
|
68 | ||||
|
69 | if cur: | |||
|
70 | yield chunk(cur) | |||
|
71 | ||||
|
72 | def mboxsplit(stream, cur): | |||
|
73 | for line in stream: | |||
|
74 | if line.startswith('From '): | |||
|
75 | for c in split(chunk(cur[1:])): | |||
|
76 | yield c | |||
|
77 | cur = [] | |||
|
78 | ||||
|
79 | cur.append(line) | |||
|
80 | ||||
|
81 | if cur: | |||
|
82 | for c in split(chunk(cur[1:])): | |||
|
83 | yield c | |||
|
84 | ||||
|
85 | def mimesplit(stream, cur): | |||
|
86 | def msgfp(m): | |||
|
87 | fp = cStringIO.StringIO() | |||
|
88 | g = email.Generator.Generator(fp, mangle_from_=False) | |||
|
89 | g.flatten(m) | |||
|
90 | fp.seek(0) | |||
|
91 | return fp | |||
|
92 | ||||
|
93 | for line in stream: | |||
|
94 | cur.append(line) | |||
|
95 | c = chunk(cur) | |||
|
96 | ||||
|
97 | m = email.Parser.Parser().parse(c) | |||
|
98 | if not m.is_multipart(): | |||
|
99 | yield msgfp(m) | |||
|
100 | else: | |||
|
101 | ok_types = ('text/plain', 'text/x-diff', 'text/x-patch') | |||
|
102 | for part in m.walk(): | |||
|
103 | ct = part.get_content_type() | |||
|
104 | if ct not in ok_types: | |||
|
105 | continue | |||
|
106 | yield msgfp(part) | |||
|
107 | ||||
|
108 | def headersplit(stream, cur): | |||
|
109 | inheader = False | |||
|
110 | ||||
|
111 | for line in stream: | |||
|
112 | if not inheader and isheader(line, inheader): | |||
|
113 | yield chunk(cur) | |||
|
114 | cur = [] | |||
|
115 | inheader = True | |||
|
116 | if inheader and not isheader(line, inheader): | |||
|
117 | inheader = False | |||
|
118 | ||||
|
119 | cur.append(line) | |||
|
120 | ||||
|
121 | if cur: | |||
|
122 | yield chunk(cur) | |||
|
123 | ||||
|
124 | def remainder(cur): | |||
|
125 | yield chunk(cur) | |||
|
126 | ||||
|
127 | class fiter(object): | |||
|
128 | def __init__(self, fp): | |||
|
129 | self.fp = fp | |||
|
130 | ||||
|
131 | def __iter__(self): | |||
|
132 | return self | |||
|
133 | ||||
|
134 | def next(self): | |||
|
135 | l = self.fp.readline() | |||
|
136 | if not l: | |||
|
137 | raise StopIteration | |||
|
138 | return l | |||
|
139 | ||||
|
140 | inheader = False | |||
|
141 | cur = [] | |||
|
142 | ||||
|
143 | mimeheaders = ['content-type'] | |||
|
144 | ||||
|
145 | if not hasattr(stream, 'next'): | |||
|
146 | # http responses, for example, have readline but not next | |||
|
147 | stream = fiter(stream) | |||
|
148 | ||||
|
149 | for line in stream: | |||
|
150 | cur.append(line) | |||
|
151 | if line.startswith('# HG changeset patch'): | |||
|
152 | return hgsplit(stream, cur) | |||
|
153 | elif line.startswith('From '): | |||
|
154 | return mboxsplit(stream, cur) | |||
|
155 | elif isheader(line, inheader): | |||
|
156 | inheader = True | |||
|
157 | if line.split(':', 1)[0].lower() in mimeheaders: | |||
|
158 | # let email parser handle this | |||
|
159 | return mimesplit(stream, cur) | |||
|
160 | elif inheader: | |||
|
161 | # No evil headers seen, split by hand | |||
|
162 | return headersplit(stream, cur) | |||
|
163 | # Not enough info, keep reading | |||
|
164 | ||||
|
165 | # if we are here, we have a very plain patch | |||
|
166 | return remainder(cur) | |||
|
167 | ||||
44 | def extract(ui, fileobj): |
|
168 | def extract(ui, fileobj): | |
45 | '''extract patch from data read from fileobj. |
|
169 | '''extract patch from data read from fileobj. | |
46 |
|
170 |
@@ -74,6 +74,13 b' hg clone -r0 a b' | |||||
74 | hg --cwd a export tip | hg --cwd b import - |
|
74 | hg --cwd a export tip | hg --cwd b import - | |
75 | rm -r b |
|
75 | rm -r b | |
76 |
|
76 | |||
|
77 | echo % import two patches in one stream | |||
|
78 | hg init b | |||
|
79 | hg --cwd a export 0:tip | hg --cwd b import - | |||
|
80 | hg --cwd a id | |||
|
81 | hg --cwd b id | |||
|
82 | rm -r b | |||
|
83 | ||||
77 | echo % override commit message |
|
84 | echo % override commit message | |
78 | hg clone -r0 a b |
|
85 | hg clone -r0 a b | |
79 | hg --cwd a export tip | hg --cwd b import -m 'override' - |
|
86 | hg --cwd a export tip | hg --cwd b import -m 'override' - |
@@ -100,6 +100,11 b' added 1 changesets with 2 changes to 2 f' | |||||
100 | updating to branch default |
|
100 | updating to branch default | |
101 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
101 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
102 | applying patch from stdin |
|
102 | applying patch from stdin | |
|
103 | % import two patches in one stream | |||
|
104 | applying patch from stdin | |||
|
105 | applied 80971e65b431 | |||
|
106 | 1d4bd90af0e4 tip | |||
|
107 | 1d4bd90af0e4 tip | |||
103 | % override commit message |
|
108 | % override commit message | |
104 | requesting all changes |
|
109 | requesting all changes | |
105 | adding changesets |
|
110 | adding changesets | |
@@ -176,6 +181,7 b' next line' | |||||
176 | parent: 0 |
|
181 | parent: 0 | |
177 | applying ../patch1 |
|
182 | applying ../patch1 | |
178 | applying ../patch2 |
|
183 | applying ../patch2 | |
|
184 | applied 1d4bd90af0e4 | |||
179 | rolling back last transaction |
|
185 | rolling back last transaction | |
180 | parent: 1 |
|
186 | parent: 1 | |
181 | % hg import in a subdirectory |
|
187 | % hg import in a subdirectory |
General Comments 0
You need to be logged in to leave comments.
Login now