Mercurial > hg > mercurial-crew-with-dirclash
annotate hgext/mq.py @ 2577:fa76c5d609c9
bdiff: improve worst case behavior by 100x.
on 5.8MB (244.000 lines) text file with similar lines, hash before
this change made diff against empty file take 75 seconds. this change
improves performance to 0.6 seconds. result is that clone of smallish
repo (137MB) with some files like this takes 1 minute instead of 10
minutes.
common case of diff is 10% slower now, probably because of worse cache
locality. but diff does not affect overall performance in common case
(less than 1% of runtime is in diff when it is working ok), so this
tradeoff looks good.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Fri, 07 Jul 2006 15:02:55 -0700 |
parents | 8264c2034970 |
children | 96950d39171d |
rev | line source |
---|---|
1808 | 1 # queue.py - patch queues for mercurial |
2 # | |
3 # Copyright 2005 Chris Mason <mason@suse.com> | |
4 # | |
5 # This software may be used and distributed according to the terms | |
6 # of the GNU General Public License, incorporated herein by reference. | |
7 | |
2554
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
8 '''patch management and development |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
9 |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
10 This extension lets you work with a stack of patches in a Mercurial |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
11 repository. It manages two stacks of patches - all known patches, and |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
12 applied patches (subset of known patches). |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
13 |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
14 Known patches are represented as patch files in the .hg/patches |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
15 directory. Applied patches are both patch files and changesets. |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
16 |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
17 Common tasks (use "hg help command" for more details): |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
18 |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
19 prepare repository to work with patches qinit |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
20 create new patch qnew |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
21 import existing patch qimport |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
22 |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
23 print patch series qseries |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
24 print applied patches qapplied |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
25 print name of top applied patch qtop |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
26 |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
27 add known patch to applied stack qpush |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
28 remove patch from applied stack qpop |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
29 refresh contents of top applied patch qrefresh |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
30 ''' |
8264c2034970
help: add help to mq extension
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2531
diff
changeset
|
31 |
1808 | 32 from mercurial.demandload import * |
33 demandload(globals(), "os sys re struct traceback errno bz2") | |
34 from mercurial.i18n import gettext as _ | |
35 from mercurial import ui, hg, revlog, commands, util | |
36 | |
37 versionstr = "0.45" | |
38 | |
39 repomap = {} | |
40 | |
2047
ebf1ecb5f4e8
Register qversion as a non repository related command
Edouard Gomez <ed.gomez@free.fr>
parents:
1863
diff
changeset
|
41 commands.norepo += " qversion" |
1808 | 42 class queue: |
43 def __init__(self, ui, path, patchdir=None): | |
44 self.basepath = path | |
45 if patchdir: | |
46 self.path = patchdir | |
47 else: | |
48 self.path = os.path.join(path, "patches") | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
49 self.opener = util.opener(self.path) |
1808 | 50 self.ui = ui |
51 self.applied = [] | |
52 self.full_series = [] | |
53 self.applied_dirty = 0 | |
54 self.series_dirty = 0 | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
55 self.series_path = "series" |
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
56 self.status_path = "status" |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
57 |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
58 if os.path.exists(os.path.join(self.path, self.series_path)): |
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
59 self.full_series = self.opener(self.series_path).read().splitlines() |
1808 | 60 self.read_series(self.full_series) |
61 | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
62 if os.path.exists(os.path.join(self.path, self.status_path)): |
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
63 self.applied = self.opener(self.status_path).read().splitlines() |
1808 | 64 |
65 def find_series(self, patch): | |
66 pre = re.compile("(\s*)([^#]+)") | |
67 index = 0 | |
68 for l in self.full_series: | |
69 m = pre.match(l) | |
70 if m: | |
71 s = m.group(2) | |
72 s = s.rstrip() | |
73 if s == patch: | |
74 return index | |
75 index += 1 | |
76 return None | |
77 | |
78 def read_series(self, list): | |
79 def matcher(list): | |
80 pre = re.compile("(\s*)([^#]+)") | |
81 for l in list: | |
82 m = pre.match(l) | |
83 if m: | |
84 s = m.group(2) | |
85 s = s.rstrip() | |
86 if len(s) > 0: | |
87 yield s | |
88 self.series = [] | |
89 self.series = [ x for x in matcher(list) ] | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
90 |
1808 | 91 def save_dirty(self): |
92 if self.applied_dirty: | |
93 if len(self.applied) > 0: | |
94 nl = "\n" | |
95 else: | |
96 nl = "" | |
97 f = self.opener(self.status_path, "w") | |
98 f.write("\n".join(self.applied) + nl) | |
99 if self.series_dirty: | |
100 if len(self.full_series) > 0: | |
101 nl = "\n" | |
102 else: | |
103 nl = "" | |
104 f = self.opener(self.series_path, "w") | |
105 f.write("\n".join(self.full_series) + nl) | |
106 | |
107 def readheaders(self, patch): | |
108 def eatdiff(lines): | |
109 while lines: | |
110 l = lines[-1] | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
111 if (l.startswith("diff -") or |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
112 l.startswith("Index:") or |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
113 l.startswith("===========")): |
1808 | 114 del lines[-1] |
115 else: | |
116 break | |
117 def eatempty(lines): | |
118 while lines: | |
119 l = lines[-1] | |
120 if re.match('\s*$', l): | |
121 del lines[-1] | |
122 else: | |
123 break | |
124 | |
125 pf = os.path.join(self.path, patch) | |
126 message = [] | |
127 comments = [] | |
128 user = None | |
2299
dacf718e1d48
Add timestamp field to export format. Make import and mq use it.
Danek Duvall <danek.duvall@sun.com>
parents:
2270
diff
changeset
|
129 date = None |
1808 | 130 format = None |
131 subject = None | |
132 diffstart = 0 | |
133 | |
134 for line in file(pf): | |
135 line = line.rstrip() | |
136 if diffstart: | |
137 if line.startswith('+++ '): | |
138 diffstart = 2 | |
139 break | |
140 if line.startswith("--- "): | |
141 diffstart = 1 | |
142 continue | |
143 elif format == "hgpatch": | |
144 # parse values when importing the result of an hg export | |
145 if line.startswith("# User "): | |
146 user = line[7:] | |
2300
52b9b6751b2c
Use "# Date" instead of "# Timestamp" for dated export/import of patches.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2299
diff
changeset
|
147 elif line.startswith("# Date "): |
52b9b6751b2c
Use "# Date" instead of "# Timestamp" for dated export/import of patches.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2299
diff
changeset
|
148 date = line[7:] |
1808 | 149 elif not line.startswith("# ") and line: |
150 message.append(line) | |
151 format = None | |
152 elif line == '# HG changeset patch': | |
153 format = "hgpatch" | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
154 elif (format != "tagdone" and (line.startswith("Subject: ") or |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
155 line.startswith("subject: "))): |
1808 | 156 subject = line[9:] |
157 format = "tag" | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
158 elif (format != "tagdone" and (line.startswith("From: ") or |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
159 line.startswith("from: "))): |
1808 | 160 user = line[6:] |
161 format = "tag" | |
162 elif format == "tag" and line == "": | |
163 # when looking for tags (subject: from: etc) they | |
164 # end once you find a blank line in the source | |
165 format = "tagdone" | |
2301
7c2623aedeb4
Strip empty lines and trailing spaces around commit messages.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2300
diff
changeset
|
166 elif message or line: |
1808 | 167 message.append(line) |
168 comments.append(line) | |
169 | |
170 eatdiff(message) | |
171 eatdiff(comments) | |
172 eatempty(message) | |
173 eatempty(comments) | |
174 | |
175 # make sure message isn't empty | |
176 if format and format.startswith("tag") and subject: | |
177 message.insert(0, "") | |
178 message.insert(0, subject) | |
2299
dacf718e1d48
Add timestamp field to export format. Make import and mq use it.
Danek Duvall <danek.duvall@sun.com>
parents:
2270
diff
changeset
|
179 return (message, comments, user, date, diffstart > 1) |
1808 | 180 |
181 def mergeone(self, repo, mergeq, head, patch, rev, wlock): | |
182 # first try just applying the patch | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
183 (err, n) = self.apply(repo, [ patch ], update_status=False, |
1808 | 184 strict=True, merge=rev, wlock=wlock) |
185 | |
186 if err == 0: | |
187 return (err, n) | |
188 | |
189 if n is None: | |
190 self.ui.warn("apply failed for patch %s\n" % patch) | |
191 sys.exit(1) | |
192 | |
193 self.ui.warn("patch didn't work out, merging %s\n" % patch) | |
194 | |
195 # apply failed, strip away that rev and merge. | |
196 repo.update(head, allow=False, force=True, wlock=wlock) | |
197 self.strip(repo, n, update=False, backup='strip', wlock=wlock) | |
198 | |
199 c = repo.changelog.read(rev) | |
200 ret = repo.update(rev, allow=True, wlock=wlock) | |
201 if ret: | |
202 self.ui.warn("update returned %d\n" % ret) | |
203 sys.exit(1) | |
204 n = repo.commit(None, c[4], c[1], force=1, wlock=wlock) | |
205 if n == None: | |
206 self.ui.warn("repo commit failed\n") | |
207 sys.exit(1) | |
208 try: | |
2299
dacf718e1d48
Add timestamp field to export format. Make import and mq use it.
Danek Duvall <danek.duvall@sun.com>
parents:
2270
diff
changeset
|
209 message, comments, user, date, patchfound = mergeq.readheaders(patch) |
1808 | 210 except: |
211 self.ui.warn("Unable to read %s\n" % patch) | |
212 sys.exit(1) | |
213 | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
214 patchf = self.opener(patch, "w") |
1808 | 215 if comments: |
216 comments = "\n".join(comments) + '\n\n' | |
217 patchf.write(comments) | |
218 commands.dodiff(patchf, self.ui, repo, head, n) | |
219 patchf.close() | |
220 return (0, n) | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
221 |
1808 | 222 def qparents(self, repo, rev=None): |
223 if rev is None: | |
224 (p1, p2) = repo.dirstate.parents() | |
225 if p2 == revlog.nullid: | |
226 return p1 | |
227 if len(self.applied) == 0: | |
228 return None | |
229 (top, patch) = self.applied[-1].split(':') | |
230 top = revlog.bin(top) | |
231 return top | |
232 pp = repo.changelog.parents(rev) | |
233 if pp[1] != revlog.nullid: | |
234 arevs = [ x.split(':')[0] for x in self.applied ] | |
235 p0 = revlog.hex(pp[0]) | |
236 p1 = revlog.hex(pp[1]) | |
237 if p0 in arevs: | |
238 return pp[0] | |
239 if p1 in arevs: | |
240 return pp[1] | |
241 return pp[0] | |
242 | |
243 def mergepatch(self, repo, mergeq, series, wlock): | |
244 if len(self.applied) == 0: | |
245 # each of the patches merged in will have two parents. This | |
246 # can confuse the qrefresh, qdiff, and strip code because it | |
247 # needs to know which parent is actually in the patch queue. | |
248 # so, we insert a merge marker with only one parent. This way | |
249 # the first patch in the queue is never a merge patch | |
250 # | |
251 pname = ".hg.patches.merge.marker" | |
252 n = repo.commit(None, '[mq]: merge marker', user=None, force=1, | |
253 wlock=wlock) | |
254 self.applied.append(revlog.hex(n) + ":" + pname) | |
255 self.applied_dirty = 1 | |
256 | |
257 head = self.qparents(repo) | |
258 | |
259 for patch in series: | |
260 patch = mergeq.lookup(patch) | |
261 if not patch: | |
262 self.ui.warn("patch %s does not exist\n" % patch) | |
263 return (1, None) | |
264 | |
265 info = mergeq.isapplied(patch) | |
266 if not info: | |
267 self.ui.warn("patch %s is not applied\n" % patch) | |
268 return (1, None) | |
269 rev = revlog.bin(info[1]) | |
270 (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock) | |
271 if head: | |
272 self.applied.append(revlog.hex(head) + ":" + patch) | |
273 self.applied_dirty = 1 | |
274 if err: | |
275 return (err, head) | |
276 return (0, head) | |
277 | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
278 def apply(self, repo, series, list=False, update_status=True, |
1808 | 279 strict=False, patchdir=None, merge=None, wlock=None): |
280 # TODO unify with commands.py | |
281 if not patchdir: | |
282 patchdir = self.path | |
283 pwd = os.getcwd() | |
284 os.chdir(repo.root) | |
285 err = 0 | |
286 if not wlock: | |
287 wlock = repo.wlock() | |
288 lock = repo.lock() | |
289 tr = repo.transaction() | |
290 n = None | |
291 for patch in series: | |
292 self.ui.warn("applying %s\n" % patch) | |
293 pf = os.path.join(patchdir, patch) | |
294 | |
295 try: | |
2299
dacf718e1d48
Add timestamp field to export format. Make import and mq use it.
Danek Duvall <danek.duvall@sun.com>
parents:
2270
diff
changeset
|
296 message, comments, user, date, patchfound = self.readheaders(patch) |
1808 | 297 except: |
298 self.ui.warn("Unable to read %s\n" % pf) | |
299 err = 1 | |
300 break | |
301 | |
302 if not message: | |
303 message = "imported patch %s\n" % patch | |
304 else: | |
305 if list: | |
306 message.append("\nimported patch %s" % patch) | |
307 message = '\n'.join(message) | |
308 | |
309 try: | |
2270
afd7c4ec000f
Fix issue240: mq: qpush fails on Solaris
Danek Duvall <danek.duvall@sun.com>
parents:
2185
diff
changeset
|
310 pp = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch') |
afd7c4ec000f
Fix issue240: mq: qpush fails on Solaris
Danek Duvall <danek.duvall@sun.com>
parents:
2185
diff
changeset
|
311 f = os.popen("%s -p1 --no-backup-if-mismatch < '%s'" % (pp, pf)) |
1808 | 312 except: |
313 self.ui.warn("patch failed, unable to continue (try -v)\n") | |
314 err = 1 | |
315 break | |
316 files = [] | |
317 fuzz = False | |
318 for l in f: | |
319 l = l.rstrip('\r\n'); | |
320 if self.ui.verbose: | |
321 self.ui.warn(l + "\n") | |
322 if l[:14] == 'patching file ': | |
323 pf = os.path.normpath(l[14:]) | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
324 # when patch finds a space in the file name, it puts |
1808 | 325 # single quotes around the filename. strip them off |
326 if pf[0] == "'" and pf[-1] == "'": | |
327 pf = pf[1:-1] | |
328 if pf not in files: | |
329 files.append(pf) | |
330 printed_file = False | |
331 file_str = l | |
332 elif l.find('with fuzz') >= 0: | |
333 if not printed_file: | |
334 self.ui.warn(file_str + '\n') | |
335 printed_file = True | |
336 self.ui.warn(l + '\n') | |
337 fuzz = True | |
338 elif l.find('saving rejects to file') >= 0: | |
339 self.ui.warn(l + '\n') | |
340 elif l.find('FAILED') >= 0: | |
341 if not printed_file: | |
342 self.ui.warn(file_str + '\n') | |
343 printed_file = True | |
344 self.ui.warn(l + '\n') | |
345 patcherr = f.close() | |
346 | |
347 if merge and len(files) > 0: | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
348 # Mark as merged and update dirstate parent info |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
349 repo.dirstate.update(repo.dirstate.filterfiles(files), 'm') |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
350 p1, p2 = repo.dirstate.parents() |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
351 repo.dirstate.setparents(p1, merge) |
1808 | 352 if len(files) > 0: |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
353 commands.addremove_lock(self.ui, repo, files, |
1808 | 354 opts={}, wlock=wlock) |
2299
dacf718e1d48
Add timestamp field to export format. Make import and mq use it.
Danek Duvall <danek.duvall@sun.com>
parents:
2270
diff
changeset
|
355 n = repo.commit(files, message, user, date, force=1, lock=lock, |
1808 | 356 wlock=wlock) |
357 | |
358 if n == None: | |
359 self.ui.warn("repo commit failed\n") | |
360 sys.exit(1) | |
361 | |
362 if update_status: | |
363 self.applied.append(revlog.hex(n) + ":" + patch) | |
364 | |
365 if patcherr: | |
366 if not patchfound: | |
367 self.ui.warn("patch %s is empty\n" % patch) | |
368 err = 0 | |
369 else: | |
370 self.ui.warn("patch failed, rejects left in working dir\n") | |
371 err = 1 | |
372 break | |
373 | |
374 if fuzz and strict: | |
375 self.ui.warn("fuzz found when applying patch, stopping\n") | |
376 err = 1 | |
377 break | |
378 tr.close() | |
379 os.chdir(pwd) | |
380 return (err, n) | |
381 | |
382 def delete(self, repo, patch): | |
383 patch = self.lookup(patch) | |
384 info = self.isapplied(patch) | |
385 if info: | |
386 self.ui.warn("cannot delete applied patch %s\n" % patch) | |
387 sys.exit(1) | |
388 if patch not in self.series: | |
389 self.ui.warn("patch %s not in series file\n" % patch) | |
390 sys.exit(1) | |
391 i = self.find_series(patch) | |
392 del self.full_series[i] | |
393 self.read_series(self.full_series) | |
394 self.series_dirty = 1 | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
395 |
1808 | 396 def check_toppatch(self, repo): |
397 if len(self.applied) > 0: | |
398 (top, patch) = self.applied[-1].split(':') | |
399 top = revlog.bin(top) | |
400 pp = repo.dirstate.parents() | |
401 if top not in pp: | |
402 self.ui.warn("queue top not at dirstate parents. top %s dirstate %s %s\n" %( revlog.short(top), revlog.short(pp[0]), revlog.short(pp[1]))) | |
403 sys.exit(1) | |
404 return top | |
405 return None | |
406 def check_localchanges(self, repo): | |
407 (c, a, r, d, u) = repo.changes(None, None) | |
408 if c or a or d or r: | |
409 self.ui.write("Local changes found, refresh first\n") | |
410 sys.exit(1) | |
411 def new(self, repo, patch, msg=None, force=None): | |
2511
041d8f0a8437
mq: hg qnew -f should refresh the new patch
Chris Mason <mason@suse.com>
parents:
2488
diff
changeset
|
412 commitfiles = [] |
041d8f0a8437
mq: hg qnew -f should refresh the new patch
Chris Mason <mason@suse.com>
parents:
2488
diff
changeset
|
413 (c, a, r, d, u) = repo.changes(None, None) |
041d8f0a8437
mq: hg qnew -f should refresh the new patch
Chris Mason <mason@suse.com>
parents:
2488
diff
changeset
|
414 if c or a or d or r: |
041d8f0a8437
mq: hg qnew -f should refresh the new patch
Chris Mason <mason@suse.com>
parents:
2488
diff
changeset
|
415 if not force: |
041d8f0a8437
mq: hg qnew -f should refresh the new patch
Chris Mason <mason@suse.com>
parents:
2488
diff
changeset
|
416 raise util.Abort(_("Local changes found, refresh first")) |
041d8f0a8437
mq: hg qnew -f should refresh the new patch
Chris Mason <mason@suse.com>
parents:
2488
diff
changeset
|
417 else: |
041d8f0a8437
mq: hg qnew -f should refresh the new patch
Chris Mason <mason@suse.com>
parents:
2488
diff
changeset
|
418 commitfiles = c + a + r |
1808 | 419 self.check_toppatch(repo) |
420 wlock = repo.wlock() | |
421 insert = self.series_end() | |
422 if msg: | |
2511
041d8f0a8437
mq: hg qnew -f should refresh the new patch
Chris Mason <mason@suse.com>
parents:
2488
diff
changeset
|
423 n = repo.commit(commitfiles, "[mq]: %s" % msg, force=True, |
041d8f0a8437
mq: hg qnew -f should refresh the new patch
Chris Mason <mason@suse.com>
parents:
2488
diff
changeset
|
424 wlock=wlock) |
1808 | 425 else: |
2511
041d8f0a8437
mq: hg qnew -f should refresh the new patch
Chris Mason <mason@suse.com>
parents:
2488
diff
changeset
|
426 n = repo.commit(commitfiles, |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
427 "New patch: %s" % patch, force=True, wlock=wlock) |
1808 | 428 if n == None: |
429 self.ui.warn("repo commit failed\n") | |
430 sys.exit(1) | |
431 self.full_series[insert:insert] = [patch] | |
432 self.applied.append(revlog.hex(n) + ":" + patch) | |
433 self.read_series(self.full_series) | |
434 self.series_dirty = 1 | |
435 self.applied_dirty = 1 | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
436 p = self.opener(patch, "w") |
1808 | 437 if msg: |
438 msg = msg + "\n" | |
439 p.write(msg) | |
440 p.close() | |
441 wlock = None | |
442 r = self.qrepo() | |
443 if r: r.add([patch]) | |
2511
041d8f0a8437
mq: hg qnew -f should refresh the new patch
Chris Mason <mason@suse.com>
parents:
2488
diff
changeset
|
444 if commitfiles: |
041d8f0a8437
mq: hg qnew -f should refresh the new patch
Chris Mason <mason@suse.com>
parents:
2488
diff
changeset
|
445 self.refresh(repo, short=True) |
1808 | 446 |
447 def strip(self, repo, rev, update=True, backup="all", wlock=None): | |
448 def limitheads(chlog, stop): | |
449 """return the list of all nodes that have no children""" | |
450 p = {} | |
451 h = [] | |
452 stoprev = 0 | |
453 if stop in chlog.nodemap: | |
454 stoprev = chlog.rev(stop) | |
455 | |
456 for r in range(chlog.count() - 1, -1, -1): | |
457 n = chlog.node(r) | |
458 if n not in p: | |
459 h.append(n) | |
460 if n == stop: | |
461 break | |
462 if r < stoprev: | |
463 break | |
464 for pn in chlog.parents(n): | |
465 p[pn] = 1 | |
466 return h | |
467 | |
468 def bundle(cg): | |
469 backupdir = repo.join("strip-backup") | |
470 if not os.path.isdir(backupdir): | |
471 os.mkdir(backupdir) | |
472 name = os.path.join(backupdir, "%s" % revlog.short(rev)) | |
473 name = savename(name) | |
474 self.ui.warn("saving bundle to %s\n" % name) | |
475 # TODO, exclusive open | |
476 f = open(name, "wb") | |
477 try: | |
478 f.write("HG10") | |
479 z = bz2.BZ2Compressor(9) | |
480 while 1: | |
481 chunk = cg.read(4096) | |
482 if not chunk: | |
483 break | |
484 f.write(z.compress(chunk)) | |
485 f.write(z.flush()) | |
486 except: | |
487 os.unlink(name) | |
488 raise | |
489 f.close() | |
490 return name | |
491 | |
492 def stripall(rev, revnum): | |
493 cl = repo.changelog | |
494 c = cl.read(rev) | |
495 mm = repo.manifest.read(c[0]) | |
496 seen = {} | |
497 | |
498 for x in xrange(revnum, cl.count()): | |
499 c = cl.read(cl.node(x)) | |
500 for f in c[3]: | |
501 if f in seen: | |
502 continue | |
503 seen[f] = 1 | |
504 if f in mm: | |
505 filerev = mm[f] | |
506 else: | |
507 filerev = 0 | |
508 seen[f] = filerev | |
509 # we go in two steps here so the strip loop happens in a | |
510 # sensible order. When stripping many files, this helps keep | |
511 # our disk access patterns under control. | |
512 list = seen.keys() | |
513 list.sort() | |
514 for f in list: | |
515 ff = repo.file(f) | |
516 filerev = seen[f] | |
517 if filerev != 0: | |
518 if filerev in ff.nodemap: | |
519 filerev = ff.rev(filerev) | |
520 else: | |
521 filerev = 0 | |
522 ff.strip(filerev, revnum) | |
523 | |
524 if not wlock: | |
525 wlock = repo.wlock() | |
526 lock = repo.lock() | |
527 chlog = repo.changelog | |
528 # TODO delete the undo files, and handle undo of merge sets | |
529 pp = chlog.parents(rev) | |
530 revnum = chlog.rev(rev) | |
531 | |
532 if update: | |
533 urev = self.qparents(repo, rev) | |
534 repo.update(urev, allow=False, force=True, wlock=wlock) | |
535 repo.dirstate.write() | |
536 | |
537 # save is a list of all the branches we are truncating away | |
538 # that we actually want to keep. changegroup will be used | |
539 # to preserve them and add them back after the truncate | |
540 saveheads = [] | |
541 savebases = {} | |
542 | |
543 tip = chlog.tip() | |
544 heads = limitheads(chlog, rev) | |
545 seen = {} | |
546 | |
547 # search through all the heads, finding those where the revision | |
548 # we want to strip away is an ancestor. Also look for merges | |
549 # that might be turned into new heads by the strip. | |
550 while heads: | |
551 h = heads.pop() | |
552 n = h | |
553 while True: | |
554 seen[n] = 1 | |
555 pp = chlog.parents(n) | |
556 if pp[1] != revlog.nullid and chlog.rev(pp[1]) > revnum: | |
557 if pp[1] not in seen: | |
558 heads.append(pp[1]) | |
559 if pp[0] == revlog.nullid: | |
560 break | |
561 if chlog.rev(pp[0]) < revnum: | |
562 break | |
563 n = pp[0] | |
564 if n == rev: | |
565 break | |
566 r = chlog.reachable(h, rev) | |
567 if rev not in r: | |
568 saveheads.append(h) | |
569 for x in r: | |
570 if chlog.rev(x) > revnum: | |
571 savebases[x] = 1 | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
572 |
1808 | 573 # create a changegroup for all the branches we need to keep |
574 if backup is "all": | |
575 backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip') | |
576 bundle(backupch) | |
577 if saveheads: | |
578 backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip') | |
579 chgrpfile = bundle(backupch) | |
580 | |
581 stripall(rev, revnum) | |
582 | |
583 change = chlog.read(rev) | |
584 repo.manifest.strip(repo.manifest.rev(change[0]), revnum) | |
585 chlog.strip(revnum, revnum) | |
586 if saveheads: | |
587 self.ui.status("adding branch\n") | |
588 commands.unbundle(self.ui, repo, chgrpfile, update=False) | |
589 if backup is not "strip": | |
590 os.unlink(chgrpfile) | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
591 |
1808 | 592 def isapplied(self, patch): |
593 """returns (index, rev, patch)""" | |
594 for i in xrange(len(self.applied)): | |
595 p = self.applied[i] | |
596 a = p.split(':') | |
597 if a[1] == patch: | |
598 return (i, a[0], a[1]) | |
599 return None | |
600 | |
601 def lookup(self, patch): | |
602 if patch == None: | |
603 return None | |
604 if patch in self.series: | |
605 return patch | |
606 if not os.path.isfile(os.path.join(self.path, patch)): | |
607 try: | |
608 sno = int(patch) | |
609 except(ValueError, OverflowError): | |
610 self.ui.warn("patch %s not in series\n" % patch) | |
611 sys.exit(1) | |
612 if sno >= len(self.series): | |
613 self.ui.warn("patch number %d is out of range\n" % sno) | |
614 sys.exit(1) | |
615 patch = self.series[sno] | |
616 else: | |
617 self.ui.warn("patch %s not in series\n" % patch) | |
618 sys.exit(1) | |
619 return patch | |
620 | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
621 def push(self, repo, patch=None, force=False, list=False, |
1808 | 622 mergeq=None, wlock=None): |
623 if not wlock: | |
624 wlock = repo.wlock() | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
625 patch = self.lookup(patch) |
1808 | 626 if patch and self.isapplied(patch): |
627 self.ui.warn("patch %s is already applied\n" % patch) | |
628 sys.exit(1) | |
629 if self.series_end() == len(self.series): | |
630 self.ui.warn("File series fully applied\n") | |
631 sys.exit(1) | |
632 if not force: | |
633 self.check_localchanges(repo) | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
634 |
1808 | 635 self.applied_dirty = 1; |
636 start = self.series_end() | |
637 if start > 0: | |
638 self.check_toppatch(repo) | |
639 if not patch: | |
640 patch = self.series[start] | |
641 end = start + 1 | |
642 else: | |
643 end = self.series.index(patch, start) + 1 | |
644 s = self.series[start:end] | |
645 if mergeq: | |
646 ret = self.mergepatch(repo, mergeq, s, wlock) | |
647 else: | |
648 ret = self.apply(repo, s, list, wlock=wlock) | |
649 top = self.applied[-1].split(':')[1] | |
650 if ret[0]: | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
651 self.ui.write("Errors during apply, please fix and refresh %s\n" % |
1808 | 652 top) |
653 else: | |
654 self.ui.write("Now at: %s\n" % top) | |
655 return ret[0] | |
656 | |
657 def pop(self, repo, patch=None, force=False, update=True, wlock=None): | |
658 def getfile(f, rev): | |
659 t = repo.file(f).read(rev) | |
660 try: | |
661 repo.wfile(f, "w").write(t) | |
662 except IOError: | |
2086
8742352db413
mq: do not fail if directory to create exists
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2047
diff
changeset
|
663 try: |
8742352db413
mq: do not fail if directory to create exists
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2047
diff
changeset
|
664 os.makedirs(os.path.dirname(repo.wjoin(f))) |
8742352db413
mq: do not fail if directory to create exists
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2047
diff
changeset
|
665 except OSError, err: |
8742352db413
mq: do not fail if directory to create exists
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2047
diff
changeset
|
666 if err.errno != errno.EEXIST: raise |
1808 | 667 repo.wfile(f, "w").write(t) |
668 | |
669 if not wlock: | |
670 wlock = repo.wlock() | |
671 if patch: | |
672 # index, rev, patch | |
673 info = self.isapplied(patch) | |
674 if not info: | |
675 patch = self.lookup(patch) | |
676 info = self.isapplied(patch) | |
677 if not info: | |
678 self.ui.warn("patch %s is not applied\n" % patch) | |
679 sys.exit(1) | |
680 if len(self.applied) == 0: | |
681 self.ui.warn("No patches applied\n") | |
682 sys.exit(1) | |
683 | |
684 if not update: | |
685 parents = repo.dirstate.parents() | |
686 rr = [ revlog.bin(x.split(':')[0]) for x in self.applied ] | |
687 for p in parents: | |
688 if p in rr: | |
689 self.ui.warn("qpop: forcing dirstate update\n") | |
690 update = True | |
691 | |
692 if not force and update: | |
693 self.check_localchanges(repo) | |
694 | |
695 self.applied_dirty = 1; | |
696 end = len(self.applied) | |
697 if not patch: | |
698 info = [len(self.applied) - 1] + self.applied[-1].split(':') | |
699 start = info[0] | |
700 rev = revlog.bin(info[1]) | |
701 | |
702 # we know there are no local changes, so we can make a simplified | |
703 # form of hg.update. | |
704 if update: | |
705 top = self.check_toppatch(repo) | |
706 qp = self.qparents(repo, rev) | |
707 changes = repo.changelog.read(qp) | |
708 mf1 = repo.manifest.readflags(changes[0]) | |
709 mmap = repo.manifest.read(changes[0]) | |
710 (c, a, r, d, u) = repo.changes(qp, top) | |
711 if d: | |
712 raise util.Abort("deletions found between repo revs") | |
713 for f in c: | |
714 getfile(f, mmap[f]) | |
715 for f in r: | |
716 getfile(f, mmap[f]) | |
717 util.set_exec(repo.wjoin(f), mf1[f]) | |
718 repo.dirstate.update(c + r, 'n') | |
719 for f in a: | |
720 try: os.unlink(repo.wjoin(f)) | |
721 except: raise | |
722 try: os.removedirs(os.path.dirname(repo.wjoin(f))) | |
723 except: pass | |
724 if a: | |
725 repo.dirstate.forget(a) | |
726 repo.dirstate.setparents(qp, revlog.nullid) | |
727 self.strip(repo, rev, update=False, backup='strip', wlock=wlock) | |
728 del self.applied[start:end] | |
729 if len(self.applied): | |
730 self.ui.write("Now at: %s\n" % self.applied[-1].split(':')[1]) | |
731 else: | |
732 self.ui.write("Patch queue now empty\n") | |
733 | |
734 def diff(self, repo, files): | |
735 top = self.check_toppatch(repo) | |
736 if not top: | |
737 self.ui.write("No patches applied\n") | |
738 return | |
739 qp = self.qparents(repo, top) | |
740 commands.dodiff(sys.stdout, self.ui, repo, qp, None, files) | |
741 | |
742 def refresh(self, repo, short=False): | |
743 if len(self.applied) == 0: | |
744 self.ui.write("No patches applied\n") | |
745 return | |
746 wlock = repo.wlock() | |
747 self.check_toppatch(repo) | |
748 qp = self.qparents(repo) | |
749 (top, patch) = self.applied[-1].split(':') | |
750 top = revlog.bin(top) | |
751 cparents = repo.changelog.parents(top) | |
752 patchparent = self.qparents(repo, top) | |
2299
dacf718e1d48
Add timestamp field to export format. Make import and mq use it.
Danek Duvall <danek.duvall@sun.com>
parents:
2270
diff
changeset
|
753 message, comments, user, date, patchfound = self.readheaders(patch) |
1808 | 754 |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
755 patchf = self.opener(patch, "w") |
1808 | 756 if comments: |
757 comments = "\n".join(comments) + '\n\n' | |
758 patchf.write(comments) | |
759 | |
760 tip = repo.changelog.tip() | |
761 if top == tip: | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
762 # if the top of our patch queue is also the tip, there is an |
1808 | 763 # optimization here. We update the dirstate in place and strip |
764 # off the tip commit. Then just commit the current directory | |
765 # tree. We can also send repo.commit the list of files | |
766 # changed to speed up the diff | |
767 # | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
768 # in short mode, we only diff the files included in the |
1808 | 769 # patch already |
770 # | |
771 # this should really read: | |
772 #(cc, dd, aa, aa2, uu) = repo.changes(tip, patchparent) | |
773 # but we do it backwards to take advantage of manifest/chlog | |
774 # caching against the next repo.changes call | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
775 # |
1808 | 776 (cc, aa, dd, aa2, uu) = repo.changes(patchparent, tip) |
777 if short: | |
778 filelist = cc + aa + dd | |
779 else: | |
780 filelist = None | |
781 (c, a, r, d, u) = repo.changes(None, None, filelist) | |
782 | |
783 # we might end up with files that were added between tip and | |
784 # the dirstate parent, but then changed in the local dirstate. | |
785 # in this case, we want them to only show up in the added section | |
786 for x in c: | |
787 if x not in aa: | |
788 cc.append(x) | |
789 # we might end up with files added by the local dirstate that | |
790 # were deleted by the patch. In this case, they should only | |
791 # show up in the changed section. | |
792 for x in a: | |
793 if x in dd: | |
794 del dd[dd.index(x)] | |
795 cc.append(x) | |
796 else: | |
797 aa.append(x) | |
798 # make sure any files deleted in the local dirstate | |
799 # are not in the add or change column of the patch | |
800 forget = [] | |
801 for x in d + r: | |
802 if x in aa: | |
803 del aa[aa.index(x)] | |
804 forget.append(x) | |
805 continue | |
806 elif x in cc: | |
807 del cc[cc.index(x)] | |
808 dd.append(x) | |
809 | |
810 c = list(util.unique(cc)) | |
811 r = list(util.unique(dd)) | |
812 a = list(util.unique(aa)) | |
813 filelist = list(util.unique(c + r + a )) | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
814 commands.dodiff(patchf, self.ui, repo, patchparent, None, |
1808 | 815 filelist, changes=(c, a, r, [], u)) |
816 patchf.close() | |
817 | |
818 changes = repo.changelog.read(tip) | |
819 repo.dirstate.setparents(*cparents) | |
820 repo.dirstate.update(a, 'a') | |
821 repo.dirstate.update(r, 'r') | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
822 repo.dirstate.update(c, 'n') |
1808 | 823 repo.dirstate.forget(forget) |
824 | |
825 if not message: | |
826 message = "patch queue: %s\n" % patch | |
827 else: | |
828 message = "\n".join(message) | |
829 self.strip(repo, top, update=False, backup='strip', wlock=wlock) | |
830 n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock) | |
831 self.applied[-1] = revlog.hex(n) + ':' + patch | |
832 self.applied_dirty = 1 | |
833 else: | |
834 commands.dodiff(patchf, self.ui, repo, patchparent, None) | |
835 patchf.close() | |
836 self.pop(repo, force=True, wlock=wlock) | |
837 self.push(repo, force=True, wlock=wlock) | |
838 | |
839 def init(self, repo, create=False): | |
840 if os.path.isdir(self.path): | |
841 raise util.Abort("patch queue directory already exists") | |
842 os.mkdir(self.path) | |
843 if create: | |
844 return self.qrepo(create=True) | |
845 | |
846 def unapplied(self, repo, patch=None): | |
847 if patch and patch not in self.series: | |
848 self.ui.warn("%s not in the series file\n" % patch) | |
849 sys.exit(1) | |
850 if not patch: | |
851 start = self.series_end() | |
852 else: | |
853 start = self.series.index(patch) + 1 | |
854 for p in self.series[start:]: | |
855 self.ui.write("%s\n" % p) | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
856 |
1808 | 857 def qseries(self, repo, missing=None): |
858 start = self.series_end() | |
859 if not missing: | |
860 for p in self.series[:start]: | |
861 if self.ui.verbose: | |
862 self.ui.write("%d A " % self.series.index(p)) | |
863 self.ui.write("%s\n" % p) | |
864 for p in self.series[start:]: | |
865 if self.ui.verbose: | |
866 self.ui.write("%d U " % self.series.index(p)) | |
867 self.ui.write("%s\n" % p) | |
868 else: | |
869 list = [] | |
870 for root, dirs, files in os.walk(self.path): | |
871 d = root[len(self.path) + 1:] | |
872 for f in files: | |
873 fl = os.path.join(d, f) | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
874 if (fl not in self.series and |
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
875 fl not in (self.status_path, self.series_path) |
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
876 and not fl.startswith('.')): |
1808 | 877 list.append(fl) |
878 list.sort() | |
879 if list: | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
880 for x in list: |
1808 | 881 if self.ui.verbose: |
882 self.ui.write("D ") | |
883 self.ui.write("%s\n" % x) | |
884 | |
885 def issaveline(self, l): | |
886 name = l.split(':')[1] | |
887 if name == '.hg.patches.save.line': | |
888 return True | |
889 | |
890 def qrepo(self, create=False): | |
891 if create or os.path.isdir(os.path.join(self.path, ".hg")): | |
1839
876e4e6ad82b
Create local ui object per repository, so .hg/hgrc don't get mixed.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1810
diff
changeset
|
892 return hg.repository(self.ui, path=self.path, create=create) |
1808 | 893 |
894 def restore(self, repo, rev, delete=None, qupdate=None): | |
895 c = repo.changelog.read(rev) | |
896 desc = c[4].strip() | |
897 lines = desc.splitlines() | |
898 i = 0 | |
899 datastart = None | |
900 series = [] | |
901 applied = [] | |
902 qpp = None | |
903 for i in xrange(0, len(lines)): | |
904 if lines[i] == 'Patch Data:': | |
905 datastart = i + 1 | |
906 elif lines[i].startswith('Dirstate:'): | |
907 l = lines[i].rstrip() | |
908 l = l[10:].split(' ') | |
909 qpp = [ hg.bin(x) for x in l ] | |
910 elif datastart != None: | |
911 l = lines[i].rstrip() | |
912 index = l.index(':') | |
913 id = l[:index] | |
914 file = l[index + 1:] | |
915 if id: | |
916 applied.append(l) | |
917 series.append(file) | |
918 if datastart == None: | |
919 self.ui.warn("No saved patch data found\n") | |
920 return 1 | |
921 self.ui.warn("restoring status: %s\n" % lines[0]) | |
922 self.full_series = series | |
923 self.applied = applied | |
924 self.read_series(self.full_series) | |
925 self.series_dirty = 1 | |
926 self.applied_dirty = 1 | |
927 heads = repo.changelog.heads() | |
928 if delete: | |
929 if rev not in heads: | |
930 self.ui.warn("save entry has children, leaving it alone\n") | |
931 else: | |
932 self.ui.warn("removing save entry %s\n" % hg.short(rev)) | |
933 pp = repo.dirstate.parents() | |
934 if rev in pp: | |
935 update = True | |
936 else: | |
937 update = False | |
938 self.strip(repo, rev, update=update, backup='strip') | |
939 if qpp: | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
940 self.ui.warn("saved queue repository parents: %s %s\n" % |
1808 | 941 (hg.short(qpp[0]), hg.short(qpp[1]))) |
942 if qupdate: | |
943 print "queue directory updating" | |
944 r = self.qrepo() | |
945 if not r: | |
946 self.ui.warn("Unable to load queue repository\n") | |
947 return 1 | |
948 r.update(qpp[0], allow=False, force=True) | |
949 | |
950 def save(self, repo, msg=None): | |
951 if len(self.applied) == 0: | |
952 self.ui.warn("save: no patches applied, exiting\n") | |
953 return 1 | |
954 if self.issaveline(self.applied[-1]): | |
955 self.ui.warn("status is already saved\n") | |
956 return 1 | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
957 |
1808 | 958 ar = [ ':' + x for x in self.full_series ] |
959 if not msg: | |
960 msg = "hg patches saved state" | |
961 else: | |
962 msg = "hg patches: " + msg.rstrip('\r\n') | |
963 r = self.qrepo() | |
964 if r: | |
965 pp = r.dirstate.parents() | |
966 msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1])) | |
967 msg += "\n\nPatch Data:\n" | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
968 text = msg + "\n".join(self.applied) + '\n' + (ar and "\n".join(ar) |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
969 + '\n' or "") |
1808 | 970 n = repo.commit(None, text, user=None, force=1) |
971 if not n: | |
972 self.ui.warn("repo commit failed\n") | |
973 return 1 | |
974 self.applied.append(revlog.hex(n) + ":" + '.hg.patches.save.line') | |
975 self.applied_dirty = 1 | |
976 | |
977 def series_end(self): | |
978 end = 0 | |
979 if len(self.applied) > 0: | |
980 (top, p) = self.applied[-1].split(':') | |
981 try: | |
982 end = self.series.index(p) | |
983 except ValueError: | |
984 return 0 | |
985 return end + 1 | |
986 return end | |
987 | |
988 def qapplied(self, repo, patch=None): | |
989 if patch and patch not in self.series: | |
990 self.ui.warn("%s not in the series file\n" % patch) | |
991 sys.exit(1) | |
992 if not patch: | |
993 end = len(self.applied) | |
994 else: | |
995 end = self.series.index(patch) + 1 | |
996 for x in xrange(end): | |
997 p = self.appliedname(x) | |
998 self.ui.write("%s\n" % p) | |
999 | |
1000 def appliedname(self, index): | |
1001 p = self.applied[index] | |
1002 if not self.ui.verbose: | |
1003 p = p.split(':')[1] | |
1004 return p | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1005 |
1808 | 1006 def top(self, repo): |
1007 if len(self.applied): | |
1008 p = self.appliedname(-1) | |
1009 self.ui.write(p + '\n') | |
1010 else: | |
1011 self.ui.write("No patches applied\n") | |
1012 | |
1013 def next(self, repo): | |
1014 end = self.series_end() | |
1015 if end == len(self.series): | |
1016 self.ui.write("All patches applied\n") | |
1017 else: | |
1018 self.ui.write(self.series[end] + '\n') | |
1019 | |
1020 def prev(self, repo): | |
1021 if len(self.applied) > 1: | |
1022 p = self.appliedname(-2) | |
1023 self.ui.write(p + '\n') | |
1024 elif len(self.applied) == 1: | |
1025 self.ui.write("Only one patch applied\n") | |
1026 else: | |
1027 self.ui.write("No patches applied\n") | |
1028 | |
1029 def qimport(self, repo, files, patch=None, existing=None, force=None): | |
1030 if len(files) > 1 and patch: | |
1031 self.ui.warn("-n option not valid when importing multiple files\n") | |
1032 sys.exit(1) | |
1033 i = 0 | |
2488
2785aeb51be4
mq: add qimported patches if patch dir is a repo
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2301
diff
changeset
|
1034 added = [] |
1808 | 1035 for filename in files: |
1036 if existing: | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1037 if not patch: |
1808 | 1038 patch = filename |
1039 if not os.path.isfile(os.path.join(self.path, patch)): | |
1040 self.ui.warn("patch %s does not exist\n" % patch) | |
1041 sys.exit(1) | |
1042 else: | |
1043 try: | |
1044 text = file(filename).read() | |
1045 except IOError: | |
1046 self.ui.warn("Unable to read %s\n" % patch) | |
1047 sys.exit(1) | |
1048 if not patch: | |
1049 patch = os.path.split(filename)[1] | |
1050 if not force and os.path.isfile(os.path.join(self.path, patch)): | |
1051 self.ui.warn("patch %s already exists\n" % patch) | |
1052 sys.exit(1) | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
1053 patchf = self.opener(patch, "w") |
1808 | 1054 patchf.write(text) |
1055 if patch in self.series: | |
1056 self.ui.warn("patch %s is already in the series file\n" % patch) | |
1057 sys.exit(1) | |
1058 index = self.series_end() + i | |
1059 self.full_series[index:index] = [patch] | |
1060 self.read_series(self.full_series) | |
1061 self.ui.warn("adding %s to series file\n" % patch) | |
1062 i += 1 | |
2488
2785aeb51be4
mq: add qimported patches if patch dir is a repo
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2301
diff
changeset
|
1063 added.append(patch) |
1808 | 1064 patch = None |
1065 self.series_dirty = 1 | |
2488
2785aeb51be4
mq: add qimported patches if patch dir is a repo
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2301
diff
changeset
|
1066 qrepo = self.qrepo() |
2785aeb51be4
mq: add qimported patches if patch dir is a repo
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2301
diff
changeset
|
1067 if qrepo: |
2785aeb51be4
mq: add qimported patches if patch dir is a repo
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2301
diff
changeset
|
1068 qrepo.add(added) |
1808 | 1069 |
1070 def delete(ui, repo, patch, **opts): | |
1071 """remove a patch from the series file""" | |
1072 q = repomap[repo] | |
1073 q.delete(repo, patch) | |
1074 q.save_dirty() | |
1075 return 0 | |
1076 | |
1077 def applied(ui, repo, patch=None, **opts): | |
1078 """print the patches already applied""" | |
1079 repomap[repo].qapplied(repo, patch) | |
1080 return 0 | |
1081 | |
1082 def unapplied(ui, repo, patch=None, **opts): | |
1083 """print the patches not yet applied""" | |
1084 repomap[repo].unapplied(repo, patch) | |
1085 return 0 | |
1086 | |
1087 def qimport(ui, repo, *filename, **opts): | |
1088 """import a patch""" | |
1089 q = repomap[repo] | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1090 q.qimport(repo, filename, patch=opts['name'], |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1091 existing=opts['existing'], force=opts['force']) |
1808 | 1092 q.save_dirty() |
1093 return 0 | |
1094 | |
1095 def init(ui, repo, **opts): | |
1096 """init a new queue repository""" | |
1097 q = repomap[repo] | |
1098 r = q.init(repo, create=opts['create_repo']) | |
1099 q.save_dirty() | |
1100 if r: | |
1101 fp = r.wopener('.hgignore', 'w') | |
1102 print >> fp, 'syntax: glob' | |
1103 print >> fp, 'status' | |
1104 fp.close() | |
1105 r.wopener('series', 'w').close() | |
1106 r.add(['.hgignore', 'series']) | |
1107 return 0 | |
1108 | |
1109 def commit(ui, repo, *pats, **opts): | |
2526
37785f986260
mq: Added help for qcommit, consistently talk about queue repository.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2488
diff
changeset
|
1110 """commit changes in the queue repository""" |
1808 | 1111 q = repomap[repo] |
1112 r = q.qrepo() | |
1113 if not r: raise util.Abort('no queue repository') | |
1114 commands.commit(r.ui, r, *pats, **opts) | |
1115 | |
1116 def series(ui, repo, **opts): | |
1117 """print the entire series file""" | |
1118 repomap[repo].qseries(repo, missing=opts['missing']) | |
1119 return 0 | |
1120 | |
1121 def top(ui, repo, **opts): | |
1122 """print the name of the current patch""" | |
1123 repomap[repo].top(repo) | |
1124 return 0 | |
1125 | |
1126 def next(ui, repo, **opts): | |
1127 """print the name of the next patch""" | |
1128 repomap[repo].next(repo) | |
1129 return 0 | |
1130 | |
1131 def prev(ui, repo, **opts): | |
1132 """print the name of the previous patch""" | |
1133 repomap[repo].prev(repo) | |
1134 return 0 | |
1135 | |
1136 def new(ui, repo, patch, **opts): | |
1137 """create a new patch""" | |
1138 q = repomap[repo] | |
1139 q.new(repo, patch, msg=opts['message'], force=opts['force']) | |
1140 q.save_dirty() | |
1141 return 0 | |
1142 | |
1143 def refresh(ui, repo, **opts): | |
1144 """update the current patch""" | |
1145 q = repomap[repo] | |
1146 q.refresh(repo, short=opts['short']) | |
1147 q.save_dirty() | |
1148 return 0 | |
1149 | |
1150 def diff(ui, repo, *files, **opts): | |
1151 """diff of the current patch""" | |
2097
4d2c2597876f
Fix hg qdiff <file>
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents:
2086
diff
changeset
|
1152 # deep in the dirstate code, the walkhelper method wants a list, not a tuple |
4d2c2597876f
Fix hg qdiff <file>
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents:
2086
diff
changeset
|
1153 repomap[repo].diff(repo, list(files)) |
1808 | 1154 return 0 |
1155 | |
1156 def lastsavename(path): | |
1157 (dir, base) = os.path.split(path) | |
1158 names = os.listdir(dir) | |
1159 namere = re.compile("%s.([0-9]+)" % base) | |
1160 max = None | |
1161 maxname = None | |
1162 for f in names: | |
1163 m = namere.match(f) | |
1164 if m: | |
1165 index = int(m.group(1)) | |
1166 if max == None or index > max: | |
1167 max = index | |
1168 maxname = f | |
1169 if maxname: | |
1170 return (os.path.join(dir, maxname), max) | |
1171 return (None, None) | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1172 |
1808 | 1173 def savename(path): |
1174 (last, index) = lastsavename(path) | |
1175 if last is None: | |
1176 index = 0 | |
1177 newpath = path + ".%d" % (index + 1) | |
1178 return newpath | |
1179 | |
1180 def push(ui, repo, patch=None, **opts): | |
1181 """push the next patch onto the stack""" | |
1182 q = repomap[repo] | |
1183 mergeq = None | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1184 |
1808 | 1185 if opts['all']: |
1186 patch = q.series[-1] | |
1187 if opts['merge']: | |
1188 if opts['name']: | |
1189 newpath = opts['name'] | |
1190 else: | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1191 newpath, i = lastsavename(q.path) |
1808 | 1192 if not newpath: |
1193 ui.warn("no saved queues found, please use -n\n") | |
1194 return 1 | |
1195 mergeq = queue(ui, repo.join(""), newpath) | |
1196 ui.warn("merging with queue at: %s\n" % mergeq.path) | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1197 ret = q.push(repo, patch, force=opts['force'], list=opts['list'], |
1808 | 1198 mergeq=mergeq) |
1199 q.save_dirty() | |
1200 return ret | |
1201 | |
1202 def pop(ui, repo, patch=None, **opts): | |
1203 """pop the current patch off the stack""" | |
1204 localupdate = True | |
1205 if opts['name']: | |
1206 q = queue(ui, repo.join(""), repo.join(opts['name'])) | |
1207 ui.warn('using patch queue: %s\n' % q.path) | |
1208 localupdate = False | |
1209 else: | |
1210 q = repomap[repo] | |
1211 if opts['all'] and len(q.applied) > 0: | |
1212 patch = q.applied[0].split(':')[1] | |
1213 q.pop(repo, patch, force=opts['force'], update=localupdate) | |
1214 q.save_dirty() | |
1215 return 0 | |
1216 | |
1217 def restore(ui, repo, rev, **opts): | |
1218 """restore the queue state saved by a rev""" | |
1219 rev = repo.lookup(rev) | |
1220 q = repomap[repo] | |
1221 q.restore(repo, rev, delete=opts['delete'], | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1222 qupdate=opts['update']) |
1808 | 1223 q.save_dirty() |
1224 return 0 | |
1225 | |
1226 def save(ui, repo, **opts): | |
1227 """save current queue state""" | |
1228 q = repomap[repo] | |
1229 ret = q.save(repo, msg=opts['message']) | |
1230 if ret: | |
1231 return ret | |
1232 q.save_dirty() | |
1233 if opts['copy']: | |
1234 path = q.path | |
1235 if opts['name']: | |
1236 newpath = os.path.join(q.basepath, opts['name']) | |
1237 if os.path.exists(newpath): | |
1238 if not os.path.isdir(newpath): | |
1239 ui.warn("destination %s exists and is not a directory\n" % | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1240 newpath) |
1808 | 1241 sys.exit(1) |
1242 if not opts['force']: | |
1243 ui.warn("destination %s exists, use -f to force\n" % | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1244 newpath) |
1808 | 1245 sys.exit(1) |
1246 else: | |
1247 newpath = savename(path) | |
1248 ui.warn("copy %s to %s\n" % (path, newpath)) | |
1249 util.copyfiles(path, newpath) | |
1250 if opts['empty']: | |
1251 try: | |
1852
fdf9cbf56ec7
Fix mq's usage of opener, which don't allow absolute paths now.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1839
diff
changeset
|
1252 os.unlink(os.path.join(q.path, q.status_path)) |
1808 | 1253 except: |
1254 pass | |
1255 return 0 | |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1256 |
1808 | 1257 def strip(ui, repo, rev, **opts): |
1258 """strip a revision and all later revs on the same branch""" | |
1259 rev = repo.lookup(rev) | |
1260 backup = 'all' | |
1261 if opts['backup']: | |
1262 backup = 'strip' | |
1263 elif opts['nobackup']: | |
1264 backup = 'none' | |
1265 repomap[repo].strip(repo, rev, backup=backup) | |
1266 return 0 | |
1267 | |
1268 def version(ui, q=None): | |
1269 """print the version number""" | |
1270 ui.write("mq version %s\n" % versionstr) | |
1271 return 0 | |
1272 | |
1273 def reposetup(ui, repo): | |
1274 repomap[repo] = queue(ui, repo.join("")) | |
1275 | |
1276 cmdtable = { | |
2185
5acd648770d0
Better help for mq: Corrected synopses, get qcommit options from commands.py.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2097
diff
changeset
|
1277 "qapplied": (applied, [], 'hg qapplied [PATCH]'), |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1278 "qcommit|qci": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1279 (commit, |
2185
5acd648770d0
Better help for mq: Corrected synopses, get qcommit options from commands.py.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2097
diff
changeset
|
1280 commands.table["^commit|ci"][1], |
5acd648770d0
Better help for mq: Corrected synopses, get qcommit options from commands.py.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2097
diff
changeset
|
1281 'hg qcommit [OPTION]... [FILE]...'), |
5acd648770d0
Better help for mq: Corrected synopses, get qcommit options from commands.py.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2097
diff
changeset
|
1282 "^qdiff": (diff, [], 'hg qdiff [FILE]...'), |
5acd648770d0
Better help for mq: Corrected synopses, get qcommit options from commands.py.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2097
diff
changeset
|
1283 "qdelete": (delete, [], 'hg qdelete PATCH'), |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1284 "^qimport": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1285 (qimport, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1286 [('e', 'existing', None, 'import file in patch dir'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1287 ('n', 'name', '', 'patch file name'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1288 ('f', 'force', None, 'overwrite existing files')], |
2185
5acd648770d0
Better help for mq: Corrected synopses, get qcommit options from commands.py.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2097
diff
changeset
|
1289 'hg qimport [-e] [-n NAME] [-f] FILE...'), |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1290 "^qinit": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1291 (init, |
2526
37785f986260
mq: Added help for qcommit, consistently talk about queue repository.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2488
diff
changeset
|
1292 [('c', 'create-repo', None, 'create queue repository')], |
2185
5acd648770d0
Better help for mq: Corrected synopses, get qcommit options from commands.py.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2097
diff
changeset
|
1293 'hg qinit [-c]'), |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1294 "qnew": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1295 (new, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1296 [('m', 'message', '', 'commit message'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1297 ('f', 'force', None, 'force')], |
2185
5acd648770d0
Better help for mq: Corrected synopses, get qcommit options from commands.py.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2097
diff
changeset
|
1298 'hg qnew [-m TEXT] [-f] PATCH'), |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1299 "qnext": (next, [], 'hg qnext'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1300 "qprev": (prev, [], 'hg qprev'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1301 "^qpop": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1302 (pop, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1303 [('a', 'all', None, 'pop all patches'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1304 ('n', 'name', '', 'queue name to pop'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1305 ('f', 'force', None, 'forget any local changes')], |
2185
5acd648770d0
Better help for mq: Corrected synopses, get qcommit options from commands.py.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2097
diff
changeset
|
1306 'hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]'), |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1307 "^qpush": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1308 (push, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1309 [('f', 'force', None, 'apply if the patch has rejects'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1310 ('l', 'list', None, 'list patch name in commit text'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1311 ('a', 'all', None, 'apply all patches'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1312 ('m', 'merge', None, 'merge from another queue'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1313 ('n', 'name', '', 'merge queue name')], |
2185
5acd648770d0
Better help for mq: Corrected synopses, get qcommit options from commands.py.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2097
diff
changeset
|
1314 'hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]'), |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1315 "^qrefresh": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1316 (refresh, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1317 [('s', 'short', None, 'short refresh')], |
2185
5acd648770d0
Better help for mq: Corrected synopses, get qcommit options from commands.py.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2097
diff
changeset
|
1318 'hg qrefresh [-s]'), |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1319 "qrestore": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1320 (restore, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1321 [('d', 'delete', None, 'delete save entry'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1322 ('u', 'update', None, 'update queue working dir')], |
2185
5acd648770d0
Better help for mq: Corrected synopses, get qcommit options from commands.py.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2097
diff
changeset
|
1323 'hg qrestore [-d] [-u] REV'), |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1324 "qsave": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1325 (save, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1326 [('m', 'message', '', 'commit message'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1327 ('c', 'copy', None, 'copy patch directory'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1328 ('n', 'name', '', 'copy directory name'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1329 ('e', 'empty', None, 'clear queue status file'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1330 ('f', 'force', None, 'force copy')], |
2185
5acd648770d0
Better help for mq: Corrected synopses, get qcommit options from commands.py.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2097
diff
changeset
|
1331 'hg qsave [-m TEXT] [-c] [-n NAME] [-e] [-f]'), |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1332 "qseries": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1333 (series, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1334 [('m', 'missing', None, 'print patches not in series')], |
2185
5acd648770d0
Better help for mq: Corrected synopses, get qcommit options from commands.py.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2097
diff
changeset
|
1335 'hg qseries [-m]'), |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1336 "^strip": |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1337 (strip, |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1338 [('f', 'force', None, 'force multi-head removal'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1339 ('b', 'backup', None, 'bundle unrelated changesets'), |
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1340 ('n', 'nobackup', None, 'no backups')], |
2185
5acd648770d0
Better help for mq: Corrected synopses, get qcommit options from commands.py.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2097
diff
changeset
|
1341 'hg strip [-f] [-b] [-n] REV'), |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1342 "qtop": (top, [], 'hg qtop'), |
2185
5acd648770d0
Better help for mq: Corrected synopses, get qcommit options from commands.py.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
2097
diff
changeset
|
1343 "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'), |
1810
7596611ab3d5
Whitespace, tab and formatting cleanups, mainly in mq.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1808
diff
changeset
|
1344 "qversion": (version, [], 'hg qversion') |
1808 | 1345 } |
1346 |