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