##// END OF EJS Templates
import: import each patch in a file or stream as a separate change...
Brendan Cully -
r10384:832f3538 default
parent child Browse files
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