##// END OF EJS Templates
Uniformisation of commit help for -m and -l....
Mathieu Clabaut -
r3857:f6f16f87 default
parent child Browse files
Show More
@@ -1,2195 +1,2190 b''
1 # queue.py - patch queues for mercurial
1 # queue.py - patch queues for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 '''patch management and development
8 '''patch management and development
9
9
10 This extension lets you work with a stack of patches in a Mercurial
10 This extension lets you work with a stack of patches in a Mercurial
11 repository. It manages two stacks of patches - all known patches, and
11 repository. It manages two stacks of patches - all known patches, and
12 applied patches (subset of known patches).
12 applied patches (subset of known patches).
13
13
14 Known patches are represented as patch files in the .hg/patches
14 Known patches are represented as patch files in the .hg/patches
15 directory. Applied patches are both patch files and changesets.
15 directory. Applied patches are both patch files and changesets.
16
16
17 Common tasks (use "hg help command" for more details):
17 Common tasks (use "hg help command" for more details):
18
18
19 prepare repository to work with patches qinit
19 prepare repository to work with patches qinit
20 create new patch qnew
20 create new patch qnew
21 import existing patch qimport
21 import existing patch qimport
22
22
23 print patch series qseries
23 print patch series qseries
24 print applied patches qapplied
24 print applied patches qapplied
25 print name of top applied patch qtop
25 print name of top applied patch qtop
26
26
27 add known patch to applied stack qpush
27 add known patch to applied stack qpush
28 remove patch from applied stack qpop
28 remove patch from applied stack qpop
29 refresh contents of top applied patch qrefresh
29 refresh contents of top applied patch qrefresh
30 '''
30 '''
31
31
32 from mercurial.demandload import *
32 from mercurial.demandload import *
33 from mercurial.i18n import gettext as _
33 from mercurial.i18n import gettext as _
34 from mercurial import commands
34 from mercurial import commands
35 demandload(globals(), "os sys re struct traceback errno bz2")
35 demandload(globals(), "os sys re struct traceback errno bz2")
36 demandload(globals(), "mercurial:cmdutil,hg,patch,revlog,util,changegroup")
36 demandload(globals(), "mercurial:cmdutil,hg,patch,revlog,util,changegroup")
37
37
38 commands.norepo += " qclone qversion"
38 commands.norepo += " qclone qversion"
39
39
40 class statusentry:
40 class statusentry:
41 def __init__(self, rev, name=None):
41 def __init__(self, rev, name=None):
42 if not name:
42 if not name:
43 fields = rev.split(':', 1)
43 fields = rev.split(':', 1)
44 if len(fields) == 2:
44 if len(fields) == 2:
45 self.rev, self.name = fields
45 self.rev, self.name = fields
46 else:
46 else:
47 self.rev, self.name = None, None
47 self.rev, self.name = None, None
48 else:
48 else:
49 self.rev, self.name = rev, name
49 self.rev, self.name = rev, name
50
50
51 def __str__(self):
51 def __str__(self):
52 return self.rev + ':' + self.name
52 return self.rev + ':' + self.name
53
53
54 class queue:
54 class queue:
55 def __init__(self, ui, path, patchdir=None):
55 def __init__(self, ui, path, patchdir=None):
56 self.basepath = path
56 self.basepath = path
57 self.path = patchdir or os.path.join(path, "patches")
57 self.path = patchdir or os.path.join(path, "patches")
58 self.opener = util.opener(self.path)
58 self.opener = util.opener(self.path)
59 self.ui = ui
59 self.ui = ui
60 self.applied = []
60 self.applied = []
61 self.full_series = []
61 self.full_series = []
62 self.applied_dirty = 0
62 self.applied_dirty = 0
63 self.series_dirty = 0
63 self.series_dirty = 0
64 self.series_path = "series"
64 self.series_path = "series"
65 self.status_path = "status"
65 self.status_path = "status"
66 self.guards_path = "guards"
66 self.guards_path = "guards"
67 self.active_guards = None
67 self.active_guards = None
68 self.guards_dirty = False
68 self.guards_dirty = False
69 self._diffopts = None
69 self._diffopts = None
70
70
71 if os.path.exists(self.join(self.series_path)):
71 if os.path.exists(self.join(self.series_path)):
72 self.full_series = self.opener(self.series_path).read().splitlines()
72 self.full_series = self.opener(self.series_path).read().splitlines()
73 self.parse_series()
73 self.parse_series()
74
74
75 if os.path.exists(self.join(self.status_path)):
75 if os.path.exists(self.join(self.status_path)):
76 lines = self.opener(self.status_path).read().splitlines()
76 lines = self.opener(self.status_path).read().splitlines()
77 self.applied = [statusentry(l) for l in lines]
77 self.applied = [statusentry(l) for l in lines]
78
78
79 def diffopts(self):
79 def diffopts(self):
80 if self._diffopts is None:
80 if self._diffopts is None:
81 self._diffopts = patch.diffopts(self.ui)
81 self._diffopts = patch.diffopts(self.ui)
82 return self._diffopts
82 return self._diffopts
83
83
84 def join(self, *p):
84 def join(self, *p):
85 return os.path.join(self.path, *p)
85 return os.path.join(self.path, *p)
86
86
87 def find_series(self, patch):
87 def find_series(self, patch):
88 pre = re.compile("(\s*)([^#]+)")
88 pre = re.compile("(\s*)([^#]+)")
89 index = 0
89 index = 0
90 for l in self.full_series:
90 for l in self.full_series:
91 m = pre.match(l)
91 m = pre.match(l)
92 if m:
92 if m:
93 s = m.group(2)
93 s = m.group(2)
94 s = s.rstrip()
94 s = s.rstrip()
95 if s == patch:
95 if s == patch:
96 return index
96 return index
97 index += 1
97 index += 1
98 return None
98 return None
99
99
100 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
100 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
101
101
102 def parse_series(self):
102 def parse_series(self):
103 self.series = []
103 self.series = []
104 self.series_guards = []
104 self.series_guards = []
105 for l in self.full_series:
105 for l in self.full_series:
106 h = l.find('#')
106 h = l.find('#')
107 if h == -1:
107 if h == -1:
108 patch = l
108 patch = l
109 comment = ''
109 comment = ''
110 elif h == 0:
110 elif h == 0:
111 continue
111 continue
112 else:
112 else:
113 patch = l[:h]
113 patch = l[:h]
114 comment = l[h:]
114 comment = l[h:]
115 patch = patch.strip()
115 patch = patch.strip()
116 if patch:
116 if patch:
117 if patch in self.series:
117 if patch in self.series:
118 raise util.Abort(_('%s appears more than once in %s') %
118 raise util.Abort(_('%s appears more than once in %s') %
119 (patch, self.join(self.series_path)))
119 (patch, self.join(self.series_path)))
120 self.series.append(patch)
120 self.series.append(patch)
121 self.series_guards.append(self.guard_re.findall(comment))
121 self.series_guards.append(self.guard_re.findall(comment))
122
122
123 def check_guard(self, guard):
123 def check_guard(self, guard):
124 bad_chars = '# \t\r\n\f'
124 bad_chars = '# \t\r\n\f'
125 first = guard[0]
125 first = guard[0]
126 for c in '-+':
126 for c in '-+':
127 if first == c:
127 if first == c:
128 return (_('guard %r starts with invalid character: %r') %
128 return (_('guard %r starts with invalid character: %r') %
129 (guard, c))
129 (guard, c))
130 for c in bad_chars:
130 for c in bad_chars:
131 if c in guard:
131 if c in guard:
132 return _('invalid character in guard %r: %r') % (guard, c)
132 return _('invalid character in guard %r: %r') % (guard, c)
133
133
134 def set_active(self, guards):
134 def set_active(self, guards):
135 for guard in guards:
135 for guard in guards:
136 bad = self.check_guard(guard)
136 bad = self.check_guard(guard)
137 if bad:
137 if bad:
138 raise util.Abort(bad)
138 raise util.Abort(bad)
139 guards = dict.fromkeys(guards).keys()
139 guards = dict.fromkeys(guards).keys()
140 guards.sort()
140 guards.sort()
141 self.ui.debug('active guards: %s\n' % ' '.join(guards))
141 self.ui.debug('active guards: %s\n' % ' '.join(guards))
142 self.active_guards = guards
142 self.active_guards = guards
143 self.guards_dirty = True
143 self.guards_dirty = True
144
144
145 def active(self):
145 def active(self):
146 if self.active_guards is None:
146 if self.active_guards is None:
147 self.active_guards = []
147 self.active_guards = []
148 try:
148 try:
149 guards = self.opener(self.guards_path).read().split()
149 guards = self.opener(self.guards_path).read().split()
150 except IOError, err:
150 except IOError, err:
151 if err.errno != errno.ENOENT: raise
151 if err.errno != errno.ENOENT: raise
152 guards = []
152 guards = []
153 for i, guard in enumerate(guards):
153 for i, guard in enumerate(guards):
154 bad = self.check_guard(guard)
154 bad = self.check_guard(guard)
155 if bad:
155 if bad:
156 self.ui.warn('%s:%d: %s\n' %
156 self.ui.warn('%s:%d: %s\n' %
157 (self.join(self.guards_path), i + 1, bad))
157 (self.join(self.guards_path), i + 1, bad))
158 else:
158 else:
159 self.active_guards.append(guard)
159 self.active_guards.append(guard)
160 return self.active_guards
160 return self.active_guards
161
161
162 def set_guards(self, idx, guards):
162 def set_guards(self, idx, guards):
163 for g in guards:
163 for g in guards:
164 if len(g) < 2:
164 if len(g) < 2:
165 raise util.Abort(_('guard %r too short') % g)
165 raise util.Abort(_('guard %r too short') % g)
166 if g[0] not in '-+':
166 if g[0] not in '-+':
167 raise util.Abort(_('guard %r starts with invalid char') % g)
167 raise util.Abort(_('guard %r starts with invalid char') % g)
168 bad = self.check_guard(g[1:])
168 bad = self.check_guard(g[1:])
169 if bad:
169 if bad:
170 raise util.Abort(bad)
170 raise util.Abort(bad)
171 drop = self.guard_re.sub('', self.full_series[idx])
171 drop = self.guard_re.sub('', self.full_series[idx])
172 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
172 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
173 self.parse_series()
173 self.parse_series()
174 self.series_dirty = True
174 self.series_dirty = True
175
175
176 def pushable(self, idx):
176 def pushable(self, idx):
177 if isinstance(idx, str):
177 if isinstance(idx, str):
178 idx = self.series.index(idx)
178 idx = self.series.index(idx)
179 patchguards = self.series_guards[idx]
179 patchguards = self.series_guards[idx]
180 if not patchguards:
180 if not patchguards:
181 return True, None
181 return True, None
182 default = False
182 default = False
183 guards = self.active()
183 guards = self.active()
184 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
184 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
185 if exactneg:
185 if exactneg:
186 return False, exactneg[0]
186 return False, exactneg[0]
187 pos = [g for g in patchguards if g[0] == '+']
187 pos = [g for g in patchguards if g[0] == '+']
188 exactpos = [g for g in pos if g[1:] in guards]
188 exactpos = [g for g in pos if g[1:] in guards]
189 if pos:
189 if pos:
190 if exactpos:
190 if exactpos:
191 return True, exactpos[0]
191 return True, exactpos[0]
192 return False, pos
192 return False, pos
193 return True, ''
193 return True, ''
194
194
195 def explain_pushable(self, idx, all_patches=False):
195 def explain_pushable(self, idx, all_patches=False):
196 write = all_patches and self.ui.write or self.ui.warn
196 write = all_patches and self.ui.write or self.ui.warn
197 if all_patches or self.ui.verbose:
197 if all_patches or self.ui.verbose:
198 if isinstance(idx, str):
198 if isinstance(idx, str):
199 idx = self.series.index(idx)
199 idx = self.series.index(idx)
200 pushable, why = self.pushable(idx)
200 pushable, why = self.pushable(idx)
201 if all_patches and pushable:
201 if all_patches and pushable:
202 if why is None:
202 if why is None:
203 write(_('allowing %s - no guards in effect\n') %
203 write(_('allowing %s - no guards in effect\n') %
204 self.series[idx])
204 self.series[idx])
205 else:
205 else:
206 if not why:
206 if not why:
207 write(_('allowing %s - no matching negative guards\n') %
207 write(_('allowing %s - no matching negative guards\n') %
208 self.series[idx])
208 self.series[idx])
209 else:
209 else:
210 write(_('allowing %s - guarded by %r\n') %
210 write(_('allowing %s - guarded by %r\n') %
211 (self.series[idx], why))
211 (self.series[idx], why))
212 if not pushable:
212 if not pushable:
213 if why:
213 if why:
214 write(_('skipping %s - guarded by %r\n') %
214 write(_('skipping %s - guarded by %r\n') %
215 (self.series[idx], ' '.join(why)))
215 (self.series[idx], ' '.join(why)))
216 else:
216 else:
217 write(_('skipping %s - no matching guards\n') %
217 write(_('skipping %s - no matching guards\n') %
218 self.series[idx])
218 self.series[idx])
219
219
220 def save_dirty(self):
220 def save_dirty(self):
221 def write_list(items, path):
221 def write_list(items, path):
222 fp = self.opener(path, 'w')
222 fp = self.opener(path, 'w')
223 for i in items:
223 for i in items:
224 print >> fp, i
224 print >> fp, i
225 fp.close()
225 fp.close()
226 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
226 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
227 if self.series_dirty: write_list(self.full_series, self.series_path)
227 if self.series_dirty: write_list(self.full_series, self.series_path)
228 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
228 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
229
229
230 def readheaders(self, patch):
230 def readheaders(self, patch):
231 def eatdiff(lines):
231 def eatdiff(lines):
232 while lines:
232 while lines:
233 l = lines[-1]
233 l = lines[-1]
234 if (l.startswith("diff -") or
234 if (l.startswith("diff -") or
235 l.startswith("Index:") or
235 l.startswith("Index:") or
236 l.startswith("===========")):
236 l.startswith("===========")):
237 del lines[-1]
237 del lines[-1]
238 else:
238 else:
239 break
239 break
240 def eatempty(lines):
240 def eatempty(lines):
241 while lines:
241 while lines:
242 l = lines[-1]
242 l = lines[-1]
243 if re.match('\s*$', l):
243 if re.match('\s*$', l):
244 del lines[-1]
244 del lines[-1]
245 else:
245 else:
246 break
246 break
247
247
248 pf = self.join(patch)
248 pf = self.join(patch)
249 message = []
249 message = []
250 comments = []
250 comments = []
251 user = None
251 user = None
252 date = None
252 date = None
253 format = None
253 format = None
254 subject = None
254 subject = None
255 diffstart = 0
255 diffstart = 0
256
256
257 for line in file(pf):
257 for line in file(pf):
258 line = line.rstrip()
258 line = line.rstrip()
259 if line.startswith('diff --git'):
259 if line.startswith('diff --git'):
260 diffstart = 2
260 diffstart = 2
261 break
261 break
262 if diffstart:
262 if diffstart:
263 if line.startswith('+++ '):
263 if line.startswith('+++ '):
264 diffstart = 2
264 diffstart = 2
265 break
265 break
266 if line.startswith("--- "):
266 if line.startswith("--- "):
267 diffstart = 1
267 diffstart = 1
268 continue
268 continue
269 elif format == "hgpatch":
269 elif format == "hgpatch":
270 # parse values when importing the result of an hg export
270 # parse values when importing the result of an hg export
271 if line.startswith("# User "):
271 if line.startswith("# User "):
272 user = line[7:]
272 user = line[7:]
273 elif line.startswith("# Date "):
273 elif line.startswith("# Date "):
274 date = line[7:]
274 date = line[7:]
275 elif not line.startswith("# ") and line:
275 elif not line.startswith("# ") and line:
276 message.append(line)
276 message.append(line)
277 format = None
277 format = None
278 elif line == '# HG changeset patch':
278 elif line == '# HG changeset patch':
279 format = "hgpatch"
279 format = "hgpatch"
280 elif (format != "tagdone" and (line.startswith("Subject: ") or
280 elif (format != "tagdone" and (line.startswith("Subject: ") or
281 line.startswith("subject: "))):
281 line.startswith("subject: "))):
282 subject = line[9:]
282 subject = line[9:]
283 format = "tag"
283 format = "tag"
284 elif (format != "tagdone" and (line.startswith("From: ") or
284 elif (format != "tagdone" and (line.startswith("From: ") or
285 line.startswith("from: "))):
285 line.startswith("from: "))):
286 user = line[6:]
286 user = line[6:]
287 format = "tag"
287 format = "tag"
288 elif format == "tag" and line == "":
288 elif format == "tag" and line == "":
289 # when looking for tags (subject: from: etc) they
289 # when looking for tags (subject: from: etc) they
290 # end once you find a blank line in the source
290 # end once you find a blank line in the source
291 format = "tagdone"
291 format = "tagdone"
292 elif message or line:
292 elif message or line:
293 message.append(line)
293 message.append(line)
294 comments.append(line)
294 comments.append(line)
295
295
296 eatdiff(message)
296 eatdiff(message)
297 eatdiff(comments)
297 eatdiff(comments)
298 eatempty(message)
298 eatempty(message)
299 eatempty(comments)
299 eatempty(comments)
300
300
301 # make sure message isn't empty
301 # make sure message isn't empty
302 if format and format.startswith("tag") and subject:
302 if format and format.startswith("tag") and subject:
303 message.insert(0, "")
303 message.insert(0, "")
304 message.insert(0, subject)
304 message.insert(0, subject)
305 return (message, comments, user, date, diffstart > 1)
305 return (message, comments, user, date, diffstart > 1)
306
306
307 def printdiff(self, repo, node1, node2=None, files=None,
307 def printdiff(self, repo, node1, node2=None, files=None,
308 fp=None, changes=None, opts={}):
308 fp=None, changes=None, opts={}):
309 fns, matchfn, anypats = cmdutil.matchpats(repo, files, opts)
309 fns, matchfn, anypats = cmdutil.matchpats(repo, files, opts)
310
310
311 patch.diff(repo, node1, node2, fns, match=matchfn,
311 patch.diff(repo, node1, node2, fns, match=matchfn,
312 fp=fp, changes=changes, opts=self.diffopts())
312 fp=fp, changes=changes, opts=self.diffopts())
313
313
314 def mergeone(self, repo, mergeq, head, patch, rev, wlock):
314 def mergeone(self, repo, mergeq, head, patch, rev, wlock):
315 # first try just applying the patch
315 # first try just applying the patch
316 (err, n) = self.apply(repo, [ patch ], update_status=False,
316 (err, n) = self.apply(repo, [ patch ], update_status=False,
317 strict=True, merge=rev, wlock=wlock)
317 strict=True, merge=rev, wlock=wlock)
318
318
319 if err == 0:
319 if err == 0:
320 return (err, n)
320 return (err, n)
321
321
322 if n is None:
322 if n is None:
323 raise util.Abort(_("apply failed for patch %s") % patch)
323 raise util.Abort(_("apply failed for patch %s") % patch)
324
324
325 self.ui.warn("patch didn't work out, merging %s\n" % patch)
325 self.ui.warn("patch didn't work out, merging %s\n" % patch)
326
326
327 # apply failed, strip away that rev and merge.
327 # apply failed, strip away that rev and merge.
328 hg.clean(repo, head, wlock=wlock)
328 hg.clean(repo, head, wlock=wlock)
329 self.strip(repo, n, update=False, backup='strip', wlock=wlock)
329 self.strip(repo, n, update=False, backup='strip', wlock=wlock)
330
330
331 c = repo.changelog.read(rev)
331 c = repo.changelog.read(rev)
332 ret = hg.merge(repo, rev, wlock=wlock)
332 ret = hg.merge(repo, rev, wlock=wlock)
333 if ret:
333 if ret:
334 raise util.Abort(_("update returned %d") % ret)
334 raise util.Abort(_("update returned %d") % ret)
335 n = repo.commit(None, c[4], c[1], force=1, wlock=wlock)
335 n = repo.commit(None, c[4], c[1], force=1, wlock=wlock)
336 if n == None:
336 if n == None:
337 raise util.Abort(_("repo commit failed"))
337 raise util.Abort(_("repo commit failed"))
338 try:
338 try:
339 message, comments, user, date, patchfound = mergeq.readheaders(patch)
339 message, comments, user, date, patchfound = mergeq.readheaders(patch)
340 except:
340 except:
341 raise util.Abort(_("unable to read %s") % patch)
341 raise util.Abort(_("unable to read %s") % patch)
342
342
343 patchf = self.opener(patch, "w")
343 patchf = self.opener(patch, "w")
344 if comments:
344 if comments:
345 comments = "\n".join(comments) + '\n\n'
345 comments = "\n".join(comments) + '\n\n'
346 patchf.write(comments)
346 patchf.write(comments)
347 self.printdiff(repo, head, n, fp=patchf)
347 self.printdiff(repo, head, n, fp=patchf)
348 patchf.close()
348 patchf.close()
349 return (0, n)
349 return (0, n)
350
350
351 def qparents(self, repo, rev=None):
351 def qparents(self, repo, rev=None):
352 if rev is None:
352 if rev is None:
353 (p1, p2) = repo.dirstate.parents()
353 (p1, p2) = repo.dirstate.parents()
354 if p2 == revlog.nullid:
354 if p2 == revlog.nullid:
355 return p1
355 return p1
356 if len(self.applied) == 0:
356 if len(self.applied) == 0:
357 return None
357 return None
358 return revlog.bin(self.applied[-1].rev)
358 return revlog.bin(self.applied[-1].rev)
359 pp = repo.changelog.parents(rev)
359 pp = repo.changelog.parents(rev)
360 if pp[1] != revlog.nullid:
360 if pp[1] != revlog.nullid:
361 arevs = [ x.rev for x in self.applied ]
361 arevs = [ x.rev for x in self.applied ]
362 p0 = revlog.hex(pp[0])
362 p0 = revlog.hex(pp[0])
363 p1 = revlog.hex(pp[1])
363 p1 = revlog.hex(pp[1])
364 if p0 in arevs:
364 if p0 in arevs:
365 return pp[0]
365 return pp[0]
366 if p1 in arevs:
366 if p1 in arevs:
367 return pp[1]
367 return pp[1]
368 return pp[0]
368 return pp[0]
369
369
370 def mergepatch(self, repo, mergeq, series, wlock):
370 def mergepatch(self, repo, mergeq, series, wlock):
371 if len(self.applied) == 0:
371 if len(self.applied) == 0:
372 # each of the patches merged in will have two parents. This
372 # each of the patches merged in will have two parents. This
373 # can confuse the qrefresh, qdiff, and strip code because it
373 # can confuse the qrefresh, qdiff, and strip code because it
374 # needs to know which parent is actually in the patch queue.
374 # needs to know which parent is actually in the patch queue.
375 # so, we insert a merge marker with only one parent. This way
375 # so, we insert a merge marker with only one parent. This way
376 # the first patch in the queue is never a merge patch
376 # the first patch in the queue is never a merge patch
377 #
377 #
378 pname = ".hg.patches.merge.marker"
378 pname = ".hg.patches.merge.marker"
379 n = repo.commit(None, '[mq]: merge marker', user=None, force=1,
379 n = repo.commit(None, '[mq]: merge marker', user=None, force=1,
380 wlock=wlock)
380 wlock=wlock)
381 self.applied.append(statusentry(revlog.hex(n), pname))
381 self.applied.append(statusentry(revlog.hex(n), pname))
382 self.applied_dirty = 1
382 self.applied_dirty = 1
383
383
384 head = self.qparents(repo)
384 head = self.qparents(repo)
385
385
386 for patch in series:
386 for patch in series:
387 patch = mergeq.lookup(patch, strict=True)
387 patch = mergeq.lookup(patch, strict=True)
388 if not patch:
388 if not patch:
389 self.ui.warn("patch %s does not exist\n" % patch)
389 self.ui.warn("patch %s does not exist\n" % patch)
390 return (1, None)
390 return (1, None)
391 pushable, reason = self.pushable(patch)
391 pushable, reason = self.pushable(patch)
392 if not pushable:
392 if not pushable:
393 self.explain_pushable(patch, all_patches=True)
393 self.explain_pushable(patch, all_patches=True)
394 continue
394 continue
395 info = mergeq.isapplied(patch)
395 info = mergeq.isapplied(patch)
396 if not info:
396 if not info:
397 self.ui.warn("patch %s is not applied\n" % patch)
397 self.ui.warn("patch %s is not applied\n" % patch)
398 return (1, None)
398 return (1, None)
399 rev = revlog.bin(info[1])
399 rev = revlog.bin(info[1])
400 (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock)
400 (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock)
401 if head:
401 if head:
402 self.applied.append(statusentry(revlog.hex(head), patch))
402 self.applied.append(statusentry(revlog.hex(head), patch))
403 self.applied_dirty = 1
403 self.applied_dirty = 1
404 if err:
404 if err:
405 return (err, head)
405 return (err, head)
406 return (0, head)
406 return (0, head)
407
407
408 def patch(self, repo, patchfile):
408 def patch(self, repo, patchfile):
409 '''Apply patchfile to the working directory.
409 '''Apply patchfile to the working directory.
410 patchfile: file name of patch'''
410 patchfile: file name of patch'''
411 files = {}
411 files = {}
412 try:
412 try:
413 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
413 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
414 files=files)
414 files=files)
415 except Exception, inst:
415 except Exception, inst:
416 self.ui.note(str(inst) + '\n')
416 self.ui.note(str(inst) + '\n')
417 if not self.ui.verbose:
417 if not self.ui.verbose:
418 self.ui.warn("patch failed, unable to continue (try -v)\n")
418 self.ui.warn("patch failed, unable to continue (try -v)\n")
419 return (False, files, False)
419 return (False, files, False)
420
420
421 return (True, files, fuzz)
421 return (True, files, fuzz)
422
422
423 def apply(self, repo, series, list=False, update_status=True,
423 def apply(self, repo, series, list=False, update_status=True,
424 strict=False, patchdir=None, merge=None, wlock=None):
424 strict=False, patchdir=None, merge=None, wlock=None):
425 # TODO unify with commands.py
425 # TODO unify with commands.py
426 if not patchdir:
426 if not patchdir:
427 patchdir = self.path
427 patchdir = self.path
428 err = 0
428 err = 0
429 if not wlock:
429 if not wlock:
430 wlock = repo.wlock()
430 wlock = repo.wlock()
431 lock = repo.lock()
431 lock = repo.lock()
432 tr = repo.transaction()
432 tr = repo.transaction()
433 n = None
433 n = None
434 for patchname in series:
434 for patchname in series:
435 pushable, reason = self.pushable(patchname)
435 pushable, reason = self.pushable(patchname)
436 if not pushable:
436 if not pushable:
437 self.explain_pushable(patchname, all_patches=True)
437 self.explain_pushable(patchname, all_patches=True)
438 continue
438 continue
439 self.ui.warn("applying %s\n" % patchname)
439 self.ui.warn("applying %s\n" % patchname)
440 pf = os.path.join(patchdir, patchname)
440 pf = os.path.join(patchdir, patchname)
441
441
442 try:
442 try:
443 message, comments, user, date, patchfound = self.readheaders(patchname)
443 message, comments, user, date, patchfound = self.readheaders(patchname)
444 except:
444 except:
445 self.ui.warn("Unable to read %s\n" % patchname)
445 self.ui.warn("Unable to read %s\n" % patchname)
446 err = 1
446 err = 1
447 break
447 break
448
448
449 if not message:
449 if not message:
450 message = "imported patch %s\n" % patchname
450 message = "imported patch %s\n" % patchname
451 else:
451 else:
452 if list:
452 if list:
453 message.append("\nimported patch %s" % patchname)
453 message.append("\nimported patch %s" % patchname)
454 message = '\n'.join(message)
454 message = '\n'.join(message)
455
455
456 (patcherr, files, fuzz) = self.patch(repo, pf)
456 (patcherr, files, fuzz) = self.patch(repo, pf)
457 patcherr = not patcherr
457 patcherr = not patcherr
458
458
459 if merge and files:
459 if merge and files:
460 # Mark as merged and update dirstate parent info
460 # Mark as merged and update dirstate parent info
461 repo.dirstate.update(repo.dirstate.filterfiles(files.keys()), 'm')
461 repo.dirstate.update(repo.dirstate.filterfiles(files.keys()), 'm')
462 p1, p2 = repo.dirstate.parents()
462 p1, p2 = repo.dirstate.parents()
463 repo.dirstate.setparents(p1, merge)
463 repo.dirstate.setparents(p1, merge)
464 files = patch.updatedir(self.ui, repo, files, wlock=wlock)
464 files = patch.updatedir(self.ui, repo, files, wlock=wlock)
465 n = repo.commit(files, message, user, date, force=1, lock=lock,
465 n = repo.commit(files, message, user, date, force=1, lock=lock,
466 wlock=wlock)
466 wlock=wlock)
467
467
468 if n == None:
468 if n == None:
469 raise util.Abort(_("repo commit failed"))
469 raise util.Abort(_("repo commit failed"))
470
470
471 if update_status:
471 if update_status:
472 self.applied.append(statusentry(revlog.hex(n), patchname))
472 self.applied.append(statusentry(revlog.hex(n), patchname))
473
473
474 if patcherr:
474 if patcherr:
475 if not patchfound:
475 if not patchfound:
476 self.ui.warn("patch %s is empty\n" % patchname)
476 self.ui.warn("patch %s is empty\n" % patchname)
477 err = 0
477 err = 0
478 else:
478 else:
479 self.ui.warn("patch failed, rejects left in working dir\n")
479 self.ui.warn("patch failed, rejects left in working dir\n")
480 err = 1
480 err = 1
481 break
481 break
482
482
483 if fuzz and strict:
483 if fuzz and strict:
484 self.ui.warn("fuzz found when applying patch, stopping\n")
484 self.ui.warn("fuzz found when applying patch, stopping\n")
485 err = 1
485 err = 1
486 break
486 break
487 tr.close()
487 tr.close()
488 return (err, n)
488 return (err, n)
489
489
490 def delete(self, repo, patches, opts):
490 def delete(self, repo, patches, opts):
491 realpatches = []
491 realpatches = []
492 for patch in patches:
492 for patch in patches:
493 patch = self.lookup(patch, strict=True)
493 patch = self.lookup(patch, strict=True)
494 info = self.isapplied(patch)
494 info = self.isapplied(patch)
495 if info:
495 if info:
496 raise util.Abort(_("cannot delete applied patch %s") % patch)
496 raise util.Abort(_("cannot delete applied patch %s") % patch)
497 if patch not in self.series:
497 if patch not in self.series:
498 raise util.Abort(_("patch %s not in series file") % patch)
498 raise util.Abort(_("patch %s not in series file") % patch)
499 realpatches.append(patch)
499 realpatches.append(patch)
500
500
501 appliedbase = 0
501 appliedbase = 0
502 if opts.get('rev'):
502 if opts.get('rev'):
503 if not self.applied:
503 if not self.applied:
504 raise util.Abort(_('no patches applied'))
504 raise util.Abort(_('no patches applied'))
505 revs = cmdutil.revrange(repo, opts['rev'])
505 revs = cmdutil.revrange(repo, opts['rev'])
506 if len(revs) > 1 and revs[0] > revs[1]:
506 if len(revs) > 1 and revs[0] > revs[1]:
507 revs.reverse()
507 revs.reverse()
508 for rev in revs:
508 for rev in revs:
509 if appliedbase >= len(self.applied):
509 if appliedbase >= len(self.applied):
510 raise util.Abort(_("revision %d is not managed") % rev)
510 raise util.Abort(_("revision %d is not managed") % rev)
511
511
512 base = revlog.bin(self.applied[appliedbase].rev)
512 base = revlog.bin(self.applied[appliedbase].rev)
513 node = repo.changelog.node(rev)
513 node = repo.changelog.node(rev)
514 if node != base:
514 if node != base:
515 raise util.Abort(_("cannot delete revision %d above "
515 raise util.Abort(_("cannot delete revision %d above "
516 "applied patches") % rev)
516 "applied patches") % rev)
517 realpatches.append(self.applied[appliedbase].name)
517 realpatches.append(self.applied[appliedbase].name)
518 appliedbase += 1
518 appliedbase += 1
519
519
520 if not opts.get('keep'):
520 if not opts.get('keep'):
521 r = self.qrepo()
521 r = self.qrepo()
522 if r:
522 if r:
523 r.remove(realpatches, True)
523 r.remove(realpatches, True)
524 else:
524 else:
525 for p in realpatches:
525 for p in realpatches:
526 os.unlink(self.join(p))
526 os.unlink(self.join(p))
527
527
528 if appliedbase:
528 if appliedbase:
529 del self.applied[:appliedbase]
529 del self.applied[:appliedbase]
530 self.applied_dirty = 1
530 self.applied_dirty = 1
531 indices = [self.find_series(p) for p in realpatches]
531 indices = [self.find_series(p) for p in realpatches]
532 indices.sort()
532 indices.sort()
533 for i in indices[-1::-1]:
533 for i in indices[-1::-1]:
534 del self.full_series[i]
534 del self.full_series[i]
535 self.parse_series()
535 self.parse_series()
536 self.series_dirty = 1
536 self.series_dirty = 1
537
537
538 def check_toppatch(self, repo):
538 def check_toppatch(self, repo):
539 if len(self.applied) > 0:
539 if len(self.applied) > 0:
540 top = revlog.bin(self.applied[-1].rev)
540 top = revlog.bin(self.applied[-1].rev)
541 pp = repo.dirstate.parents()
541 pp = repo.dirstate.parents()
542 if top not in pp:
542 if top not in pp:
543 raise util.Abort(_("queue top not at same revision as working directory"))
543 raise util.Abort(_("queue top not at same revision as working directory"))
544 return top
544 return top
545 return None
545 return None
546 def check_localchanges(self, repo, force=False, refresh=True):
546 def check_localchanges(self, repo, force=False, refresh=True):
547 m, a, r, d = repo.status()[:4]
547 m, a, r, d = repo.status()[:4]
548 if m or a or r or d:
548 if m or a or r or d:
549 if not force:
549 if not force:
550 if refresh:
550 if refresh:
551 raise util.Abort(_("local changes found, refresh first"))
551 raise util.Abort(_("local changes found, refresh first"))
552 else:
552 else:
553 raise util.Abort(_("local changes found"))
553 raise util.Abort(_("local changes found"))
554 return m, a, r, d
554 return m, a, r, d
555 def new(self, repo, patch, msg=None, force=None):
555 def new(self, repo, patch, msg=None, force=None):
556 if os.path.exists(self.join(patch)):
556 if os.path.exists(self.join(patch)):
557 raise util.Abort(_('patch "%s" already exists') % patch)
557 raise util.Abort(_('patch "%s" already exists') % patch)
558 m, a, r, d = self.check_localchanges(repo, force)
558 m, a, r, d = self.check_localchanges(repo, force)
559 commitfiles = m + a + r
559 commitfiles = m + a + r
560 self.check_toppatch(repo)
560 self.check_toppatch(repo)
561 wlock = repo.wlock()
561 wlock = repo.wlock()
562 insert = self.full_series_end()
562 insert = self.full_series_end()
563 if msg:
563 if msg:
564 n = repo.commit(commitfiles, "[mq]: %s" % msg, force=True,
564 n = repo.commit(commitfiles, "[mq]: %s" % msg, force=True,
565 wlock=wlock)
565 wlock=wlock)
566 else:
566 else:
567 n = repo.commit(commitfiles,
567 n = repo.commit(commitfiles,
568 "New patch: %s" % patch, force=True, wlock=wlock)
568 "New patch: %s" % patch, force=True, wlock=wlock)
569 if n == None:
569 if n == None:
570 raise util.Abort(_("repo commit failed"))
570 raise util.Abort(_("repo commit failed"))
571 self.full_series[insert:insert] = [patch]
571 self.full_series[insert:insert] = [patch]
572 self.applied.append(statusentry(revlog.hex(n), patch))
572 self.applied.append(statusentry(revlog.hex(n), patch))
573 self.parse_series()
573 self.parse_series()
574 self.series_dirty = 1
574 self.series_dirty = 1
575 self.applied_dirty = 1
575 self.applied_dirty = 1
576 p = self.opener(patch, "w")
576 p = self.opener(patch, "w")
577 if msg:
577 if msg:
578 msg = msg + "\n"
578 msg = msg + "\n"
579 p.write(msg)
579 p.write(msg)
580 p.close()
580 p.close()
581 wlock = None
581 wlock = None
582 r = self.qrepo()
582 r = self.qrepo()
583 if r: r.add([patch])
583 if r: r.add([patch])
584 if commitfiles:
584 if commitfiles:
585 self.refresh(repo, short=True)
585 self.refresh(repo, short=True)
586
586
587 def strip(self, repo, rev, update=True, backup="all", wlock=None):
587 def strip(self, repo, rev, update=True, backup="all", wlock=None):
588 def limitheads(chlog, stop):
588 def limitheads(chlog, stop):
589 """return the list of all nodes that have no children"""
589 """return the list of all nodes that have no children"""
590 p = {}
590 p = {}
591 h = []
591 h = []
592 stoprev = 0
592 stoprev = 0
593 if stop in chlog.nodemap:
593 if stop in chlog.nodemap:
594 stoprev = chlog.rev(stop)
594 stoprev = chlog.rev(stop)
595
595
596 for r in xrange(chlog.count() - 1, -1, -1):
596 for r in xrange(chlog.count() - 1, -1, -1):
597 n = chlog.node(r)
597 n = chlog.node(r)
598 if n not in p:
598 if n not in p:
599 h.append(n)
599 h.append(n)
600 if n == stop:
600 if n == stop:
601 break
601 break
602 if r < stoprev:
602 if r < stoprev:
603 break
603 break
604 for pn in chlog.parents(n):
604 for pn in chlog.parents(n):
605 p[pn] = 1
605 p[pn] = 1
606 return h
606 return h
607
607
608 def bundle(cg):
608 def bundle(cg):
609 backupdir = repo.join("strip-backup")
609 backupdir = repo.join("strip-backup")
610 if not os.path.isdir(backupdir):
610 if not os.path.isdir(backupdir):
611 os.mkdir(backupdir)
611 os.mkdir(backupdir)
612 name = os.path.join(backupdir, "%s" % revlog.short(rev))
612 name = os.path.join(backupdir, "%s" % revlog.short(rev))
613 name = savename(name)
613 name = savename(name)
614 self.ui.warn("saving bundle to %s\n" % name)
614 self.ui.warn("saving bundle to %s\n" % name)
615 return changegroup.writebundle(cg, name, "HG10BZ")
615 return changegroup.writebundle(cg, name, "HG10BZ")
616
616
617 def stripall(rev, revnum):
617 def stripall(rev, revnum):
618 cl = repo.changelog
618 cl = repo.changelog
619 c = cl.read(rev)
619 c = cl.read(rev)
620 mm = repo.manifest.read(c[0])
620 mm = repo.manifest.read(c[0])
621 seen = {}
621 seen = {}
622
622
623 for x in xrange(revnum, cl.count()):
623 for x in xrange(revnum, cl.count()):
624 c = cl.read(cl.node(x))
624 c = cl.read(cl.node(x))
625 for f in c[3]:
625 for f in c[3]:
626 if f in seen:
626 if f in seen:
627 continue
627 continue
628 seen[f] = 1
628 seen[f] = 1
629 if f in mm:
629 if f in mm:
630 filerev = mm[f]
630 filerev = mm[f]
631 else:
631 else:
632 filerev = 0
632 filerev = 0
633 seen[f] = filerev
633 seen[f] = filerev
634 # we go in two steps here so the strip loop happens in a
634 # we go in two steps here so the strip loop happens in a
635 # sensible order. When stripping many files, this helps keep
635 # sensible order. When stripping many files, this helps keep
636 # our disk access patterns under control.
636 # our disk access patterns under control.
637 seen_list = seen.keys()
637 seen_list = seen.keys()
638 seen_list.sort()
638 seen_list.sort()
639 for f in seen_list:
639 for f in seen_list:
640 ff = repo.file(f)
640 ff = repo.file(f)
641 filerev = seen[f]
641 filerev = seen[f]
642 if filerev != 0:
642 if filerev != 0:
643 if filerev in ff.nodemap:
643 if filerev in ff.nodemap:
644 filerev = ff.rev(filerev)
644 filerev = ff.rev(filerev)
645 else:
645 else:
646 filerev = 0
646 filerev = 0
647 ff.strip(filerev, revnum)
647 ff.strip(filerev, revnum)
648
648
649 if not wlock:
649 if not wlock:
650 wlock = repo.wlock()
650 wlock = repo.wlock()
651 lock = repo.lock()
651 lock = repo.lock()
652 chlog = repo.changelog
652 chlog = repo.changelog
653 # TODO delete the undo files, and handle undo of merge sets
653 # TODO delete the undo files, and handle undo of merge sets
654 pp = chlog.parents(rev)
654 pp = chlog.parents(rev)
655 revnum = chlog.rev(rev)
655 revnum = chlog.rev(rev)
656
656
657 if update:
657 if update:
658 self.check_localchanges(repo, refresh=False)
658 self.check_localchanges(repo, refresh=False)
659 urev = self.qparents(repo, rev)
659 urev = self.qparents(repo, rev)
660 hg.clean(repo, urev, wlock=wlock)
660 hg.clean(repo, urev, wlock=wlock)
661 repo.dirstate.write()
661 repo.dirstate.write()
662
662
663 # save is a list of all the branches we are truncating away
663 # save is a list of all the branches we are truncating away
664 # that we actually want to keep. changegroup will be used
664 # that we actually want to keep. changegroup will be used
665 # to preserve them and add them back after the truncate
665 # to preserve them and add them back after the truncate
666 saveheads = []
666 saveheads = []
667 savebases = {}
667 savebases = {}
668
668
669 heads = limitheads(chlog, rev)
669 heads = limitheads(chlog, rev)
670 seen = {}
670 seen = {}
671
671
672 # search through all the heads, finding those where the revision
672 # search through all the heads, finding those where the revision
673 # we want to strip away is an ancestor. Also look for merges
673 # we want to strip away is an ancestor. Also look for merges
674 # that might be turned into new heads by the strip.
674 # that might be turned into new heads by the strip.
675 while heads:
675 while heads:
676 h = heads.pop()
676 h = heads.pop()
677 n = h
677 n = h
678 while True:
678 while True:
679 seen[n] = 1
679 seen[n] = 1
680 pp = chlog.parents(n)
680 pp = chlog.parents(n)
681 if pp[1] != revlog.nullid and chlog.rev(pp[1]) > revnum:
681 if pp[1] != revlog.nullid and chlog.rev(pp[1]) > revnum:
682 if pp[1] not in seen:
682 if pp[1] not in seen:
683 heads.append(pp[1])
683 heads.append(pp[1])
684 if pp[0] == revlog.nullid:
684 if pp[0] == revlog.nullid:
685 break
685 break
686 if chlog.rev(pp[0]) < revnum:
686 if chlog.rev(pp[0]) < revnum:
687 break
687 break
688 n = pp[0]
688 n = pp[0]
689 if n == rev:
689 if n == rev:
690 break
690 break
691 r = chlog.reachable(h, rev)
691 r = chlog.reachable(h, rev)
692 if rev not in r:
692 if rev not in r:
693 saveheads.append(h)
693 saveheads.append(h)
694 for x in r:
694 for x in r:
695 if chlog.rev(x) > revnum:
695 if chlog.rev(x) > revnum:
696 savebases[x] = 1
696 savebases[x] = 1
697
697
698 # create a changegroup for all the branches we need to keep
698 # create a changegroup for all the branches we need to keep
699 if backup == "all":
699 if backup == "all":
700 backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip')
700 backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip')
701 bundle(backupch)
701 bundle(backupch)
702 if saveheads:
702 if saveheads:
703 backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip')
703 backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip')
704 chgrpfile = bundle(backupch)
704 chgrpfile = bundle(backupch)
705
705
706 stripall(rev, revnum)
706 stripall(rev, revnum)
707
707
708 change = chlog.read(rev)
708 change = chlog.read(rev)
709 chlog.strip(revnum, revnum)
709 chlog.strip(revnum, revnum)
710 repo.manifest.strip(repo.manifest.rev(change[0]), revnum)
710 repo.manifest.strip(repo.manifest.rev(change[0]), revnum)
711 if saveheads:
711 if saveheads:
712 self.ui.status("adding branch\n")
712 self.ui.status("adding branch\n")
713 commands.unbundle(self.ui, repo, chgrpfile, update=False)
713 commands.unbundle(self.ui, repo, chgrpfile, update=False)
714 if backup != "strip":
714 if backup != "strip":
715 os.unlink(chgrpfile)
715 os.unlink(chgrpfile)
716
716
717 def isapplied(self, patch):
717 def isapplied(self, patch):
718 """returns (index, rev, patch)"""
718 """returns (index, rev, patch)"""
719 for i in xrange(len(self.applied)):
719 for i in xrange(len(self.applied)):
720 a = self.applied[i]
720 a = self.applied[i]
721 if a.name == patch:
721 if a.name == patch:
722 return (i, a.rev, a.name)
722 return (i, a.rev, a.name)
723 return None
723 return None
724
724
725 # if the exact patch name does not exist, we try a few
725 # if the exact patch name does not exist, we try a few
726 # variations. If strict is passed, we try only #1
726 # variations. If strict is passed, we try only #1
727 #
727 #
728 # 1) a number to indicate an offset in the series file
728 # 1) a number to indicate an offset in the series file
729 # 2) a unique substring of the patch name was given
729 # 2) a unique substring of the patch name was given
730 # 3) patchname[-+]num to indicate an offset in the series file
730 # 3) patchname[-+]num to indicate an offset in the series file
731 def lookup(self, patch, strict=False):
731 def lookup(self, patch, strict=False):
732 patch = patch and str(patch)
732 patch = patch and str(patch)
733
733
734 def partial_name(s):
734 def partial_name(s):
735 if s in self.series:
735 if s in self.series:
736 return s
736 return s
737 matches = [x for x in self.series if s in x]
737 matches = [x for x in self.series if s in x]
738 if len(matches) > 1:
738 if len(matches) > 1:
739 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
739 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
740 for m in matches:
740 for m in matches:
741 self.ui.warn(' %s\n' % m)
741 self.ui.warn(' %s\n' % m)
742 return None
742 return None
743 if matches:
743 if matches:
744 return matches[0]
744 return matches[0]
745 if len(self.series) > 0 and len(self.applied) > 0:
745 if len(self.series) > 0 and len(self.applied) > 0:
746 if s == 'qtip':
746 if s == 'qtip':
747 return self.series[self.series_end()-1]
747 return self.series[self.series_end()-1]
748 if s == 'qbase':
748 if s == 'qbase':
749 return self.series[0]
749 return self.series[0]
750 return None
750 return None
751 if patch == None:
751 if patch == None:
752 return None
752 return None
753
753
754 # we don't want to return a partial match until we make
754 # we don't want to return a partial match until we make
755 # sure the file name passed in does not exist (checked below)
755 # sure the file name passed in does not exist (checked below)
756 res = partial_name(patch)
756 res = partial_name(patch)
757 if res and res == patch:
757 if res and res == patch:
758 return res
758 return res
759
759
760 if not os.path.isfile(self.join(patch)):
760 if not os.path.isfile(self.join(patch)):
761 try:
761 try:
762 sno = int(patch)
762 sno = int(patch)
763 except(ValueError, OverflowError):
763 except(ValueError, OverflowError):
764 pass
764 pass
765 else:
765 else:
766 if sno < len(self.series):
766 if sno < len(self.series):
767 return self.series[sno]
767 return self.series[sno]
768 if not strict:
768 if not strict:
769 # return any partial match made above
769 # return any partial match made above
770 if res:
770 if res:
771 return res
771 return res
772 minus = patch.rfind('-')
772 minus = patch.rfind('-')
773 if minus >= 0:
773 if minus >= 0:
774 res = partial_name(patch[:minus])
774 res = partial_name(patch[:minus])
775 if res:
775 if res:
776 i = self.series.index(res)
776 i = self.series.index(res)
777 try:
777 try:
778 off = int(patch[minus+1:] or 1)
778 off = int(patch[minus+1:] or 1)
779 except(ValueError, OverflowError):
779 except(ValueError, OverflowError):
780 pass
780 pass
781 else:
781 else:
782 if i - off >= 0:
782 if i - off >= 0:
783 return self.series[i - off]
783 return self.series[i - off]
784 plus = patch.rfind('+')
784 plus = patch.rfind('+')
785 if plus >= 0:
785 if plus >= 0:
786 res = partial_name(patch[:plus])
786 res = partial_name(patch[:plus])
787 if res:
787 if res:
788 i = self.series.index(res)
788 i = self.series.index(res)
789 try:
789 try:
790 off = int(patch[plus+1:] or 1)
790 off = int(patch[plus+1:] or 1)
791 except(ValueError, OverflowError):
791 except(ValueError, OverflowError):
792 pass
792 pass
793 else:
793 else:
794 if i + off < len(self.series):
794 if i + off < len(self.series):
795 return self.series[i + off]
795 return self.series[i + off]
796 raise util.Abort(_("patch %s not in series") % patch)
796 raise util.Abort(_("patch %s not in series") % patch)
797
797
798 def push(self, repo, patch=None, force=False, list=False,
798 def push(self, repo, patch=None, force=False, list=False,
799 mergeq=None, wlock=None):
799 mergeq=None, wlock=None):
800 if not wlock:
800 if not wlock:
801 wlock = repo.wlock()
801 wlock = repo.wlock()
802 patch = self.lookup(patch)
802 patch = self.lookup(patch)
803 if patch and self.isapplied(patch):
803 if patch and self.isapplied(patch):
804 raise util.Abort(_("patch %s is already applied") % patch)
804 raise util.Abort(_("patch %s is already applied") % patch)
805 if self.series_end() == len(self.series):
805 if self.series_end() == len(self.series):
806 raise util.Abort(_("patch series fully applied"))
806 raise util.Abort(_("patch series fully applied"))
807 if not force:
807 if not force:
808 self.check_localchanges(repo)
808 self.check_localchanges(repo)
809
809
810 self.applied_dirty = 1;
810 self.applied_dirty = 1;
811 start = self.series_end()
811 start = self.series_end()
812 if start > 0:
812 if start > 0:
813 self.check_toppatch(repo)
813 self.check_toppatch(repo)
814 if not patch:
814 if not patch:
815 patch = self.series[start]
815 patch = self.series[start]
816 end = start + 1
816 end = start + 1
817 else:
817 else:
818 end = self.series.index(patch, start) + 1
818 end = self.series.index(patch, start) + 1
819 s = self.series[start:end]
819 s = self.series[start:end]
820 if mergeq:
820 if mergeq:
821 ret = self.mergepatch(repo, mergeq, s, wlock)
821 ret = self.mergepatch(repo, mergeq, s, wlock)
822 else:
822 else:
823 ret = self.apply(repo, s, list, wlock=wlock)
823 ret = self.apply(repo, s, list, wlock=wlock)
824 top = self.applied[-1].name
824 top = self.applied[-1].name
825 if ret[0]:
825 if ret[0]:
826 self.ui.write("Errors during apply, please fix and refresh %s\n" %
826 self.ui.write("Errors during apply, please fix and refresh %s\n" %
827 top)
827 top)
828 else:
828 else:
829 self.ui.write("Now at: %s\n" % top)
829 self.ui.write("Now at: %s\n" % top)
830 return ret[0]
830 return ret[0]
831
831
832 def pop(self, repo, patch=None, force=False, update=True, all=False,
832 def pop(self, repo, patch=None, force=False, update=True, all=False,
833 wlock=None):
833 wlock=None):
834 def getfile(f, rev):
834 def getfile(f, rev):
835 t = repo.file(f).read(rev)
835 t = repo.file(f).read(rev)
836 try:
836 try:
837 repo.wfile(f, "w").write(t)
837 repo.wfile(f, "w").write(t)
838 except IOError:
838 except IOError:
839 try:
839 try:
840 os.makedirs(os.path.dirname(repo.wjoin(f)))
840 os.makedirs(os.path.dirname(repo.wjoin(f)))
841 except OSError, err:
841 except OSError, err:
842 if err.errno != errno.EEXIST: raise
842 if err.errno != errno.EEXIST: raise
843 repo.wfile(f, "w").write(t)
843 repo.wfile(f, "w").write(t)
844
844
845 if not wlock:
845 if not wlock:
846 wlock = repo.wlock()
846 wlock = repo.wlock()
847 if patch:
847 if patch:
848 # index, rev, patch
848 # index, rev, patch
849 info = self.isapplied(patch)
849 info = self.isapplied(patch)
850 if not info:
850 if not info:
851 patch = self.lookup(patch)
851 patch = self.lookup(patch)
852 info = self.isapplied(patch)
852 info = self.isapplied(patch)
853 if not info:
853 if not info:
854 raise util.Abort(_("patch %s is not applied") % patch)
854 raise util.Abort(_("patch %s is not applied") % patch)
855 if len(self.applied) == 0:
855 if len(self.applied) == 0:
856 raise util.Abort(_("no patches applied"))
856 raise util.Abort(_("no patches applied"))
857
857
858 if not update:
858 if not update:
859 parents = repo.dirstate.parents()
859 parents = repo.dirstate.parents()
860 rr = [ revlog.bin(x.rev) for x in self.applied ]
860 rr = [ revlog.bin(x.rev) for x in self.applied ]
861 for p in parents:
861 for p in parents:
862 if p in rr:
862 if p in rr:
863 self.ui.warn("qpop: forcing dirstate update\n")
863 self.ui.warn("qpop: forcing dirstate update\n")
864 update = True
864 update = True
865
865
866 if not force and update:
866 if not force and update:
867 self.check_localchanges(repo)
867 self.check_localchanges(repo)
868
868
869 self.applied_dirty = 1;
869 self.applied_dirty = 1;
870 end = len(self.applied)
870 end = len(self.applied)
871 if not patch:
871 if not patch:
872 if all:
872 if all:
873 popi = 0
873 popi = 0
874 else:
874 else:
875 popi = len(self.applied) - 1
875 popi = len(self.applied) - 1
876 else:
876 else:
877 popi = info[0] + 1
877 popi = info[0] + 1
878 if popi >= end:
878 if popi >= end:
879 self.ui.warn("qpop: %s is already at the top\n" % patch)
879 self.ui.warn("qpop: %s is already at the top\n" % patch)
880 return
880 return
881 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
881 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
882
882
883 start = info[0]
883 start = info[0]
884 rev = revlog.bin(info[1])
884 rev = revlog.bin(info[1])
885
885
886 # we know there are no local changes, so we can make a simplified
886 # we know there are no local changes, so we can make a simplified
887 # form of hg.update.
887 # form of hg.update.
888 if update:
888 if update:
889 top = self.check_toppatch(repo)
889 top = self.check_toppatch(repo)
890 qp = self.qparents(repo, rev)
890 qp = self.qparents(repo, rev)
891 changes = repo.changelog.read(qp)
891 changes = repo.changelog.read(qp)
892 mmap = repo.manifest.read(changes[0])
892 mmap = repo.manifest.read(changes[0])
893 m, a, r, d, u = repo.status(qp, top)[:5]
893 m, a, r, d, u = repo.status(qp, top)[:5]
894 if d:
894 if d:
895 raise util.Abort("deletions found between repo revs")
895 raise util.Abort("deletions found between repo revs")
896 for f in m:
896 for f in m:
897 getfile(f, mmap[f])
897 getfile(f, mmap[f])
898 for f in r:
898 for f in r:
899 getfile(f, mmap[f])
899 getfile(f, mmap[f])
900 util.set_exec(repo.wjoin(f), mmap.execf(f))
900 util.set_exec(repo.wjoin(f), mmap.execf(f))
901 repo.dirstate.update(m + r, 'n')
901 repo.dirstate.update(m + r, 'n')
902 for f in a:
902 for f in a:
903 try:
903 try:
904 os.unlink(repo.wjoin(f))
904 os.unlink(repo.wjoin(f))
905 except OSError, e:
905 except OSError, e:
906 if e.errno != errno.ENOENT:
906 if e.errno != errno.ENOENT:
907 raise
907 raise
908 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
908 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
909 except: pass
909 except: pass
910 if a:
910 if a:
911 repo.dirstate.forget(a)
911 repo.dirstate.forget(a)
912 repo.dirstate.setparents(qp, revlog.nullid)
912 repo.dirstate.setparents(qp, revlog.nullid)
913 self.strip(repo, rev, update=False, backup='strip', wlock=wlock)
913 self.strip(repo, rev, update=False, backup='strip', wlock=wlock)
914 del self.applied[start:end]
914 del self.applied[start:end]
915 if len(self.applied):
915 if len(self.applied):
916 self.ui.write("Now at: %s\n" % self.applied[-1].name)
916 self.ui.write("Now at: %s\n" % self.applied[-1].name)
917 else:
917 else:
918 self.ui.write("Patch queue now empty\n")
918 self.ui.write("Patch queue now empty\n")
919
919
920 def diff(self, repo, pats, opts):
920 def diff(self, repo, pats, opts):
921 top = self.check_toppatch(repo)
921 top = self.check_toppatch(repo)
922 if not top:
922 if not top:
923 self.ui.write("No patches applied\n")
923 self.ui.write("No patches applied\n")
924 return
924 return
925 qp = self.qparents(repo, top)
925 qp = self.qparents(repo, top)
926 if opts.get('git'):
926 if opts.get('git'):
927 self.diffopts().git = True
927 self.diffopts().git = True
928 self.printdiff(repo, qp, files=pats, opts=opts)
928 self.printdiff(repo, qp, files=pats, opts=opts)
929
929
930 def refresh(self, repo, pats=None, **opts):
930 def refresh(self, repo, pats=None, **opts):
931 if len(self.applied) == 0:
931 if len(self.applied) == 0:
932 self.ui.write("No patches applied\n")
932 self.ui.write("No patches applied\n")
933 return 1
933 return 1
934 wlock = repo.wlock()
934 wlock = repo.wlock()
935 self.check_toppatch(repo)
935 self.check_toppatch(repo)
936 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
936 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
937 top = revlog.bin(top)
937 top = revlog.bin(top)
938 cparents = repo.changelog.parents(top)
938 cparents = repo.changelog.parents(top)
939 patchparent = self.qparents(repo, top)
939 patchparent = self.qparents(repo, top)
940 message, comments, user, date, patchfound = self.readheaders(patchfn)
940 message, comments, user, date, patchfound = self.readheaders(patchfn)
941
941
942 patchf = self.opener(patchfn, "w")
942 patchf = self.opener(patchfn, "w")
943 msg = opts.get('msg', '').rstrip()
943 msg = opts.get('msg', '').rstrip()
944 if msg:
944 if msg:
945 if comments:
945 if comments:
946 # Remove existing message.
946 # Remove existing message.
947 ci = 0
947 ci = 0
948 for mi in xrange(len(message)):
948 for mi in xrange(len(message)):
949 while message[mi] != comments[ci]:
949 while message[mi] != comments[ci]:
950 ci += 1
950 ci += 1
951 del comments[ci]
951 del comments[ci]
952 comments.append(msg)
952 comments.append(msg)
953 if comments:
953 if comments:
954 comments = "\n".join(comments) + '\n\n'
954 comments = "\n".join(comments) + '\n\n'
955 patchf.write(comments)
955 patchf.write(comments)
956
956
957 if opts.get('git'):
957 if opts.get('git'):
958 self.diffopts().git = True
958 self.diffopts().git = True
959 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
959 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
960 tip = repo.changelog.tip()
960 tip = repo.changelog.tip()
961 if top == tip:
961 if top == tip:
962 # if the top of our patch queue is also the tip, there is an
962 # if the top of our patch queue is also the tip, there is an
963 # optimization here. We update the dirstate in place and strip
963 # optimization here. We update the dirstate in place and strip
964 # off the tip commit. Then just commit the current directory
964 # off the tip commit. Then just commit the current directory
965 # tree. We can also send repo.commit the list of files
965 # tree. We can also send repo.commit the list of files
966 # changed to speed up the diff
966 # changed to speed up the diff
967 #
967 #
968 # in short mode, we only diff the files included in the
968 # in short mode, we only diff the files included in the
969 # patch already
969 # patch already
970 #
970 #
971 # this should really read:
971 # this should really read:
972 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
972 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
973 # but we do it backwards to take advantage of manifest/chlog
973 # but we do it backwards to take advantage of manifest/chlog
974 # caching against the next repo.status call
974 # caching against the next repo.status call
975 #
975 #
976 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
976 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
977 changes = repo.changelog.read(tip)
977 changes = repo.changelog.read(tip)
978 man = repo.manifest.read(changes[0])
978 man = repo.manifest.read(changes[0])
979 aaa = aa[:]
979 aaa = aa[:]
980 if opts.get('short'):
980 if opts.get('short'):
981 filelist = mm + aa + dd
981 filelist = mm + aa + dd
982 else:
982 else:
983 filelist = None
983 filelist = None
984 m, a, r, d, u = repo.status(files=filelist)[:5]
984 m, a, r, d, u = repo.status(files=filelist)[:5]
985
985
986 # we might end up with files that were added between tip and
986 # we might end up with files that were added between tip and
987 # the dirstate parent, but then changed in the local dirstate.
987 # the dirstate parent, but then changed in the local dirstate.
988 # in this case, we want them to only show up in the added section
988 # in this case, we want them to only show up in the added section
989 for x in m:
989 for x in m:
990 if x not in aa:
990 if x not in aa:
991 mm.append(x)
991 mm.append(x)
992 # we might end up with files added by the local dirstate that
992 # we might end up with files added by the local dirstate that
993 # were deleted by the patch. In this case, they should only
993 # were deleted by the patch. In this case, they should only
994 # show up in the changed section.
994 # show up in the changed section.
995 for x in a:
995 for x in a:
996 if x in dd:
996 if x in dd:
997 del dd[dd.index(x)]
997 del dd[dd.index(x)]
998 mm.append(x)
998 mm.append(x)
999 else:
999 else:
1000 aa.append(x)
1000 aa.append(x)
1001 # make sure any files deleted in the local dirstate
1001 # make sure any files deleted in the local dirstate
1002 # are not in the add or change column of the patch
1002 # are not in the add or change column of the patch
1003 forget = []
1003 forget = []
1004 for x in d + r:
1004 for x in d + r:
1005 if x in aa:
1005 if x in aa:
1006 del aa[aa.index(x)]
1006 del aa[aa.index(x)]
1007 forget.append(x)
1007 forget.append(x)
1008 continue
1008 continue
1009 elif x in mm:
1009 elif x in mm:
1010 del mm[mm.index(x)]
1010 del mm[mm.index(x)]
1011 dd.append(x)
1011 dd.append(x)
1012
1012
1013 m = util.unique(mm)
1013 m = util.unique(mm)
1014 r = util.unique(dd)
1014 r = util.unique(dd)
1015 a = util.unique(aa)
1015 a = util.unique(aa)
1016 filelist = filter(matchfn, util.unique(m + r + a))
1016 filelist = filter(matchfn, util.unique(m + r + a))
1017 patch.diff(repo, patchparent, files=filelist, match=matchfn,
1017 patch.diff(repo, patchparent, files=filelist, match=matchfn,
1018 fp=patchf, changes=(m, a, r, [], u),
1018 fp=patchf, changes=(m, a, r, [], u),
1019 opts=self.diffopts())
1019 opts=self.diffopts())
1020 patchf.close()
1020 patchf.close()
1021
1021
1022 repo.dirstate.setparents(*cparents)
1022 repo.dirstate.setparents(*cparents)
1023 copies = {}
1023 copies = {}
1024 for dst in a:
1024 for dst in a:
1025 src = repo.dirstate.copied(dst)
1025 src = repo.dirstate.copied(dst)
1026 if src is None:
1026 if src is None:
1027 continue
1027 continue
1028 copies.setdefault(src, []).append(dst)
1028 copies.setdefault(src, []).append(dst)
1029 repo.dirstate.update(a, 'a')
1029 repo.dirstate.update(a, 'a')
1030 # remember the copies between patchparent and tip
1030 # remember the copies between patchparent and tip
1031 # this may be slow, so don't do it if we're not tracking copies
1031 # this may be slow, so don't do it if we're not tracking copies
1032 if self.diffopts().git:
1032 if self.diffopts().git:
1033 for dst in aaa:
1033 for dst in aaa:
1034 f = repo.file(dst)
1034 f = repo.file(dst)
1035 src = f.renamed(man[dst])
1035 src = f.renamed(man[dst])
1036 if src:
1036 if src:
1037 copies[src[0]] = copies.get(dst, [])
1037 copies[src[0]] = copies.get(dst, [])
1038 if dst in a:
1038 if dst in a:
1039 copies[src[0]].append(dst)
1039 copies[src[0]].append(dst)
1040 # we can't copy a file created by the patch itself
1040 # we can't copy a file created by the patch itself
1041 if dst in copies:
1041 if dst in copies:
1042 del copies[dst]
1042 del copies[dst]
1043 for src, dsts in copies.iteritems():
1043 for src, dsts in copies.iteritems():
1044 for dst in dsts:
1044 for dst in dsts:
1045 repo.dirstate.copy(src, dst)
1045 repo.dirstate.copy(src, dst)
1046 repo.dirstate.update(r, 'r')
1046 repo.dirstate.update(r, 'r')
1047 # if the patch excludes a modified file, mark that file with mtime=0
1047 # if the patch excludes a modified file, mark that file with mtime=0
1048 # so status can see it.
1048 # so status can see it.
1049 mm = []
1049 mm = []
1050 for i in xrange(len(m)-1, -1, -1):
1050 for i in xrange(len(m)-1, -1, -1):
1051 if not matchfn(m[i]):
1051 if not matchfn(m[i]):
1052 mm.append(m[i])
1052 mm.append(m[i])
1053 del m[i]
1053 del m[i]
1054 repo.dirstate.update(m, 'n')
1054 repo.dirstate.update(m, 'n')
1055 repo.dirstate.update(mm, 'n', st_mtime=0)
1055 repo.dirstate.update(mm, 'n', st_mtime=0)
1056 repo.dirstate.forget(forget)
1056 repo.dirstate.forget(forget)
1057
1057
1058 if not msg:
1058 if not msg:
1059 if not message:
1059 if not message:
1060 message = "patch queue: %s\n" % patchfn
1060 message = "patch queue: %s\n" % patchfn
1061 else:
1061 else:
1062 message = "\n".join(message)
1062 message = "\n".join(message)
1063 else:
1063 else:
1064 message = msg
1064 message = msg
1065
1065
1066 self.strip(repo, top, update=False, backup='strip', wlock=wlock)
1066 self.strip(repo, top, update=False, backup='strip', wlock=wlock)
1067 n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock)
1067 n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock)
1068 self.applied[-1] = statusentry(revlog.hex(n), patchfn)
1068 self.applied[-1] = statusentry(revlog.hex(n), patchfn)
1069 self.applied_dirty = 1
1069 self.applied_dirty = 1
1070 else:
1070 else:
1071 self.printdiff(repo, patchparent, fp=patchf)
1071 self.printdiff(repo, patchparent, fp=patchf)
1072 patchf.close()
1072 patchf.close()
1073 added = repo.status()[1]
1073 added = repo.status()[1]
1074 for a in added:
1074 for a in added:
1075 f = repo.wjoin(a)
1075 f = repo.wjoin(a)
1076 try:
1076 try:
1077 os.unlink(f)
1077 os.unlink(f)
1078 except OSError, e:
1078 except OSError, e:
1079 if e.errno != errno.ENOENT:
1079 if e.errno != errno.ENOENT:
1080 raise
1080 raise
1081 try: os.removedirs(os.path.dirname(f))
1081 try: os.removedirs(os.path.dirname(f))
1082 except: pass
1082 except: pass
1083 # forget the file copies in the dirstate
1083 # forget the file copies in the dirstate
1084 # push should readd the files later on
1084 # push should readd the files later on
1085 repo.dirstate.forget(added)
1085 repo.dirstate.forget(added)
1086 self.pop(repo, force=True, wlock=wlock)
1086 self.pop(repo, force=True, wlock=wlock)
1087 self.push(repo, force=True, wlock=wlock)
1087 self.push(repo, force=True, wlock=wlock)
1088
1088
1089 def init(self, repo, create=False):
1089 def init(self, repo, create=False):
1090 if os.path.isdir(self.path):
1090 if os.path.isdir(self.path):
1091 raise util.Abort(_("patch queue directory already exists"))
1091 raise util.Abort(_("patch queue directory already exists"))
1092 os.mkdir(self.path)
1092 os.mkdir(self.path)
1093 if create:
1093 if create:
1094 return self.qrepo(create=True)
1094 return self.qrepo(create=True)
1095
1095
1096 def unapplied(self, repo, patch=None):
1096 def unapplied(self, repo, patch=None):
1097 if patch and patch not in self.series:
1097 if patch and patch not in self.series:
1098 raise util.Abort(_("patch %s is not in series file") % patch)
1098 raise util.Abort(_("patch %s is not in series file") % patch)
1099 if not patch:
1099 if not patch:
1100 start = self.series_end()
1100 start = self.series_end()
1101 else:
1101 else:
1102 start = self.series.index(patch) + 1
1102 start = self.series.index(patch) + 1
1103 unapplied = []
1103 unapplied = []
1104 for i in xrange(start, len(self.series)):
1104 for i in xrange(start, len(self.series)):
1105 pushable, reason = self.pushable(i)
1105 pushable, reason = self.pushable(i)
1106 if pushable:
1106 if pushable:
1107 unapplied.append((i, self.series[i]))
1107 unapplied.append((i, self.series[i]))
1108 self.explain_pushable(i)
1108 self.explain_pushable(i)
1109 return unapplied
1109 return unapplied
1110
1110
1111 def qseries(self, repo, missing=None, start=0, length=0, status=None,
1111 def qseries(self, repo, missing=None, start=0, length=0, status=None,
1112 summary=False):
1112 summary=False):
1113 def displayname(patchname):
1113 def displayname(patchname):
1114 if summary:
1114 if summary:
1115 msg = self.readheaders(patchname)[0]
1115 msg = self.readheaders(patchname)[0]
1116 msg = msg and ': ' + msg[0] or ': '
1116 msg = msg and ': ' + msg[0] or ': '
1117 else:
1117 else:
1118 msg = ''
1118 msg = ''
1119 return '%s%s' % (patchname, msg)
1119 return '%s%s' % (patchname, msg)
1120
1120
1121 def pname(i):
1121 def pname(i):
1122 if status == 'A':
1122 if status == 'A':
1123 return self.applied[i].name
1123 return self.applied[i].name
1124 else:
1124 else:
1125 return self.series[i]
1125 return self.series[i]
1126
1126
1127 applied = dict.fromkeys([p.name for p in self.applied])
1127 applied = dict.fromkeys([p.name for p in self.applied])
1128 if not length:
1128 if not length:
1129 length = len(self.series) - start
1129 length = len(self.series) - start
1130 if not missing:
1130 if not missing:
1131 for i in xrange(start, start+length):
1131 for i in xrange(start, start+length):
1132 pfx = ''
1132 pfx = ''
1133 patch = pname(i)
1133 patch = pname(i)
1134 if self.ui.verbose:
1134 if self.ui.verbose:
1135 if patch in applied:
1135 if patch in applied:
1136 stat = 'A'
1136 stat = 'A'
1137 elif self.pushable(i)[0]:
1137 elif self.pushable(i)[0]:
1138 stat = 'U'
1138 stat = 'U'
1139 else:
1139 else:
1140 stat = 'G'
1140 stat = 'G'
1141 pfx = '%d %s ' % (i, stat)
1141 pfx = '%d %s ' % (i, stat)
1142 self.ui.write('%s%s\n' % (pfx, displayname(patch)))
1142 self.ui.write('%s%s\n' % (pfx, displayname(patch)))
1143 else:
1143 else:
1144 msng_list = []
1144 msng_list = []
1145 for root, dirs, files in os.walk(self.path):
1145 for root, dirs, files in os.walk(self.path):
1146 d = root[len(self.path) + 1:]
1146 d = root[len(self.path) + 1:]
1147 for f in files:
1147 for f in files:
1148 fl = os.path.join(d, f)
1148 fl = os.path.join(d, f)
1149 if (fl not in self.series and
1149 if (fl not in self.series and
1150 fl not in (self.status_path, self.series_path)
1150 fl not in (self.status_path, self.series_path)
1151 and not fl.startswith('.')):
1151 and not fl.startswith('.')):
1152 msng_list.append(fl)
1152 msng_list.append(fl)
1153 msng_list.sort()
1153 msng_list.sort()
1154 for x in msng_list:
1154 for x in msng_list:
1155 pfx = self.ui.verbose and ('D ') or ''
1155 pfx = self.ui.verbose and ('D ') or ''
1156 self.ui.write("%s%s\n" % (pfx, displayname(x)))
1156 self.ui.write("%s%s\n" % (pfx, displayname(x)))
1157
1157
1158 def issaveline(self, l):
1158 def issaveline(self, l):
1159 if l.name == '.hg.patches.save.line':
1159 if l.name == '.hg.patches.save.line':
1160 return True
1160 return True
1161
1161
1162 def qrepo(self, create=False):
1162 def qrepo(self, create=False):
1163 if create or os.path.isdir(self.join(".hg")):
1163 if create or os.path.isdir(self.join(".hg")):
1164 return hg.repository(self.ui, path=self.path, create=create)
1164 return hg.repository(self.ui, path=self.path, create=create)
1165
1165
1166 def restore(self, repo, rev, delete=None, qupdate=None):
1166 def restore(self, repo, rev, delete=None, qupdate=None):
1167 c = repo.changelog.read(rev)
1167 c = repo.changelog.read(rev)
1168 desc = c[4].strip()
1168 desc = c[4].strip()
1169 lines = desc.splitlines()
1169 lines = desc.splitlines()
1170 i = 0
1170 i = 0
1171 datastart = None
1171 datastart = None
1172 series = []
1172 series = []
1173 applied = []
1173 applied = []
1174 qpp = None
1174 qpp = None
1175 for i in xrange(0, len(lines)):
1175 for i in xrange(0, len(lines)):
1176 if lines[i] == 'Patch Data:':
1176 if lines[i] == 'Patch Data:':
1177 datastart = i + 1
1177 datastart = i + 1
1178 elif lines[i].startswith('Dirstate:'):
1178 elif lines[i].startswith('Dirstate:'):
1179 l = lines[i].rstrip()
1179 l = lines[i].rstrip()
1180 l = l[10:].split(' ')
1180 l = l[10:].split(' ')
1181 qpp = [ hg.bin(x) for x in l ]
1181 qpp = [ hg.bin(x) for x in l ]
1182 elif datastart != None:
1182 elif datastart != None:
1183 l = lines[i].rstrip()
1183 l = lines[i].rstrip()
1184 se = statusentry(l)
1184 se = statusentry(l)
1185 file_ = se.name
1185 file_ = se.name
1186 if se.rev:
1186 if se.rev:
1187 applied.append(se)
1187 applied.append(se)
1188 else:
1188 else:
1189 series.append(file_)
1189 series.append(file_)
1190 if datastart == None:
1190 if datastart == None:
1191 self.ui.warn("No saved patch data found\n")
1191 self.ui.warn("No saved patch data found\n")
1192 return 1
1192 return 1
1193 self.ui.warn("restoring status: %s\n" % lines[0])
1193 self.ui.warn("restoring status: %s\n" % lines[0])
1194 self.full_series = series
1194 self.full_series = series
1195 self.applied = applied
1195 self.applied = applied
1196 self.parse_series()
1196 self.parse_series()
1197 self.series_dirty = 1
1197 self.series_dirty = 1
1198 self.applied_dirty = 1
1198 self.applied_dirty = 1
1199 heads = repo.changelog.heads()
1199 heads = repo.changelog.heads()
1200 if delete:
1200 if delete:
1201 if rev not in heads:
1201 if rev not in heads:
1202 self.ui.warn("save entry has children, leaving it alone\n")
1202 self.ui.warn("save entry has children, leaving it alone\n")
1203 else:
1203 else:
1204 self.ui.warn("removing save entry %s\n" % hg.short(rev))
1204 self.ui.warn("removing save entry %s\n" % hg.short(rev))
1205 pp = repo.dirstate.parents()
1205 pp = repo.dirstate.parents()
1206 if rev in pp:
1206 if rev in pp:
1207 update = True
1207 update = True
1208 else:
1208 else:
1209 update = False
1209 update = False
1210 self.strip(repo, rev, update=update, backup='strip')
1210 self.strip(repo, rev, update=update, backup='strip')
1211 if qpp:
1211 if qpp:
1212 self.ui.warn("saved queue repository parents: %s %s\n" %
1212 self.ui.warn("saved queue repository parents: %s %s\n" %
1213 (hg.short(qpp[0]), hg.short(qpp[1])))
1213 (hg.short(qpp[0]), hg.short(qpp[1])))
1214 if qupdate:
1214 if qupdate:
1215 print "queue directory updating"
1215 print "queue directory updating"
1216 r = self.qrepo()
1216 r = self.qrepo()
1217 if not r:
1217 if not r:
1218 self.ui.warn("Unable to load queue repository\n")
1218 self.ui.warn("Unable to load queue repository\n")
1219 return 1
1219 return 1
1220 hg.clean(r, qpp[0])
1220 hg.clean(r, qpp[0])
1221
1221
1222 def save(self, repo, msg=None):
1222 def save(self, repo, msg=None):
1223 if len(self.applied) == 0:
1223 if len(self.applied) == 0:
1224 self.ui.warn("save: no patches applied, exiting\n")
1224 self.ui.warn("save: no patches applied, exiting\n")
1225 return 1
1225 return 1
1226 if self.issaveline(self.applied[-1]):
1226 if self.issaveline(self.applied[-1]):
1227 self.ui.warn("status is already saved\n")
1227 self.ui.warn("status is already saved\n")
1228 return 1
1228 return 1
1229
1229
1230 ar = [ ':' + x for x in self.full_series ]
1230 ar = [ ':' + x for x in self.full_series ]
1231 if not msg:
1231 if not msg:
1232 msg = "hg patches saved state"
1232 msg = "hg patches saved state"
1233 else:
1233 else:
1234 msg = "hg patches: " + msg.rstrip('\r\n')
1234 msg = "hg patches: " + msg.rstrip('\r\n')
1235 r = self.qrepo()
1235 r = self.qrepo()
1236 if r:
1236 if r:
1237 pp = r.dirstate.parents()
1237 pp = r.dirstate.parents()
1238 msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1]))
1238 msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1]))
1239 msg += "\n\nPatch Data:\n"
1239 msg += "\n\nPatch Data:\n"
1240 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1240 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1241 "\n".join(ar) + '\n' or "")
1241 "\n".join(ar) + '\n' or "")
1242 n = repo.commit(None, text, user=None, force=1)
1242 n = repo.commit(None, text, user=None, force=1)
1243 if not n:
1243 if not n:
1244 self.ui.warn("repo commit failed\n")
1244 self.ui.warn("repo commit failed\n")
1245 return 1
1245 return 1
1246 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1246 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1247 self.applied_dirty = 1
1247 self.applied_dirty = 1
1248
1248
1249 def full_series_end(self):
1249 def full_series_end(self):
1250 if len(self.applied) > 0:
1250 if len(self.applied) > 0:
1251 p = self.applied[-1].name
1251 p = self.applied[-1].name
1252 end = self.find_series(p)
1252 end = self.find_series(p)
1253 if end == None:
1253 if end == None:
1254 return len(self.full_series)
1254 return len(self.full_series)
1255 return end + 1
1255 return end + 1
1256 return 0
1256 return 0
1257
1257
1258 def series_end(self, all_patches=False):
1258 def series_end(self, all_patches=False):
1259 end = 0
1259 end = 0
1260 def next(start):
1260 def next(start):
1261 if all_patches:
1261 if all_patches:
1262 return start
1262 return start
1263 i = start
1263 i = start
1264 while i < len(self.series):
1264 while i < len(self.series):
1265 p, reason = self.pushable(i)
1265 p, reason = self.pushable(i)
1266 if p:
1266 if p:
1267 break
1267 break
1268 self.explain_pushable(i)
1268 self.explain_pushable(i)
1269 i += 1
1269 i += 1
1270 return i
1270 return i
1271 if len(self.applied) > 0:
1271 if len(self.applied) > 0:
1272 p = self.applied[-1].name
1272 p = self.applied[-1].name
1273 try:
1273 try:
1274 end = self.series.index(p)
1274 end = self.series.index(p)
1275 except ValueError:
1275 except ValueError:
1276 return 0
1276 return 0
1277 return next(end + 1)
1277 return next(end + 1)
1278 return next(end)
1278 return next(end)
1279
1279
1280 def appliedname(self, index):
1280 def appliedname(self, index):
1281 pname = self.applied[index].name
1281 pname = self.applied[index].name
1282 if not self.ui.verbose:
1282 if not self.ui.verbose:
1283 p = pname
1283 p = pname
1284 else:
1284 else:
1285 p = str(self.series.index(pname)) + " " + pname
1285 p = str(self.series.index(pname)) + " " + pname
1286 return p
1286 return p
1287
1287
1288 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1288 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1289 force=None, git=False):
1289 force=None, git=False):
1290 def checkseries(patchname):
1290 def checkseries(patchname):
1291 if patchname in self.series:
1291 if patchname in self.series:
1292 raise util.Abort(_('patch %s is already in the series file')
1292 raise util.Abort(_('patch %s is already in the series file')
1293 % patchname)
1293 % patchname)
1294 def checkfile(patchname):
1294 def checkfile(patchname):
1295 if not force and os.path.exists(self.join(patchname)):
1295 if not force and os.path.exists(self.join(patchname)):
1296 raise util.Abort(_('patch "%s" already exists')
1296 raise util.Abort(_('patch "%s" already exists')
1297 % patchname)
1297 % patchname)
1298
1298
1299 if rev:
1299 if rev:
1300 if files:
1300 if files:
1301 raise util.Abort(_('option "-r" not valid when importing '
1301 raise util.Abort(_('option "-r" not valid when importing '
1302 'files'))
1302 'files'))
1303 rev = cmdutil.revrange(repo, rev)
1303 rev = cmdutil.revrange(repo, rev)
1304 rev.sort(lambda x, y: cmp(y, x))
1304 rev.sort(lambda x, y: cmp(y, x))
1305 if (len(files) > 1 or len(rev) > 1) and patchname:
1305 if (len(files) > 1 or len(rev) > 1) and patchname:
1306 raise util.Abort(_('option "-n" not valid when importing multiple '
1306 raise util.Abort(_('option "-n" not valid when importing multiple '
1307 'patches'))
1307 'patches'))
1308 i = 0
1308 i = 0
1309 added = []
1309 added = []
1310 if rev:
1310 if rev:
1311 # If mq patches are applied, we can only import revisions
1311 # If mq patches are applied, we can only import revisions
1312 # that form a linear path to qbase.
1312 # that form a linear path to qbase.
1313 # Otherwise, they should form a linear path to a head.
1313 # Otherwise, they should form a linear path to a head.
1314 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1314 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1315 if len(heads) > 1:
1315 if len(heads) > 1:
1316 raise util.Abort(_('revision %d is the root of more than one '
1316 raise util.Abort(_('revision %d is the root of more than one '
1317 'branch') % rev[-1])
1317 'branch') % rev[-1])
1318 if self.applied:
1318 if self.applied:
1319 base = revlog.hex(repo.changelog.node(rev[0]))
1319 base = revlog.hex(repo.changelog.node(rev[0]))
1320 if base in [n.rev for n in self.applied]:
1320 if base in [n.rev for n in self.applied]:
1321 raise util.Abort(_('revision %d is already managed')
1321 raise util.Abort(_('revision %d is already managed')
1322 % rev[0])
1322 % rev[0])
1323 if heads != [revlog.bin(self.applied[-1].rev)]:
1323 if heads != [revlog.bin(self.applied[-1].rev)]:
1324 raise util.Abort(_('revision %d is not the parent of '
1324 raise util.Abort(_('revision %d is not the parent of '
1325 'the queue') % rev[0])
1325 'the queue') % rev[0])
1326 base = repo.changelog.rev(revlog.bin(self.applied[0].rev))
1326 base = repo.changelog.rev(revlog.bin(self.applied[0].rev))
1327 lastparent = repo.changelog.parentrevs(base)[0]
1327 lastparent = repo.changelog.parentrevs(base)[0]
1328 else:
1328 else:
1329 if heads != [repo.changelog.node(rev[0])]:
1329 if heads != [repo.changelog.node(rev[0])]:
1330 raise util.Abort(_('revision %d has unmanaged children')
1330 raise util.Abort(_('revision %d has unmanaged children')
1331 % rev[0])
1331 % rev[0])
1332 lastparent = None
1332 lastparent = None
1333
1333
1334 if git:
1334 if git:
1335 self.diffopts().git = True
1335 self.diffopts().git = True
1336
1336
1337 for r in rev:
1337 for r in rev:
1338 p1, p2 = repo.changelog.parentrevs(r)
1338 p1, p2 = repo.changelog.parentrevs(r)
1339 n = repo.changelog.node(r)
1339 n = repo.changelog.node(r)
1340 if p2 != revlog.nullrev:
1340 if p2 != revlog.nullrev:
1341 raise util.Abort(_('cannot import merge revision %d') % r)
1341 raise util.Abort(_('cannot import merge revision %d') % r)
1342 if lastparent and lastparent != r:
1342 if lastparent and lastparent != r:
1343 raise util.Abort(_('revision %d is not the parent of %d')
1343 raise util.Abort(_('revision %d is not the parent of %d')
1344 % (r, lastparent))
1344 % (r, lastparent))
1345 lastparent = p1
1345 lastparent = p1
1346
1346
1347 if not patchname:
1347 if not patchname:
1348 patchname = '%d.diff' % r
1348 patchname = '%d.diff' % r
1349 checkseries(patchname)
1349 checkseries(patchname)
1350 checkfile(patchname)
1350 checkfile(patchname)
1351 self.full_series.insert(0, patchname)
1351 self.full_series.insert(0, patchname)
1352
1352
1353 patchf = self.opener(patchname, "w")
1353 patchf = self.opener(patchname, "w")
1354 patch.export(repo, [n], fp=patchf, opts=self.diffopts())
1354 patch.export(repo, [n], fp=patchf, opts=self.diffopts())
1355 patchf.close()
1355 patchf.close()
1356
1356
1357 se = statusentry(revlog.hex(n), patchname)
1357 se = statusentry(revlog.hex(n), patchname)
1358 self.applied.insert(0, se)
1358 self.applied.insert(0, se)
1359
1359
1360 added.append(patchname)
1360 added.append(patchname)
1361 patchname = None
1361 patchname = None
1362 self.parse_series()
1362 self.parse_series()
1363 self.applied_dirty = 1
1363 self.applied_dirty = 1
1364
1364
1365 for filename in files:
1365 for filename in files:
1366 if existing:
1366 if existing:
1367 if filename == '-':
1367 if filename == '-':
1368 raise util.Abort(_('-e is incompatible with import from -'))
1368 raise util.Abort(_('-e is incompatible with import from -'))
1369 if not patchname:
1369 if not patchname:
1370 patchname = filename
1370 patchname = filename
1371 if not os.path.isfile(self.join(patchname)):
1371 if not os.path.isfile(self.join(patchname)):
1372 raise util.Abort(_("patch %s does not exist") % patchname)
1372 raise util.Abort(_("patch %s does not exist") % patchname)
1373 else:
1373 else:
1374 try:
1374 try:
1375 if filename == '-':
1375 if filename == '-':
1376 if not patchname:
1376 if not patchname:
1377 raise util.Abort(_('need --name to import a patch from -'))
1377 raise util.Abort(_('need --name to import a patch from -'))
1378 text = sys.stdin.read()
1378 text = sys.stdin.read()
1379 else:
1379 else:
1380 text = file(filename).read()
1380 text = file(filename).read()
1381 except IOError:
1381 except IOError:
1382 raise util.Abort(_("unable to read %s") % patchname)
1382 raise util.Abort(_("unable to read %s") % patchname)
1383 if not patchname:
1383 if not patchname:
1384 patchname = os.path.basename(filename)
1384 patchname = os.path.basename(filename)
1385 checkfile(patchname)
1385 checkfile(patchname)
1386 patchf = self.opener(patchname, "w")
1386 patchf = self.opener(patchname, "w")
1387 patchf.write(text)
1387 patchf.write(text)
1388 checkseries(patchname)
1388 checkseries(patchname)
1389 index = self.full_series_end() + i
1389 index = self.full_series_end() + i
1390 self.full_series[index:index] = [patchname]
1390 self.full_series[index:index] = [patchname]
1391 self.parse_series()
1391 self.parse_series()
1392 self.ui.warn("adding %s to series file\n" % patchname)
1392 self.ui.warn("adding %s to series file\n" % patchname)
1393 i += 1
1393 i += 1
1394 added.append(patchname)
1394 added.append(patchname)
1395 patchname = None
1395 patchname = None
1396 self.series_dirty = 1
1396 self.series_dirty = 1
1397 qrepo = self.qrepo()
1397 qrepo = self.qrepo()
1398 if qrepo:
1398 if qrepo:
1399 qrepo.add(added)
1399 qrepo.add(added)
1400
1400
1401 def delete(ui, repo, *patches, **opts):
1401 def delete(ui, repo, *patches, **opts):
1402 """remove patches from queue
1402 """remove patches from queue
1403
1403
1404 With --rev, mq will stop managing the named revisions. The
1404 With --rev, mq will stop managing the named revisions. The
1405 patches must be applied and at the base of the stack. This option
1405 patches must be applied and at the base of the stack. This option
1406 is useful when the patches have been applied upstream.
1406 is useful when the patches have been applied upstream.
1407
1407
1408 Otherwise, the patches must not be applied.
1408 Otherwise, the patches must not be applied.
1409
1409
1410 With --keep, the patch files are preserved in the patch directory."""
1410 With --keep, the patch files are preserved in the patch directory."""
1411 q = repo.mq
1411 q = repo.mq
1412 q.delete(repo, patches, opts)
1412 q.delete(repo, patches, opts)
1413 q.save_dirty()
1413 q.save_dirty()
1414 return 0
1414 return 0
1415
1415
1416 def applied(ui, repo, patch=None, **opts):
1416 def applied(ui, repo, patch=None, **opts):
1417 """print the patches already applied"""
1417 """print the patches already applied"""
1418 q = repo.mq
1418 q = repo.mq
1419 if patch:
1419 if patch:
1420 if patch not in q.series:
1420 if patch not in q.series:
1421 raise util.Abort(_("patch %s is not in series file") % patch)
1421 raise util.Abort(_("patch %s is not in series file") % patch)
1422 end = q.series.index(patch) + 1
1422 end = q.series.index(patch) + 1
1423 else:
1423 else:
1424 end = len(q.applied)
1424 end = len(q.applied)
1425 if not end:
1425 if not end:
1426 return
1426 return
1427
1427
1428 return q.qseries(repo, length=end, status='A', summary=opts.get('summary'))
1428 return q.qseries(repo, length=end, status='A', summary=opts.get('summary'))
1429
1429
1430 def unapplied(ui, repo, patch=None, **opts):
1430 def unapplied(ui, repo, patch=None, **opts):
1431 """print the patches not yet applied"""
1431 """print the patches not yet applied"""
1432 q = repo.mq
1432 q = repo.mq
1433 if patch:
1433 if patch:
1434 if patch not in q.series:
1434 if patch not in q.series:
1435 raise util.Abort(_("patch %s is not in series file") % patch)
1435 raise util.Abort(_("patch %s is not in series file") % patch)
1436 start = q.series.index(patch) + 1
1436 start = q.series.index(patch) + 1
1437 else:
1437 else:
1438 start = q.series_end()
1438 start = q.series_end()
1439 q.qseries(repo, start=start, summary=opts.get('summary'))
1439 q.qseries(repo, start=start, summary=opts.get('summary'))
1440
1440
1441 def qimport(ui, repo, *filename, **opts):
1441 def qimport(ui, repo, *filename, **opts):
1442 """import a patch
1442 """import a patch
1443
1443
1444 The patch will have the same name as its source file unless you
1444 The patch will have the same name as its source file unless you
1445 give it a new one with --name.
1445 give it a new one with --name.
1446
1446
1447 You can register an existing patch inside the patch directory
1447 You can register an existing patch inside the patch directory
1448 with the --existing flag.
1448 with the --existing flag.
1449
1449
1450 With --force, an existing patch of the same name will be overwritten.
1450 With --force, an existing patch of the same name will be overwritten.
1451
1451
1452 An existing changeset may be placed under mq control with --rev
1452 An existing changeset may be placed under mq control with --rev
1453 (e.g. qimport --rev tip -n patch will place tip under mq control).
1453 (e.g. qimport --rev tip -n patch will place tip under mq control).
1454 With --git, patches imported with --rev will use the git diff
1454 With --git, patches imported with --rev will use the git diff
1455 format.
1455 format.
1456 """
1456 """
1457 q = repo.mq
1457 q = repo.mq
1458 q.qimport(repo, filename, patchname=opts['name'],
1458 q.qimport(repo, filename, patchname=opts['name'],
1459 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1459 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1460 git=opts['git'])
1460 git=opts['git'])
1461 q.save_dirty()
1461 q.save_dirty()
1462 return 0
1462 return 0
1463
1463
1464 def init(ui, repo, **opts):
1464 def init(ui, repo, **opts):
1465 """init a new queue repository
1465 """init a new queue repository
1466
1466
1467 The queue repository is unversioned by default. If -c is
1467 The queue repository is unversioned by default. If -c is
1468 specified, qinit will create a separate nested repository
1468 specified, qinit will create a separate nested repository
1469 for patches. Use qcommit to commit changes to this queue
1469 for patches. Use qcommit to commit changes to this queue
1470 repository."""
1470 repository."""
1471 q = repo.mq
1471 q = repo.mq
1472 r = q.init(repo, create=opts['create_repo'])
1472 r = q.init(repo, create=opts['create_repo'])
1473 q.save_dirty()
1473 q.save_dirty()
1474 if r:
1474 if r:
1475 fp = r.wopener('.hgignore', 'w')
1475 fp = r.wopener('.hgignore', 'w')
1476 print >> fp, 'syntax: glob'
1476 print >> fp, 'syntax: glob'
1477 print >> fp, 'status'
1477 print >> fp, 'status'
1478 fp.close()
1478 fp.close()
1479 r.wopener('series', 'w').close()
1479 r.wopener('series', 'w').close()
1480 r.add(['.hgignore', 'series'])
1480 r.add(['.hgignore', 'series'])
1481 return 0
1481 return 0
1482
1482
1483 def clone(ui, source, dest=None, **opts):
1483 def clone(ui, source, dest=None, **opts):
1484 '''clone main and patch repository at same time
1484 '''clone main and patch repository at same time
1485
1485
1486 If source is local, destination will have no patches applied. If
1486 If source is local, destination will have no patches applied. If
1487 source is remote, this command can not check if patches are
1487 source is remote, this command can not check if patches are
1488 applied in source, so cannot guarantee that patches are not
1488 applied in source, so cannot guarantee that patches are not
1489 applied in destination. If you clone remote repository, be sure
1489 applied in destination. If you clone remote repository, be sure
1490 before that it has no patches applied.
1490 before that it has no patches applied.
1491
1491
1492 Source patch repository is looked for in <src>/.hg/patches by
1492 Source patch repository is looked for in <src>/.hg/patches by
1493 default. Use -p <url> to change.
1493 default. Use -p <url> to change.
1494 '''
1494 '''
1495 commands.setremoteconfig(ui, opts)
1495 commands.setremoteconfig(ui, opts)
1496 if dest is None:
1496 if dest is None:
1497 dest = hg.defaultdest(source)
1497 dest = hg.defaultdest(source)
1498 sr = hg.repository(ui, ui.expandpath(source))
1498 sr = hg.repository(ui, ui.expandpath(source))
1499 qbase, destrev = None, None
1499 qbase, destrev = None, None
1500 if sr.local():
1500 if sr.local():
1501 reposetup(ui, sr)
1501 reposetup(ui, sr)
1502 if sr.mq.applied:
1502 if sr.mq.applied:
1503 qbase = revlog.bin(sr.mq.applied[0].rev)
1503 qbase = revlog.bin(sr.mq.applied[0].rev)
1504 if not hg.islocal(dest):
1504 if not hg.islocal(dest):
1505 destrev = sr.parents(qbase)[0]
1505 destrev = sr.parents(qbase)[0]
1506 ui.note(_('cloning main repo\n'))
1506 ui.note(_('cloning main repo\n'))
1507 sr, dr = hg.clone(ui, sr, dest,
1507 sr, dr = hg.clone(ui, sr, dest,
1508 pull=opts['pull'],
1508 pull=opts['pull'],
1509 rev=destrev,
1509 rev=destrev,
1510 update=False,
1510 update=False,
1511 stream=opts['uncompressed'])
1511 stream=opts['uncompressed'])
1512 ui.note(_('cloning patch repo\n'))
1512 ui.note(_('cloning patch repo\n'))
1513 spr, dpr = hg.clone(ui, opts['patches'] or (sr.url() + '/.hg/patches'),
1513 spr, dpr = hg.clone(ui, opts['patches'] or (sr.url() + '/.hg/patches'),
1514 dr.url() + '/.hg/patches',
1514 dr.url() + '/.hg/patches',
1515 pull=opts['pull'],
1515 pull=opts['pull'],
1516 update=not opts['noupdate'],
1516 update=not opts['noupdate'],
1517 stream=opts['uncompressed'])
1517 stream=opts['uncompressed'])
1518 if dr.local():
1518 if dr.local():
1519 if qbase:
1519 if qbase:
1520 ui.note(_('stripping applied patches from destination repo\n'))
1520 ui.note(_('stripping applied patches from destination repo\n'))
1521 reposetup(ui, dr)
1521 reposetup(ui, dr)
1522 dr.mq.strip(dr, qbase, update=False, backup=None)
1522 dr.mq.strip(dr, qbase, update=False, backup=None)
1523 if not opts['noupdate']:
1523 if not opts['noupdate']:
1524 ui.note(_('updating destination repo\n'))
1524 ui.note(_('updating destination repo\n'))
1525 hg.update(dr, dr.changelog.tip())
1525 hg.update(dr, dr.changelog.tip())
1526
1526
1527 def commit(ui, repo, *pats, **opts):
1527 def commit(ui, repo, *pats, **opts):
1528 """commit changes in the queue repository"""
1528 """commit changes in the queue repository"""
1529 q = repo.mq
1529 q = repo.mq
1530 r = q.qrepo()
1530 r = q.qrepo()
1531 if not r: raise util.Abort('no queue repository')
1531 if not r: raise util.Abort('no queue repository')
1532 commands.commit(r.ui, r, *pats, **opts)
1532 commands.commit(r.ui, r, *pats, **opts)
1533
1533
1534 def series(ui, repo, **opts):
1534 def series(ui, repo, **opts):
1535 """print the entire series file"""
1535 """print the entire series file"""
1536 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1536 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1537 return 0
1537 return 0
1538
1538
1539 def top(ui, repo, **opts):
1539 def top(ui, repo, **opts):
1540 """print the name of the current patch"""
1540 """print the name of the current patch"""
1541 q = repo.mq
1541 q = repo.mq
1542 t = len(q.applied)
1542 t = len(q.applied)
1543 if t:
1543 if t:
1544 return q.qseries(repo, start=t-1, length=1, status='A',
1544 return q.qseries(repo, start=t-1, length=1, status='A',
1545 summary=opts.get('summary'))
1545 summary=opts.get('summary'))
1546 else:
1546 else:
1547 ui.write("No patches applied\n")
1547 ui.write("No patches applied\n")
1548 return 1
1548 return 1
1549
1549
1550 def next(ui, repo, **opts):
1550 def next(ui, repo, **opts):
1551 """print the name of the next patch"""
1551 """print the name of the next patch"""
1552 q = repo.mq
1552 q = repo.mq
1553 end = q.series_end()
1553 end = q.series_end()
1554 if end == len(q.series):
1554 if end == len(q.series):
1555 ui.write("All patches applied\n")
1555 ui.write("All patches applied\n")
1556 return 1
1556 return 1
1557 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1557 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1558
1558
1559 def prev(ui, repo, **opts):
1559 def prev(ui, repo, **opts):
1560 """print the name of the previous patch"""
1560 """print the name of the previous patch"""
1561 q = repo.mq
1561 q = repo.mq
1562 l = len(q.applied)
1562 l = len(q.applied)
1563 if l == 1:
1563 if l == 1:
1564 ui.write("Only one patch applied\n")
1564 ui.write("Only one patch applied\n")
1565 return 1
1565 return 1
1566 if not l:
1566 if not l:
1567 ui.write("No patches applied\n")
1567 ui.write("No patches applied\n")
1568 return 1
1568 return 1
1569 return q.qseries(repo, start=l-2, length=1, status='A',
1569 return q.qseries(repo, start=l-2, length=1, status='A',
1570 summary=opts.get('summary'))
1570 summary=opts.get('summary'))
1571
1571
1572 def new(ui, repo, patch, **opts):
1572 def new(ui, repo, patch, **opts):
1573 """create a new patch
1573 """create a new patch
1574
1574
1575 qnew creates a new patch on top of the currently-applied patch
1575 qnew creates a new patch on top of the currently-applied patch
1576 (if any). It will refuse to run if there are any outstanding
1576 (if any). It will refuse to run if there are any outstanding
1577 changes unless -f is specified, in which case the patch will
1577 changes unless -f is specified, in which case the patch will
1578 be initialised with them.
1578 be initialised with them.
1579
1579
1580 -e, -m or -l set the patch header as well as the commit message.
1580 -e, -m or -l set the patch header as well as the commit message.
1581 If none is specified, the patch header is empty and the
1581 If none is specified, the patch header is empty and the
1582 commit message is 'New patch: PATCH'"""
1582 commit message is 'New patch: PATCH'"""
1583 q = repo.mq
1583 q = repo.mq
1584 message = commands.logmessage(opts)
1584 message = commands.logmessage(opts)
1585 if opts['edit']:
1585 if opts['edit']:
1586 message = ui.edit(message, ui.username())
1586 message = ui.edit(message, ui.username())
1587 q.new(repo, patch, msg=message, force=opts['force'])
1587 q.new(repo, patch, msg=message, force=opts['force'])
1588 q.save_dirty()
1588 q.save_dirty()
1589 return 0
1589 return 0
1590
1590
1591 def refresh(ui, repo, *pats, **opts):
1591 def refresh(ui, repo, *pats, **opts):
1592 """update the current patch
1592 """update the current patch
1593
1593
1594 If any file patterns are provided, the refreshed patch will contain only
1594 If any file patterns are provided, the refreshed patch will contain only
1595 the modifications that match those patterns; the remaining modifications
1595 the modifications that match those patterns; the remaining modifications
1596 will remain in the working directory.
1596 will remain in the working directory.
1597 """
1597 """
1598 q = repo.mq
1598 q = repo.mq
1599 message = commands.logmessage(opts)
1599 message = commands.logmessage(opts)
1600 if opts['edit']:
1600 if opts['edit']:
1601 if message:
1601 if message:
1602 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1602 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1603 patch = q.applied[-1].name
1603 patch = q.applied[-1].name
1604 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1604 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1605 message = ui.edit('\n'.join(message), user or ui.username())
1605 message = ui.edit('\n'.join(message), user or ui.username())
1606 ret = q.refresh(repo, pats, msg=message, **opts)
1606 ret = q.refresh(repo, pats, msg=message, **opts)
1607 q.save_dirty()
1607 q.save_dirty()
1608 return ret
1608 return ret
1609
1609
1610 def diff(ui, repo, *pats, **opts):
1610 def diff(ui, repo, *pats, **opts):
1611 """diff of the current patch"""
1611 """diff of the current patch"""
1612 repo.mq.diff(repo, pats, opts)
1612 repo.mq.diff(repo, pats, opts)
1613 return 0
1613 return 0
1614
1614
1615 def fold(ui, repo, *files, **opts):
1615 def fold(ui, repo, *files, **opts):
1616 """fold the named patches into the current patch
1616 """fold the named patches into the current patch
1617
1617
1618 Patches must not yet be applied. Each patch will be successively
1618 Patches must not yet be applied. Each patch will be successively
1619 applied to the current patch in the order given. If all the
1619 applied to the current patch in the order given. If all the
1620 patches apply successfully, the current patch will be refreshed
1620 patches apply successfully, the current patch will be refreshed
1621 with the new cumulative patch, and the folded patches will
1621 with the new cumulative patch, and the folded patches will
1622 be deleted. With -k/--keep, the folded patch files will not
1622 be deleted. With -k/--keep, the folded patch files will not
1623 be removed afterwards.
1623 be removed afterwards.
1624
1624
1625 The header for each folded patch will be concatenated with
1625 The header for each folded patch will be concatenated with
1626 the current patch header, separated by a line of '* * *'."""
1626 the current patch header, separated by a line of '* * *'."""
1627
1627
1628 q = repo.mq
1628 q = repo.mq
1629
1629
1630 if not files:
1630 if not files:
1631 raise util.Abort(_('qfold requires at least one patch name'))
1631 raise util.Abort(_('qfold requires at least one patch name'))
1632 if not q.check_toppatch(repo):
1632 if not q.check_toppatch(repo):
1633 raise util.Abort(_('No patches applied'))
1633 raise util.Abort(_('No patches applied'))
1634
1634
1635 message = commands.logmessage(opts)
1635 message = commands.logmessage(opts)
1636 if opts['edit']:
1636 if opts['edit']:
1637 if message:
1637 if message:
1638 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1638 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1639
1639
1640 parent = q.lookup('qtip')
1640 parent = q.lookup('qtip')
1641 patches = []
1641 patches = []
1642 messages = []
1642 messages = []
1643 for f in files:
1643 for f in files:
1644 p = q.lookup(f)
1644 p = q.lookup(f)
1645 if p in patches or p == parent:
1645 if p in patches or p == parent:
1646 ui.warn(_('Skipping already folded patch %s') % p)
1646 ui.warn(_('Skipping already folded patch %s') % p)
1647 if q.isapplied(p):
1647 if q.isapplied(p):
1648 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1648 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1649 patches.append(p)
1649 patches.append(p)
1650
1650
1651 for p in patches:
1651 for p in patches:
1652 if not message:
1652 if not message:
1653 messages.append(q.readheaders(p)[0])
1653 messages.append(q.readheaders(p)[0])
1654 pf = q.join(p)
1654 pf = q.join(p)
1655 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1655 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1656 if not patchsuccess:
1656 if not patchsuccess:
1657 raise util.Abort(_('Error folding patch %s') % p)
1657 raise util.Abort(_('Error folding patch %s') % p)
1658 patch.updatedir(ui, repo, files)
1658 patch.updatedir(ui, repo, files)
1659
1659
1660 if not message:
1660 if not message:
1661 message, comments, user = q.readheaders(parent)[0:3]
1661 message, comments, user = q.readheaders(parent)[0:3]
1662 for msg in messages:
1662 for msg in messages:
1663 message.append('* * *')
1663 message.append('* * *')
1664 message.extend(msg)
1664 message.extend(msg)
1665 message = '\n'.join(message)
1665 message = '\n'.join(message)
1666
1666
1667 if opts['edit']:
1667 if opts['edit']:
1668 message = ui.edit(message, user or ui.username())
1668 message = ui.edit(message, user or ui.username())
1669
1669
1670 q.refresh(repo, msg=message)
1670 q.refresh(repo, msg=message)
1671 q.delete(repo, patches, opts)
1671 q.delete(repo, patches, opts)
1672 q.save_dirty()
1672 q.save_dirty()
1673
1673
1674 def guard(ui, repo, *args, **opts):
1674 def guard(ui, repo, *args, **opts):
1675 '''set or print guards for a patch
1675 '''set or print guards for a patch
1676
1676
1677 Guards control whether a patch can be pushed. A patch with no
1677 Guards control whether a patch can be pushed. A patch with no
1678 guards is always pushed. A patch with a positive guard ("+foo") is
1678 guards is always pushed. A patch with a positive guard ("+foo") is
1679 pushed only if the qselect command has activated it. A patch with
1679 pushed only if the qselect command has activated it. A patch with
1680 a negative guard ("-foo") is never pushed if the qselect command
1680 a negative guard ("-foo") is never pushed if the qselect command
1681 has activated it.
1681 has activated it.
1682
1682
1683 With no arguments, print the currently active guards.
1683 With no arguments, print the currently active guards.
1684 With arguments, set guards for the named patch.
1684 With arguments, set guards for the named patch.
1685
1685
1686 To set a negative guard "-foo" on topmost patch ("--" is needed so
1686 To set a negative guard "-foo" on topmost patch ("--" is needed so
1687 hg will not interpret "-foo" as an option):
1687 hg will not interpret "-foo" as an option):
1688 hg qguard -- -foo
1688 hg qguard -- -foo
1689
1689
1690 To set guards on another patch:
1690 To set guards on another patch:
1691 hg qguard other.patch +2.6.17 -stable
1691 hg qguard other.patch +2.6.17 -stable
1692 '''
1692 '''
1693 def status(idx):
1693 def status(idx):
1694 guards = q.series_guards[idx] or ['unguarded']
1694 guards = q.series_guards[idx] or ['unguarded']
1695 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1695 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1696 q = repo.mq
1696 q = repo.mq
1697 patch = None
1697 patch = None
1698 args = list(args)
1698 args = list(args)
1699 if opts['list']:
1699 if opts['list']:
1700 if args or opts['none']:
1700 if args or opts['none']:
1701 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1701 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1702 for i in xrange(len(q.series)):
1702 for i in xrange(len(q.series)):
1703 status(i)
1703 status(i)
1704 return
1704 return
1705 if not args or args[0][0:1] in '-+':
1705 if not args or args[0][0:1] in '-+':
1706 if not q.applied:
1706 if not q.applied:
1707 raise util.Abort(_('no patches applied'))
1707 raise util.Abort(_('no patches applied'))
1708 patch = q.applied[-1].name
1708 patch = q.applied[-1].name
1709 if patch is None and args[0][0:1] not in '-+':
1709 if patch is None and args[0][0:1] not in '-+':
1710 patch = args.pop(0)
1710 patch = args.pop(0)
1711 if patch is None:
1711 if patch is None:
1712 raise util.Abort(_('no patch to work with'))
1712 raise util.Abort(_('no patch to work with'))
1713 if args or opts['none']:
1713 if args or opts['none']:
1714 q.set_guards(q.find_series(patch), args)
1714 q.set_guards(q.find_series(patch), args)
1715 q.save_dirty()
1715 q.save_dirty()
1716 else:
1716 else:
1717 status(q.series.index(q.lookup(patch)))
1717 status(q.series.index(q.lookup(patch)))
1718
1718
1719 def header(ui, repo, patch=None):
1719 def header(ui, repo, patch=None):
1720 """Print the header of the topmost or specified patch"""
1720 """Print the header of the topmost or specified patch"""
1721 q = repo.mq
1721 q = repo.mq
1722
1722
1723 if patch:
1723 if patch:
1724 patch = q.lookup(patch)
1724 patch = q.lookup(patch)
1725 else:
1725 else:
1726 if not q.applied:
1726 if not q.applied:
1727 ui.write('No patches applied\n')
1727 ui.write('No patches applied\n')
1728 return 1
1728 return 1
1729 patch = q.lookup('qtip')
1729 patch = q.lookup('qtip')
1730 message = repo.mq.readheaders(patch)[0]
1730 message = repo.mq.readheaders(patch)[0]
1731
1731
1732 ui.write('\n'.join(message) + '\n')
1732 ui.write('\n'.join(message) + '\n')
1733
1733
1734 def lastsavename(path):
1734 def lastsavename(path):
1735 (directory, base) = os.path.split(path)
1735 (directory, base) = os.path.split(path)
1736 names = os.listdir(directory)
1736 names = os.listdir(directory)
1737 namere = re.compile("%s.([0-9]+)" % base)
1737 namere = re.compile("%s.([0-9]+)" % base)
1738 maxindex = None
1738 maxindex = None
1739 maxname = None
1739 maxname = None
1740 for f in names:
1740 for f in names:
1741 m = namere.match(f)
1741 m = namere.match(f)
1742 if m:
1742 if m:
1743 index = int(m.group(1))
1743 index = int(m.group(1))
1744 if maxindex == None or index > maxindex:
1744 if maxindex == None or index > maxindex:
1745 maxindex = index
1745 maxindex = index
1746 maxname = f
1746 maxname = f
1747 if maxname:
1747 if maxname:
1748 return (os.path.join(directory, maxname), maxindex)
1748 return (os.path.join(directory, maxname), maxindex)
1749 return (None, None)
1749 return (None, None)
1750
1750
1751 def savename(path):
1751 def savename(path):
1752 (last, index) = lastsavename(path)
1752 (last, index) = lastsavename(path)
1753 if last is None:
1753 if last is None:
1754 index = 0
1754 index = 0
1755 newpath = path + ".%d" % (index + 1)
1755 newpath = path + ".%d" % (index + 1)
1756 return newpath
1756 return newpath
1757
1757
1758 def push(ui, repo, patch=None, **opts):
1758 def push(ui, repo, patch=None, **opts):
1759 """push the next patch onto the stack"""
1759 """push the next patch onto the stack"""
1760 q = repo.mq
1760 q = repo.mq
1761 mergeq = None
1761 mergeq = None
1762
1762
1763 if opts['all']:
1763 if opts['all']:
1764 if not q.series:
1764 if not q.series:
1765 raise util.Abort(_('no patches in series'))
1765 raise util.Abort(_('no patches in series'))
1766 patch = q.series[-1]
1766 patch = q.series[-1]
1767 if opts['merge']:
1767 if opts['merge']:
1768 if opts['name']:
1768 if opts['name']:
1769 newpath = opts['name']
1769 newpath = opts['name']
1770 else:
1770 else:
1771 newpath, i = lastsavename(q.path)
1771 newpath, i = lastsavename(q.path)
1772 if not newpath:
1772 if not newpath:
1773 ui.warn("no saved queues found, please use -n\n")
1773 ui.warn("no saved queues found, please use -n\n")
1774 return 1
1774 return 1
1775 mergeq = queue(ui, repo.join(""), newpath)
1775 mergeq = queue(ui, repo.join(""), newpath)
1776 ui.warn("merging with queue at: %s\n" % mergeq.path)
1776 ui.warn("merging with queue at: %s\n" % mergeq.path)
1777 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
1777 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
1778 mergeq=mergeq)
1778 mergeq=mergeq)
1779 q.save_dirty()
1779 q.save_dirty()
1780 return ret
1780 return ret
1781
1781
1782 def pop(ui, repo, patch=None, **opts):
1782 def pop(ui, repo, patch=None, **opts):
1783 """pop the current patch off the stack"""
1783 """pop the current patch off the stack"""
1784 localupdate = True
1784 localupdate = True
1785 if opts['name']:
1785 if opts['name']:
1786 q = queue(ui, repo.join(""), repo.join(opts['name']))
1786 q = queue(ui, repo.join(""), repo.join(opts['name']))
1787 ui.warn('using patch queue: %s\n' % q.path)
1787 ui.warn('using patch queue: %s\n' % q.path)
1788 localupdate = False
1788 localupdate = False
1789 else:
1789 else:
1790 q = repo.mq
1790 q = repo.mq
1791 q.pop(repo, patch, force=opts['force'], update=localupdate, all=opts['all'])
1791 q.pop(repo, patch, force=opts['force'], update=localupdate, all=opts['all'])
1792 q.save_dirty()
1792 q.save_dirty()
1793 return 0
1793 return 0
1794
1794
1795 def rename(ui, repo, patch, name=None, **opts):
1795 def rename(ui, repo, patch, name=None, **opts):
1796 """rename a patch
1796 """rename a patch
1797
1797
1798 With one argument, renames the current patch to PATCH1.
1798 With one argument, renames the current patch to PATCH1.
1799 With two arguments, renames PATCH1 to PATCH2."""
1799 With two arguments, renames PATCH1 to PATCH2."""
1800
1800
1801 q = repo.mq
1801 q = repo.mq
1802
1802
1803 if not name:
1803 if not name:
1804 name = patch
1804 name = patch
1805 patch = None
1805 patch = None
1806
1806
1807 if patch:
1807 if patch:
1808 patch = q.lookup(patch)
1808 patch = q.lookup(patch)
1809 else:
1809 else:
1810 if not q.applied:
1810 if not q.applied:
1811 ui.write(_('No patches applied\n'))
1811 ui.write(_('No patches applied\n'))
1812 return
1812 return
1813 patch = q.lookup('qtip')
1813 patch = q.lookup('qtip')
1814 absdest = q.join(name)
1814 absdest = q.join(name)
1815 if os.path.isdir(absdest):
1815 if os.path.isdir(absdest):
1816 name = os.path.join(name, os.path.basename(patch))
1816 name = os.path.join(name, os.path.basename(patch))
1817 absdest = q.join(name)
1817 absdest = q.join(name)
1818 if os.path.exists(absdest):
1818 if os.path.exists(absdest):
1819 raise util.Abort(_('%s already exists') % absdest)
1819 raise util.Abort(_('%s already exists') % absdest)
1820
1820
1821 if name in q.series:
1821 if name in q.series:
1822 raise util.Abort(_('A patch named %s already exists in the series file') % name)
1822 raise util.Abort(_('A patch named %s already exists in the series file') % name)
1823
1823
1824 if ui.verbose:
1824 if ui.verbose:
1825 ui.write('Renaming %s to %s\n' % (patch, name))
1825 ui.write('Renaming %s to %s\n' % (patch, name))
1826 i = q.find_series(patch)
1826 i = q.find_series(patch)
1827 guards = q.guard_re.findall(q.full_series[i])
1827 guards = q.guard_re.findall(q.full_series[i])
1828 q.full_series[i] = name + ''.join([' #' + g for g in guards])
1828 q.full_series[i] = name + ''.join([' #' + g for g in guards])
1829 q.parse_series()
1829 q.parse_series()
1830 q.series_dirty = 1
1830 q.series_dirty = 1
1831
1831
1832 info = q.isapplied(patch)
1832 info = q.isapplied(patch)
1833 if info:
1833 if info:
1834 q.applied[info[0]] = statusentry(info[1], name)
1834 q.applied[info[0]] = statusentry(info[1], name)
1835 q.applied_dirty = 1
1835 q.applied_dirty = 1
1836
1836
1837 util.rename(q.join(patch), absdest)
1837 util.rename(q.join(patch), absdest)
1838 r = q.qrepo()
1838 r = q.qrepo()
1839 if r:
1839 if r:
1840 wlock = r.wlock()
1840 wlock = r.wlock()
1841 if r.dirstate.state(name) == 'r':
1841 if r.dirstate.state(name) == 'r':
1842 r.undelete([name], wlock)
1842 r.undelete([name], wlock)
1843 r.copy(patch, name, wlock)
1843 r.copy(patch, name, wlock)
1844 r.remove([patch], False, wlock)
1844 r.remove([patch], False, wlock)
1845
1845
1846 q.save_dirty()
1846 q.save_dirty()
1847
1847
1848 def restore(ui, repo, rev, **opts):
1848 def restore(ui, repo, rev, **opts):
1849 """restore the queue state saved by a rev"""
1849 """restore the queue state saved by a rev"""
1850 rev = repo.lookup(rev)
1850 rev = repo.lookup(rev)
1851 q = repo.mq
1851 q = repo.mq
1852 q.restore(repo, rev, delete=opts['delete'],
1852 q.restore(repo, rev, delete=opts['delete'],
1853 qupdate=opts['update'])
1853 qupdate=opts['update'])
1854 q.save_dirty()
1854 q.save_dirty()
1855 return 0
1855 return 0
1856
1856
1857 def save(ui, repo, **opts):
1857 def save(ui, repo, **opts):
1858 """save current queue state"""
1858 """save current queue state"""
1859 q = repo.mq
1859 q = repo.mq
1860 message = commands.logmessage(opts)
1860 message = commands.logmessage(opts)
1861 ret = q.save(repo, msg=message)
1861 ret = q.save(repo, msg=message)
1862 if ret:
1862 if ret:
1863 return ret
1863 return ret
1864 q.save_dirty()
1864 q.save_dirty()
1865 if opts['copy']:
1865 if opts['copy']:
1866 path = q.path
1866 path = q.path
1867 if opts['name']:
1867 if opts['name']:
1868 newpath = os.path.join(q.basepath, opts['name'])
1868 newpath = os.path.join(q.basepath, opts['name'])
1869 if os.path.exists(newpath):
1869 if os.path.exists(newpath):
1870 if not os.path.isdir(newpath):
1870 if not os.path.isdir(newpath):
1871 raise util.Abort(_('destination %s exists and is not '
1871 raise util.Abort(_('destination %s exists and is not '
1872 'a directory') % newpath)
1872 'a directory') % newpath)
1873 if not opts['force']:
1873 if not opts['force']:
1874 raise util.Abort(_('destination %s exists, '
1874 raise util.Abort(_('destination %s exists, '
1875 'use -f to force') % newpath)
1875 'use -f to force') % newpath)
1876 else:
1876 else:
1877 newpath = savename(path)
1877 newpath = savename(path)
1878 ui.warn("copy %s to %s\n" % (path, newpath))
1878 ui.warn("copy %s to %s\n" % (path, newpath))
1879 util.copyfiles(path, newpath)
1879 util.copyfiles(path, newpath)
1880 if opts['empty']:
1880 if opts['empty']:
1881 try:
1881 try:
1882 os.unlink(q.join(q.status_path))
1882 os.unlink(q.join(q.status_path))
1883 except:
1883 except:
1884 pass
1884 pass
1885 return 0
1885 return 0
1886
1886
1887 def strip(ui, repo, rev, **opts):
1887 def strip(ui, repo, rev, **opts):
1888 """strip a revision and all later revs on the same branch"""
1888 """strip a revision and all later revs on the same branch"""
1889 rev = repo.lookup(rev)
1889 rev = repo.lookup(rev)
1890 backup = 'all'
1890 backup = 'all'
1891 if opts['backup']:
1891 if opts['backup']:
1892 backup = 'strip'
1892 backup = 'strip'
1893 elif opts['nobackup']:
1893 elif opts['nobackup']:
1894 backup = 'none'
1894 backup = 'none'
1895 update = repo.dirstate.parents()[0] != revlog.nullid
1895 update = repo.dirstate.parents()[0] != revlog.nullid
1896 repo.mq.strip(repo, rev, backup=backup, update=update)
1896 repo.mq.strip(repo, rev, backup=backup, update=update)
1897 return 0
1897 return 0
1898
1898
1899 def select(ui, repo, *args, **opts):
1899 def select(ui, repo, *args, **opts):
1900 '''set or print guarded patches to push
1900 '''set or print guarded patches to push
1901
1901
1902 Use the qguard command to set or print guards on patch, then use
1902 Use the qguard command to set or print guards on patch, then use
1903 qselect to tell mq which guards to use. A patch will be pushed if it
1903 qselect to tell mq which guards to use. A patch will be pushed if it
1904 has no guards or any positive guards match the currently selected guard,
1904 has no guards or any positive guards match the currently selected guard,
1905 but will not be pushed if any negative guards match the current guard.
1905 but will not be pushed if any negative guards match the current guard.
1906 For example:
1906 For example:
1907
1907
1908 qguard foo.patch -stable (negative guard)
1908 qguard foo.patch -stable (negative guard)
1909 qguard bar.patch +stable (positive guard)
1909 qguard bar.patch +stable (positive guard)
1910 qselect stable
1910 qselect stable
1911
1911
1912 This activates the "stable" guard. mq will skip foo.patch (because
1912 This activates the "stable" guard. mq will skip foo.patch (because
1913 it has a negative match) but push bar.patch (because it
1913 it has a negative match) but push bar.patch (because it
1914 has a positive match).
1914 has a positive match).
1915
1915
1916 With no arguments, prints the currently active guards.
1916 With no arguments, prints the currently active guards.
1917 With one argument, sets the active guard.
1917 With one argument, sets the active guard.
1918
1918
1919 Use -n/--none to deactivate guards (no other arguments needed).
1919 Use -n/--none to deactivate guards (no other arguments needed).
1920 When no guards are active, patches with positive guards are skipped
1920 When no guards are active, patches with positive guards are skipped
1921 and patches with negative guards are pushed.
1921 and patches with negative guards are pushed.
1922
1922
1923 qselect can change the guards on applied patches. It does not pop
1923 qselect can change the guards on applied patches. It does not pop
1924 guarded patches by default. Use --pop to pop back to the last applied
1924 guarded patches by default. Use --pop to pop back to the last applied
1925 patch that is not guarded. Use --reapply (which implies --pop) to push
1925 patch that is not guarded. Use --reapply (which implies --pop) to push
1926 back to the current patch afterwards, but skip guarded patches.
1926 back to the current patch afterwards, but skip guarded patches.
1927
1927
1928 Use -s/--series to print a list of all guards in the series file (no
1928 Use -s/--series to print a list of all guards in the series file (no
1929 other arguments needed). Use -v for more information.'''
1929 other arguments needed). Use -v for more information.'''
1930
1930
1931 q = repo.mq
1931 q = repo.mq
1932 guards = q.active()
1932 guards = q.active()
1933 if args or opts['none']:
1933 if args or opts['none']:
1934 old_unapplied = q.unapplied(repo)
1934 old_unapplied = q.unapplied(repo)
1935 old_guarded = [i for i in xrange(len(q.applied)) if
1935 old_guarded = [i for i in xrange(len(q.applied)) if
1936 not q.pushable(i)[0]]
1936 not q.pushable(i)[0]]
1937 q.set_active(args)
1937 q.set_active(args)
1938 q.save_dirty()
1938 q.save_dirty()
1939 if not args:
1939 if not args:
1940 ui.status(_('guards deactivated\n'))
1940 ui.status(_('guards deactivated\n'))
1941 if not opts['pop'] and not opts['reapply']:
1941 if not opts['pop'] and not opts['reapply']:
1942 unapplied = q.unapplied(repo)
1942 unapplied = q.unapplied(repo)
1943 guarded = [i for i in xrange(len(q.applied))
1943 guarded = [i for i in xrange(len(q.applied))
1944 if not q.pushable(i)[0]]
1944 if not q.pushable(i)[0]]
1945 if len(unapplied) != len(old_unapplied):
1945 if len(unapplied) != len(old_unapplied):
1946 ui.status(_('number of unguarded, unapplied patches has '
1946 ui.status(_('number of unguarded, unapplied patches has '
1947 'changed from %d to %d\n') %
1947 'changed from %d to %d\n') %
1948 (len(old_unapplied), len(unapplied)))
1948 (len(old_unapplied), len(unapplied)))
1949 if len(guarded) != len(old_guarded):
1949 if len(guarded) != len(old_guarded):
1950 ui.status(_('number of guarded, applied patches has changed '
1950 ui.status(_('number of guarded, applied patches has changed '
1951 'from %d to %d\n') %
1951 'from %d to %d\n') %
1952 (len(old_guarded), len(guarded)))
1952 (len(old_guarded), len(guarded)))
1953 elif opts['series']:
1953 elif opts['series']:
1954 guards = {}
1954 guards = {}
1955 noguards = 0
1955 noguards = 0
1956 for gs in q.series_guards:
1956 for gs in q.series_guards:
1957 if not gs:
1957 if not gs:
1958 noguards += 1
1958 noguards += 1
1959 for g in gs:
1959 for g in gs:
1960 guards.setdefault(g, 0)
1960 guards.setdefault(g, 0)
1961 guards[g] += 1
1961 guards[g] += 1
1962 if ui.verbose:
1962 if ui.verbose:
1963 guards['NONE'] = noguards
1963 guards['NONE'] = noguards
1964 guards = guards.items()
1964 guards = guards.items()
1965 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
1965 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
1966 if guards:
1966 if guards:
1967 ui.note(_('guards in series file:\n'))
1967 ui.note(_('guards in series file:\n'))
1968 for guard, count in guards:
1968 for guard, count in guards:
1969 ui.note('%2d ' % count)
1969 ui.note('%2d ' % count)
1970 ui.write(guard, '\n')
1970 ui.write(guard, '\n')
1971 else:
1971 else:
1972 ui.note(_('no guards in series file\n'))
1972 ui.note(_('no guards in series file\n'))
1973 else:
1973 else:
1974 if guards:
1974 if guards:
1975 ui.note(_('active guards:\n'))
1975 ui.note(_('active guards:\n'))
1976 for g in guards:
1976 for g in guards:
1977 ui.write(g, '\n')
1977 ui.write(g, '\n')
1978 else:
1978 else:
1979 ui.write(_('no active guards\n'))
1979 ui.write(_('no active guards\n'))
1980 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
1980 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
1981 popped = False
1981 popped = False
1982 if opts['pop'] or opts['reapply']:
1982 if opts['pop'] or opts['reapply']:
1983 for i in xrange(len(q.applied)):
1983 for i in xrange(len(q.applied)):
1984 pushable, reason = q.pushable(i)
1984 pushable, reason = q.pushable(i)
1985 if not pushable:
1985 if not pushable:
1986 ui.status(_('popping guarded patches\n'))
1986 ui.status(_('popping guarded patches\n'))
1987 popped = True
1987 popped = True
1988 if i == 0:
1988 if i == 0:
1989 q.pop(repo, all=True)
1989 q.pop(repo, all=True)
1990 else:
1990 else:
1991 q.pop(repo, i-1)
1991 q.pop(repo, i-1)
1992 break
1992 break
1993 if popped:
1993 if popped:
1994 try:
1994 try:
1995 if reapply:
1995 if reapply:
1996 ui.status(_('reapplying unguarded patches\n'))
1996 ui.status(_('reapplying unguarded patches\n'))
1997 q.push(repo, reapply)
1997 q.push(repo, reapply)
1998 finally:
1998 finally:
1999 q.save_dirty()
1999 q.save_dirty()
2000
2000
2001 def reposetup(ui, repo):
2001 def reposetup(ui, repo):
2002 class mqrepo(repo.__class__):
2002 class mqrepo(repo.__class__):
2003 def abort_if_wdir_patched(self, errmsg, force=False):
2003 def abort_if_wdir_patched(self, errmsg, force=False):
2004 if self.mq.applied and not force:
2004 if self.mq.applied and not force:
2005 parent = revlog.hex(self.dirstate.parents()[0])
2005 parent = revlog.hex(self.dirstate.parents()[0])
2006 if parent in [s.rev for s in self.mq.applied]:
2006 if parent in [s.rev for s in self.mq.applied]:
2007 raise util.Abort(errmsg)
2007 raise util.Abort(errmsg)
2008
2008
2009 def commit(self, *args, **opts):
2009 def commit(self, *args, **opts):
2010 if len(args) >= 6:
2010 if len(args) >= 6:
2011 force = args[5]
2011 force = args[5]
2012 else:
2012 else:
2013 force = opts.get('force')
2013 force = opts.get('force')
2014 self.abort_if_wdir_patched(
2014 self.abort_if_wdir_patched(
2015 _('cannot commit over an applied mq patch'),
2015 _('cannot commit over an applied mq patch'),
2016 force)
2016 force)
2017
2017
2018 return super(mqrepo, self).commit(*args, **opts)
2018 return super(mqrepo, self).commit(*args, **opts)
2019
2019
2020 def push(self, remote, force=False, revs=None):
2020 def push(self, remote, force=False, revs=None):
2021 if self.mq.applied and not force:
2021 if self.mq.applied and not force:
2022 raise util.Abort(_('source has mq patches applied'))
2022 raise util.Abort(_('source has mq patches applied'))
2023 return super(mqrepo, self).push(remote, force, revs)
2023 return super(mqrepo, self).push(remote, force, revs)
2024
2024
2025 def tags(self):
2025 def tags(self):
2026 if self.tagscache:
2026 if self.tagscache:
2027 return self.tagscache
2027 return self.tagscache
2028
2028
2029 tagscache = super(mqrepo, self).tags()
2029 tagscache = super(mqrepo, self).tags()
2030
2030
2031 q = self.mq
2031 q = self.mq
2032 if not q.applied:
2032 if not q.applied:
2033 return tagscache
2033 return tagscache
2034
2034
2035 mqtags = [(patch.rev, patch.name) for patch in q.applied]
2035 mqtags = [(patch.rev, patch.name) for patch in q.applied]
2036 mqtags.append((mqtags[-1][0], 'qtip'))
2036 mqtags.append((mqtags[-1][0], 'qtip'))
2037 mqtags.append((mqtags[0][0], 'qbase'))
2037 mqtags.append((mqtags[0][0], 'qbase'))
2038 for patch in mqtags:
2038 for patch in mqtags:
2039 if patch[1] in tagscache:
2039 if patch[1] in tagscache:
2040 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1])
2040 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1])
2041 else:
2041 else:
2042 tagscache[patch[1]] = revlog.bin(patch[0])
2042 tagscache[patch[1]] = revlog.bin(patch[0])
2043
2043
2044 return tagscache
2044 return tagscache
2045
2045
2046 def _branchtags(self):
2046 def _branchtags(self):
2047 q = self.mq
2047 q = self.mq
2048 if not q.applied:
2048 if not q.applied:
2049 return super(mqrepo, self)._branchtags()
2049 return super(mqrepo, self)._branchtags()
2050
2050
2051 self.branchcache = {} # avoid recursion in changectx
2051 self.branchcache = {} # avoid recursion in changectx
2052 cl = self.changelog
2052 cl = self.changelog
2053 partial, last, lrev = self._readbranchcache()
2053 partial, last, lrev = self._readbranchcache()
2054
2054
2055 qbase = cl.rev(revlog.bin(q.applied[0].rev))
2055 qbase = cl.rev(revlog.bin(q.applied[0].rev))
2056 start = lrev + 1
2056 start = lrev + 1
2057 if start < qbase:
2057 if start < qbase:
2058 # update the cache (excluding the patches) and save it
2058 # update the cache (excluding the patches) and save it
2059 self._updatebranchcache(partial, lrev+1, qbase)
2059 self._updatebranchcache(partial, lrev+1, qbase)
2060 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2060 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2061 start = qbase
2061 start = qbase
2062 # if start = qbase, the cache is as updated as it should be.
2062 # if start = qbase, the cache is as updated as it should be.
2063 # if start > qbase, the cache includes (part of) the patches.
2063 # if start > qbase, the cache includes (part of) the patches.
2064 # we might as well use it, but we won't save it.
2064 # we might as well use it, but we won't save it.
2065
2065
2066 # update the cache up to the tip
2066 # update the cache up to the tip
2067 self._updatebranchcache(partial, start, cl.count())
2067 self._updatebranchcache(partial, start, cl.count())
2068
2068
2069 return partial
2069 return partial
2070
2070
2071 if repo.local():
2071 if repo.local():
2072 repo.__class__ = mqrepo
2072 repo.__class__ = mqrepo
2073 repo.mq = queue(ui, repo.join(""))
2073 repo.mq = queue(ui, repo.join(""))
2074
2074
2075 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2075 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2076
2076
2077 cmdtable = {
2077 cmdtable = {
2078 "qapplied": (applied, [] + seriesopts, 'hg qapplied [-s] [PATCH]'),
2078 "qapplied": (applied, [] + seriesopts, 'hg qapplied [-s] [PATCH]'),
2079 "qclone": (clone,
2079 "qclone": (clone,
2080 [('', 'pull', None, _('use pull protocol to copy metadata')),
2080 [('', 'pull', None, _('use pull protocol to copy metadata')),
2081 ('U', 'noupdate', None, _('do not update the new working directories')),
2081 ('U', 'noupdate', None, _('do not update the new working directories')),
2082 ('', 'uncompressed', None,
2082 ('', 'uncompressed', None,
2083 _('use uncompressed transfer (fast over LAN)')),
2083 _('use uncompressed transfer (fast over LAN)')),
2084 ('e', 'ssh', '', _('specify ssh command to use')),
2084 ('e', 'ssh', '', _('specify ssh command to use')),
2085 ('p', 'patches', '', _('location of source patch repo')),
2085 ('p', 'patches', '', _('location of source patch repo')),
2086 ('', 'remotecmd', '',
2086 ('', 'remotecmd', '',
2087 _('specify hg command to run on the remote side'))],
2087 _('specify hg command to run on the remote side'))],
2088 'hg qclone [OPTION]... SOURCE [DEST]'),
2088 'hg qclone [OPTION]... SOURCE [DEST]'),
2089 "qcommit|qci":
2089 "qcommit|qci":
2090 (commit,
2090 (commit,
2091 commands.table["^commit|ci"][1],
2091 commands.table["^commit|ci"][1],
2092 'hg qcommit [OPTION]... [FILE]...'),
2092 'hg qcommit [OPTION]... [FILE]...'),
2093 "^qdiff": (diff,
2093 "^qdiff": (diff,
2094 [('g', 'git', None, _('use git extended diff format')),
2094 [('g', 'git', None, _('use git extended diff format')),
2095 ('I', 'include', [], _('include names matching the given patterns')),
2095 ('I', 'include', [], _('include names matching the given patterns')),
2096 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2096 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2097 'hg qdiff [-I] [-X] [FILE]...'),
2097 'hg qdiff [-I] [-X] [FILE]...'),
2098 "qdelete|qremove|qrm":
2098 "qdelete|qremove|qrm":
2099 (delete,
2099 (delete,
2100 [('k', 'keep', None, _('keep patch file')),
2100 [('k', 'keep', None, _('keep patch file')),
2101 ('r', 'rev', [], _('stop managing a revision'))],
2101 ('r', 'rev', [], _('stop managing a revision'))],
2102 'hg qdelete [-k] [-r REV]... PATCH...'),
2102 'hg qdelete [-k] [-r REV]... PATCH...'),
2103 'qfold':
2103 'qfold':
2104 (fold,
2104 (fold,
2105 [('e', 'edit', None, _('edit patch header')),
2105 [('e', 'edit', None, _('edit patch header')),
2106 ('k', 'keep', None, _('keep folded patch files')),
2106 ('k', 'keep', None, _('keep folded patch files'))
2107 ('m', 'message', '', _('set patch header to <text>')),
2107 ] + commands.commitopts,
2108 ('l', 'logfile', '', _('set patch header to contents of <file>'))],
2109 'hg qfold [-e] [-m <text>] [-l <file] PATCH...'),
2108 'hg qfold [-e] [-m <text>] [-l <file] PATCH...'),
2110 'qguard': (guard, [('l', 'list', None, _('list all patches and guards')),
2109 'qguard': (guard, [('l', 'list', None, _('list all patches and guards')),
2111 ('n', 'none', None, _('drop all guards'))],
2110 ('n', 'none', None, _('drop all guards'))],
2112 'hg qguard [PATCH] [+GUARD...] [-GUARD...]'),
2111 'hg qguard [PATCH] [+GUARD...] [-GUARD...]'),
2113 'qheader': (header, [],
2112 'qheader': (header, [],
2114 _('hg qheader [PATCH]')),
2113 _('hg qheader [PATCH]')),
2115 "^qimport":
2114 "^qimport":
2116 (qimport,
2115 (qimport,
2117 [('e', 'existing', None, 'import file in patch dir'),
2116 [('e', 'existing', None, 'import file in patch dir'),
2118 ('n', 'name', '', 'patch file name'),
2117 ('n', 'name', '', 'patch file name'),
2119 ('f', 'force', None, 'overwrite existing files'),
2118 ('f', 'force', None, 'overwrite existing files'),
2120 ('r', 'rev', [], 'place existing revisions under mq control'),
2119 ('r', 'rev', [], 'place existing revisions under mq control'),
2121 ('g', 'git', None, _('use git extended diff format'))],
2120 ('g', 'git', None, _('use git extended diff format'))],
2122 'hg qimport [-e] [-n NAME] [-f] [-g] [-r REV]... FILE...'),
2121 'hg qimport [-e] [-n NAME] [-f] [-g] [-r REV]... FILE...'),
2123 "^qinit":
2122 "^qinit":
2124 (init,
2123 (init,
2125 [('c', 'create-repo', None, 'create queue repository')],
2124 [('c', 'create-repo', None, 'create queue repository')],
2126 'hg qinit [-c]'),
2125 'hg qinit [-c]'),
2127 "qnew":
2126 "qnew":
2128 (new,
2127 (new,
2129 [('e', 'edit', None, _('edit commit message')),
2128 [('e', 'edit', None, _('edit commit message')),
2130 ('m', 'message', '', _('use <text> as commit message')),
2129 ('f', 'force', None, _('import uncommitted changes into patch'))
2131 ('l', 'logfile', '', _('read the commit message from <file>')),
2130 ] + commands.commitopts,
2132 ('f', 'force', None, _('import uncommitted changes into patch'))],
2133 'hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH'),
2131 'hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH'),
2134 "qnext": (next, [] + seriesopts, 'hg qnext [-s]'),
2132 "qnext": (next, [] + seriesopts, 'hg qnext [-s]'),
2135 "qprev": (prev, [] + seriesopts, 'hg qprev [-s]'),
2133 "qprev": (prev, [] + seriesopts, 'hg qprev [-s]'),
2136 "^qpop":
2134 "^qpop":
2137 (pop,
2135 (pop,
2138 [('a', 'all', None, 'pop all patches'),
2136 [('a', 'all', None, 'pop all patches'),
2139 ('n', 'name', '', 'queue name to pop'),
2137 ('n', 'name', '', 'queue name to pop'),
2140 ('f', 'force', None, 'forget any local changes')],
2138 ('f', 'force', None, 'forget any local changes')],
2141 'hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]'),
2139 'hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]'),
2142 "^qpush":
2140 "^qpush":
2143 (push,
2141 (push,
2144 [('f', 'force', None, 'apply if the patch has rejects'),
2142 [('f', 'force', None, 'apply if the patch has rejects'),
2145 ('l', 'list', None, 'list patch name in commit text'),
2143 ('l', 'list', None, 'list patch name in commit text'),
2146 ('a', 'all', None, 'apply all patches'),
2144 ('a', 'all', None, 'apply all patches'),
2147 ('m', 'merge', None, 'merge from another queue'),
2145 ('m', 'merge', None, 'merge from another queue'),
2148 ('n', 'name', '', 'merge queue name')],
2146 ('n', 'name', '', 'merge queue name')],
2149 'hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]'),
2147 'hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]'),
2150 "^qrefresh":
2148 "^qrefresh":
2151 (refresh,
2149 (refresh,
2152 [('e', 'edit', None, _('edit commit message')),
2150 [('e', 'edit', None, _('edit commit message')),
2153 ('m', 'message', '', _('change commit message to <text>')),
2154 ('l', 'logfile', '', _('change commit message to <file> content')),
2155 ('g', 'git', None, _('use git extended diff format')),
2151 ('g', 'git', None, _('use git extended diff format')),
2156 ('s', 'short', None, 'refresh only files already in the patch'),
2152 ('s', 'short', None, 'refresh only files already in the patch'),
2157 ('I', 'include', [], _('include names matching the given patterns')),
2153 ('I', 'include', [], _('include names matching the given patterns')),
2158 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2154 ('X', 'exclude', [], _('exclude names matching the given patterns'))
2155 ] + commands.commitopts,
2159 'hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] FILES...'),
2156 'hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] FILES...'),
2160 'qrename|qmv':
2157 'qrename|qmv':
2161 (rename, [], 'hg qrename PATCH1 [PATCH2]'),
2158 (rename, [], 'hg qrename PATCH1 [PATCH2]'),
2162 "qrestore":
2159 "qrestore":
2163 (restore,
2160 (restore,
2164 [('d', 'delete', None, 'delete save entry'),
2161 [('d', 'delete', None, 'delete save entry'),
2165 ('u', 'update', None, 'update queue working dir')],
2162 ('u', 'update', None, 'update queue working dir')],
2166 'hg qrestore [-d] [-u] REV'),
2163 'hg qrestore [-d] [-u] REV'),
2167 "qsave":
2164 "qsave":
2168 (save,
2165 (save,
2169 [('m', 'message', '', _('use <text> as commit message')),
2166 [('c', 'copy', None, 'copy patch directory'),
2170 ('l', 'logfile', '', _('read the commit message from <file>')),
2171 ('c', 'copy', None, 'copy patch directory'),
2172 ('n', 'name', '', 'copy directory name'),
2167 ('n', 'name', '', 'copy directory name'),
2173 ('e', 'empty', None, 'clear queue status file'),
2168 ('e', 'empty', None, 'clear queue status file'),
2174 ('f', 'force', None, 'force copy')],
2169 ('f', 'force', None, 'force copy')] + commands.commitopts,
2175 'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
2170 'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
2176 "qselect": (select,
2171 "qselect": (select,
2177 [('n', 'none', None, _('disable all guards')),
2172 [('n', 'none', None, _('disable all guards')),
2178 ('s', 'series', None, _('list all guards in series file')),
2173 ('s', 'series', None, _('list all guards in series file')),
2179 ('', 'pop', None,
2174 ('', 'pop', None,
2180 _('pop to before first guarded applied patch')),
2175 _('pop to before first guarded applied patch')),
2181 ('', 'reapply', None, _('pop, then reapply patches'))],
2176 ('', 'reapply', None, _('pop, then reapply patches'))],
2182 'hg qselect [OPTION...] [GUARD...]'),
2177 'hg qselect [OPTION...] [GUARD...]'),
2183 "qseries":
2178 "qseries":
2184 (series,
2179 (series,
2185 [('m', 'missing', None, 'print patches not in series')] + seriesopts,
2180 [('m', 'missing', None, 'print patches not in series')] + seriesopts,
2186 'hg qseries [-ms]'),
2181 'hg qseries [-ms]'),
2187 "^strip":
2182 "^strip":
2188 (strip,
2183 (strip,
2189 [('f', 'force', None, 'force multi-head removal'),
2184 [('f', 'force', None, 'force multi-head removal'),
2190 ('b', 'backup', None, 'bundle unrelated changesets'),
2185 ('b', 'backup', None, 'bundle unrelated changesets'),
2191 ('n', 'nobackup', None, 'no backups')],
2186 ('n', 'nobackup', None, 'no backups')],
2192 'hg strip [-f] [-b] [-n] REV'),
2187 'hg strip [-f] [-b] [-n] REV'),
2193 "qtop": (top, [] + seriesopts, 'hg qtop [-s]'),
2188 "qtop": (top, [] + seriesopts, 'hg qtop [-s]'),
2194 "qunapplied": (unapplied, [] + seriesopts, 'hg qunapplied [-s] [PATCH]'),
2189 "qunapplied": (unapplied, [] + seriesopts, 'hg qunapplied [-s] [PATCH]'),
2195 }
2190 }
@@ -1,3314 +1,3314 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 from demandload import demandload
9 from node import *
9 from node import *
10 from i18n import gettext as _
10 from i18n import gettext as _
11 demandload(globals(), "bisect os re sys signal imp urllib pdb shlex stat")
11 demandload(globals(), "bisect os re sys signal imp urllib pdb shlex stat")
12 demandload(globals(), "fancyopts ui hg util lock revlog bundlerepo")
12 demandload(globals(), "fancyopts ui hg util lock revlog bundlerepo")
13 demandload(globals(), "difflib patch time help mdiff tempfile")
13 demandload(globals(), "difflib patch time help mdiff tempfile")
14 demandload(globals(), "traceback errno version atexit")
14 demandload(globals(), "traceback errno version atexit")
15 demandload(globals(), "archival changegroup cmdutil hgweb.server sshserver")
15 demandload(globals(), "archival changegroup cmdutil hgweb.server sshserver")
16
16
17 class UnknownCommand(Exception):
17 class UnknownCommand(Exception):
18 """Exception raised if command is not in the command table."""
18 """Exception raised if command is not in the command table."""
19 class AmbiguousCommand(Exception):
19 class AmbiguousCommand(Exception):
20 """Exception raised if command shortcut matches more than one command."""
20 """Exception raised if command shortcut matches more than one command."""
21
21
22 def bail_if_changed(repo):
22 def bail_if_changed(repo):
23 modified, added, removed, deleted = repo.status()[:4]
23 modified, added, removed, deleted = repo.status()[:4]
24 if modified or added or removed or deleted:
24 if modified or added or removed or deleted:
25 raise util.Abort(_("outstanding uncommitted changes"))
25 raise util.Abort(_("outstanding uncommitted changes"))
26
26
27 def logmessage(opts):
27 def logmessage(opts):
28 """ get the log message according to -m and -l option """
28 """ get the log message according to -m and -l option """
29 message = opts['message']
29 message = opts['message']
30 logfile = opts['logfile']
30 logfile = opts['logfile']
31
31
32 if message and logfile:
32 if message and logfile:
33 raise util.Abort(_('options --message and --logfile are mutually '
33 raise util.Abort(_('options --message and --logfile are mutually '
34 'exclusive'))
34 'exclusive'))
35 if not message and logfile:
35 if not message and logfile:
36 try:
36 try:
37 if logfile == '-':
37 if logfile == '-':
38 message = sys.stdin.read()
38 message = sys.stdin.read()
39 else:
39 else:
40 message = open(logfile).read()
40 message = open(logfile).read()
41 except IOError, inst:
41 except IOError, inst:
42 raise util.Abort(_("can't read commit message '%s': %s") %
42 raise util.Abort(_("can't read commit message '%s': %s") %
43 (logfile, inst.strerror))
43 (logfile, inst.strerror))
44 return message
44 return message
45
45
46 def setremoteconfig(ui, opts):
46 def setremoteconfig(ui, opts):
47 "copy remote options to ui tree"
47 "copy remote options to ui tree"
48 if opts.get('ssh'):
48 if opts.get('ssh'):
49 ui.setconfig("ui", "ssh", opts['ssh'])
49 ui.setconfig("ui", "ssh", opts['ssh'])
50 if opts.get('remotecmd'):
50 if opts.get('remotecmd'):
51 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
51 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
52
52
53 # Commands start here, listed alphabetically
53 # Commands start here, listed alphabetically
54
54
55 def add(ui, repo, *pats, **opts):
55 def add(ui, repo, *pats, **opts):
56 """add the specified files on the next commit
56 """add the specified files on the next commit
57
57
58 Schedule files to be version controlled and added to the repository.
58 Schedule files to be version controlled and added to the repository.
59
59
60 The files will be added to the repository at the next commit. To
60 The files will be added to the repository at the next commit. To
61 undo an add before that, see hg revert.
61 undo an add before that, see hg revert.
62
62
63 If no names are given, add all files in the repository.
63 If no names are given, add all files in the repository.
64 """
64 """
65
65
66 names = []
66 names = []
67 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
67 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
68 if exact:
68 if exact:
69 if ui.verbose:
69 if ui.verbose:
70 ui.status(_('adding %s\n') % rel)
70 ui.status(_('adding %s\n') % rel)
71 names.append(abs)
71 names.append(abs)
72 elif repo.dirstate.state(abs) == '?':
72 elif repo.dirstate.state(abs) == '?':
73 ui.status(_('adding %s\n') % rel)
73 ui.status(_('adding %s\n') % rel)
74 names.append(abs)
74 names.append(abs)
75 if not opts.get('dry_run'):
75 if not opts.get('dry_run'):
76 repo.add(names)
76 repo.add(names)
77
77
78 def addremove(ui, repo, *pats, **opts):
78 def addremove(ui, repo, *pats, **opts):
79 """add all new files, delete all missing files
79 """add all new files, delete all missing files
80
80
81 Add all new files and remove all missing files from the repository.
81 Add all new files and remove all missing files from the repository.
82
82
83 New files are ignored if they match any of the patterns in .hgignore. As
83 New files are ignored if they match any of the patterns in .hgignore. As
84 with add, these changes take effect at the next commit.
84 with add, these changes take effect at the next commit.
85
85
86 Use the -s option to detect renamed files. With a parameter > 0,
86 Use the -s option to detect renamed files. With a parameter > 0,
87 this compares every removed file with every added file and records
87 this compares every removed file with every added file and records
88 those similar enough as renames. This option takes a percentage
88 those similar enough as renames. This option takes a percentage
89 between 0 (disabled) and 100 (files must be identical) as its
89 between 0 (disabled) and 100 (files must be identical) as its
90 parameter. Detecting renamed files this way can be expensive.
90 parameter. Detecting renamed files this way can be expensive.
91 """
91 """
92 sim = float(opts.get('similarity') or 0)
92 sim = float(opts.get('similarity') or 0)
93 if sim < 0 or sim > 100:
93 if sim < 0 or sim > 100:
94 raise util.Abort(_('similarity must be between 0 and 100'))
94 raise util.Abort(_('similarity must be between 0 and 100'))
95 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
95 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
96
96
97 def annotate(ui, repo, *pats, **opts):
97 def annotate(ui, repo, *pats, **opts):
98 """show changeset information per file line
98 """show changeset information per file line
99
99
100 List changes in files, showing the revision id responsible for each line
100 List changes in files, showing the revision id responsible for each line
101
101
102 This command is useful to discover who did a change or when a change took
102 This command is useful to discover who did a change or when a change took
103 place.
103 place.
104
104
105 Without the -a option, annotate will avoid processing files it
105 Without the -a option, annotate will avoid processing files it
106 detects as binary. With -a, annotate will generate an annotation
106 detects as binary. With -a, annotate will generate an annotation
107 anyway, probably with undesirable results.
107 anyway, probably with undesirable results.
108 """
108 """
109 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
109 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
110
110
111 if not pats:
111 if not pats:
112 raise util.Abort(_('at least one file name or pattern required'))
112 raise util.Abort(_('at least one file name or pattern required'))
113
113
114 opmap = [['user', lambda x: ui.shortuser(x.user())],
114 opmap = [['user', lambda x: ui.shortuser(x.user())],
115 ['number', lambda x: str(x.rev())],
115 ['number', lambda x: str(x.rev())],
116 ['changeset', lambda x: short(x.node())],
116 ['changeset', lambda x: short(x.node())],
117 ['date', getdate], ['follow', lambda x: x.path()]]
117 ['date', getdate], ['follow', lambda x: x.path()]]
118 if (not opts['user'] and not opts['changeset'] and not opts['date']
118 if (not opts['user'] and not opts['changeset'] and not opts['date']
119 and not opts['follow']):
119 and not opts['follow']):
120 opts['number'] = 1
120 opts['number'] = 1
121
121
122 ctx = repo.changectx(opts['rev'])
122 ctx = repo.changectx(opts['rev'])
123
123
124 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
124 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
125 node=ctx.node()):
125 node=ctx.node()):
126 fctx = ctx.filectx(abs)
126 fctx = ctx.filectx(abs)
127 if not opts['text'] and util.binary(fctx.data()):
127 if not opts['text'] and util.binary(fctx.data()):
128 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
128 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
129 continue
129 continue
130
130
131 lines = fctx.annotate(follow=opts.get('follow'))
131 lines = fctx.annotate(follow=opts.get('follow'))
132 pieces = []
132 pieces = []
133
133
134 for o, f in opmap:
134 for o, f in opmap:
135 if opts[o]:
135 if opts[o]:
136 l = [f(n) for n, dummy in lines]
136 l = [f(n) for n, dummy in lines]
137 if l:
137 if l:
138 m = max(map(len, l))
138 m = max(map(len, l))
139 pieces.append(["%*s" % (m, x) for x in l])
139 pieces.append(["%*s" % (m, x) for x in l])
140
140
141 if pieces:
141 if pieces:
142 for p, l in zip(zip(*pieces), lines):
142 for p, l in zip(zip(*pieces), lines):
143 ui.write("%s: %s" % (" ".join(p), l[1]))
143 ui.write("%s: %s" % (" ".join(p), l[1]))
144
144
145 def archive(ui, repo, dest, **opts):
145 def archive(ui, repo, dest, **opts):
146 '''create unversioned archive of a repository revision
146 '''create unversioned archive of a repository revision
147
147
148 By default, the revision used is the parent of the working
148 By default, the revision used is the parent of the working
149 directory; use "-r" to specify a different revision.
149 directory; use "-r" to specify a different revision.
150
150
151 To specify the type of archive to create, use "-t". Valid
151 To specify the type of archive to create, use "-t". Valid
152 types are:
152 types are:
153
153
154 "files" (default): a directory full of files
154 "files" (default): a directory full of files
155 "tar": tar archive, uncompressed
155 "tar": tar archive, uncompressed
156 "tbz2": tar archive, compressed using bzip2
156 "tbz2": tar archive, compressed using bzip2
157 "tgz": tar archive, compressed using gzip
157 "tgz": tar archive, compressed using gzip
158 "uzip": zip archive, uncompressed
158 "uzip": zip archive, uncompressed
159 "zip": zip archive, compressed using deflate
159 "zip": zip archive, compressed using deflate
160
160
161 The exact name of the destination archive or directory is given
161 The exact name of the destination archive or directory is given
162 using a format string; see "hg help export" for details.
162 using a format string; see "hg help export" for details.
163
163
164 Each member added to an archive file has a directory prefix
164 Each member added to an archive file has a directory prefix
165 prepended. Use "-p" to specify a format string for the prefix.
165 prepended. Use "-p" to specify a format string for the prefix.
166 The default is the basename of the archive, with suffixes removed.
166 The default is the basename of the archive, with suffixes removed.
167 '''
167 '''
168
168
169 node = repo.changectx(opts['rev']).node()
169 node = repo.changectx(opts['rev']).node()
170 dest = cmdutil.make_filename(repo, dest, node)
170 dest = cmdutil.make_filename(repo, dest, node)
171 if os.path.realpath(dest) == repo.root:
171 if os.path.realpath(dest) == repo.root:
172 raise util.Abort(_('repository root cannot be destination'))
172 raise util.Abort(_('repository root cannot be destination'))
173 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
173 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
174 kind = opts.get('type') or 'files'
174 kind = opts.get('type') or 'files'
175 prefix = opts['prefix']
175 prefix = opts['prefix']
176 if dest == '-':
176 if dest == '-':
177 if kind == 'files':
177 if kind == 'files':
178 raise util.Abort(_('cannot archive plain files to stdout'))
178 raise util.Abort(_('cannot archive plain files to stdout'))
179 dest = sys.stdout
179 dest = sys.stdout
180 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
180 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
181 prefix = cmdutil.make_filename(repo, prefix, node)
181 prefix = cmdutil.make_filename(repo, prefix, node)
182 archival.archive(repo, dest, node, kind, not opts['no_decode'],
182 archival.archive(repo, dest, node, kind, not opts['no_decode'],
183 matchfn, prefix)
183 matchfn, prefix)
184
184
185 def backout(ui, repo, rev, **opts):
185 def backout(ui, repo, rev, **opts):
186 '''reverse effect of earlier changeset
186 '''reverse effect of earlier changeset
187
187
188 Commit the backed out changes as a new changeset. The new
188 Commit the backed out changes as a new changeset. The new
189 changeset is a child of the backed out changeset.
189 changeset is a child of the backed out changeset.
190
190
191 If you back out a changeset other than the tip, a new head is
191 If you back out a changeset other than the tip, a new head is
192 created. This head is the parent of the working directory. If
192 created. This head is the parent of the working directory. If
193 you back out an old changeset, your working directory will appear
193 you back out an old changeset, your working directory will appear
194 old after the backout. You should merge the backout changeset
194 old after the backout. You should merge the backout changeset
195 with another head.
195 with another head.
196
196
197 The --merge option remembers the parent of the working directory
197 The --merge option remembers the parent of the working directory
198 before starting the backout, then merges the new head with that
198 before starting the backout, then merges the new head with that
199 changeset afterwards. This saves you from doing the merge by
199 changeset afterwards. This saves you from doing the merge by
200 hand. The result of this merge is not committed, as for a normal
200 hand. The result of this merge is not committed, as for a normal
201 merge.'''
201 merge.'''
202
202
203 bail_if_changed(repo)
203 bail_if_changed(repo)
204 op1, op2 = repo.dirstate.parents()
204 op1, op2 = repo.dirstate.parents()
205 if op2 != nullid:
205 if op2 != nullid:
206 raise util.Abort(_('outstanding uncommitted merge'))
206 raise util.Abort(_('outstanding uncommitted merge'))
207 node = repo.lookup(rev)
207 node = repo.lookup(rev)
208 p1, p2 = repo.changelog.parents(node)
208 p1, p2 = repo.changelog.parents(node)
209 if p1 == nullid:
209 if p1 == nullid:
210 raise util.Abort(_('cannot back out a change with no parents'))
210 raise util.Abort(_('cannot back out a change with no parents'))
211 if p2 != nullid:
211 if p2 != nullid:
212 if not opts['parent']:
212 if not opts['parent']:
213 raise util.Abort(_('cannot back out a merge changeset without '
213 raise util.Abort(_('cannot back out a merge changeset without '
214 '--parent'))
214 '--parent'))
215 p = repo.lookup(opts['parent'])
215 p = repo.lookup(opts['parent'])
216 if p not in (p1, p2):
216 if p not in (p1, p2):
217 raise util.Abort(_('%s is not a parent of %s') %
217 raise util.Abort(_('%s is not a parent of %s') %
218 (short(p), short(node)))
218 (short(p), short(node)))
219 parent = p
219 parent = p
220 else:
220 else:
221 if opts['parent']:
221 if opts['parent']:
222 raise util.Abort(_('cannot use --parent on non-merge changeset'))
222 raise util.Abort(_('cannot use --parent on non-merge changeset'))
223 parent = p1
223 parent = p1
224 hg.clean(repo, node, show_stats=False)
224 hg.clean(repo, node, show_stats=False)
225 revert_opts = opts.copy()
225 revert_opts = opts.copy()
226 revert_opts['date'] = None
226 revert_opts['date'] = None
227 revert_opts['all'] = True
227 revert_opts['all'] = True
228 revert_opts['rev'] = hex(parent)
228 revert_opts['rev'] = hex(parent)
229 revert(ui, repo, **revert_opts)
229 revert(ui, repo, **revert_opts)
230 commit_opts = opts.copy()
230 commit_opts = opts.copy()
231 commit_opts['addremove'] = False
231 commit_opts['addremove'] = False
232 if not commit_opts['message'] and not commit_opts['logfile']:
232 if not commit_opts['message'] and not commit_opts['logfile']:
233 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
233 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
234 commit_opts['force_editor'] = True
234 commit_opts['force_editor'] = True
235 commit(ui, repo, **commit_opts)
235 commit(ui, repo, **commit_opts)
236 def nice(node):
236 def nice(node):
237 return '%d:%s' % (repo.changelog.rev(node), short(node))
237 return '%d:%s' % (repo.changelog.rev(node), short(node))
238 ui.status(_('changeset %s backs out changeset %s\n') %
238 ui.status(_('changeset %s backs out changeset %s\n') %
239 (nice(repo.changelog.tip()), nice(node)))
239 (nice(repo.changelog.tip()), nice(node)))
240 if op1 != node:
240 if op1 != node:
241 if opts['merge']:
241 if opts['merge']:
242 ui.status(_('merging with changeset %s\n') % nice(op1))
242 ui.status(_('merging with changeset %s\n') % nice(op1))
243 n = _lookup(repo, hex(op1))
243 n = _lookup(repo, hex(op1))
244 hg.merge(repo, n)
244 hg.merge(repo, n)
245 else:
245 else:
246 ui.status(_('the backout changeset is a new head - '
246 ui.status(_('the backout changeset is a new head - '
247 'do not forget to merge\n'))
247 'do not forget to merge\n'))
248 ui.status(_('(use "backout --merge" '
248 ui.status(_('(use "backout --merge" '
249 'if you want to auto-merge)\n'))
249 'if you want to auto-merge)\n'))
250
250
251 def branch(ui, repo, label=None):
251 def branch(ui, repo, label=None):
252 """set or show the current branch name
252 """set or show the current branch name
253
253
254 With <name>, set the current branch name. Otherwise, show the
254 With <name>, set the current branch name. Otherwise, show the
255 current branch name.
255 current branch name.
256 """
256 """
257
257
258 if label is not None:
258 if label is not None:
259 repo.opener("branch", "w").write(label)
259 repo.opener("branch", "w").write(label)
260 else:
260 else:
261 b = repo.workingctx().branch()
261 b = repo.workingctx().branch()
262 if b:
262 if b:
263 ui.write("%s\n" % b)
263 ui.write("%s\n" % b)
264
264
265 def branches(ui, repo):
265 def branches(ui, repo):
266 """list repository named branches
266 """list repository named branches
267
267
268 List the repository's named branches.
268 List the repository's named branches.
269 """
269 """
270 b = repo.branchtags()
270 b = repo.branchtags()
271 l = [(-repo.changelog.rev(n), n, t) for t, n in b.items()]
271 l = [(-repo.changelog.rev(n), n, t) for t, n in b.items()]
272 l.sort()
272 l.sort()
273 for r, n, t in l:
273 for r, n, t in l:
274 hexfunc = ui.debugflag and hex or short
274 hexfunc = ui.debugflag and hex or short
275 if ui.quiet:
275 if ui.quiet:
276 ui.write("%s\n" % t)
276 ui.write("%s\n" % t)
277 else:
277 else:
278 t = util.localsub(t, 30)
278 t = util.localsub(t, 30)
279 t += " " * (30 - util.locallen(t))
279 t += " " * (30 - util.locallen(t))
280 ui.write("%s %s:%s\n" % (t, -r, hexfunc(n)))
280 ui.write("%s %s:%s\n" % (t, -r, hexfunc(n)))
281
281
282 def bundle(ui, repo, fname, dest=None, **opts):
282 def bundle(ui, repo, fname, dest=None, **opts):
283 """create a changegroup file
283 """create a changegroup file
284
284
285 Generate a compressed changegroup file collecting changesets not
285 Generate a compressed changegroup file collecting changesets not
286 found in the other repository.
286 found in the other repository.
287
287
288 If no destination repository is specified the destination is assumed
288 If no destination repository is specified the destination is assumed
289 to have all the nodes specified by one or more --base parameters.
289 to have all the nodes specified by one or more --base parameters.
290
290
291 The bundle file can then be transferred using conventional means and
291 The bundle file can then be transferred using conventional means and
292 applied to another repository with the unbundle or pull command.
292 applied to another repository with the unbundle or pull command.
293 This is useful when direct push and pull are not available or when
293 This is useful when direct push and pull are not available or when
294 exporting an entire repository is undesirable.
294 exporting an entire repository is undesirable.
295
295
296 Applying bundles preserves all changeset contents including
296 Applying bundles preserves all changeset contents including
297 permissions, copy/rename information, and revision history.
297 permissions, copy/rename information, and revision history.
298 """
298 """
299 revs = opts.get('rev') or None
299 revs = opts.get('rev') or None
300 if revs:
300 if revs:
301 revs = [repo.lookup(rev) for rev in revs]
301 revs = [repo.lookup(rev) for rev in revs]
302 base = opts.get('base')
302 base = opts.get('base')
303 if base:
303 if base:
304 if dest:
304 if dest:
305 raise util.Abort(_("--base is incompatible with specifiying "
305 raise util.Abort(_("--base is incompatible with specifiying "
306 "a destination"))
306 "a destination"))
307 base = [repo.lookup(rev) for rev in base]
307 base = [repo.lookup(rev) for rev in base]
308 # create the right base
308 # create the right base
309 # XXX: nodesbetween / changegroup* should be "fixed" instead
309 # XXX: nodesbetween / changegroup* should be "fixed" instead
310 o = []
310 o = []
311 has = {nullid: None}
311 has = {nullid: None}
312 for n in base:
312 for n in base:
313 has.update(repo.changelog.reachable(n))
313 has.update(repo.changelog.reachable(n))
314 if revs:
314 if revs:
315 visit = list(revs)
315 visit = list(revs)
316 else:
316 else:
317 visit = repo.changelog.heads()
317 visit = repo.changelog.heads()
318 seen = {}
318 seen = {}
319 while visit:
319 while visit:
320 n = visit.pop(0)
320 n = visit.pop(0)
321 parents = [p for p in repo.changelog.parents(n) if p not in has]
321 parents = [p for p in repo.changelog.parents(n) if p not in has]
322 if len(parents) == 0:
322 if len(parents) == 0:
323 o.insert(0, n)
323 o.insert(0, n)
324 else:
324 else:
325 for p in parents:
325 for p in parents:
326 if p not in seen:
326 if p not in seen:
327 seen[p] = 1
327 seen[p] = 1
328 visit.append(p)
328 visit.append(p)
329 else:
329 else:
330 setremoteconfig(ui, opts)
330 setremoteconfig(ui, opts)
331 dest = ui.expandpath(dest or 'default-push', dest or 'default')
331 dest = ui.expandpath(dest or 'default-push', dest or 'default')
332 other = hg.repository(ui, dest)
332 other = hg.repository(ui, dest)
333 o = repo.findoutgoing(other, force=opts['force'])
333 o = repo.findoutgoing(other, force=opts['force'])
334
334
335 if revs:
335 if revs:
336 cg = repo.changegroupsubset(o, revs, 'bundle')
336 cg = repo.changegroupsubset(o, revs, 'bundle')
337 else:
337 else:
338 cg = repo.changegroup(o, 'bundle')
338 cg = repo.changegroup(o, 'bundle')
339 changegroup.writebundle(cg, fname, "HG10BZ")
339 changegroup.writebundle(cg, fname, "HG10BZ")
340
340
341 def cat(ui, repo, file1, *pats, **opts):
341 def cat(ui, repo, file1, *pats, **opts):
342 """output the latest or given revisions of files
342 """output the latest or given revisions of files
343
343
344 Print the specified files as they were at the given revision.
344 Print the specified files as they were at the given revision.
345 If no revision is given then working dir parent is used, or tip
345 If no revision is given then working dir parent is used, or tip
346 if no revision is checked out.
346 if no revision is checked out.
347
347
348 Output may be to a file, in which case the name of the file is
348 Output may be to a file, in which case the name of the file is
349 given using a format string. The formatting rules are the same as
349 given using a format string. The formatting rules are the same as
350 for the export command, with the following additions:
350 for the export command, with the following additions:
351
351
352 %s basename of file being printed
352 %s basename of file being printed
353 %d dirname of file being printed, or '.' if in repo root
353 %d dirname of file being printed, or '.' if in repo root
354 %p root-relative path name of file being printed
354 %p root-relative path name of file being printed
355 """
355 """
356 ctx = repo.changectx(opts['rev'])
356 ctx = repo.changectx(opts['rev'])
357 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
357 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
358 ctx.node()):
358 ctx.node()):
359 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
359 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
360 fp.write(ctx.filectx(abs).data())
360 fp.write(ctx.filectx(abs).data())
361
361
362 def clone(ui, source, dest=None, **opts):
362 def clone(ui, source, dest=None, **opts):
363 """make a copy of an existing repository
363 """make a copy of an existing repository
364
364
365 Create a copy of an existing repository in a new directory.
365 Create a copy of an existing repository in a new directory.
366
366
367 If no destination directory name is specified, it defaults to the
367 If no destination directory name is specified, it defaults to the
368 basename of the source.
368 basename of the source.
369
369
370 The location of the source is added to the new repository's
370 The location of the source is added to the new repository's
371 .hg/hgrc file, as the default to be used for future pulls.
371 .hg/hgrc file, as the default to be used for future pulls.
372
372
373 For efficiency, hardlinks are used for cloning whenever the source
373 For efficiency, hardlinks are used for cloning whenever the source
374 and destination are on the same filesystem (note this applies only
374 and destination are on the same filesystem (note this applies only
375 to the repository data, not to the checked out files). Some
375 to the repository data, not to the checked out files). Some
376 filesystems, such as AFS, implement hardlinking incorrectly, but
376 filesystems, such as AFS, implement hardlinking incorrectly, but
377 do not report errors. In these cases, use the --pull option to
377 do not report errors. In these cases, use the --pull option to
378 avoid hardlinking.
378 avoid hardlinking.
379
379
380 You can safely clone repositories and checked out files using full
380 You can safely clone repositories and checked out files using full
381 hardlinks with
381 hardlinks with
382
382
383 $ cp -al REPO REPOCLONE
383 $ cp -al REPO REPOCLONE
384
384
385 which is the fastest way to clone. However, the operation is not
385 which is the fastest way to clone. However, the operation is not
386 atomic (making sure REPO is not modified during the operation is
386 atomic (making sure REPO is not modified during the operation is
387 up to you) and you have to make sure your editor breaks hardlinks
387 up to you) and you have to make sure your editor breaks hardlinks
388 (Emacs and most Linux Kernel tools do so).
388 (Emacs and most Linux Kernel tools do so).
389
389
390 If you use the -r option to clone up to a specific revision, no
390 If you use the -r option to clone up to a specific revision, no
391 subsequent revisions will be present in the cloned repository.
391 subsequent revisions will be present in the cloned repository.
392 This option implies --pull, even on local repositories.
392 This option implies --pull, even on local repositories.
393
393
394 See pull for valid source format details.
394 See pull for valid source format details.
395
395
396 It is possible to specify an ssh:// URL as the destination, but no
396 It is possible to specify an ssh:// URL as the destination, but no
397 .hg/hgrc and working directory will be created on the remote side.
397 .hg/hgrc and working directory will be created on the remote side.
398 Look at the help text for the pull command for important details
398 Look at the help text for the pull command for important details
399 about ssh:// URLs.
399 about ssh:// URLs.
400 """
400 """
401 setremoteconfig(ui, opts)
401 setremoteconfig(ui, opts)
402 hg.clone(ui, ui.expandpath(source), dest,
402 hg.clone(ui, ui.expandpath(source), dest,
403 pull=opts['pull'],
403 pull=opts['pull'],
404 stream=opts['uncompressed'],
404 stream=opts['uncompressed'],
405 rev=opts['rev'],
405 rev=opts['rev'],
406 update=not opts['noupdate'])
406 update=not opts['noupdate'])
407
407
408 def commit(ui, repo, *pats, **opts):
408 def commit(ui, repo, *pats, **opts):
409 """commit the specified files or all outstanding changes
409 """commit the specified files or all outstanding changes
410
410
411 Commit changes to the given files into the repository.
411 Commit changes to the given files into the repository.
412
412
413 If a list of files is omitted, all changes reported by "hg status"
413 If a list of files is omitted, all changes reported by "hg status"
414 will be committed.
414 will be committed.
415
415
416 If no commit message is specified, the editor configured in your hgrc
416 If no commit message is specified, the editor configured in your hgrc
417 or in the EDITOR environment variable is started to enter a message.
417 or in the EDITOR environment variable is started to enter a message.
418 """
418 """
419 message = logmessage(opts)
419 message = logmessage(opts)
420
420
421 if opts['addremove']:
421 if opts['addremove']:
422 cmdutil.addremove(repo, pats, opts)
422 cmdutil.addremove(repo, pats, opts)
423 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
423 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
424 if pats:
424 if pats:
425 status = repo.status(files=fns, match=match)
425 status = repo.status(files=fns, match=match)
426 modified, added, removed, deleted, unknown = status[:5]
426 modified, added, removed, deleted, unknown = status[:5]
427 files = modified + added + removed
427 files = modified + added + removed
428 slist = None
428 slist = None
429 for f in fns:
429 for f in fns:
430 if f not in files:
430 if f not in files:
431 rf = repo.wjoin(f)
431 rf = repo.wjoin(f)
432 if f in unknown:
432 if f in unknown:
433 raise util.Abort(_("file %s not tracked!") % rf)
433 raise util.Abort(_("file %s not tracked!") % rf)
434 try:
434 try:
435 mode = os.lstat(rf)[stat.ST_MODE]
435 mode = os.lstat(rf)[stat.ST_MODE]
436 except OSError:
436 except OSError:
437 raise util.Abort(_("file %s not found!") % rf)
437 raise util.Abort(_("file %s not found!") % rf)
438 if stat.S_ISDIR(mode):
438 if stat.S_ISDIR(mode):
439 name = f + '/'
439 name = f + '/'
440 if slist is None:
440 if slist is None:
441 slist = list(files)
441 slist = list(files)
442 slist.sort()
442 slist.sort()
443 i = bisect.bisect(slist, name)
443 i = bisect.bisect(slist, name)
444 if i >= len(slist) or not slist[i].startswith(name):
444 if i >= len(slist) or not slist[i].startswith(name):
445 raise util.Abort(_("no match under directory %s!")
445 raise util.Abort(_("no match under directory %s!")
446 % rf)
446 % rf)
447 elif not stat.S_ISREG(mode):
447 elif not stat.S_ISREG(mode):
448 raise util.Abort(_("can't commit %s: "
448 raise util.Abort(_("can't commit %s: "
449 "unsupported file type!") % rf)
449 "unsupported file type!") % rf)
450 else:
450 else:
451 files = []
451 files = []
452 try:
452 try:
453 repo.commit(files, message, opts['user'], opts['date'], match,
453 repo.commit(files, message, opts['user'], opts['date'], match,
454 force_editor=opts.get('force_editor'))
454 force_editor=opts.get('force_editor'))
455 except ValueError, inst:
455 except ValueError, inst:
456 raise util.Abort(str(inst))
456 raise util.Abort(str(inst))
457
457
458 def docopy(ui, repo, pats, opts, wlock):
458 def docopy(ui, repo, pats, opts, wlock):
459 # called with the repo lock held
459 # called with the repo lock held
460 #
460 #
461 # hgsep => pathname that uses "/" to separate directories
461 # hgsep => pathname that uses "/" to separate directories
462 # ossep => pathname that uses os.sep to separate directories
462 # ossep => pathname that uses os.sep to separate directories
463 cwd = repo.getcwd()
463 cwd = repo.getcwd()
464 errors = 0
464 errors = 0
465 copied = []
465 copied = []
466 targets = {}
466 targets = {}
467
467
468 # abs: hgsep
468 # abs: hgsep
469 # rel: ossep
469 # rel: ossep
470 # return: hgsep
470 # return: hgsep
471 def okaytocopy(abs, rel, exact):
471 def okaytocopy(abs, rel, exact):
472 reasons = {'?': _('is not managed'),
472 reasons = {'?': _('is not managed'),
473 'a': _('has been marked for add'),
473 'a': _('has been marked for add'),
474 'r': _('has been marked for remove')}
474 'r': _('has been marked for remove')}
475 state = repo.dirstate.state(abs)
475 state = repo.dirstate.state(abs)
476 reason = reasons.get(state)
476 reason = reasons.get(state)
477 if reason:
477 if reason:
478 if state == 'a':
478 if state == 'a':
479 origsrc = repo.dirstate.copied(abs)
479 origsrc = repo.dirstate.copied(abs)
480 if origsrc is not None:
480 if origsrc is not None:
481 return origsrc
481 return origsrc
482 if exact:
482 if exact:
483 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
483 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
484 else:
484 else:
485 return abs
485 return abs
486
486
487 # origsrc: hgsep
487 # origsrc: hgsep
488 # abssrc: hgsep
488 # abssrc: hgsep
489 # relsrc: ossep
489 # relsrc: ossep
490 # target: ossep
490 # target: ossep
491 def copy(origsrc, abssrc, relsrc, target, exact):
491 def copy(origsrc, abssrc, relsrc, target, exact):
492 abstarget = util.canonpath(repo.root, cwd, target)
492 abstarget = util.canonpath(repo.root, cwd, target)
493 reltarget = util.pathto(cwd, abstarget)
493 reltarget = util.pathto(cwd, abstarget)
494 prevsrc = targets.get(abstarget)
494 prevsrc = targets.get(abstarget)
495 if prevsrc is not None:
495 if prevsrc is not None:
496 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
496 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
497 (reltarget, util.localpath(abssrc),
497 (reltarget, util.localpath(abssrc),
498 util.localpath(prevsrc)))
498 util.localpath(prevsrc)))
499 return
499 return
500 if (not opts['after'] and os.path.exists(reltarget) or
500 if (not opts['after'] and os.path.exists(reltarget) or
501 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
501 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
502 if not opts['force']:
502 if not opts['force']:
503 ui.warn(_('%s: not overwriting - file exists\n') %
503 ui.warn(_('%s: not overwriting - file exists\n') %
504 reltarget)
504 reltarget)
505 return
505 return
506 if not opts['after'] and not opts.get('dry_run'):
506 if not opts['after'] and not opts.get('dry_run'):
507 os.unlink(reltarget)
507 os.unlink(reltarget)
508 if opts['after']:
508 if opts['after']:
509 if not os.path.exists(reltarget):
509 if not os.path.exists(reltarget):
510 return
510 return
511 else:
511 else:
512 targetdir = os.path.dirname(reltarget) or '.'
512 targetdir = os.path.dirname(reltarget) or '.'
513 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
513 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
514 os.makedirs(targetdir)
514 os.makedirs(targetdir)
515 try:
515 try:
516 restore = repo.dirstate.state(abstarget) == 'r'
516 restore = repo.dirstate.state(abstarget) == 'r'
517 if restore and not opts.get('dry_run'):
517 if restore and not opts.get('dry_run'):
518 repo.undelete([abstarget], wlock)
518 repo.undelete([abstarget], wlock)
519 try:
519 try:
520 if not opts.get('dry_run'):
520 if not opts.get('dry_run'):
521 util.copyfile(relsrc, reltarget)
521 util.copyfile(relsrc, reltarget)
522 restore = False
522 restore = False
523 finally:
523 finally:
524 if restore:
524 if restore:
525 repo.remove([abstarget], wlock)
525 repo.remove([abstarget], wlock)
526 except IOError, inst:
526 except IOError, inst:
527 if inst.errno == errno.ENOENT:
527 if inst.errno == errno.ENOENT:
528 ui.warn(_('%s: deleted in working copy\n') % relsrc)
528 ui.warn(_('%s: deleted in working copy\n') % relsrc)
529 else:
529 else:
530 ui.warn(_('%s: cannot copy - %s\n') %
530 ui.warn(_('%s: cannot copy - %s\n') %
531 (relsrc, inst.strerror))
531 (relsrc, inst.strerror))
532 errors += 1
532 errors += 1
533 return
533 return
534 if ui.verbose or not exact:
534 if ui.verbose or not exact:
535 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
535 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
536 targets[abstarget] = abssrc
536 targets[abstarget] = abssrc
537 if abstarget != origsrc and not opts.get('dry_run'):
537 if abstarget != origsrc and not opts.get('dry_run'):
538 repo.copy(origsrc, abstarget, wlock)
538 repo.copy(origsrc, abstarget, wlock)
539 copied.append((abssrc, relsrc, exact))
539 copied.append((abssrc, relsrc, exact))
540
540
541 # pat: ossep
541 # pat: ossep
542 # dest ossep
542 # dest ossep
543 # srcs: list of (hgsep, hgsep, ossep, bool)
543 # srcs: list of (hgsep, hgsep, ossep, bool)
544 # return: function that takes hgsep and returns ossep
544 # return: function that takes hgsep and returns ossep
545 def targetpathfn(pat, dest, srcs):
545 def targetpathfn(pat, dest, srcs):
546 if os.path.isdir(pat):
546 if os.path.isdir(pat):
547 abspfx = util.canonpath(repo.root, cwd, pat)
547 abspfx = util.canonpath(repo.root, cwd, pat)
548 abspfx = util.localpath(abspfx)
548 abspfx = util.localpath(abspfx)
549 if destdirexists:
549 if destdirexists:
550 striplen = len(os.path.split(abspfx)[0])
550 striplen = len(os.path.split(abspfx)[0])
551 else:
551 else:
552 striplen = len(abspfx)
552 striplen = len(abspfx)
553 if striplen:
553 if striplen:
554 striplen += len(os.sep)
554 striplen += len(os.sep)
555 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
555 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
556 elif destdirexists:
556 elif destdirexists:
557 res = lambda p: os.path.join(dest,
557 res = lambda p: os.path.join(dest,
558 os.path.basename(util.localpath(p)))
558 os.path.basename(util.localpath(p)))
559 else:
559 else:
560 res = lambda p: dest
560 res = lambda p: dest
561 return res
561 return res
562
562
563 # pat: ossep
563 # pat: ossep
564 # dest ossep
564 # dest ossep
565 # srcs: list of (hgsep, hgsep, ossep, bool)
565 # srcs: list of (hgsep, hgsep, ossep, bool)
566 # return: function that takes hgsep and returns ossep
566 # return: function that takes hgsep and returns ossep
567 def targetpathafterfn(pat, dest, srcs):
567 def targetpathafterfn(pat, dest, srcs):
568 if util.patkind(pat, None)[0]:
568 if util.patkind(pat, None)[0]:
569 # a mercurial pattern
569 # a mercurial pattern
570 res = lambda p: os.path.join(dest,
570 res = lambda p: os.path.join(dest,
571 os.path.basename(util.localpath(p)))
571 os.path.basename(util.localpath(p)))
572 else:
572 else:
573 abspfx = util.canonpath(repo.root, cwd, pat)
573 abspfx = util.canonpath(repo.root, cwd, pat)
574 if len(abspfx) < len(srcs[0][0]):
574 if len(abspfx) < len(srcs[0][0]):
575 # A directory. Either the target path contains the last
575 # A directory. Either the target path contains the last
576 # component of the source path or it does not.
576 # component of the source path or it does not.
577 def evalpath(striplen):
577 def evalpath(striplen):
578 score = 0
578 score = 0
579 for s in srcs:
579 for s in srcs:
580 t = os.path.join(dest, util.localpath(s[0])[striplen:])
580 t = os.path.join(dest, util.localpath(s[0])[striplen:])
581 if os.path.exists(t):
581 if os.path.exists(t):
582 score += 1
582 score += 1
583 return score
583 return score
584
584
585 abspfx = util.localpath(abspfx)
585 abspfx = util.localpath(abspfx)
586 striplen = len(abspfx)
586 striplen = len(abspfx)
587 if striplen:
587 if striplen:
588 striplen += len(os.sep)
588 striplen += len(os.sep)
589 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
589 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
590 score = evalpath(striplen)
590 score = evalpath(striplen)
591 striplen1 = len(os.path.split(abspfx)[0])
591 striplen1 = len(os.path.split(abspfx)[0])
592 if striplen1:
592 if striplen1:
593 striplen1 += len(os.sep)
593 striplen1 += len(os.sep)
594 if evalpath(striplen1) > score:
594 if evalpath(striplen1) > score:
595 striplen = striplen1
595 striplen = striplen1
596 res = lambda p: os.path.join(dest,
596 res = lambda p: os.path.join(dest,
597 util.localpath(p)[striplen:])
597 util.localpath(p)[striplen:])
598 else:
598 else:
599 # a file
599 # a file
600 if destdirexists:
600 if destdirexists:
601 res = lambda p: os.path.join(dest,
601 res = lambda p: os.path.join(dest,
602 os.path.basename(util.localpath(p)))
602 os.path.basename(util.localpath(p)))
603 else:
603 else:
604 res = lambda p: dest
604 res = lambda p: dest
605 return res
605 return res
606
606
607
607
608 pats = list(pats)
608 pats = list(pats)
609 if not pats:
609 if not pats:
610 raise util.Abort(_('no source or destination specified'))
610 raise util.Abort(_('no source or destination specified'))
611 if len(pats) == 1:
611 if len(pats) == 1:
612 raise util.Abort(_('no destination specified'))
612 raise util.Abort(_('no destination specified'))
613 dest = pats.pop()
613 dest = pats.pop()
614 destdirexists = os.path.isdir(dest)
614 destdirexists = os.path.isdir(dest)
615 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
615 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
616 raise util.Abort(_('with multiple sources, destination must be an '
616 raise util.Abort(_('with multiple sources, destination must be an '
617 'existing directory'))
617 'existing directory'))
618 if opts['after']:
618 if opts['after']:
619 tfn = targetpathafterfn
619 tfn = targetpathafterfn
620 else:
620 else:
621 tfn = targetpathfn
621 tfn = targetpathfn
622 copylist = []
622 copylist = []
623 for pat in pats:
623 for pat in pats:
624 srcs = []
624 srcs = []
625 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
625 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
626 origsrc = okaytocopy(abssrc, relsrc, exact)
626 origsrc = okaytocopy(abssrc, relsrc, exact)
627 if origsrc:
627 if origsrc:
628 srcs.append((origsrc, abssrc, relsrc, exact))
628 srcs.append((origsrc, abssrc, relsrc, exact))
629 if not srcs:
629 if not srcs:
630 continue
630 continue
631 copylist.append((tfn(pat, dest, srcs), srcs))
631 copylist.append((tfn(pat, dest, srcs), srcs))
632 if not copylist:
632 if not copylist:
633 raise util.Abort(_('no files to copy'))
633 raise util.Abort(_('no files to copy'))
634
634
635 for targetpath, srcs in copylist:
635 for targetpath, srcs in copylist:
636 for origsrc, abssrc, relsrc, exact in srcs:
636 for origsrc, abssrc, relsrc, exact in srcs:
637 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
637 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
638
638
639 if errors:
639 if errors:
640 ui.warn(_('(consider using --after)\n'))
640 ui.warn(_('(consider using --after)\n'))
641 return errors, copied
641 return errors, copied
642
642
643 def copy(ui, repo, *pats, **opts):
643 def copy(ui, repo, *pats, **opts):
644 """mark files as copied for the next commit
644 """mark files as copied for the next commit
645
645
646 Mark dest as having copies of source files. If dest is a
646 Mark dest as having copies of source files. If dest is a
647 directory, copies are put in that directory. If dest is a file,
647 directory, copies are put in that directory. If dest is a file,
648 there can only be one source.
648 there can only be one source.
649
649
650 By default, this command copies the contents of files as they
650 By default, this command copies the contents of files as they
651 stand in the working directory. If invoked with --after, the
651 stand in the working directory. If invoked with --after, the
652 operation is recorded, but no copying is performed.
652 operation is recorded, but no copying is performed.
653
653
654 This command takes effect in the next commit. To undo a copy
654 This command takes effect in the next commit. To undo a copy
655 before that, see hg revert.
655 before that, see hg revert.
656 """
656 """
657 wlock = repo.wlock(0)
657 wlock = repo.wlock(0)
658 errs, copied = docopy(ui, repo, pats, opts, wlock)
658 errs, copied = docopy(ui, repo, pats, opts, wlock)
659 return errs
659 return errs
660
660
661 def debugancestor(ui, index, rev1, rev2):
661 def debugancestor(ui, index, rev1, rev2):
662 """find the ancestor revision of two revisions in a given index"""
662 """find the ancestor revision of two revisions in a given index"""
663 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
663 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
664 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
664 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
665 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
665 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
666
666
667 def debugcomplete(ui, cmd='', **opts):
667 def debugcomplete(ui, cmd='', **opts):
668 """returns the completion list associated with the given command"""
668 """returns the completion list associated with the given command"""
669
669
670 if opts['options']:
670 if opts['options']:
671 options = []
671 options = []
672 otables = [globalopts]
672 otables = [globalopts]
673 if cmd:
673 if cmd:
674 aliases, entry = findcmd(ui, cmd)
674 aliases, entry = findcmd(ui, cmd)
675 otables.append(entry[1])
675 otables.append(entry[1])
676 for t in otables:
676 for t in otables:
677 for o in t:
677 for o in t:
678 if o[0]:
678 if o[0]:
679 options.append('-%s' % o[0])
679 options.append('-%s' % o[0])
680 options.append('--%s' % o[1])
680 options.append('--%s' % o[1])
681 ui.write("%s\n" % "\n".join(options))
681 ui.write("%s\n" % "\n".join(options))
682 return
682 return
683
683
684 clist = findpossible(ui, cmd).keys()
684 clist = findpossible(ui, cmd).keys()
685 clist.sort()
685 clist.sort()
686 ui.write("%s\n" % "\n".join(clist))
686 ui.write("%s\n" % "\n".join(clist))
687
687
688 def debugrebuildstate(ui, repo, rev=None):
688 def debugrebuildstate(ui, repo, rev=None):
689 """rebuild the dirstate as it would look like for the given revision"""
689 """rebuild the dirstate as it would look like for the given revision"""
690 if not rev:
690 if not rev:
691 rev = repo.changelog.tip()
691 rev = repo.changelog.tip()
692 else:
692 else:
693 rev = repo.lookup(rev)
693 rev = repo.lookup(rev)
694 change = repo.changelog.read(rev)
694 change = repo.changelog.read(rev)
695 n = change[0]
695 n = change[0]
696 files = repo.manifest.read(n)
696 files = repo.manifest.read(n)
697 wlock = repo.wlock()
697 wlock = repo.wlock()
698 repo.dirstate.rebuild(rev, files)
698 repo.dirstate.rebuild(rev, files)
699
699
700 def debugcheckstate(ui, repo):
700 def debugcheckstate(ui, repo):
701 """validate the correctness of the current dirstate"""
701 """validate the correctness of the current dirstate"""
702 parent1, parent2 = repo.dirstate.parents()
702 parent1, parent2 = repo.dirstate.parents()
703 repo.dirstate.read()
703 repo.dirstate.read()
704 dc = repo.dirstate.map
704 dc = repo.dirstate.map
705 keys = dc.keys()
705 keys = dc.keys()
706 keys.sort()
706 keys.sort()
707 m1n = repo.changelog.read(parent1)[0]
707 m1n = repo.changelog.read(parent1)[0]
708 m2n = repo.changelog.read(parent2)[0]
708 m2n = repo.changelog.read(parent2)[0]
709 m1 = repo.manifest.read(m1n)
709 m1 = repo.manifest.read(m1n)
710 m2 = repo.manifest.read(m2n)
710 m2 = repo.manifest.read(m2n)
711 errors = 0
711 errors = 0
712 for f in dc:
712 for f in dc:
713 state = repo.dirstate.state(f)
713 state = repo.dirstate.state(f)
714 if state in "nr" and f not in m1:
714 if state in "nr" and f not in m1:
715 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
715 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
716 errors += 1
716 errors += 1
717 if state in "a" and f in m1:
717 if state in "a" and f in m1:
718 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
718 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
719 errors += 1
719 errors += 1
720 if state in "m" and f not in m1 and f not in m2:
720 if state in "m" and f not in m1 and f not in m2:
721 ui.warn(_("%s in state %s, but not in either manifest\n") %
721 ui.warn(_("%s in state %s, but not in either manifest\n") %
722 (f, state))
722 (f, state))
723 errors += 1
723 errors += 1
724 for f in m1:
724 for f in m1:
725 state = repo.dirstate.state(f)
725 state = repo.dirstate.state(f)
726 if state not in "nrm":
726 if state not in "nrm":
727 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
727 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
728 errors += 1
728 errors += 1
729 if errors:
729 if errors:
730 error = _(".hg/dirstate inconsistent with current parent's manifest")
730 error = _(".hg/dirstate inconsistent with current parent's manifest")
731 raise util.Abort(error)
731 raise util.Abort(error)
732
732
733 def showconfig(ui, repo, *values, **opts):
733 def showconfig(ui, repo, *values, **opts):
734 """show combined config settings from all hgrc files
734 """show combined config settings from all hgrc files
735
735
736 With no args, print names and values of all config items.
736 With no args, print names and values of all config items.
737
737
738 With one arg of the form section.name, print just the value of
738 With one arg of the form section.name, print just the value of
739 that config item.
739 that config item.
740
740
741 With multiple args, print names and values of all config items
741 With multiple args, print names and values of all config items
742 with matching section names."""
742 with matching section names."""
743
743
744 untrusted = bool(opts.get('untrusted'))
744 untrusted = bool(opts.get('untrusted'))
745 if values:
745 if values:
746 if len([v for v in values if '.' in v]) > 1:
746 if len([v for v in values if '.' in v]) > 1:
747 raise util.Abort(_('only one config item permitted'))
747 raise util.Abort(_('only one config item permitted'))
748 for section, name, value in ui.walkconfig(untrusted=untrusted):
748 for section, name, value in ui.walkconfig(untrusted=untrusted):
749 sectname = section + '.' + name
749 sectname = section + '.' + name
750 if values:
750 if values:
751 for v in values:
751 for v in values:
752 if v == section:
752 if v == section:
753 ui.write('%s=%s\n' % (sectname, value))
753 ui.write('%s=%s\n' % (sectname, value))
754 elif v == sectname:
754 elif v == sectname:
755 ui.write(value, '\n')
755 ui.write(value, '\n')
756 else:
756 else:
757 ui.write('%s=%s\n' % (sectname, value))
757 ui.write('%s=%s\n' % (sectname, value))
758
758
759 def debugsetparents(ui, repo, rev1, rev2=None):
759 def debugsetparents(ui, repo, rev1, rev2=None):
760 """manually set the parents of the current working directory
760 """manually set the parents of the current working directory
761
761
762 This is useful for writing repository conversion tools, but should
762 This is useful for writing repository conversion tools, but should
763 be used with care.
763 be used with care.
764 """
764 """
765
765
766 if not rev2:
766 if not rev2:
767 rev2 = hex(nullid)
767 rev2 = hex(nullid)
768
768
769 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
769 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
770
770
771 def debugstate(ui, repo):
771 def debugstate(ui, repo):
772 """show the contents of the current dirstate"""
772 """show the contents of the current dirstate"""
773 repo.dirstate.read()
773 repo.dirstate.read()
774 dc = repo.dirstate.map
774 dc = repo.dirstate.map
775 keys = dc.keys()
775 keys = dc.keys()
776 keys.sort()
776 keys.sort()
777 for file_ in keys:
777 for file_ in keys:
778 ui.write("%c %3o %10d %s %s\n"
778 ui.write("%c %3o %10d %s %s\n"
779 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
779 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
780 time.strftime("%x %X",
780 time.strftime("%x %X",
781 time.localtime(dc[file_][3])), file_))
781 time.localtime(dc[file_][3])), file_))
782 for f in repo.dirstate.copies():
782 for f in repo.dirstate.copies():
783 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
783 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
784
784
785 def debugdata(ui, file_, rev):
785 def debugdata(ui, file_, rev):
786 """dump the contents of an data file revision"""
786 """dump the contents of an data file revision"""
787 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
787 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
788 file_[:-2] + ".i", file_, 0)
788 file_[:-2] + ".i", file_, 0)
789 try:
789 try:
790 ui.write(r.revision(r.lookup(rev)))
790 ui.write(r.revision(r.lookup(rev)))
791 except KeyError:
791 except KeyError:
792 raise util.Abort(_('invalid revision identifier %s') % rev)
792 raise util.Abort(_('invalid revision identifier %s') % rev)
793
793
794 def debugdate(ui, date, range=None, **opts):
794 def debugdate(ui, date, range=None, **opts):
795 """parse and display a date"""
795 """parse and display a date"""
796 if opts["extended"]:
796 if opts["extended"]:
797 d = util.parsedate(date, util.extendeddateformats)
797 d = util.parsedate(date, util.extendeddateformats)
798 else:
798 else:
799 d = util.parsedate(date)
799 d = util.parsedate(date)
800 ui.write("internal: %s %s\n" % d)
800 ui.write("internal: %s %s\n" % d)
801 ui.write("standard: %s\n" % util.datestr(d))
801 ui.write("standard: %s\n" % util.datestr(d))
802 if range:
802 if range:
803 m = util.matchdate(range)
803 m = util.matchdate(range)
804 ui.write("match: %s\n" % m(d[0]))
804 ui.write("match: %s\n" % m(d[0]))
805
805
806 def debugindex(ui, file_):
806 def debugindex(ui, file_):
807 """dump the contents of an index file"""
807 """dump the contents of an index file"""
808 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
808 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
809 ui.write(" rev offset length base linkrev" +
809 ui.write(" rev offset length base linkrev" +
810 " nodeid p1 p2\n")
810 " nodeid p1 p2\n")
811 for i in xrange(r.count()):
811 for i in xrange(r.count()):
812 node = r.node(i)
812 node = r.node(i)
813 pp = r.parents(node)
813 pp = r.parents(node)
814 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
814 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
815 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
815 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
816 short(node), short(pp[0]), short(pp[1])))
816 short(node), short(pp[0]), short(pp[1])))
817
817
818 def debugindexdot(ui, file_):
818 def debugindexdot(ui, file_):
819 """dump an index DAG as a .dot file"""
819 """dump an index DAG as a .dot file"""
820 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
820 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
821 ui.write("digraph G {\n")
821 ui.write("digraph G {\n")
822 for i in xrange(r.count()):
822 for i in xrange(r.count()):
823 node = r.node(i)
823 node = r.node(i)
824 pp = r.parents(node)
824 pp = r.parents(node)
825 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
825 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
826 if pp[1] != nullid:
826 if pp[1] != nullid:
827 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
827 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
828 ui.write("}\n")
828 ui.write("}\n")
829
829
830 def debuginstall(ui):
830 def debuginstall(ui):
831 '''test Mercurial installation'''
831 '''test Mercurial installation'''
832
832
833 def writetemp(contents):
833 def writetemp(contents):
834 (fd, name) = tempfile.mkstemp()
834 (fd, name) = tempfile.mkstemp()
835 f = os.fdopen(fd, "wb")
835 f = os.fdopen(fd, "wb")
836 f.write(contents)
836 f.write(contents)
837 f.close()
837 f.close()
838 return name
838 return name
839
839
840 problems = 0
840 problems = 0
841
841
842 # encoding
842 # encoding
843 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
843 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
844 try:
844 try:
845 util.fromlocal("test")
845 util.fromlocal("test")
846 except util.Abort, inst:
846 except util.Abort, inst:
847 ui.write(" %s\n" % inst)
847 ui.write(" %s\n" % inst)
848 ui.write(_(" (check that your locale is properly set)\n"))
848 ui.write(_(" (check that your locale is properly set)\n"))
849 problems += 1
849 problems += 1
850
850
851 # compiled modules
851 # compiled modules
852 ui.status(_("Checking extensions...\n"))
852 ui.status(_("Checking extensions...\n"))
853 try:
853 try:
854 import bdiff, mpatch, base85
854 import bdiff, mpatch, base85
855 except Exception, inst:
855 except Exception, inst:
856 ui.write(" %s\n" % inst)
856 ui.write(" %s\n" % inst)
857 ui.write(_(" One or more extensions could not be found"))
857 ui.write(_(" One or more extensions could not be found"))
858 ui.write(_(" (check that you compiled the extensions)\n"))
858 ui.write(_(" (check that you compiled the extensions)\n"))
859 problems += 1
859 problems += 1
860
860
861 # templates
861 # templates
862 ui.status(_("Checking templates...\n"))
862 ui.status(_("Checking templates...\n"))
863 try:
863 try:
864 import templater
864 import templater
865 t = templater.templater(templater.templatepath("map-cmdline.default"))
865 t = templater.templater(templater.templatepath("map-cmdline.default"))
866 except Exception, inst:
866 except Exception, inst:
867 ui.write(" %s\n" % inst)
867 ui.write(" %s\n" % inst)
868 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
868 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
869 problems += 1
869 problems += 1
870
870
871 # patch
871 # patch
872 ui.status(_("Checking patch...\n"))
872 ui.status(_("Checking patch...\n"))
873 path = os.environ.get('PATH', '')
873 path = os.environ.get('PATH', '')
874 patcher = util.find_in_path('gpatch', path,
874 patcher = util.find_in_path('gpatch', path,
875 util.find_in_path('patch', path, None))
875 util.find_in_path('patch', path, None))
876 if not patcher:
876 if not patcher:
877 ui.write(_(" Can't find patch or gpatch in PATH\n"))
877 ui.write(_(" Can't find patch or gpatch in PATH\n"))
878 ui.write(_(" (specify a patch utility in your .hgrc file)\n"))
878 ui.write(_(" (specify a patch utility in your .hgrc file)\n"))
879 problems += 1
879 problems += 1
880 else:
880 else:
881 # actually attempt a patch here
881 # actually attempt a patch here
882 a = "1\n2\n3\n4\n"
882 a = "1\n2\n3\n4\n"
883 b = "1\n2\n3\ninsert\n4\n"
883 b = "1\n2\n3\ninsert\n4\n"
884 d = mdiff.unidiff(a, None, b, None, "a")
884 d = mdiff.unidiff(a, None, b, None, "a")
885 fa = writetemp(a)
885 fa = writetemp(a)
886 fd = writetemp(d)
886 fd = writetemp(d)
887 fp = os.popen('%s %s %s' % (patcher, fa, fd))
887 fp = os.popen('%s %s %s' % (patcher, fa, fd))
888 files = []
888 files = []
889 output = ""
889 output = ""
890 for line in fp:
890 for line in fp:
891 output += line
891 output += line
892 if line.startswith('patching file '):
892 if line.startswith('patching file '):
893 pf = util.parse_patch_output(line.rstrip())
893 pf = util.parse_patch_output(line.rstrip())
894 files.append(pf)
894 files.append(pf)
895 if files != [fa]:
895 if files != [fa]:
896 ui.write(_(" unexpected patch output!"))
896 ui.write(_(" unexpected patch output!"))
897 ui.write(_(" (you may have an incompatible version of patch)\n"))
897 ui.write(_(" (you may have an incompatible version of patch)\n"))
898 ui.write(data)
898 ui.write(data)
899 problems += 1
899 problems += 1
900 a = file(fa).read()
900 a = file(fa).read()
901 if a != b:
901 if a != b:
902 ui.write(_(" patch test failed!"))
902 ui.write(_(" patch test failed!"))
903 ui.write(_(" (you may have an incompatible version of patch)\n"))
903 ui.write(_(" (you may have an incompatible version of patch)\n"))
904 problems += 1
904 problems += 1
905 os.unlink(fa)
905 os.unlink(fa)
906 os.unlink(fd)
906 os.unlink(fd)
907
907
908 # merge helper
908 # merge helper
909 ui.status(_("Checking merge helper...\n"))
909 ui.status(_("Checking merge helper...\n"))
910 cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge")
910 cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge")
911 or "hgmerge")
911 or "hgmerge")
912 cmdpath = util.find_in_path(cmd, path)
912 cmdpath = util.find_in_path(cmd, path)
913 if not cmdpath:
913 if not cmdpath:
914 cmdpath = util.find_in_path(cmd.split()[0], path)
914 cmdpath = util.find_in_path(cmd.split()[0], path)
915 if not cmdpath:
915 if not cmdpath:
916 if cmd == 'hgmerge':
916 if cmd == 'hgmerge':
917 ui.write(_(" No merge helper set and can't find default"
917 ui.write(_(" No merge helper set and can't find default"
918 " hgmerge script in PATH\n"))
918 " hgmerge script in PATH\n"))
919 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
919 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
920 else:
920 else:
921 ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd)
921 ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd)
922 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
922 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
923 problems += 1
923 problems += 1
924 else:
924 else:
925 # actually attempt a patch here
925 # actually attempt a patch here
926 fa = writetemp("1\n2\n3\n4\n")
926 fa = writetemp("1\n2\n3\n4\n")
927 fl = writetemp("1\n2\n3\ninsert\n4\n")
927 fl = writetemp("1\n2\n3\ninsert\n4\n")
928 fr = writetemp("begin\n1\n2\n3\n4\n")
928 fr = writetemp("begin\n1\n2\n3\n4\n")
929 r = os.system('%s %s %s %s' % (cmd, fl, fa, fr))
929 r = os.system('%s %s %s %s' % (cmd, fl, fa, fr))
930 if r:
930 if r:
931 ui.write(_(" got unexpected merge error %d!") % r)
931 ui.write(_(" got unexpected merge error %d!") % r)
932 problems += 1
932 problems += 1
933 m = file(fl).read()
933 m = file(fl).read()
934 if m != "begin\n1\n2\n3\ninsert\n4\n":
934 if m != "begin\n1\n2\n3\ninsert\n4\n":
935 ui.write(_(" got unexpected merge results!") % r)
935 ui.write(_(" got unexpected merge results!") % r)
936 ui.write(_(" (your merge helper may have the"
936 ui.write(_(" (your merge helper may have the"
937 " wrong argument order)\n"))
937 " wrong argument order)\n"))
938 ui.write(m)
938 ui.write(m)
939 os.unlink(fa)
939 os.unlink(fa)
940 os.unlink(fl)
940 os.unlink(fl)
941 os.unlink(fr)
941 os.unlink(fr)
942
942
943 # editor
943 # editor
944 ui.status(_("Checking commit editor...\n"))
944 ui.status(_("Checking commit editor...\n"))
945 editor = (os.environ.get("HGEDITOR") or
945 editor = (os.environ.get("HGEDITOR") or
946 ui.config("ui", "editor") or
946 ui.config("ui", "editor") or
947 os.environ.get("EDITOR", "vi"))
947 os.environ.get("EDITOR", "vi"))
948 cmdpath = util.find_in_path(editor, path)
948 cmdpath = util.find_in_path(editor, path)
949 if not cmdpath:
949 if not cmdpath:
950 cmdpath = util.find_in_path(editor.split()[0], path)
950 cmdpath = util.find_in_path(editor.split()[0], path)
951 if not cmdpath:
951 if not cmdpath:
952 if editor == 'vi':
952 if editor == 'vi':
953 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
953 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
954 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
954 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
955 else:
955 else:
956 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
956 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
957 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
957 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
958 problems += 1
958 problems += 1
959
959
960 # check username
960 # check username
961 ui.status(_("Checking username...\n"))
961 ui.status(_("Checking username...\n"))
962 user = os.environ.get("HGUSER")
962 user = os.environ.get("HGUSER")
963 if user is None:
963 if user is None:
964 user = ui.config("ui", "username")
964 user = ui.config("ui", "username")
965 if user is None:
965 if user is None:
966 user = os.environ.get("EMAIL")
966 user = os.environ.get("EMAIL")
967 if not user:
967 if not user:
968 ui.warn(" ")
968 ui.warn(" ")
969 ui.username()
969 ui.username()
970 ui.write(_(" (specify a username in your .hgrc file)\n"))
970 ui.write(_(" (specify a username in your .hgrc file)\n"))
971
971
972 if not problems:
972 if not problems:
973 ui.status(_("No problems detected\n"))
973 ui.status(_("No problems detected\n"))
974 else:
974 else:
975 ui.write(_("%s problems detected,"
975 ui.write(_("%s problems detected,"
976 " please check your install!\n") % problems)
976 " please check your install!\n") % problems)
977
977
978 return problems
978 return problems
979
979
980 def debugrename(ui, repo, file1, *pats, **opts):
980 def debugrename(ui, repo, file1, *pats, **opts):
981 """dump rename information"""
981 """dump rename information"""
982
982
983 ctx = repo.changectx(opts.get('rev', 'tip'))
983 ctx = repo.changectx(opts.get('rev', 'tip'))
984 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
984 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
985 ctx.node()):
985 ctx.node()):
986 m = ctx.filectx(abs).renamed()
986 m = ctx.filectx(abs).renamed()
987 if m:
987 if m:
988 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
988 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
989 else:
989 else:
990 ui.write(_("%s not renamed\n") % rel)
990 ui.write(_("%s not renamed\n") % rel)
991
991
992 def debugwalk(ui, repo, *pats, **opts):
992 def debugwalk(ui, repo, *pats, **opts):
993 """show how files match on given patterns"""
993 """show how files match on given patterns"""
994 items = list(cmdutil.walk(repo, pats, opts))
994 items = list(cmdutil.walk(repo, pats, opts))
995 if not items:
995 if not items:
996 return
996 return
997 fmt = '%%s %%-%ds %%-%ds %%s' % (
997 fmt = '%%s %%-%ds %%-%ds %%s' % (
998 max([len(abs) for (src, abs, rel, exact) in items]),
998 max([len(abs) for (src, abs, rel, exact) in items]),
999 max([len(rel) for (src, abs, rel, exact) in items]))
999 max([len(rel) for (src, abs, rel, exact) in items]))
1000 for src, abs, rel, exact in items:
1000 for src, abs, rel, exact in items:
1001 line = fmt % (src, abs, rel, exact and 'exact' or '')
1001 line = fmt % (src, abs, rel, exact and 'exact' or '')
1002 ui.write("%s\n" % line.rstrip())
1002 ui.write("%s\n" % line.rstrip())
1003
1003
1004 def diff(ui, repo, *pats, **opts):
1004 def diff(ui, repo, *pats, **opts):
1005 """diff repository (or selected files)
1005 """diff repository (or selected files)
1006
1006
1007 Show differences between revisions for the specified files.
1007 Show differences between revisions for the specified files.
1008
1008
1009 Differences between files are shown using the unified diff format.
1009 Differences between files are shown using the unified diff format.
1010
1010
1011 NOTE: diff may generate unexpected results for merges, as it will
1011 NOTE: diff may generate unexpected results for merges, as it will
1012 default to comparing against the working directory's first parent
1012 default to comparing against the working directory's first parent
1013 changeset if no revisions are specified.
1013 changeset if no revisions are specified.
1014
1014
1015 When two revision arguments are given, then changes are shown
1015 When two revision arguments are given, then changes are shown
1016 between those revisions. If only one revision is specified then
1016 between those revisions. If only one revision is specified then
1017 that revision is compared to the working directory, and, when no
1017 that revision is compared to the working directory, and, when no
1018 revisions are specified, the working directory files are compared
1018 revisions are specified, the working directory files are compared
1019 to its parent.
1019 to its parent.
1020
1020
1021 Without the -a option, diff will avoid generating diffs of files
1021 Without the -a option, diff will avoid generating diffs of files
1022 it detects as binary. With -a, diff will generate a diff anyway,
1022 it detects as binary. With -a, diff will generate a diff anyway,
1023 probably with undesirable results.
1023 probably with undesirable results.
1024 """
1024 """
1025 node1, node2 = cmdutil.revpair(repo, opts['rev'])
1025 node1, node2 = cmdutil.revpair(repo, opts['rev'])
1026
1026
1027 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1027 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1028
1028
1029 patch.diff(repo, node1, node2, fns, match=matchfn,
1029 patch.diff(repo, node1, node2, fns, match=matchfn,
1030 opts=patch.diffopts(ui, opts))
1030 opts=patch.diffopts(ui, opts))
1031
1031
1032 def export(ui, repo, *changesets, **opts):
1032 def export(ui, repo, *changesets, **opts):
1033 """dump the header and diffs for one or more changesets
1033 """dump the header and diffs for one or more changesets
1034
1034
1035 Print the changeset header and diffs for one or more revisions.
1035 Print the changeset header and diffs for one or more revisions.
1036
1036
1037 The information shown in the changeset header is: author,
1037 The information shown in the changeset header is: author,
1038 changeset hash, parent(s) and commit comment.
1038 changeset hash, parent(s) and commit comment.
1039
1039
1040 NOTE: export may generate unexpected diff output for merge changesets,
1040 NOTE: export may generate unexpected diff output for merge changesets,
1041 as it will compare the merge changeset against its first parent only.
1041 as it will compare the merge changeset against its first parent only.
1042
1042
1043 Output may be to a file, in which case the name of the file is
1043 Output may be to a file, in which case the name of the file is
1044 given using a format string. The formatting rules are as follows:
1044 given using a format string. The formatting rules are as follows:
1045
1045
1046 %% literal "%" character
1046 %% literal "%" character
1047 %H changeset hash (40 bytes of hexadecimal)
1047 %H changeset hash (40 bytes of hexadecimal)
1048 %N number of patches being generated
1048 %N number of patches being generated
1049 %R changeset revision number
1049 %R changeset revision number
1050 %b basename of the exporting repository
1050 %b basename of the exporting repository
1051 %h short-form changeset hash (12 bytes of hexadecimal)
1051 %h short-form changeset hash (12 bytes of hexadecimal)
1052 %n zero-padded sequence number, starting at 1
1052 %n zero-padded sequence number, starting at 1
1053 %r zero-padded changeset revision number
1053 %r zero-padded changeset revision number
1054
1054
1055 Without the -a option, export will avoid generating diffs of files
1055 Without the -a option, export will avoid generating diffs of files
1056 it detects as binary. With -a, export will generate a diff anyway,
1056 it detects as binary. With -a, export will generate a diff anyway,
1057 probably with undesirable results.
1057 probably with undesirable results.
1058
1058
1059 With the --switch-parent option, the diff will be against the second
1059 With the --switch-parent option, the diff will be against the second
1060 parent. It can be useful to review a merge.
1060 parent. It can be useful to review a merge.
1061 """
1061 """
1062 if not changesets:
1062 if not changesets:
1063 raise util.Abort(_("export requires at least one changeset"))
1063 raise util.Abort(_("export requires at least one changeset"))
1064 revs = cmdutil.revrange(repo, changesets)
1064 revs = cmdutil.revrange(repo, changesets)
1065 if len(revs) > 1:
1065 if len(revs) > 1:
1066 ui.note(_('exporting patches:\n'))
1066 ui.note(_('exporting patches:\n'))
1067 else:
1067 else:
1068 ui.note(_('exporting patch:\n'))
1068 ui.note(_('exporting patch:\n'))
1069 patch.export(repo, map(repo.lookup, revs), template=opts['output'],
1069 patch.export(repo, map(repo.lookup, revs), template=opts['output'],
1070 switch_parent=opts['switch_parent'],
1070 switch_parent=opts['switch_parent'],
1071 opts=patch.diffopts(ui, opts))
1071 opts=patch.diffopts(ui, opts))
1072
1072
1073 def grep(ui, repo, pattern, *pats, **opts):
1073 def grep(ui, repo, pattern, *pats, **opts):
1074 """search for a pattern in specified files and revisions
1074 """search for a pattern in specified files and revisions
1075
1075
1076 Search revisions of files for a regular expression.
1076 Search revisions of files for a regular expression.
1077
1077
1078 This command behaves differently than Unix grep. It only accepts
1078 This command behaves differently than Unix grep. It only accepts
1079 Python/Perl regexps. It searches repository history, not the
1079 Python/Perl regexps. It searches repository history, not the
1080 working directory. It always prints the revision number in which
1080 working directory. It always prints the revision number in which
1081 a match appears.
1081 a match appears.
1082
1082
1083 By default, grep only prints output for the first revision of a
1083 By default, grep only prints output for the first revision of a
1084 file in which it finds a match. To get it to print every revision
1084 file in which it finds a match. To get it to print every revision
1085 that contains a change in match status ("-" for a match that
1085 that contains a change in match status ("-" for a match that
1086 becomes a non-match, or "+" for a non-match that becomes a match),
1086 becomes a non-match, or "+" for a non-match that becomes a match),
1087 use the --all flag.
1087 use the --all flag.
1088 """
1088 """
1089 reflags = 0
1089 reflags = 0
1090 if opts['ignore_case']:
1090 if opts['ignore_case']:
1091 reflags |= re.I
1091 reflags |= re.I
1092 regexp = re.compile(pattern, reflags)
1092 regexp = re.compile(pattern, reflags)
1093 sep, eol = ':', '\n'
1093 sep, eol = ':', '\n'
1094 if opts['print0']:
1094 if opts['print0']:
1095 sep = eol = '\0'
1095 sep = eol = '\0'
1096
1096
1097 fcache = {}
1097 fcache = {}
1098 def getfile(fn):
1098 def getfile(fn):
1099 if fn not in fcache:
1099 if fn not in fcache:
1100 fcache[fn] = repo.file(fn)
1100 fcache[fn] = repo.file(fn)
1101 return fcache[fn]
1101 return fcache[fn]
1102
1102
1103 def matchlines(body):
1103 def matchlines(body):
1104 begin = 0
1104 begin = 0
1105 linenum = 0
1105 linenum = 0
1106 while True:
1106 while True:
1107 match = regexp.search(body, begin)
1107 match = regexp.search(body, begin)
1108 if not match:
1108 if not match:
1109 break
1109 break
1110 mstart, mend = match.span()
1110 mstart, mend = match.span()
1111 linenum += body.count('\n', begin, mstart) + 1
1111 linenum += body.count('\n', begin, mstart) + 1
1112 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1112 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1113 lend = body.find('\n', mend)
1113 lend = body.find('\n', mend)
1114 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1114 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1115 begin = lend + 1
1115 begin = lend + 1
1116
1116
1117 class linestate(object):
1117 class linestate(object):
1118 def __init__(self, line, linenum, colstart, colend):
1118 def __init__(self, line, linenum, colstart, colend):
1119 self.line = line
1119 self.line = line
1120 self.linenum = linenum
1120 self.linenum = linenum
1121 self.colstart = colstart
1121 self.colstart = colstart
1122 self.colend = colend
1122 self.colend = colend
1123
1123
1124 def __eq__(self, other):
1124 def __eq__(self, other):
1125 return self.line == other.line
1125 return self.line == other.line
1126
1126
1127 matches = {}
1127 matches = {}
1128 copies = {}
1128 copies = {}
1129 def grepbody(fn, rev, body):
1129 def grepbody(fn, rev, body):
1130 matches[rev].setdefault(fn, [])
1130 matches[rev].setdefault(fn, [])
1131 m = matches[rev][fn]
1131 m = matches[rev][fn]
1132 for lnum, cstart, cend, line in matchlines(body):
1132 for lnum, cstart, cend, line in matchlines(body):
1133 s = linestate(line, lnum, cstart, cend)
1133 s = linestate(line, lnum, cstart, cend)
1134 m.append(s)
1134 m.append(s)
1135
1135
1136 def difflinestates(a, b):
1136 def difflinestates(a, b):
1137 sm = difflib.SequenceMatcher(None, a, b)
1137 sm = difflib.SequenceMatcher(None, a, b)
1138 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1138 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1139 if tag == 'insert':
1139 if tag == 'insert':
1140 for i in xrange(blo, bhi):
1140 for i in xrange(blo, bhi):
1141 yield ('+', b[i])
1141 yield ('+', b[i])
1142 elif tag == 'delete':
1142 elif tag == 'delete':
1143 for i in xrange(alo, ahi):
1143 for i in xrange(alo, ahi):
1144 yield ('-', a[i])
1144 yield ('-', a[i])
1145 elif tag == 'replace':
1145 elif tag == 'replace':
1146 for i in xrange(alo, ahi):
1146 for i in xrange(alo, ahi):
1147 yield ('-', a[i])
1147 yield ('-', a[i])
1148 for i in xrange(blo, bhi):
1148 for i in xrange(blo, bhi):
1149 yield ('+', b[i])
1149 yield ('+', b[i])
1150
1150
1151 prev = {}
1151 prev = {}
1152 def display(fn, rev, states, prevstates):
1152 def display(fn, rev, states, prevstates):
1153 counts = {'-': 0, '+': 0}
1153 counts = {'-': 0, '+': 0}
1154 filerevmatches = {}
1154 filerevmatches = {}
1155 if incrementing or not opts['all']:
1155 if incrementing or not opts['all']:
1156 a, b, r = prevstates, states, rev
1156 a, b, r = prevstates, states, rev
1157 else:
1157 else:
1158 a, b, r = states, prevstates, prev.get(fn, -1)
1158 a, b, r = states, prevstates, prev.get(fn, -1)
1159 for change, l in difflinestates(a, b):
1159 for change, l in difflinestates(a, b):
1160 cols = [fn, str(r)]
1160 cols = [fn, str(r)]
1161 if opts['line_number']:
1161 if opts['line_number']:
1162 cols.append(str(l.linenum))
1162 cols.append(str(l.linenum))
1163 if opts['all']:
1163 if opts['all']:
1164 cols.append(change)
1164 cols.append(change)
1165 if opts['user']:
1165 if opts['user']:
1166 cols.append(ui.shortuser(get(r)[1]))
1166 cols.append(ui.shortuser(get(r)[1]))
1167 if opts['files_with_matches']:
1167 if opts['files_with_matches']:
1168 c = (fn, r)
1168 c = (fn, r)
1169 if c in filerevmatches:
1169 if c in filerevmatches:
1170 continue
1170 continue
1171 filerevmatches[c] = 1
1171 filerevmatches[c] = 1
1172 else:
1172 else:
1173 cols.append(l.line)
1173 cols.append(l.line)
1174 ui.write(sep.join(cols), eol)
1174 ui.write(sep.join(cols), eol)
1175 counts[change] += 1
1175 counts[change] += 1
1176 return counts['+'], counts['-']
1176 return counts['+'], counts['-']
1177
1177
1178 fstate = {}
1178 fstate = {}
1179 skip = {}
1179 skip = {}
1180 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1180 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1181 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1181 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1182 count = 0
1182 count = 0
1183 incrementing = False
1183 incrementing = False
1184 follow = opts.get('follow')
1184 follow = opts.get('follow')
1185 for st, rev, fns in changeiter:
1185 for st, rev, fns in changeiter:
1186 if st == 'window':
1186 if st == 'window':
1187 incrementing = rev
1187 incrementing = rev
1188 matches.clear()
1188 matches.clear()
1189 elif st == 'add':
1189 elif st == 'add':
1190 mf = repo.changectx(rev).manifest()
1190 mf = repo.changectx(rev).manifest()
1191 matches[rev] = {}
1191 matches[rev] = {}
1192 for fn in fns:
1192 for fn in fns:
1193 if fn in skip:
1193 if fn in skip:
1194 continue
1194 continue
1195 fstate.setdefault(fn, {})
1195 fstate.setdefault(fn, {})
1196 try:
1196 try:
1197 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1197 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1198 if follow:
1198 if follow:
1199 copied = getfile(fn).renamed(mf[fn])
1199 copied = getfile(fn).renamed(mf[fn])
1200 if copied:
1200 if copied:
1201 copies.setdefault(rev, {})[fn] = copied[0]
1201 copies.setdefault(rev, {})[fn] = copied[0]
1202 except KeyError:
1202 except KeyError:
1203 pass
1203 pass
1204 elif st == 'iter':
1204 elif st == 'iter':
1205 states = matches[rev].items()
1205 states = matches[rev].items()
1206 states.sort()
1206 states.sort()
1207 for fn, m in states:
1207 for fn, m in states:
1208 copy = copies.get(rev, {}).get(fn)
1208 copy = copies.get(rev, {}).get(fn)
1209 if fn in skip:
1209 if fn in skip:
1210 if copy:
1210 if copy:
1211 skip[copy] = True
1211 skip[copy] = True
1212 continue
1212 continue
1213 if incrementing or not opts['all'] or fstate[fn]:
1213 if incrementing or not opts['all'] or fstate[fn]:
1214 pos, neg = display(fn, rev, m, fstate[fn])
1214 pos, neg = display(fn, rev, m, fstate[fn])
1215 count += pos + neg
1215 count += pos + neg
1216 if pos and not opts['all']:
1216 if pos and not opts['all']:
1217 skip[fn] = True
1217 skip[fn] = True
1218 if copy:
1218 if copy:
1219 skip[copy] = True
1219 skip[copy] = True
1220 fstate[fn] = m
1220 fstate[fn] = m
1221 if copy:
1221 if copy:
1222 fstate[copy] = m
1222 fstate[copy] = m
1223 prev[fn] = rev
1223 prev[fn] = rev
1224
1224
1225 if not incrementing:
1225 if not incrementing:
1226 fstate = fstate.items()
1226 fstate = fstate.items()
1227 fstate.sort()
1227 fstate.sort()
1228 for fn, state in fstate:
1228 for fn, state in fstate:
1229 if fn in skip:
1229 if fn in skip:
1230 continue
1230 continue
1231 if fn not in copies.get(prev[fn], {}):
1231 if fn not in copies.get(prev[fn], {}):
1232 display(fn, rev, {}, state)
1232 display(fn, rev, {}, state)
1233 return (count == 0 and 1) or 0
1233 return (count == 0 and 1) or 0
1234
1234
1235 def heads(ui, repo, **opts):
1235 def heads(ui, repo, **opts):
1236 """show current repository heads
1236 """show current repository heads
1237
1237
1238 Show all repository head changesets.
1238 Show all repository head changesets.
1239
1239
1240 Repository "heads" are changesets that don't have children
1240 Repository "heads" are changesets that don't have children
1241 changesets. They are where development generally takes place and
1241 changesets. They are where development generally takes place and
1242 are the usual targets for update and merge operations.
1242 are the usual targets for update and merge operations.
1243 """
1243 """
1244 if opts['rev']:
1244 if opts['rev']:
1245 heads = repo.heads(repo.lookup(opts['rev']))
1245 heads = repo.heads(repo.lookup(opts['rev']))
1246 else:
1246 else:
1247 heads = repo.heads()
1247 heads = repo.heads()
1248 displayer = cmdutil.show_changeset(ui, repo, opts)
1248 displayer = cmdutil.show_changeset(ui, repo, opts)
1249 for n in heads:
1249 for n in heads:
1250 displayer.show(changenode=n)
1250 displayer.show(changenode=n)
1251
1251
1252 def help_(ui, name=None, with_version=False):
1252 def help_(ui, name=None, with_version=False):
1253 """show help for a command, extension, or list of commands
1253 """show help for a command, extension, or list of commands
1254
1254
1255 With no arguments, print a list of commands and short help.
1255 With no arguments, print a list of commands and short help.
1256
1256
1257 Given a command name, print help for that command.
1257 Given a command name, print help for that command.
1258
1258
1259 Given an extension name, print help for that extension, and the
1259 Given an extension name, print help for that extension, and the
1260 commands it provides."""
1260 commands it provides."""
1261 option_lists = []
1261 option_lists = []
1262
1262
1263 def helpcmd(name):
1263 def helpcmd(name):
1264 if with_version:
1264 if with_version:
1265 version_(ui)
1265 version_(ui)
1266 ui.write('\n')
1266 ui.write('\n')
1267 aliases, i = findcmd(ui, name)
1267 aliases, i = findcmd(ui, name)
1268 # synopsis
1268 # synopsis
1269 ui.write("%s\n\n" % i[2])
1269 ui.write("%s\n\n" % i[2])
1270
1270
1271 # description
1271 # description
1272 doc = i[0].__doc__
1272 doc = i[0].__doc__
1273 if not doc:
1273 if not doc:
1274 doc = _("(No help text available)")
1274 doc = _("(No help text available)")
1275 if ui.quiet:
1275 if ui.quiet:
1276 doc = doc.splitlines(0)[0]
1276 doc = doc.splitlines(0)[0]
1277 ui.write("%s\n" % doc.rstrip())
1277 ui.write("%s\n" % doc.rstrip())
1278
1278
1279 if not ui.quiet:
1279 if not ui.quiet:
1280 # aliases
1280 # aliases
1281 if len(aliases) > 1:
1281 if len(aliases) > 1:
1282 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1282 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1283
1283
1284 # options
1284 # options
1285 if i[1]:
1285 if i[1]:
1286 option_lists.append(("options", i[1]))
1286 option_lists.append(("options", i[1]))
1287
1287
1288 def helplist(select=None):
1288 def helplist(select=None):
1289 h = {}
1289 h = {}
1290 cmds = {}
1290 cmds = {}
1291 for c, e in table.items():
1291 for c, e in table.items():
1292 f = c.split("|", 1)[0]
1292 f = c.split("|", 1)[0]
1293 if select and not select(f):
1293 if select and not select(f):
1294 continue
1294 continue
1295 if name == "shortlist" and not f.startswith("^"):
1295 if name == "shortlist" and not f.startswith("^"):
1296 continue
1296 continue
1297 f = f.lstrip("^")
1297 f = f.lstrip("^")
1298 if not ui.debugflag and f.startswith("debug"):
1298 if not ui.debugflag and f.startswith("debug"):
1299 continue
1299 continue
1300 doc = e[0].__doc__
1300 doc = e[0].__doc__
1301 if not doc:
1301 if not doc:
1302 doc = _("(No help text available)")
1302 doc = _("(No help text available)")
1303 h[f] = doc.splitlines(0)[0].rstrip()
1303 h[f] = doc.splitlines(0)[0].rstrip()
1304 cmds[f] = c.lstrip("^")
1304 cmds[f] = c.lstrip("^")
1305
1305
1306 fns = h.keys()
1306 fns = h.keys()
1307 fns.sort()
1307 fns.sort()
1308 m = max(map(len, fns))
1308 m = max(map(len, fns))
1309 for f in fns:
1309 for f in fns:
1310 if ui.verbose:
1310 if ui.verbose:
1311 commands = cmds[f].replace("|",", ")
1311 commands = cmds[f].replace("|",", ")
1312 ui.write(" %s:\n %s\n"%(commands, h[f]))
1312 ui.write(" %s:\n %s\n"%(commands, h[f]))
1313 else:
1313 else:
1314 ui.write(' %-*s %s\n' % (m, f, h[f]))
1314 ui.write(' %-*s %s\n' % (m, f, h[f]))
1315
1315
1316 def helptopic(name):
1316 def helptopic(name):
1317 v = None
1317 v = None
1318 for i in help.helptable:
1318 for i in help.helptable:
1319 l = i.split('|')
1319 l = i.split('|')
1320 if name in l:
1320 if name in l:
1321 v = i
1321 v = i
1322 header = l[-1]
1322 header = l[-1]
1323 if not v:
1323 if not v:
1324 raise UnknownCommand(name)
1324 raise UnknownCommand(name)
1325
1325
1326 # description
1326 # description
1327 doc = help.helptable[v]
1327 doc = help.helptable[v]
1328 if not doc:
1328 if not doc:
1329 doc = _("(No help text available)")
1329 doc = _("(No help text available)")
1330 if callable(doc):
1330 if callable(doc):
1331 doc = doc()
1331 doc = doc()
1332
1332
1333 ui.write("%s\n" % header)
1333 ui.write("%s\n" % header)
1334 ui.write("%s\n" % doc.rstrip())
1334 ui.write("%s\n" % doc.rstrip())
1335
1335
1336 def helpext(name):
1336 def helpext(name):
1337 try:
1337 try:
1338 mod = findext(name)
1338 mod = findext(name)
1339 except KeyError:
1339 except KeyError:
1340 raise UnknownCommand(name)
1340 raise UnknownCommand(name)
1341
1341
1342 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1342 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1343 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1343 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1344 for d in doc[1:]:
1344 for d in doc[1:]:
1345 ui.write(d, '\n')
1345 ui.write(d, '\n')
1346
1346
1347 ui.status('\n')
1347 ui.status('\n')
1348 if ui.verbose:
1348 if ui.verbose:
1349 ui.status(_('list of commands:\n\n'))
1349 ui.status(_('list of commands:\n\n'))
1350 else:
1350 else:
1351 ui.status(_('list of commands (use "hg help -v %s" '
1351 ui.status(_('list of commands (use "hg help -v %s" '
1352 'to show aliases and global options):\n\n') % name)
1352 'to show aliases and global options):\n\n') % name)
1353
1353
1354 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in mod.cmdtable])
1354 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in mod.cmdtable])
1355 helplist(modcmds.has_key)
1355 helplist(modcmds.has_key)
1356
1356
1357 if name and name != 'shortlist':
1357 if name and name != 'shortlist':
1358 i = None
1358 i = None
1359 for f in (helpcmd, helptopic, helpext):
1359 for f in (helpcmd, helptopic, helpext):
1360 try:
1360 try:
1361 f(name)
1361 f(name)
1362 i = None
1362 i = None
1363 break
1363 break
1364 except UnknownCommand, inst:
1364 except UnknownCommand, inst:
1365 i = inst
1365 i = inst
1366 if i:
1366 if i:
1367 raise i
1367 raise i
1368
1368
1369 else:
1369 else:
1370 # program name
1370 # program name
1371 if ui.verbose or with_version:
1371 if ui.verbose or with_version:
1372 version_(ui)
1372 version_(ui)
1373 else:
1373 else:
1374 ui.status(_("Mercurial Distributed SCM\n"))
1374 ui.status(_("Mercurial Distributed SCM\n"))
1375 ui.status('\n')
1375 ui.status('\n')
1376
1376
1377 # list of commands
1377 # list of commands
1378 if name == "shortlist":
1378 if name == "shortlist":
1379 ui.status(_('basic commands (use "hg help" '
1379 ui.status(_('basic commands (use "hg help" '
1380 'for the full list or option "-v" for details):\n\n'))
1380 'for the full list or option "-v" for details):\n\n'))
1381 elif ui.verbose:
1381 elif ui.verbose:
1382 ui.status(_('list of commands:\n\n'))
1382 ui.status(_('list of commands:\n\n'))
1383 else:
1383 else:
1384 ui.status(_('list of commands (use "hg help -v" '
1384 ui.status(_('list of commands (use "hg help -v" '
1385 'to show aliases and global options):\n\n'))
1385 'to show aliases and global options):\n\n'))
1386
1386
1387 helplist()
1387 helplist()
1388
1388
1389 # global options
1389 # global options
1390 if ui.verbose:
1390 if ui.verbose:
1391 option_lists.append(("global options", globalopts))
1391 option_lists.append(("global options", globalopts))
1392
1392
1393 # list all option lists
1393 # list all option lists
1394 opt_output = []
1394 opt_output = []
1395 for title, options in option_lists:
1395 for title, options in option_lists:
1396 opt_output.append(("\n%s:\n" % title, None))
1396 opt_output.append(("\n%s:\n" % title, None))
1397 for shortopt, longopt, default, desc in options:
1397 for shortopt, longopt, default, desc in options:
1398 if "DEPRECATED" in desc and not ui.verbose: continue
1398 if "DEPRECATED" in desc and not ui.verbose: continue
1399 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1399 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1400 longopt and " --%s" % longopt),
1400 longopt and " --%s" % longopt),
1401 "%s%s" % (desc,
1401 "%s%s" % (desc,
1402 default
1402 default
1403 and _(" (default: %s)") % default
1403 and _(" (default: %s)") % default
1404 or "")))
1404 or "")))
1405
1405
1406 if opt_output:
1406 if opt_output:
1407 opts_len = max([len(line[0]) for line in opt_output if line[1]])
1407 opts_len = max([len(line[0]) for line in opt_output if line[1]])
1408 for first, second in opt_output:
1408 for first, second in opt_output:
1409 if second:
1409 if second:
1410 ui.write(" %-*s %s\n" % (opts_len, first, second))
1410 ui.write(" %-*s %s\n" % (opts_len, first, second))
1411 else:
1411 else:
1412 ui.write("%s\n" % first)
1412 ui.write("%s\n" % first)
1413
1413
1414 def identify(ui, repo):
1414 def identify(ui, repo):
1415 """print information about the working copy
1415 """print information about the working copy
1416
1416
1417 Print a short summary of the current state of the repo.
1417 Print a short summary of the current state of the repo.
1418
1418
1419 This summary identifies the repository state using one or two parent
1419 This summary identifies the repository state using one or two parent
1420 hash identifiers, followed by a "+" if there are uncommitted changes
1420 hash identifiers, followed by a "+" if there are uncommitted changes
1421 in the working directory, followed by a list of tags for this revision.
1421 in the working directory, followed by a list of tags for this revision.
1422 """
1422 """
1423 parents = [p for p in repo.dirstate.parents() if p != nullid]
1423 parents = [p for p in repo.dirstate.parents() if p != nullid]
1424 if not parents:
1424 if not parents:
1425 ui.write(_("unknown\n"))
1425 ui.write(_("unknown\n"))
1426 return
1426 return
1427
1427
1428 hexfunc = ui.debugflag and hex or short
1428 hexfunc = ui.debugflag and hex or short
1429 modified, added, removed, deleted = repo.status()[:4]
1429 modified, added, removed, deleted = repo.status()[:4]
1430 output = ["%s%s" %
1430 output = ["%s%s" %
1431 ('+'.join([hexfunc(parent) for parent in parents]),
1431 ('+'.join([hexfunc(parent) for parent in parents]),
1432 (modified or added or removed or deleted) and "+" or "")]
1432 (modified or added or removed or deleted) and "+" or "")]
1433
1433
1434 if not ui.quiet:
1434 if not ui.quiet:
1435
1435
1436 branch = repo.workingctx().branch()
1436 branch = repo.workingctx().branch()
1437 if branch:
1437 if branch:
1438 output.append("(%s)" % branch)
1438 output.append("(%s)" % branch)
1439
1439
1440 # multiple tags for a single parent separated by '/'
1440 # multiple tags for a single parent separated by '/'
1441 parenttags = ['/'.join(tags)
1441 parenttags = ['/'.join(tags)
1442 for tags in map(repo.nodetags, parents) if tags]
1442 for tags in map(repo.nodetags, parents) if tags]
1443 # tags for multiple parents separated by ' + '
1443 # tags for multiple parents separated by ' + '
1444 if parenttags:
1444 if parenttags:
1445 output.append(' + '.join(parenttags))
1445 output.append(' + '.join(parenttags))
1446
1446
1447 ui.write("%s\n" % ' '.join(output))
1447 ui.write("%s\n" % ' '.join(output))
1448
1448
1449 def import_(ui, repo, patch1, *patches, **opts):
1449 def import_(ui, repo, patch1, *patches, **opts):
1450 """import an ordered set of patches
1450 """import an ordered set of patches
1451
1451
1452 Import a list of patches and commit them individually.
1452 Import a list of patches and commit them individually.
1453
1453
1454 If there are outstanding changes in the working directory, import
1454 If there are outstanding changes in the working directory, import
1455 will abort unless given the -f flag.
1455 will abort unless given the -f flag.
1456
1456
1457 You can import a patch straight from a mail message. Even patches
1457 You can import a patch straight from a mail message. Even patches
1458 as attachments work (body part must be type text/plain or
1458 as attachments work (body part must be type text/plain or
1459 text/x-patch to be used). From and Subject headers of email
1459 text/x-patch to be used). From and Subject headers of email
1460 message are used as default committer and commit message. All
1460 message are used as default committer and commit message. All
1461 text/plain body parts before first diff are added to commit
1461 text/plain body parts before first diff are added to commit
1462 message.
1462 message.
1463
1463
1464 If imported patch was generated by hg export, user and description
1464 If imported patch was generated by hg export, user and description
1465 from patch override values from message headers and body. Values
1465 from patch override values from message headers and body. Values
1466 given on command line with -m and -u override these.
1466 given on command line with -m and -u override these.
1467
1467
1468 To read a patch from standard input, use patch name "-".
1468 To read a patch from standard input, use patch name "-".
1469 """
1469 """
1470 patches = (patch1,) + patches
1470 patches = (patch1,) + patches
1471
1471
1472 if not opts['force']:
1472 if not opts['force']:
1473 bail_if_changed(repo)
1473 bail_if_changed(repo)
1474
1474
1475 d = opts["base"]
1475 d = opts["base"]
1476 strip = opts["strip"]
1476 strip = opts["strip"]
1477
1477
1478 wlock = repo.wlock()
1478 wlock = repo.wlock()
1479 lock = repo.lock()
1479 lock = repo.lock()
1480
1480
1481 for p in patches:
1481 for p in patches:
1482 pf = os.path.join(d, p)
1482 pf = os.path.join(d, p)
1483
1483
1484 if pf == '-':
1484 if pf == '-':
1485 ui.status(_("applying patch from stdin\n"))
1485 ui.status(_("applying patch from stdin\n"))
1486 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1486 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1487 else:
1487 else:
1488 ui.status(_("applying %s\n") % p)
1488 ui.status(_("applying %s\n") % p)
1489 tmpname, message, user, date = patch.extract(ui, file(pf))
1489 tmpname, message, user, date = patch.extract(ui, file(pf))
1490
1490
1491 if tmpname is None:
1491 if tmpname is None:
1492 raise util.Abort(_('no diffs found'))
1492 raise util.Abort(_('no diffs found'))
1493
1493
1494 try:
1494 try:
1495 if opts['message']:
1495 cmdline_message = logmessage(opts)
1496 if cmdline_message:
1496 # pickup the cmdline msg
1497 # pickup the cmdline msg
1497 message = opts['message']
1498 message = cmdline_message
1498 elif message:
1499 elif message:
1499 # pickup the patch msg
1500 # pickup the patch msg
1500 message = message.strip()
1501 message = message.strip()
1501 else:
1502 else:
1502 # launch the editor
1503 # launch the editor
1503 message = None
1504 message = None
1504 ui.debug(_('message:\n%s\n') % message)
1505 ui.debug(_('message:\n%s\n') % message)
1505
1506
1506 files = {}
1507 files = {}
1507 try:
1508 try:
1508 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1509 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1509 files=files)
1510 files=files)
1510 finally:
1511 finally:
1511 files = patch.updatedir(ui, repo, files, wlock=wlock)
1512 files = patch.updatedir(ui, repo, files, wlock=wlock)
1512 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1513 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1513 finally:
1514 finally:
1514 os.unlink(tmpname)
1515 os.unlink(tmpname)
1515
1516
1516 def incoming(ui, repo, source="default", **opts):
1517 def incoming(ui, repo, source="default", **opts):
1517 """show new changesets found in source
1518 """show new changesets found in source
1518
1519
1519 Show new changesets found in the specified path/URL or the default
1520 Show new changesets found in the specified path/URL or the default
1520 pull location. These are the changesets that would be pulled if a pull
1521 pull location. These are the changesets that would be pulled if a pull
1521 was requested.
1522 was requested.
1522
1523
1523 For remote repository, using --bundle avoids downloading the changesets
1524 For remote repository, using --bundle avoids downloading the changesets
1524 twice if the incoming is followed by a pull.
1525 twice if the incoming is followed by a pull.
1525
1526
1526 See pull for valid source format details.
1527 See pull for valid source format details.
1527 """
1528 """
1528 source = ui.expandpath(source)
1529 source = ui.expandpath(source)
1529 setremoteconfig(ui, opts)
1530 setremoteconfig(ui, opts)
1530
1531
1531 other = hg.repository(ui, source)
1532 other = hg.repository(ui, source)
1532 incoming = repo.findincoming(other, force=opts["force"])
1533 incoming = repo.findincoming(other, force=opts["force"])
1533 if not incoming:
1534 if not incoming:
1534 ui.status(_("no changes found\n"))
1535 ui.status(_("no changes found\n"))
1535 return
1536 return
1536
1537
1537 cleanup = None
1538 cleanup = None
1538 try:
1539 try:
1539 fname = opts["bundle"]
1540 fname = opts["bundle"]
1540 if fname or not other.local():
1541 if fname or not other.local():
1541 # create a bundle (uncompressed if other repo is not local)
1542 # create a bundle (uncompressed if other repo is not local)
1542 cg = other.changegroup(incoming, "incoming")
1543 cg = other.changegroup(incoming, "incoming")
1543 bundletype = other.local() and "HG10BZ" or "HG10UN"
1544 bundletype = other.local() and "HG10BZ" or "HG10UN"
1544 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1545 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1545 # keep written bundle?
1546 # keep written bundle?
1546 if opts["bundle"]:
1547 if opts["bundle"]:
1547 cleanup = None
1548 cleanup = None
1548 if not other.local():
1549 if not other.local():
1549 # use the created uncompressed bundlerepo
1550 # use the created uncompressed bundlerepo
1550 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1551 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1551
1552
1552 revs = None
1553 revs = None
1553 if opts['rev']:
1554 if opts['rev']:
1554 revs = [other.lookup(rev) for rev in opts['rev']]
1555 revs = [other.lookup(rev) for rev in opts['rev']]
1555 o = other.changelog.nodesbetween(incoming, revs)[0]
1556 o = other.changelog.nodesbetween(incoming, revs)[0]
1556 if opts['newest_first']:
1557 if opts['newest_first']:
1557 o.reverse()
1558 o.reverse()
1558 displayer = cmdutil.show_changeset(ui, other, opts)
1559 displayer = cmdutil.show_changeset(ui, other, opts)
1559 for n in o:
1560 for n in o:
1560 parents = [p for p in other.changelog.parents(n) if p != nullid]
1561 parents = [p for p in other.changelog.parents(n) if p != nullid]
1561 if opts['no_merges'] and len(parents) == 2:
1562 if opts['no_merges'] and len(parents) == 2:
1562 continue
1563 continue
1563 displayer.show(changenode=n)
1564 displayer.show(changenode=n)
1564 finally:
1565 finally:
1565 if hasattr(other, 'close'):
1566 if hasattr(other, 'close'):
1566 other.close()
1567 other.close()
1567 if cleanup:
1568 if cleanup:
1568 os.unlink(cleanup)
1569 os.unlink(cleanup)
1569
1570
1570 def init(ui, dest=".", **opts):
1571 def init(ui, dest=".", **opts):
1571 """create a new repository in the given directory
1572 """create a new repository in the given directory
1572
1573
1573 Initialize a new repository in the given directory. If the given
1574 Initialize a new repository in the given directory. If the given
1574 directory does not exist, it is created.
1575 directory does not exist, it is created.
1575
1576
1576 If no directory is given, the current directory is used.
1577 If no directory is given, the current directory is used.
1577
1578
1578 It is possible to specify an ssh:// URL as the destination.
1579 It is possible to specify an ssh:// URL as the destination.
1579 Look at the help text for the pull command for important details
1580 Look at the help text for the pull command for important details
1580 about ssh:// URLs.
1581 about ssh:// URLs.
1581 """
1582 """
1582 setremoteconfig(ui, opts)
1583 setremoteconfig(ui, opts)
1583 hg.repository(ui, dest, create=1)
1584 hg.repository(ui, dest, create=1)
1584
1585
1585 def locate(ui, repo, *pats, **opts):
1586 def locate(ui, repo, *pats, **opts):
1586 """locate files matching specific patterns
1587 """locate files matching specific patterns
1587
1588
1588 Print all files under Mercurial control whose names match the
1589 Print all files under Mercurial control whose names match the
1589 given patterns.
1590 given patterns.
1590
1591
1591 This command searches the current directory and its
1592 This command searches the current directory and its
1592 subdirectories. To search an entire repository, move to the root
1593 subdirectories. To search an entire repository, move to the root
1593 of the repository.
1594 of the repository.
1594
1595
1595 If no patterns are given to match, this command prints all file
1596 If no patterns are given to match, this command prints all file
1596 names.
1597 names.
1597
1598
1598 If you want to feed the output of this command into the "xargs"
1599 If you want to feed the output of this command into the "xargs"
1599 command, use the "-0" option to both this command and "xargs".
1600 command, use the "-0" option to both this command and "xargs".
1600 This will avoid the problem of "xargs" treating single filenames
1601 This will avoid the problem of "xargs" treating single filenames
1601 that contain white space as multiple filenames.
1602 that contain white space as multiple filenames.
1602 """
1603 """
1603 end = opts['print0'] and '\0' or '\n'
1604 end = opts['print0'] and '\0' or '\n'
1604 rev = opts['rev']
1605 rev = opts['rev']
1605 if rev:
1606 if rev:
1606 node = repo.lookup(rev)
1607 node = repo.lookup(rev)
1607 else:
1608 else:
1608 node = None
1609 node = None
1609
1610
1610 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1611 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1611 head='(?:.*/|)'):
1612 head='(?:.*/|)'):
1612 if not node and repo.dirstate.state(abs) == '?':
1613 if not node and repo.dirstate.state(abs) == '?':
1613 continue
1614 continue
1614 if opts['fullpath']:
1615 if opts['fullpath']:
1615 ui.write(os.path.join(repo.root, abs), end)
1616 ui.write(os.path.join(repo.root, abs), end)
1616 else:
1617 else:
1617 ui.write(((pats and rel) or abs), end)
1618 ui.write(((pats and rel) or abs), end)
1618
1619
1619 def log(ui, repo, *pats, **opts):
1620 def log(ui, repo, *pats, **opts):
1620 """show revision history of entire repository or files
1621 """show revision history of entire repository or files
1621
1622
1622 Print the revision history of the specified files or the entire
1623 Print the revision history of the specified files or the entire
1623 project.
1624 project.
1624
1625
1625 File history is shown without following rename or copy history of
1626 File history is shown without following rename or copy history of
1626 files. Use -f/--follow with a file name to follow history across
1627 files. Use -f/--follow with a file name to follow history across
1627 renames and copies. --follow without a file name will only show
1628 renames and copies. --follow without a file name will only show
1628 ancestors or descendants of the starting revision. --follow-first
1629 ancestors or descendants of the starting revision. --follow-first
1629 only follows the first parent of merge revisions.
1630 only follows the first parent of merge revisions.
1630
1631
1631 If no revision range is specified, the default is tip:0 unless
1632 If no revision range is specified, the default is tip:0 unless
1632 --follow is set, in which case the working directory parent is
1633 --follow is set, in which case the working directory parent is
1633 used as the starting revision.
1634 used as the starting revision.
1634
1635
1635 By default this command outputs: changeset id and hash, tags,
1636 By default this command outputs: changeset id and hash, tags,
1636 non-trivial parents, user, date and time, and a summary for each
1637 non-trivial parents, user, date and time, and a summary for each
1637 commit. When the -v/--verbose switch is used, the list of changed
1638 commit. When the -v/--verbose switch is used, the list of changed
1638 files and full commit message is shown.
1639 files and full commit message is shown.
1639
1640
1640 NOTE: log -p may generate unexpected diff output for merge
1641 NOTE: log -p may generate unexpected diff output for merge
1641 changesets, as it will compare the merge changeset against its
1642 changesets, as it will compare the merge changeset against its
1642 first parent only. Also, the files: list will only reflect files
1643 first parent only. Also, the files: list will only reflect files
1643 that are different from BOTH parents.
1644 that are different from BOTH parents.
1644
1645
1645 """
1646 """
1646
1647
1647 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1648 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1648 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1649 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1649
1650
1650 if opts['limit']:
1651 if opts['limit']:
1651 try:
1652 try:
1652 limit = int(opts['limit'])
1653 limit = int(opts['limit'])
1653 except ValueError:
1654 except ValueError:
1654 raise util.Abort(_('limit must be a positive integer'))
1655 raise util.Abort(_('limit must be a positive integer'))
1655 if limit <= 0: raise util.Abort(_('limit must be positive'))
1656 if limit <= 0: raise util.Abort(_('limit must be positive'))
1656 else:
1657 else:
1657 limit = sys.maxint
1658 limit = sys.maxint
1658 count = 0
1659 count = 0
1659
1660
1660 if opts['copies'] and opts['rev']:
1661 if opts['copies'] and opts['rev']:
1661 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1662 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1662 else:
1663 else:
1663 endrev = repo.changelog.count()
1664 endrev = repo.changelog.count()
1664 rcache = {}
1665 rcache = {}
1665 ncache = {}
1666 ncache = {}
1666 dcache = []
1667 dcache = []
1667 def getrenamed(fn, rev, man):
1668 def getrenamed(fn, rev, man):
1668 '''looks up all renames for a file (up to endrev) the first
1669 '''looks up all renames for a file (up to endrev) the first
1669 time the file is given. It indexes on the changerev and only
1670 time the file is given. It indexes on the changerev and only
1670 parses the manifest if linkrev != changerev.
1671 parses the manifest if linkrev != changerev.
1671 Returns rename info for fn at changerev rev.'''
1672 Returns rename info for fn at changerev rev.'''
1672 if fn not in rcache:
1673 if fn not in rcache:
1673 rcache[fn] = {}
1674 rcache[fn] = {}
1674 ncache[fn] = {}
1675 ncache[fn] = {}
1675 fl = repo.file(fn)
1676 fl = repo.file(fn)
1676 for i in xrange(fl.count()):
1677 for i in xrange(fl.count()):
1677 node = fl.node(i)
1678 node = fl.node(i)
1678 lr = fl.linkrev(node)
1679 lr = fl.linkrev(node)
1679 renamed = fl.renamed(node)
1680 renamed = fl.renamed(node)
1680 rcache[fn][lr] = renamed
1681 rcache[fn][lr] = renamed
1681 if renamed:
1682 if renamed:
1682 ncache[fn][node] = renamed
1683 ncache[fn][node] = renamed
1683 if lr >= endrev:
1684 if lr >= endrev:
1684 break
1685 break
1685 if rev in rcache[fn]:
1686 if rev in rcache[fn]:
1686 return rcache[fn][rev]
1687 return rcache[fn][rev]
1687 mr = repo.manifest.rev(man)
1688 mr = repo.manifest.rev(man)
1688 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1689 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1689 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1690 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1690 if not dcache or dcache[0] != man:
1691 if not dcache or dcache[0] != man:
1691 dcache[:] = [man, repo.manifest.readdelta(man)]
1692 dcache[:] = [man, repo.manifest.readdelta(man)]
1692 if fn in dcache[1]:
1693 if fn in dcache[1]:
1693 return ncache[fn].get(dcache[1][fn])
1694 return ncache[fn].get(dcache[1][fn])
1694 return None
1695 return None
1695
1696
1696 df = False
1697 df = False
1697 if opts["date"]:
1698 if opts["date"]:
1698 df = util.matchdate(opts["date"])
1699 df = util.matchdate(opts["date"])
1699
1700
1700
1701
1701 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1702 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1702 for st, rev, fns in changeiter:
1703 for st, rev, fns in changeiter:
1703 if st == 'add':
1704 if st == 'add':
1704 changenode = repo.changelog.node(rev)
1705 changenode = repo.changelog.node(rev)
1705 parents = [p for p in repo.changelog.parentrevs(rev)
1706 parents = [p for p in repo.changelog.parentrevs(rev)
1706 if p != nullrev]
1707 if p != nullrev]
1707 if opts['no_merges'] and len(parents) == 2:
1708 if opts['no_merges'] and len(parents) == 2:
1708 continue
1709 continue
1709 if opts['only_merges'] and len(parents) != 2:
1710 if opts['only_merges'] and len(parents) != 2:
1710 continue
1711 continue
1711
1712
1712 if df:
1713 if df:
1713 changes = get(rev)
1714 changes = get(rev)
1714 if not df(changes[2][0]):
1715 if not df(changes[2][0]):
1715 continue
1716 continue
1716
1717
1717 if opts['keyword']:
1718 if opts['keyword']:
1718 changes = get(rev)
1719 changes = get(rev)
1719 miss = 0
1720 miss = 0
1720 for k in [kw.lower() for kw in opts['keyword']]:
1721 for k in [kw.lower() for kw in opts['keyword']]:
1721 if not (k in changes[1].lower() or
1722 if not (k in changes[1].lower() or
1722 k in changes[4].lower() or
1723 k in changes[4].lower() or
1723 k in " ".join(changes[3][:20]).lower()):
1724 k in " ".join(changes[3][:20]).lower()):
1724 miss = 1
1725 miss = 1
1725 break
1726 break
1726 if miss:
1727 if miss:
1727 continue
1728 continue
1728
1729
1729 copies = []
1730 copies = []
1730 if opts.get('copies') and rev:
1731 if opts.get('copies') and rev:
1731 mf = get(rev)[0]
1732 mf = get(rev)[0]
1732 for fn in get(rev)[3]:
1733 for fn in get(rev)[3]:
1733 rename = getrenamed(fn, rev, mf)
1734 rename = getrenamed(fn, rev, mf)
1734 if rename:
1735 if rename:
1735 copies.append((fn, rename[0]))
1736 copies.append((fn, rename[0]))
1736 displayer.show(rev, changenode, copies=copies)
1737 displayer.show(rev, changenode, copies=copies)
1737 elif st == 'iter':
1738 elif st == 'iter':
1738 if count == limit: break
1739 if count == limit: break
1739 if displayer.flush(rev):
1740 if displayer.flush(rev):
1740 count += 1
1741 count += 1
1741
1742
1742 def manifest(ui, repo, rev=None):
1743 def manifest(ui, repo, rev=None):
1743 """output the latest or given revision of the project manifest
1744 """output the latest or given revision of the project manifest
1744
1745
1745 Print a list of version controlled files for the given revision.
1746 Print a list of version controlled files for the given revision.
1746
1747
1747 The manifest is the list of files being version controlled. If no revision
1748 The manifest is the list of files being version controlled. If no revision
1748 is given then the first parent of the working directory is used.
1749 is given then the first parent of the working directory is used.
1749
1750
1750 With -v flag, print file permissions. With --debug flag, print
1751 With -v flag, print file permissions. With --debug flag, print
1751 file revision hashes.
1752 file revision hashes.
1752 """
1753 """
1753
1754
1754 m = repo.changectx(rev).manifest()
1755 m = repo.changectx(rev).manifest()
1755 files = m.keys()
1756 files = m.keys()
1756 files.sort()
1757 files.sort()
1757
1758
1758 for f in files:
1759 for f in files:
1759 if ui.debugflag:
1760 if ui.debugflag:
1760 ui.write("%40s " % hex(m[f]))
1761 ui.write("%40s " % hex(m[f]))
1761 if ui.verbose:
1762 if ui.verbose:
1762 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1763 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1763 ui.write("%s\n" % f)
1764 ui.write("%s\n" % f)
1764
1765
1765 def merge(ui, repo, node=None, force=None, branch=None):
1766 def merge(ui, repo, node=None, force=None, branch=None):
1766 """Merge working directory with another revision
1767 """Merge working directory with another revision
1767
1768
1768 Merge the contents of the current working directory and the
1769 Merge the contents of the current working directory and the
1769 requested revision. Files that changed between either parent are
1770 requested revision. Files that changed between either parent are
1770 marked as changed for the next commit and a commit must be
1771 marked as changed for the next commit and a commit must be
1771 performed before any further updates are allowed.
1772 performed before any further updates are allowed.
1772
1773
1773 If no revision is specified, the working directory's parent is a
1774 If no revision is specified, the working directory's parent is a
1774 head revision, and the repository contains exactly one other head,
1775 head revision, and the repository contains exactly one other head,
1775 the other head is merged with by default. Otherwise, an explicit
1776 the other head is merged with by default. Otherwise, an explicit
1776 revision to merge with must be provided.
1777 revision to merge with must be provided.
1777 """
1778 """
1778
1779
1779 if node or branch:
1780 if node or branch:
1780 node = _lookup(repo, node, branch)
1781 node = _lookup(repo, node, branch)
1781 else:
1782 else:
1782 heads = repo.heads()
1783 heads = repo.heads()
1783 if len(heads) > 2:
1784 if len(heads) > 2:
1784 raise util.Abort(_('repo has %d heads - '
1785 raise util.Abort(_('repo has %d heads - '
1785 'please merge with an explicit rev') %
1786 'please merge with an explicit rev') %
1786 len(heads))
1787 len(heads))
1787 if len(heads) == 1:
1788 if len(heads) == 1:
1788 raise util.Abort(_('there is nothing to merge - '
1789 raise util.Abort(_('there is nothing to merge - '
1789 'use "hg update" instead'))
1790 'use "hg update" instead'))
1790 parent = repo.dirstate.parents()[0]
1791 parent = repo.dirstate.parents()[0]
1791 if parent not in heads:
1792 if parent not in heads:
1792 raise util.Abort(_('working dir not at a head rev - '
1793 raise util.Abort(_('working dir not at a head rev - '
1793 'use "hg update" or merge with an explicit rev'))
1794 'use "hg update" or merge with an explicit rev'))
1794 node = parent == heads[0] and heads[-1] or heads[0]
1795 node = parent == heads[0] and heads[-1] or heads[0]
1795 return hg.merge(repo, node, force=force)
1796 return hg.merge(repo, node, force=force)
1796
1797
1797 def outgoing(ui, repo, dest=None, **opts):
1798 def outgoing(ui, repo, dest=None, **opts):
1798 """show changesets not found in destination
1799 """show changesets not found in destination
1799
1800
1800 Show changesets not found in the specified destination repository or
1801 Show changesets not found in the specified destination repository or
1801 the default push location. These are the changesets that would be pushed
1802 the default push location. These are the changesets that would be pushed
1802 if a push was requested.
1803 if a push was requested.
1803
1804
1804 See pull for valid destination format details.
1805 See pull for valid destination format details.
1805 """
1806 """
1806 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1807 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1807 setremoteconfig(ui, opts)
1808 setremoteconfig(ui, opts)
1808 revs = None
1809 revs = None
1809 if opts['rev']:
1810 if opts['rev']:
1810 revs = [repo.lookup(rev) for rev in opts['rev']]
1811 revs = [repo.lookup(rev) for rev in opts['rev']]
1811
1812
1812 other = hg.repository(ui, dest)
1813 other = hg.repository(ui, dest)
1813 o = repo.findoutgoing(other, force=opts['force'])
1814 o = repo.findoutgoing(other, force=opts['force'])
1814 if not o:
1815 if not o:
1815 ui.status(_("no changes found\n"))
1816 ui.status(_("no changes found\n"))
1816 return
1817 return
1817 o = repo.changelog.nodesbetween(o, revs)[0]
1818 o = repo.changelog.nodesbetween(o, revs)[0]
1818 if opts['newest_first']:
1819 if opts['newest_first']:
1819 o.reverse()
1820 o.reverse()
1820 displayer = cmdutil.show_changeset(ui, repo, opts)
1821 displayer = cmdutil.show_changeset(ui, repo, opts)
1821 for n in o:
1822 for n in o:
1822 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1823 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1823 if opts['no_merges'] and len(parents) == 2:
1824 if opts['no_merges'] and len(parents) == 2:
1824 continue
1825 continue
1825 displayer.show(changenode=n)
1826 displayer.show(changenode=n)
1826
1827
1827 def parents(ui, repo, file_=None, **opts):
1828 def parents(ui, repo, file_=None, **opts):
1828 """show the parents of the working dir or revision
1829 """show the parents of the working dir or revision
1829
1830
1830 Print the working directory's parent revisions.
1831 Print the working directory's parent revisions.
1831 """
1832 """
1832 rev = opts.get('rev')
1833 rev = opts.get('rev')
1833 if rev:
1834 if rev:
1834 if file_:
1835 if file_:
1835 ctx = repo.filectx(file_, changeid=rev)
1836 ctx = repo.filectx(file_, changeid=rev)
1836 else:
1837 else:
1837 ctx = repo.changectx(rev)
1838 ctx = repo.changectx(rev)
1838 p = [cp.node() for cp in ctx.parents()]
1839 p = [cp.node() for cp in ctx.parents()]
1839 else:
1840 else:
1840 p = repo.dirstate.parents()
1841 p = repo.dirstate.parents()
1841
1842
1842 displayer = cmdutil.show_changeset(ui, repo, opts)
1843 displayer = cmdutil.show_changeset(ui, repo, opts)
1843 for n in p:
1844 for n in p:
1844 if n != nullid:
1845 if n != nullid:
1845 displayer.show(changenode=n)
1846 displayer.show(changenode=n)
1846
1847
1847 def paths(ui, repo, search=None):
1848 def paths(ui, repo, search=None):
1848 """show definition of symbolic path names
1849 """show definition of symbolic path names
1849
1850
1850 Show definition of symbolic path name NAME. If no name is given, show
1851 Show definition of symbolic path name NAME. If no name is given, show
1851 definition of available names.
1852 definition of available names.
1852
1853
1853 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1854 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1854 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1855 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1855 """
1856 """
1856 if search:
1857 if search:
1857 for name, path in ui.configitems("paths"):
1858 for name, path in ui.configitems("paths"):
1858 if name == search:
1859 if name == search:
1859 ui.write("%s\n" % path)
1860 ui.write("%s\n" % path)
1860 return
1861 return
1861 ui.warn(_("not found!\n"))
1862 ui.warn(_("not found!\n"))
1862 return 1
1863 return 1
1863 else:
1864 else:
1864 for name, path in ui.configitems("paths"):
1865 for name, path in ui.configitems("paths"):
1865 ui.write("%s = %s\n" % (name, path))
1866 ui.write("%s = %s\n" % (name, path))
1866
1867
1867 def postincoming(ui, repo, modheads, optupdate):
1868 def postincoming(ui, repo, modheads, optupdate):
1868 if modheads == 0:
1869 if modheads == 0:
1869 return
1870 return
1870 if optupdate:
1871 if optupdate:
1871 if modheads == 1:
1872 if modheads == 1:
1872 return hg.update(repo, repo.changelog.tip()) # update
1873 return hg.update(repo, repo.changelog.tip()) # update
1873 else:
1874 else:
1874 ui.status(_("not updating, since new heads added\n"))
1875 ui.status(_("not updating, since new heads added\n"))
1875 if modheads > 1:
1876 if modheads > 1:
1876 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1877 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1877 else:
1878 else:
1878 ui.status(_("(run 'hg update' to get a working copy)\n"))
1879 ui.status(_("(run 'hg update' to get a working copy)\n"))
1879
1880
1880 def pull(ui, repo, source="default", **opts):
1881 def pull(ui, repo, source="default", **opts):
1881 """pull changes from the specified source
1882 """pull changes from the specified source
1882
1883
1883 Pull changes from a remote repository to a local one.
1884 Pull changes from a remote repository to a local one.
1884
1885
1885 This finds all changes from the repository at the specified path
1886 This finds all changes from the repository at the specified path
1886 or URL and adds them to the local repository. By default, this
1887 or URL and adds them to the local repository. By default, this
1887 does not update the copy of the project in the working directory.
1888 does not update the copy of the project in the working directory.
1888
1889
1889 Valid URLs are of the form:
1890 Valid URLs are of the form:
1890
1891
1891 local/filesystem/path (or file://local/filesystem/path)
1892 local/filesystem/path (or file://local/filesystem/path)
1892 http://[user@]host[:port]/[path]
1893 http://[user@]host[:port]/[path]
1893 https://[user@]host[:port]/[path]
1894 https://[user@]host[:port]/[path]
1894 ssh://[user@]host[:port]/[path]
1895 ssh://[user@]host[:port]/[path]
1895 static-http://host[:port]/[path]
1896 static-http://host[:port]/[path]
1896
1897
1897 Paths in the local filesystem can either point to Mercurial
1898 Paths in the local filesystem can either point to Mercurial
1898 repositories or to bundle files (as created by 'hg bundle' or
1899 repositories or to bundle files (as created by 'hg bundle' or
1899 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1900 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1900 allows access to a Mercurial repository where you simply use a web
1901 allows access to a Mercurial repository where you simply use a web
1901 server to publish the .hg directory as static content.
1902 server to publish the .hg directory as static content.
1902
1903
1903 Some notes about using SSH with Mercurial:
1904 Some notes about using SSH with Mercurial:
1904 - SSH requires an accessible shell account on the destination machine
1905 - SSH requires an accessible shell account on the destination machine
1905 and a copy of hg in the remote path or specified with as remotecmd.
1906 and a copy of hg in the remote path or specified with as remotecmd.
1906 - path is relative to the remote user's home directory by default.
1907 - path is relative to the remote user's home directory by default.
1907 Use an extra slash at the start of a path to specify an absolute path:
1908 Use an extra slash at the start of a path to specify an absolute path:
1908 ssh://example.com//tmp/repository
1909 ssh://example.com//tmp/repository
1909 - Mercurial doesn't use its own compression via SSH; the right thing
1910 - Mercurial doesn't use its own compression via SSH; the right thing
1910 to do is to configure it in your ~/.ssh/config, e.g.:
1911 to do is to configure it in your ~/.ssh/config, e.g.:
1911 Host *.mylocalnetwork.example.com
1912 Host *.mylocalnetwork.example.com
1912 Compression no
1913 Compression no
1913 Host *
1914 Host *
1914 Compression yes
1915 Compression yes
1915 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1916 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1916 with the --ssh command line option.
1917 with the --ssh command line option.
1917 """
1918 """
1918 source = ui.expandpath(source)
1919 source = ui.expandpath(source)
1919 setremoteconfig(ui, opts)
1920 setremoteconfig(ui, opts)
1920
1921
1921 other = hg.repository(ui, source)
1922 other = hg.repository(ui, source)
1922 ui.status(_('pulling from %s\n') % (source))
1923 ui.status(_('pulling from %s\n') % (source))
1923 revs = None
1924 revs = None
1924 if opts['rev']:
1925 if opts['rev']:
1925 if 'lookup' in other.capabilities:
1926 if 'lookup' in other.capabilities:
1926 revs = [other.lookup(rev) for rev in opts['rev']]
1927 revs = [other.lookup(rev) for rev in opts['rev']]
1927 else:
1928 else:
1928 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1929 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1929 raise util.Abort(error)
1930 raise util.Abort(error)
1930 modheads = repo.pull(other, heads=revs, force=opts['force'])
1931 modheads = repo.pull(other, heads=revs, force=opts['force'])
1931 return postincoming(ui, repo, modheads, opts['update'])
1932 return postincoming(ui, repo, modheads, opts['update'])
1932
1933
1933 def push(ui, repo, dest=None, **opts):
1934 def push(ui, repo, dest=None, **opts):
1934 """push changes to the specified destination
1935 """push changes to the specified destination
1935
1936
1936 Push changes from the local repository to the given destination.
1937 Push changes from the local repository to the given destination.
1937
1938
1938 This is the symmetrical operation for pull. It helps to move
1939 This is the symmetrical operation for pull. It helps to move
1939 changes from the current repository to a different one. If the
1940 changes from the current repository to a different one. If the
1940 destination is local this is identical to a pull in that directory
1941 destination is local this is identical to a pull in that directory
1941 from the current one.
1942 from the current one.
1942
1943
1943 By default, push will refuse to run if it detects the result would
1944 By default, push will refuse to run if it detects the result would
1944 increase the number of remote heads. This generally indicates the
1945 increase the number of remote heads. This generally indicates the
1945 the client has forgotten to sync and merge before pushing.
1946 the client has forgotten to sync and merge before pushing.
1946
1947
1947 Valid URLs are of the form:
1948 Valid URLs are of the form:
1948
1949
1949 local/filesystem/path (or file://local/filesystem/path)
1950 local/filesystem/path (or file://local/filesystem/path)
1950 ssh://[user@]host[:port]/[path]
1951 ssh://[user@]host[:port]/[path]
1951 http://[user@]host[:port]/[path]
1952 http://[user@]host[:port]/[path]
1952 https://[user@]host[:port]/[path]
1953 https://[user@]host[:port]/[path]
1953
1954
1954 Look at the help text for the pull command for important details
1955 Look at the help text for the pull command for important details
1955 about ssh:// URLs.
1956 about ssh:// URLs.
1956
1957
1957 Pushing to http:// and https:// URLs is only possible, if this
1958 Pushing to http:// and https:// URLs is only possible, if this
1958 feature is explicitly enabled on the remote Mercurial server.
1959 feature is explicitly enabled on the remote Mercurial server.
1959 """
1960 """
1960 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1961 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1961 setremoteconfig(ui, opts)
1962 setremoteconfig(ui, opts)
1962
1963
1963 other = hg.repository(ui, dest)
1964 other = hg.repository(ui, dest)
1964 ui.status('pushing to %s\n' % (dest))
1965 ui.status('pushing to %s\n' % (dest))
1965 revs = None
1966 revs = None
1966 if opts['rev']:
1967 if opts['rev']:
1967 revs = [repo.lookup(rev) for rev in opts['rev']]
1968 revs = [repo.lookup(rev) for rev in opts['rev']]
1968 r = repo.push(other, opts['force'], revs=revs)
1969 r = repo.push(other, opts['force'], revs=revs)
1969 return r == 0
1970 return r == 0
1970
1971
1971 def rawcommit(ui, repo, *pats, **opts):
1972 def rawcommit(ui, repo, *pats, **opts):
1972 """raw commit interface (DEPRECATED)
1973 """raw commit interface (DEPRECATED)
1973
1974
1974 (DEPRECATED)
1975 (DEPRECATED)
1975 Lowlevel commit, for use in helper scripts.
1976 Lowlevel commit, for use in helper scripts.
1976
1977
1977 This command is not intended to be used by normal users, as it is
1978 This command is not intended to be used by normal users, as it is
1978 primarily useful for importing from other SCMs.
1979 primarily useful for importing from other SCMs.
1979
1980
1980 This command is now deprecated and will be removed in a future
1981 This command is now deprecated and will be removed in a future
1981 release, please use debugsetparents and commit instead.
1982 release, please use debugsetparents and commit instead.
1982 """
1983 """
1983
1984
1984 ui.warn(_("(the rawcommit command is deprecated)\n"))
1985 ui.warn(_("(the rawcommit command is deprecated)\n"))
1985
1986
1986 message = logmessage(opts)
1987 message = logmessage(opts)
1987
1988
1988 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
1989 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
1989 if opts['files']:
1990 if opts['files']:
1990 files += open(opts['files']).read().splitlines()
1991 files += open(opts['files']).read().splitlines()
1991
1992
1992 parents = [repo.lookup(p) for p in opts['parent']]
1993 parents = [repo.lookup(p) for p in opts['parent']]
1993
1994
1994 try:
1995 try:
1995 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
1996 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
1996 except ValueError, inst:
1997 except ValueError, inst:
1997 raise util.Abort(str(inst))
1998 raise util.Abort(str(inst))
1998
1999
1999 def recover(ui, repo):
2000 def recover(ui, repo):
2000 """roll back an interrupted transaction
2001 """roll back an interrupted transaction
2001
2002
2002 Recover from an interrupted commit or pull.
2003 Recover from an interrupted commit or pull.
2003
2004
2004 This command tries to fix the repository status after an interrupted
2005 This command tries to fix the repository status after an interrupted
2005 operation. It should only be necessary when Mercurial suggests it.
2006 operation. It should only be necessary when Mercurial suggests it.
2006 """
2007 """
2007 if repo.recover():
2008 if repo.recover():
2008 return hg.verify(repo)
2009 return hg.verify(repo)
2009 return 1
2010 return 1
2010
2011
2011 def remove(ui, repo, *pats, **opts):
2012 def remove(ui, repo, *pats, **opts):
2012 """remove the specified files on the next commit
2013 """remove the specified files on the next commit
2013
2014
2014 Schedule the indicated files for removal from the repository.
2015 Schedule the indicated files for removal from the repository.
2015
2016
2016 This only removes files from the current branch, not from the
2017 This only removes files from the current branch, not from the
2017 entire project history. If the files still exist in the working
2018 entire project history. If the files still exist in the working
2018 directory, they will be deleted from it. If invoked with --after,
2019 directory, they will be deleted from it. If invoked with --after,
2019 files that have been manually deleted are marked as removed.
2020 files that have been manually deleted are marked as removed.
2020
2021
2021 This command schedules the files to be removed at the next commit.
2022 This command schedules the files to be removed at the next commit.
2022 To undo a remove before that, see hg revert.
2023 To undo a remove before that, see hg revert.
2023
2024
2024 Modified files and added files are not removed by default. To
2025 Modified files and added files are not removed by default. To
2025 remove them, use the -f/--force option.
2026 remove them, use the -f/--force option.
2026 """
2027 """
2027 names = []
2028 names = []
2028 if not opts['after'] and not pats:
2029 if not opts['after'] and not pats:
2029 raise util.Abort(_('no files specified'))
2030 raise util.Abort(_('no files specified'))
2030 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2031 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2031 exact = dict.fromkeys(files)
2032 exact = dict.fromkeys(files)
2032 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2033 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2033 modified, added, removed, deleted, unknown = mardu
2034 modified, added, removed, deleted, unknown = mardu
2034 remove, forget = [], []
2035 remove, forget = [], []
2035 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2036 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2036 reason = None
2037 reason = None
2037 if abs not in deleted and opts['after']:
2038 if abs not in deleted and opts['after']:
2038 reason = _('is still present')
2039 reason = _('is still present')
2039 elif abs in modified and not opts['force']:
2040 elif abs in modified and not opts['force']:
2040 reason = _('is modified (use -f to force removal)')
2041 reason = _('is modified (use -f to force removal)')
2041 elif abs in added:
2042 elif abs in added:
2042 if opts['force']:
2043 if opts['force']:
2043 forget.append(abs)
2044 forget.append(abs)
2044 continue
2045 continue
2045 reason = _('has been marked for add (use -f to force removal)')
2046 reason = _('has been marked for add (use -f to force removal)')
2046 elif abs in unknown:
2047 elif abs in unknown:
2047 reason = _('is not managed')
2048 reason = _('is not managed')
2048 elif abs in removed:
2049 elif abs in removed:
2049 continue
2050 continue
2050 if reason:
2051 if reason:
2051 if exact:
2052 if exact:
2052 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2053 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2053 else:
2054 else:
2054 if ui.verbose or not exact:
2055 if ui.verbose or not exact:
2055 ui.status(_('removing %s\n') % rel)
2056 ui.status(_('removing %s\n') % rel)
2056 remove.append(abs)
2057 remove.append(abs)
2057 repo.forget(forget)
2058 repo.forget(forget)
2058 repo.remove(remove, unlink=not opts['after'])
2059 repo.remove(remove, unlink=not opts['after'])
2059
2060
2060 def rename(ui, repo, *pats, **opts):
2061 def rename(ui, repo, *pats, **opts):
2061 """rename files; equivalent of copy + remove
2062 """rename files; equivalent of copy + remove
2062
2063
2063 Mark dest as copies of sources; mark sources for deletion. If
2064 Mark dest as copies of sources; mark sources for deletion. If
2064 dest is a directory, copies are put in that directory. If dest is
2065 dest is a directory, copies are put in that directory. If dest is
2065 a file, there can only be one source.
2066 a file, there can only be one source.
2066
2067
2067 By default, this command copies the contents of files as they
2068 By default, this command copies the contents of files as they
2068 stand in the working directory. If invoked with --after, the
2069 stand in the working directory. If invoked with --after, the
2069 operation is recorded, but no copying is performed.
2070 operation is recorded, but no copying is performed.
2070
2071
2071 This command takes effect in the next commit. To undo a rename
2072 This command takes effect in the next commit. To undo a rename
2072 before that, see hg revert.
2073 before that, see hg revert.
2073 """
2074 """
2074 wlock = repo.wlock(0)
2075 wlock = repo.wlock(0)
2075 errs, copied = docopy(ui, repo, pats, opts, wlock)
2076 errs, copied = docopy(ui, repo, pats, opts, wlock)
2076 names = []
2077 names = []
2077 for abs, rel, exact in copied:
2078 for abs, rel, exact in copied:
2078 if ui.verbose or not exact:
2079 if ui.verbose or not exact:
2079 ui.status(_('removing %s\n') % rel)
2080 ui.status(_('removing %s\n') % rel)
2080 names.append(abs)
2081 names.append(abs)
2081 if not opts.get('dry_run'):
2082 if not opts.get('dry_run'):
2082 repo.remove(names, True, wlock)
2083 repo.remove(names, True, wlock)
2083 return errs
2084 return errs
2084
2085
2085 def revert(ui, repo, *pats, **opts):
2086 def revert(ui, repo, *pats, **opts):
2086 """revert files or dirs to their states as of some revision
2087 """revert files or dirs to their states as of some revision
2087
2088
2088 With no revision specified, revert the named files or directories
2089 With no revision specified, revert the named files or directories
2089 to the contents they had in the parent of the working directory.
2090 to the contents they had in the parent of the working directory.
2090 This restores the contents of the affected files to an unmodified
2091 This restores the contents of the affected files to an unmodified
2091 state and unschedules adds, removes, copies, and renames. If the
2092 state and unschedules adds, removes, copies, and renames. If the
2092 working directory has two parents, you must explicitly specify the
2093 working directory has two parents, you must explicitly specify the
2093 revision to revert to.
2094 revision to revert to.
2094
2095
2095 Modified files are saved with a .orig suffix before reverting.
2096 Modified files are saved with a .orig suffix before reverting.
2096 To disable these backups, use --no-backup.
2097 To disable these backups, use --no-backup.
2097
2098
2098 Using the -r option, revert the given files or directories to their
2099 Using the -r option, revert the given files or directories to their
2099 contents as of a specific revision. This can be helpful to "roll
2100 contents as of a specific revision. This can be helpful to "roll
2100 back" some or all of a change that should not have been committed.
2101 back" some or all of a change that should not have been committed.
2101
2102
2102 Revert modifies the working directory. It does not commit any
2103 Revert modifies the working directory. It does not commit any
2103 changes, or change the parent of the working directory. If you
2104 changes, or change the parent of the working directory. If you
2104 revert to a revision other than the parent of the working
2105 revert to a revision other than the parent of the working
2105 directory, the reverted files will thus appear modified
2106 directory, the reverted files will thus appear modified
2106 afterwards.
2107 afterwards.
2107
2108
2108 If a file has been deleted, it is recreated. If the executable
2109 If a file has been deleted, it is recreated. If the executable
2109 mode of a file was changed, it is reset.
2110 mode of a file was changed, it is reset.
2110
2111
2111 If names are given, all files matching the names are reverted.
2112 If names are given, all files matching the names are reverted.
2112
2113
2113 If no arguments are given, no files are reverted.
2114 If no arguments are given, no files are reverted.
2114 """
2115 """
2115
2116
2116 if opts["date"]:
2117 if opts["date"]:
2117 if opts["rev"]:
2118 if opts["rev"]:
2118 raise util.Abort(_("you can't specify a revision and a date"))
2119 raise util.Abort(_("you can't specify a revision and a date"))
2119 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2120 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2120
2121
2121 if not pats and not opts['all']:
2122 if not pats and not opts['all']:
2122 raise util.Abort(_('no files or directories specified; '
2123 raise util.Abort(_('no files or directories specified; '
2123 'use --all to revert the whole repo'))
2124 'use --all to revert the whole repo'))
2124
2125
2125 parent, p2 = repo.dirstate.parents()
2126 parent, p2 = repo.dirstate.parents()
2126 if not opts['rev'] and p2 != nullid:
2127 if not opts['rev'] and p2 != nullid:
2127 raise util.Abort(_('uncommitted merge - please provide a '
2128 raise util.Abort(_('uncommitted merge - please provide a '
2128 'specific revision'))
2129 'specific revision'))
2129 node = repo.changectx(opts['rev']).node()
2130 node = repo.changectx(opts['rev']).node()
2130 mf = repo.manifest.read(repo.changelog.read(node)[0])
2131 mf = repo.manifest.read(repo.changelog.read(node)[0])
2131 if node == parent:
2132 if node == parent:
2132 pmf = mf
2133 pmf = mf
2133 else:
2134 else:
2134 pmf = None
2135 pmf = None
2135
2136
2136 wlock = repo.wlock()
2137 wlock = repo.wlock()
2137
2138
2138 # need all matching names in dirstate and manifest of target rev,
2139 # need all matching names in dirstate and manifest of target rev,
2139 # so have to walk both. do not print errors if files exist in one
2140 # so have to walk both. do not print errors if files exist in one
2140 # but not other.
2141 # but not other.
2141
2142
2142 names = {}
2143 names = {}
2143 target_only = {}
2144 target_only = {}
2144
2145
2145 # walk dirstate.
2146 # walk dirstate.
2146
2147
2147 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2148 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2148 badmatch=mf.has_key):
2149 badmatch=mf.has_key):
2149 names[abs] = (rel, exact)
2150 names[abs] = (rel, exact)
2150 if src == 'b':
2151 if src == 'b':
2151 target_only[abs] = True
2152 target_only[abs] = True
2152
2153
2153 # walk target manifest.
2154 # walk target manifest.
2154
2155
2155 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2156 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2156 badmatch=names.has_key):
2157 badmatch=names.has_key):
2157 if abs in names: continue
2158 if abs in names: continue
2158 names[abs] = (rel, exact)
2159 names[abs] = (rel, exact)
2159 target_only[abs] = True
2160 target_only[abs] = True
2160
2161
2161 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2162 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2162 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2163 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2163
2164
2164 revert = ([], _('reverting %s\n'))
2165 revert = ([], _('reverting %s\n'))
2165 add = ([], _('adding %s\n'))
2166 add = ([], _('adding %s\n'))
2166 remove = ([], _('removing %s\n'))
2167 remove = ([], _('removing %s\n'))
2167 forget = ([], _('forgetting %s\n'))
2168 forget = ([], _('forgetting %s\n'))
2168 undelete = ([], _('undeleting %s\n'))
2169 undelete = ([], _('undeleting %s\n'))
2169 update = {}
2170 update = {}
2170
2171
2171 disptable = (
2172 disptable = (
2172 # dispatch table:
2173 # dispatch table:
2173 # file state
2174 # file state
2174 # action if in target manifest
2175 # action if in target manifest
2175 # action if not in target manifest
2176 # action if not in target manifest
2176 # make backup if in target manifest
2177 # make backup if in target manifest
2177 # make backup if not in target manifest
2178 # make backup if not in target manifest
2178 (modified, revert, remove, True, True),
2179 (modified, revert, remove, True, True),
2179 (added, revert, forget, True, False),
2180 (added, revert, forget, True, False),
2180 (removed, undelete, None, False, False),
2181 (removed, undelete, None, False, False),
2181 (deleted, revert, remove, False, False),
2182 (deleted, revert, remove, False, False),
2182 (unknown, add, None, True, False),
2183 (unknown, add, None, True, False),
2183 (target_only, add, None, False, False),
2184 (target_only, add, None, False, False),
2184 )
2185 )
2185
2186
2186 entries = names.items()
2187 entries = names.items()
2187 entries.sort()
2188 entries.sort()
2188
2189
2189 for abs, (rel, exact) in entries:
2190 for abs, (rel, exact) in entries:
2190 mfentry = mf.get(abs)
2191 mfentry = mf.get(abs)
2191 def handle(xlist, dobackup):
2192 def handle(xlist, dobackup):
2192 xlist[0].append(abs)
2193 xlist[0].append(abs)
2193 update[abs] = 1
2194 update[abs] = 1
2194 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2195 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2195 bakname = "%s.orig" % rel
2196 bakname = "%s.orig" % rel
2196 ui.note(_('saving current version of %s as %s\n') %
2197 ui.note(_('saving current version of %s as %s\n') %
2197 (rel, bakname))
2198 (rel, bakname))
2198 if not opts.get('dry_run'):
2199 if not opts.get('dry_run'):
2199 util.copyfile(rel, bakname)
2200 util.copyfile(rel, bakname)
2200 if ui.verbose or not exact:
2201 if ui.verbose or not exact:
2201 ui.status(xlist[1] % rel)
2202 ui.status(xlist[1] % rel)
2202 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2203 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2203 if abs not in table: continue
2204 if abs not in table: continue
2204 # file has changed in dirstate
2205 # file has changed in dirstate
2205 if mfentry:
2206 if mfentry:
2206 handle(hitlist, backuphit)
2207 handle(hitlist, backuphit)
2207 elif misslist is not None:
2208 elif misslist is not None:
2208 handle(misslist, backupmiss)
2209 handle(misslist, backupmiss)
2209 else:
2210 else:
2210 if exact: ui.warn(_('file not managed: %s\n') % rel)
2211 if exact: ui.warn(_('file not managed: %s\n') % rel)
2211 break
2212 break
2212 else:
2213 else:
2213 # file has not changed in dirstate
2214 # file has not changed in dirstate
2214 if node == parent:
2215 if node == parent:
2215 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2216 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2216 continue
2217 continue
2217 if pmf is None:
2218 if pmf is None:
2218 # only need parent manifest in this unlikely case,
2219 # only need parent manifest in this unlikely case,
2219 # so do not read by default
2220 # so do not read by default
2220 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2221 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2221 if abs in pmf:
2222 if abs in pmf:
2222 if mfentry:
2223 if mfentry:
2223 # if version of file is same in parent and target
2224 # if version of file is same in parent and target
2224 # manifests, do nothing
2225 # manifests, do nothing
2225 if pmf[abs] != mfentry:
2226 if pmf[abs] != mfentry:
2226 handle(revert, False)
2227 handle(revert, False)
2227 else:
2228 else:
2228 handle(remove, False)
2229 handle(remove, False)
2229
2230
2230 if not opts.get('dry_run'):
2231 if not opts.get('dry_run'):
2231 repo.dirstate.forget(forget[0])
2232 repo.dirstate.forget(forget[0])
2232 r = hg.revert(repo, node, update.has_key, wlock)
2233 r = hg.revert(repo, node, update.has_key, wlock)
2233 repo.dirstate.update(add[0], 'a')
2234 repo.dirstate.update(add[0], 'a')
2234 repo.dirstate.update(undelete[0], 'n')
2235 repo.dirstate.update(undelete[0], 'n')
2235 repo.dirstate.update(remove[0], 'r')
2236 repo.dirstate.update(remove[0], 'r')
2236 return r
2237 return r
2237
2238
2238 def rollback(ui, repo):
2239 def rollback(ui, repo):
2239 """roll back the last transaction in this repository
2240 """roll back the last transaction in this repository
2240
2241
2241 Roll back the last transaction in this repository, restoring the
2242 Roll back the last transaction in this repository, restoring the
2242 project to its state prior to the transaction.
2243 project to its state prior to the transaction.
2243
2244
2244 Transactions are used to encapsulate the effects of all commands
2245 Transactions are used to encapsulate the effects of all commands
2245 that create new changesets or propagate existing changesets into a
2246 that create new changesets or propagate existing changesets into a
2246 repository. For example, the following commands are transactional,
2247 repository. For example, the following commands are transactional,
2247 and their effects can be rolled back:
2248 and their effects can be rolled back:
2248
2249
2249 commit
2250 commit
2250 import
2251 import
2251 pull
2252 pull
2252 push (with this repository as destination)
2253 push (with this repository as destination)
2253 unbundle
2254 unbundle
2254
2255
2255 This command should be used with care. There is only one level of
2256 This command should be used with care. There is only one level of
2256 rollback, and there is no way to undo a rollback.
2257 rollback, and there is no way to undo a rollback.
2257
2258
2258 This command is not intended for use on public repositories. Once
2259 This command is not intended for use on public repositories. Once
2259 changes are visible for pull by other users, rolling a transaction
2260 changes are visible for pull by other users, rolling a transaction
2260 back locally is ineffective (someone else may already have pulled
2261 back locally is ineffective (someone else may already have pulled
2261 the changes). Furthermore, a race is possible with readers of the
2262 the changes). Furthermore, a race is possible with readers of the
2262 repository; for example an in-progress pull from the repository
2263 repository; for example an in-progress pull from the repository
2263 may fail if a rollback is performed.
2264 may fail if a rollback is performed.
2264 """
2265 """
2265 repo.rollback()
2266 repo.rollback()
2266
2267
2267 def root(ui, repo):
2268 def root(ui, repo):
2268 """print the root (top) of the current working dir
2269 """print the root (top) of the current working dir
2269
2270
2270 Print the root directory of the current repository.
2271 Print the root directory of the current repository.
2271 """
2272 """
2272 ui.write(repo.root + "\n")
2273 ui.write(repo.root + "\n")
2273
2274
2274 def serve(ui, repo, **opts):
2275 def serve(ui, repo, **opts):
2275 """export the repository via HTTP
2276 """export the repository via HTTP
2276
2277
2277 Start a local HTTP repository browser and pull server.
2278 Start a local HTTP repository browser and pull server.
2278
2279
2279 By default, the server logs accesses to stdout and errors to
2280 By default, the server logs accesses to stdout and errors to
2280 stderr. Use the "-A" and "-E" options to log to files.
2281 stderr. Use the "-A" and "-E" options to log to files.
2281 """
2282 """
2282
2283
2283 if opts["stdio"]:
2284 if opts["stdio"]:
2284 if repo is None:
2285 if repo is None:
2285 raise hg.RepoError(_("There is no Mercurial repository here"
2286 raise hg.RepoError(_("There is no Mercurial repository here"
2286 " (.hg not found)"))
2287 " (.hg not found)"))
2287 s = sshserver.sshserver(ui, repo)
2288 s = sshserver.sshserver(ui, repo)
2288 s.serve_forever()
2289 s.serve_forever()
2289
2290
2290 optlist = ("name templates style address port ipv6"
2291 optlist = ("name templates style address port ipv6"
2291 " accesslog errorlog webdir_conf")
2292 " accesslog errorlog webdir_conf")
2292 for o in optlist.split():
2293 for o in optlist.split():
2293 if opts[o]:
2294 if opts[o]:
2294 ui.setconfig("web", o, str(opts[o]))
2295 ui.setconfig("web", o, str(opts[o]))
2295
2296
2296 if repo is None and not ui.config("web", "webdir_conf"):
2297 if repo is None and not ui.config("web", "webdir_conf"):
2297 raise hg.RepoError(_("There is no Mercurial repository here"
2298 raise hg.RepoError(_("There is no Mercurial repository here"
2298 " (.hg not found)"))
2299 " (.hg not found)"))
2299
2300
2300 if opts['daemon'] and not opts['daemon_pipefds']:
2301 if opts['daemon'] and not opts['daemon_pipefds']:
2301 rfd, wfd = os.pipe()
2302 rfd, wfd = os.pipe()
2302 args = sys.argv[:]
2303 args = sys.argv[:]
2303 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2304 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2304 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2305 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2305 args[0], args)
2306 args[0], args)
2306 os.close(wfd)
2307 os.close(wfd)
2307 os.read(rfd, 1)
2308 os.read(rfd, 1)
2308 os._exit(0)
2309 os._exit(0)
2309
2310
2310 httpd = hgweb.server.create_server(ui, repo)
2311 httpd = hgweb.server.create_server(ui, repo)
2311
2312
2312 if ui.verbose:
2313 if ui.verbose:
2313 if httpd.port != 80:
2314 if httpd.port != 80:
2314 ui.status(_('listening at http://%s:%d/\n') %
2315 ui.status(_('listening at http://%s:%d/\n') %
2315 (httpd.addr, httpd.port))
2316 (httpd.addr, httpd.port))
2316 else:
2317 else:
2317 ui.status(_('listening at http://%s/\n') % httpd.addr)
2318 ui.status(_('listening at http://%s/\n') % httpd.addr)
2318
2319
2319 if opts['pid_file']:
2320 if opts['pid_file']:
2320 fp = open(opts['pid_file'], 'w')
2321 fp = open(opts['pid_file'], 'w')
2321 fp.write(str(os.getpid()) + '\n')
2322 fp.write(str(os.getpid()) + '\n')
2322 fp.close()
2323 fp.close()
2323
2324
2324 if opts['daemon_pipefds']:
2325 if opts['daemon_pipefds']:
2325 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2326 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2326 os.close(rfd)
2327 os.close(rfd)
2327 os.write(wfd, 'y')
2328 os.write(wfd, 'y')
2328 os.close(wfd)
2329 os.close(wfd)
2329 sys.stdout.flush()
2330 sys.stdout.flush()
2330 sys.stderr.flush()
2331 sys.stderr.flush()
2331 fd = os.open(util.nulldev, os.O_RDWR)
2332 fd = os.open(util.nulldev, os.O_RDWR)
2332 if fd != 0: os.dup2(fd, 0)
2333 if fd != 0: os.dup2(fd, 0)
2333 if fd != 1: os.dup2(fd, 1)
2334 if fd != 1: os.dup2(fd, 1)
2334 if fd != 2: os.dup2(fd, 2)
2335 if fd != 2: os.dup2(fd, 2)
2335 if fd not in (0, 1, 2): os.close(fd)
2336 if fd not in (0, 1, 2): os.close(fd)
2336
2337
2337 httpd.serve_forever()
2338 httpd.serve_forever()
2338
2339
2339 def status(ui, repo, *pats, **opts):
2340 def status(ui, repo, *pats, **opts):
2340 """show changed files in the working directory
2341 """show changed files in the working directory
2341
2342
2342 Show status of files in the repository. If names are given, only
2343 Show status of files in the repository. If names are given, only
2343 files that match are shown. Files that are clean or ignored, are
2344 files that match are shown. Files that are clean or ignored, are
2344 not listed unless -c (clean), -i (ignored) or -A is given.
2345 not listed unless -c (clean), -i (ignored) or -A is given.
2345
2346
2346 NOTE: status may appear to disagree with diff if permissions have
2347 NOTE: status may appear to disagree with diff if permissions have
2347 changed or a merge has occurred. The standard diff format does not
2348 changed or a merge has occurred. The standard diff format does not
2348 report permission changes and diff only reports changes relative
2349 report permission changes and diff only reports changes relative
2349 to one merge parent.
2350 to one merge parent.
2350
2351
2351 If one revision is given, it is used as the base revision.
2352 If one revision is given, it is used as the base revision.
2352 If two revisions are given, the difference between them is shown.
2353 If two revisions are given, the difference between them is shown.
2353
2354
2354 The codes used to show the status of files are:
2355 The codes used to show the status of files are:
2355 M = modified
2356 M = modified
2356 A = added
2357 A = added
2357 R = removed
2358 R = removed
2358 C = clean
2359 C = clean
2359 ! = deleted, but still tracked
2360 ! = deleted, but still tracked
2360 ? = not tracked
2361 ? = not tracked
2361 I = ignored (not shown by default)
2362 I = ignored (not shown by default)
2362 = the previous added file was copied from here
2363 = the previous added file was copied from here
2363 """
2364 """
2364
2365
2365 all = opts['all']
2366 all = opts['all']
2366 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2367 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2367
2368
2368 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2369 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2369 cwd = (pats and repo.getcwd()) or ''
2370 cwd = (pats and repo.getcwd()) or ''
2370 modified, added, removed, deleted, unknown, ignored, clean = [
2371 modified, added, removed, deleted, unknown, ignored, clean = [
2371 [util.pathto(cwd, x) for x in n]
2372 [util.pathto(cwd, x) for x in n]
2372 for n in repo.status(node1=node1, node2=node2, files=files,
2373 for n in repo.status(node1=node1, node2=node2, files=files,
2373 match=matchfn,
2374 match=matchfn,
2374 list_ignored=all or opts['ignored'],
2375 list_ignored=all or opts['ignored'],
2375 list_clean=all or opts['clean'])]
2376 list_clean=all or opts['clean'])]
2376
2377
2377 changetypes = (('modified', 'M', modified),
2378 changetypes = (('modified', 'M', modified),
2378 ('added', 'A', added),
2379 ('added', 'A', added),
2379 ('removed', 'R', removed),
2380 ('removed', 'R', removed),
2380 ('deleted', '!', deleted),
2381 ('deleted', '!', deleted),
2381 ('unknown', '?', unknown),
2382 ('unknown', '?', unknown),
2382 ('ignored', 'I', ignored))
2383 ('ignored', 'I', ignored))
2383
2384
2384 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2385 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2385
2386
2386 end = opts['print0'] and '\0' or '\n'
2387 end = opts['print0'] and '\0' or '\n'
2387
2388
2388 for opt, char, changes in ([ct for ct in explicit_changetypes
2389 for opt, char, changes in ([ct for ct in explicit_changetypes
2389 if all or opts[ct[0]]]
2390 if all or opts[ct[0]]]
2390 or changetypes):
2391 or changetypes):
2391 if opts['no_status']:
2392 if opts['no_status']:
2392 format = "%%s%s" % end
2393 format = "%%s%s" % end
2393 else:
2394 else:
2394 format = "%s %%s%s" % (char, end)
2395 format = "%s %%s%s" % (char, end)
2395
2396
2396 for f in changes:
2397 for f in changes:
2397 ui.write(format % f)
2398 ui.write(format % f)
2398 if ((all or opts.get('copies')) and not opts.get('no_status')):
2399 if ((all or opts.get('copies')) and not opts.get('no_status')):
2399 copied = repo.dirstate.copied(f)
2400 copied = repo.dirstate.copied(f)
2400 if copied:
2401 if copied:
2401 ui.write(' %s%s' % (copied, end))
2402 ui.write(' %s%s' % (copied, end))
2402
2403
2403 def tag(ui, repo, name, rev_=None, **opts):
2404 def tag(ui, repo, name, rev_=None, **opts):
2404 """add a tag for the current tip or a given revision
2405 """add a tag for the current tip or a given revision
2405
2406
2406 Name a particular revision using <name>.
2407 Name a particular revision using <name>.
2407
2408
2408 Tags are used to name particular revisions of the repository and are
2409 Tags are used to name particular revisions of the repository and are
2409 very useful to compare different revision, to go back to significant
2410 very useful to compare different revision, to go back to significant
2410 earlier versions or to mark branch points as releases, etc.
2411 earlier versions or to mark branch points as releases, etc.
2411
2412
2412 If no revision is given, the parent of the working directory is used.
2413 If no revision is given, the parent of the working directory is used.
2413
2414
2414 To facilitate version control, distribution, and merging of tags,
2415 To facilitate version control, distribution, and merging of tags,
2415 they are stored as a file named ".hgtags" which is managed
2416 they are stored as a file named ".hgtags" which is managed
2416 similarly to other project files and can be hand-edited if
2417 similarly to other project files and can be hand-edited if
2417 necessary. The file '.hg/localtags' is used for local tags (not
2418 necessary. The file '.hg/localtags' is used for local tags (not
2418 shared among repositories).
2419 shared among repositories).
2419 """
2420 """
2420 if name in ['tip', '.', 'null']:
2421 if name in ['tip', '.', 'null']:
2421 raise util.Abort(_("the name '%s' is reserved") % name)
2422 raise util.Abort(_("the name '%s' is reserved") % name)
2422 if rev_ is not None:
2423 if rev_ is not None:
2423 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2424 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2424 "please use 'hg tag [-r REV] NAME' instead\n"))
2425 "please use 'hg tag [-r REV] NAME' instead\n"))
2425 if opts['rev']:
2426 if opts['rev']:
2426 raise util.Abort(_("use only one form to specify the revision"))
2427 raise util.Abort(_("use only one form to specify the revision"))
2427 if opts['rev']:
2428 if opts['rev']:
2428 rev_ = opts['rev']
2429 rev_ = opts['rev']
2429 if not rev_ and repo.dirstate.parents()[1] != nullid:
2430 if not rev_ and repo.dirstate.parents()[1] != nullid:
2430 raise util.Abort(_('uncommitted merge - please provide a '
2431 raise util.Abort(_('uncommitted merge - please provide a '
2431 'specific revision'))
2432 'specific revision'))
2432 r = repo.changectx(rev_).node()
2433 r = repo.changectx(rev_).node()
2433
2434
2434 message = opts['message']
2435 message = opts['message']
2435 if not message:
2436 if not message:
2436 message = _('Added tag %s for changeset %s') % (name, short(r))
2437 message = _('Added tag %s for changeset %s') % (name, short(r))
2437
2438
2438 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2439 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2439
2440
2440 def tags(ui, repo):
2441 def tags(ui, repo):
2441 """list repository tags
2442 """list repository tags
2442
2443
2443 List the repository tags.
2444 List the repository tags.
2444
2445
2445 This lists both regular and local tags.
2446 This lists both regular and local tags.
2446 """
2447 """
2447
2448
2448 l = repo.tagslist()
2449 l = repo.tagslist()
2449 l.reverse()
2450 l.reverse()
2450 hexfunc = ui.debugflag and hex or short
2451 hexfunc = ui.debugflag and hex or short
2451 for t, n in l:
2452 for t, n in l:
2452 try:
2453 try:
2453 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2454 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2454 except KeyError:
2455 except KeyError:
2455 r = " ?:?"
2456 r = " ?:?"
2456 if ui.quiet:
2457 if ui.quiet:
2457 ui.write("%s\n" % t)
2458 ui.write("%s\n" % t)
2458 else:
2459 else:
2459 t = util.localsub(t, 30)
2460 t = util.localsub(t, 30)
2460 t += " " * (30 - util.locallen(t))
2461 t += " " * (30 - util.locallen(t))
2461 ui.write("%s %s\n" % (t, r))
2462 ui.write("%s %s\n" % (t, r))
2462
2463
2463 def tip(ui, repo, **opts):
2464 def tip(ui, repo, **opts):
2464 """show the tip revision
2465 """show the tip revision
2465
2466
2466 Show the tip revision.
2467 Show the tip revision.
2467 """
2468 """
2468 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2469 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2469
2470
2470 def unbundle(ui, repo, fname, **opts):
2471 def unbundle(ui, repo, fname, **opts):
2471 """apply a changegroup file
2472 """apply a changegroup file
2472
2473
2473 Apply a compressed changegroup file generated by the bundle
2474 Apply a compressed changegroup file generated by the bundle
2474 command.
2475 command.
2475 """
2476 """
2476 gen = changegroup.readbundle(urllib.urlopen(fname))
2477 gen = changegroup.readbundle(urllib.urlopen(fname))
2477 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2478 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2478 return postincoming(ui, repo, modheads, opts['update'])
2479 return postincoming(ui, repo, modheads, opts['update'])
2479
2480
2480 def update(ui, repo, node=None, clean=False, branch=None, date=None):
2481 def update(ui, repo, node=None, clean=False, branch=None, date=None):
2481 """update or merge working directory
2482 """update or merge working directory
2482
2483
2483 Update the working directory to the specified revision.
2484 Update the working directory to the specified revision.
2484
2485
2485 If there are no outstanding changes in the working directory and
2486 If there are no outstanding changes in the working directory and
2486 there is a linear relationship between the current version and the
2487 there is a linear relationship between the current version and the
2487 requested version, the result is the requested version.
2488 requested version, the result is the requested version.
2488
2489
2489 To merge the working directory with another revision, use the
2490 To merge the working directory with another revision, use the
2490 merge command.
2491 merge command.
2491
2492
2492 By default, update will refuse to run if doing so would require
2493 By default, update will refuse to run if doing so would require
2493 merging or discarding local changes.
2494 merging or discarding local changes.
2494 """
2495 """
2495 if date:
2496 if date:
2496 if node:
2497 if node:
2497 raise util.Abort(_("you can't specify a revision and a date"))
2498 raise util.Abort(_("you can't specify a revision and a date"))
2498 node = cmdutil.finddate(ui, repo, date)
2499 node = cmdutil.finddate(ui, repo, date)
2499
2500
2500 node = _lookup(repo, node, branch)
2501 node = _lookup(repo, node, branch)
2501 if clean:
2502 if clean:
2502 return hg.clean(repo, node)
2503 return hg.clean(repo, node)
2503 else:
2504 else:
2504 return hg.update(repo, node)
2505 return hg.update(repo, node)
2505
2506
2506 def _lookup(repo, node, branch=None):
2507 def _lookup(repo, node, branch=None):
2507 if branch:
2508 if branch:
2508 repo.ui.warn(_("the --branch option is deprecated, "
2509 repo.ui.warn(_("the --branch option is deprecated, "
2509 "please use 'hg branch' instead\n"))
2510 "please use 'hg branch' instead\n"))
2510 br = repo.branchlookup(branch=branch)
2511 br = repo.branchlookup(branch=branch)
2511 found = []
2512 found = []
2512 for x in br:
2513 for x in br:
2513 if branch in br[x]:
2514 if branch in br[x]:
2514 found.append(x)
2515 found.append(x)
2515 if len(found) > 1:
2516 if len(found) > 1:
2516 repo.ui.warn(_("Found multiple heads for %s\n") % branch)
2517 repo.ui.warn(_("Found multiple heads for %s\n") % branch)
2517 for x in found:
2518 for x in found:
2518 cmdutil.show_changeset(ui, repo, {}).show(changenode=x)
2519 cmdutil.show_changeset(ui, repo, {}).show(changenode=x)
2519 raise util.Abort("")
2520 raise util.Abort("")
2520 if len(found) == 1:
2521 if len(found) == 1:
2521 node = found[0]
2522 node = found[0]
2522 repo.ui.warn(_("Using head %s for branch %s\n")
2523 repo.ui.warn(_("Using head %s for branch %s\n")
2523 % (short(node), branch))
2524 % (short(node), branch))
2524 else:
2525 else:
2525 raise util.Abort(_("branch %s not found") % branch)
2526 raise util.Abort(_("branch %s not found") % branch)
2526 else:
2527 else:
2527 node = node and repo.lookup(node) or repo.changelog.tip()
2528 node = node and repo.lookup(node) or repo.changelog.tip()
2528 return node
2529 return node
2529
2530
2530 def verify(ui, repo):
2531 def verify(ui, repo):
2531 """verify the integrity of the repository
2532 """verify the integrity of the repository
2532
2533
2533 Verify the integrity of the current repository.
2534 Verify the integrity of the current repository.
2534
2535
2535 This will perform an extensive check of the repository's
2536 This will perform an extensive check of the repository's
2536 integrity, validating the hashes and checksums of each entry in
2537 integrity, validating the hashes and checksums of each entry in
2537 the changelog, manifest, and tracked files, as well as the
2538 the changelog, manifest, and tracked files, as well as the
2538 integrity of their crosslinks and indices.
2539 integrity of their crosslinks and indices.
2539 """
2540 """
2540 return hg.verify(repo)
2541 return hg.verify(repo)
2541
2542
2542 def version_(ui):
2543 def version_(ui):
2543 """output version and copyright information"""
2544 """output version and copyright information"""
2544 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2545 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2545 % version.get_version())
2546 % version.get_version())
2546 ui.status(_(
2547 ui.status(_(
2547 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
2548 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
2548 "This is free software; see the source for copying conditions. "
2549 "This is free software; see the source for copying conditions. "
2549 "There is NO\nwarranty; "
2550 "There is NO\nwarranty; "
2550 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2551 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2551 ))
2552 ))
2552
2553
2553 # Command options and aliases are listed here, alphabetically
2554 # Command options and aliases are listed here, alphabetically
2554
2555
2555 globalopts = [
2556 globalopts = [
2556 ('R', 'repository', '',
2557 ('R', 'repository', '',
2557 _('repository root directory or symbolic path name')),
2558 _('repository root directory or symbolic path name')),
2558 ('', 'cwd', '', _('change working directory')),
2559 ('', 'cwd', '', _('change working directory')),
2559 ('y', 'noninteractive', None,
2560 ('y', 'noninteractive', None,
2560 _('do not prompt, assume \'yes\' for any required answers')),
2561 _('do not prompt, assume \'yes\' for any required answers')),
2561 ('q', 'quiet', None, _('suppress output')),
2562 ('q', 'quiet', None, _('suppress output')),
2562 ('v', 'verbose', None, _('enable additional output')),
2563 ('v', 'verbose', None, _('enable additional output')),
2563 ('', 'config', [], _('set/override config option')),
2564 ('', 'config', [], _('set/override config option')),
2564 ('', 'debug', None, _('enable debugging output')),
2565 ('', 'debug', None, _('enable debugging output')),
2565 ('', 'debugger', None, _('start debugger')),
2566 ('', 'debugger', None, _('start debugger')),
2566 ('', 'encoding', util._encoding, _('set the charset encoding')),
2567 ('', 'encoding', util._encoding, _('set the charset encoding')),
2567 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2568 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2568 ('', 'lsprof', None, _('print improved command execution profile')),
2569 ('', 'lsprof', None, _('print improved command execution profile')),
2569 ('', 'traceback', None, _('print traceback on exception')),
2570 ('', 'traceback', None, _('print traceback on exception')),
2570 ('', 'time', None, _('time how long the command takes')),
2571 ('', 'time', None, _('time how long the command takes')),
2571 ('', 'profile', None, _('print command execution profile')),
2572 ('', 'profile', None, _('print command execution profile')),
2572 ('', 'version', None, _('output version information and exit')),
2573 ('', 'version', None, _('output version information and exit')),
2573 ('h', 'help', None, _('display help and exit')),
2574 ('h', 'help', None, _('display help and exit')),
2574 ]
2575 ]
2575
2576
2576 dryrunopts = [('n', 'dry-run', None,
2577 dryrunopts = [('n', 'dry-run', None,
2577 _('do not perform actions, just print output'))]
2578 _('do not perform actions, just print output'))]
2578
2579
2579 remoteopts = [
2580 remoteopts = [
2580 ('e', 'ssh', '', _('specify ssh command to use')),
2581 ('e', 'ssh', '', _('specify ssh command to use')),
2581 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2582 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2582 ]
2583 ]
2583
2584
2584 walkopts = [
2585 walkopts = [
2585 ('I', 'include', [], _('include names matching the given patterns')),
2586 ('I', 'include', [], _('include names matching the given patterns')),
2586 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2587 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2587 ]
2588 ]
2588
2589
2590 commitopts = [
2591 ('m', 'message', '', _('use <text> as commit message')),
2592 ('l', 'logfile', '', _('read commit message from <file>')),
2593 ]
2594
2589 table = {
2595 table = {
2590 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2596 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2591 "addremove":
2597 "addremove":
2592 (addremove,
2598 (addremove,
2593 [('s', 'similarity', '',
2599 [('s', 'similarity', '',
2594 _('guess renamed files by similarity (0<=s<=100)')),
2600 _('guess renamed files by similarity (0<=s<=100)')),
2595 ] + walkopts + dryrunopts,
2601 ] + walkopts + dryrunopts,
2596 _('hg addremove [OPTION]... [FILE]...')),
2602 _('hg addremove [OPTION]... [FILE]...')),
2597 "^annotate":
2603 "^annotate":
2598 (annotate,
2604 (annotate,
2599 [('r', 'rev', '', _('annotate the specified revision')),
2605 [('r', 'rev', '', _('annotate the specified revision')),
2600 ('f', 'follow', None, _('follow file copies and renames')),
2606 ('f', 'follow', None, _('follow file copies and renames')),
2601 ('a', 'text', None, _('treat all files as text')),
2607 ('a', 'text', None, _('treat all files as text')),
2602 ('u', 'user', None, _('list the author')),
2608 ('u', 'user', None, _('list the author')),
2603 ('d', 'date', None, _('list the date')),
2609 ('d', 'date', None, _('list the date')),
2604 ('n', 'number', None, _('list the revision number (default)')),
2610 ('n', 'number', None, _('list the revision number (default)')),
2605 ('c', 'changeset', None, _('list the changeset')),
2611 ('c', 'changeset', None, _('list the changeset')),
2606 ] + walkopts,
2612 ] + walkopts,
2607 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2613 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2608 "archive":
2614 "archive":
2609 (archive,
2615 (archive,
2610 [('', 'no-decode', None, _('do not pass files through decoders')),
2616 [('', 'no-decode', None, _('do not pass files through decoders')),
2611 ('p', 'prefix', '', _('directory prefix for files in archive')),
2617 ('p', 'prefix', '', _('directory prefix for files in archive')),
2612 ('r', 'rev', '', _('revision to distribute')),
2618 ('r', 'rev', '', _('revision to distribute')),
2613 ('t', 'type', '', _('type of distribution to create')),
2619 ('t', 'type', '', _('type of distribution to create')),
2614 ] + walkopts,
2620 ] + walkopts,
2615 _('hg archive [OPTION]... DEST')),
2621 _('hg archive [OPTION]... DEST')),
2616 "backout":
2622 "backout":
2617 (backout,
2623 (backout,
2618 [('', 'merge', None,
2624 [('', 'merge', None,
2619 _('merge with old dirstate parent after backout')),
2625 _('merge with old dirstate parent after backout')),
2620 ('m', 'message', '', _('use <text> as commit message')),
2621 ('l', 'logfile', '', _('read commit message from <file>')),
2622 ('d', 'date', '', _('record datecode as commit date')),
2626 ('d', 'date', '', _('record datecode as commit date')),
2623 ('', 'parent', '', _('parent to choose when backing out merge')),
2627 ('', 'parent', '', _('parent to choose when backing out merge')),
2624 ('u', 'user', '', _('record user as committer')),
2628 ('u', 'user', '', _('record user as committer')),
2625 ] + walkopts,
2629 ] + walkopts + commitopts,
2626 _('hg backout [OPTION]... REV')),
2630 _('hg backout [OPTION]... REV')),
2627 "branch": (branch, [], _('hg branch [NAME]')),
2631 "branch": (branch, [], _('hg branch [NAME]')),
2628 "branches": (branches, [], _('hg branches')),
2632 "branches": (branches, [], _('hg branches')),
2629 "bundle":
2633 "bundle":
2630 (bundle,
2634 (bundle,
2631 [('f', 'force', None,
2635 [('f', 'force', None,
2632 _('run even when remote repository is unrelated')),
2636 _('run even when remote repository is unrelated')),
2633 ('r', 'rev', [],
2637 ('r', 'rev', [],
2634 _('a changeset you would like to bundle')),
2638 _('a changeset you would like to bundle')),
2635 ('', 'base', [],
2639 ('', 'base', [],
2636 _('a base changeset to specify instead of a destination')),
2640 _('a base changeset to specify instead of a destination')),
2637 ] + remoteopts,
2641 ] + remoteopts,
2638 _('hg bundle [--base REV]... [--rev REV]... FILE [DEST]')),
2642 _('hg bundle [--base REV]... [--rev REV]... FILE [DEST]')),
2639 "cat":
2643 "cat":
2640 (cat,
2644 (cat,
2641 [('o', 'output', '', _('print output to file with formatted name')),
2645 [('o', 'output', '', _('print output to file with formatted name')),
2642 ('r', 'rev', '', _('print the given revision')),
2646 ('r', 'rev', '', _('print the given revision')),
2643 ] + walkopts,
2647 ] + walkopts,
2644 _('hg cat [OPTION]... FILE...')),
2648 _('hg cat [OPTION]... FILE...')),
2645 "^clone":
2649 "^clone":
2646 (clone,
2650 (clone,
2647 [('U', 'noupdate', None, _('do not update the new working directory')),
2651 [('U', 'noupdate', None, _('do not update the new working directory')),
2648 ('r', 'rev', [],
2652 ('r', 'rev', [],
2649 _('a changeset you would like to have after cloning')),
2653 _('a changeset you would like to have after cloning')),
2650 ('', 'pull', None, _('use pull protocol to copy metadata')),
2654 ('', 'pull', None, _('use pull protocol to copy metadata')),
2651 ('', 'uncompressed', None,
2655 ('', 'uncompressed', None,
2652 _('use uncompressed transfer (fast over LAN)')),
2656 _('use uncompressed transfer (fast over LAN)')),
2653 ] + remoteopts,
2657 ] + remoteopts,
2654 _('hg clone [OPTION]... SOURCE [DEST]')),
2658 _('hg clone [OPTION]... SOURCE [DEST]')),
2655 "^commit|ci":
2659 "^commit|ci":
2656 (commit,
2660 (commit,
2657 [('A', 'addremove', None,
2661 [('A', 'addremove', None,
2658 _('mark new/missing files as added/removed before committing')),
2662 _('mark new/missing files as added/removed before committing')),
2659 ('m', 'message', '', _('use <text> as commit message')),
2660 ('l', 'logfile', '', _('read the commit message from <file>')),
2661 ('d', 'date', '', _('record datecode as commit date')),
2663 ('d', 'date', '', _('record datecode as commit date')),
2662 ('u', 'user', '', _('record user as commiter')),
2664 ('u', 'user', '', _('record user as commiter')),
2663 ] + walkopts,
2665 ] + walkopts + commitopts,
2664 _('hg commit [OPTION]... [FILE]...')),
2666 _('hg commit [OPTION]... [FILE]...')),
2665 "copy|cp":
2667 "copy|cp":
2666 (copy,
2668 (copy,
2667 [('A', 'after', None, _('record a copy that has already occurred')),
2669 [('A', 'after', None, _('record a copy that has already occurred')),
2668 ('f', 'force', None,
2670 ('f', 'force', None,
2669 _('forcibly copy over an existing managed file')),
2671 _('forcibly copy over an existing managed file')),
2670 ] + walkopts + dryrunopts,
2672 ] + walkopts + dryrunopts,
2671 _('hg copy [OPTION]... [SOURCE]... DEST')),
2673 _('hg copy [OPTION]... [SOURCE]... DEST')),
2672 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2674 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2673 "debugcomplete":
2675 "debugcomplete":
2674 (debugcomplete,
2676 (debugcomplete,
2675 [('o', 'options', None, _('show the command options'))],
2677 [('o', 'options', None, _('show the command options'))],
2676 _('debugcomplete [-o] CMD')),
2678 _('debugcomplete [-o] CMD')),
2677 "debuginstall": (debuginstall, [], _('debuginstall')),
2679 "debuginstall": (debuginstall, [], _('debuginstall')),
2678 "debugrebuildstate":
2680 "debugrebuildstate":
2679 (debugrebuildstate,
2681 (debugrebuildstate,
2680 [('r', 'rev', '', _('revision to rebuild to'))],
2682 [('r', 'rev', '', _('revision to rebuild to'))],
2681 _('debugrebuildstate [-r REV] [REV]')),
2683 _('debugrebuildstate [-r REV] [REV]')),
2682 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2684 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2683 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2685 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2684 "debugstate": (debugstate, [], _('debugstate')),
2686 "debugstate": (debugstate, [], _('debugstate')),
2685 "debugdate":
2687 "debugdate":
2686 (debugdate,
2688 (debugdate,
2687 [('e', 'extended', None, _('try extended date formats'))],
2689 [('e', 'extended', None, _('try extended date formats'))],
2688 _('debugdate [-e] DATE [RANGE]')),
2690 _('debugdate [-e] DATE [RANGE]')),
2689 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2691 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2690 "debugindex": (debugindex, [], _('debugindex FILE')),
2692 "debugindex": (debugindex, [], _('debugindex FILE')),
2691 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2693 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2692 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2694 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2693 "debugwalk": (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2695 "debugwalk": (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2694 "^diff":
2696 "^diff":
2695 (diff,
2697 (diff,
2696 [('r', 'rev', [], _('revision')),
2698 [('r', 'rev', [], _('revision')),
2697 ('a', 'text', None, _('treat all files as text')),
2699 ('a', 'text', None, _('treat all files as text')),
2698 ('p', 'show-function', None,
2700 ('p', 'show-function', None,
2699 _('show which function each change is in')),
2701 _('show which function each change is in')),
2700 ('g', 'git', None, _('use git extended diff format')),
2702 ('g', 'git', None, _('use git extended diff format')),
2701 ('', 'nodates', None, _("don't include dates in diff headers")),
2703 ('', 'nodates', None, _("don't include dates in diff headers")),
2702 ('w', 'ignore-all-space', None,
2704 ('w', 'ignore-all-space', None,
2703 _('ignore white space when comparing lines')),
2705 _('ignore white space when comparing lines')),
2704 ('b', 'ignore-space-change', None,
2706 ('b', 'ignore-space-change', None,
2705 _('ignore changes in the amount of white space')),
2707 _('ignore changes in the amount of white space')),
2706 ('B', 'ignore-blank-lines', None,
2708 ('B', 'ignore-blank-lines', None,
2707 _('ignore changes whose lines are all blank')),
2709 _('ignore changes whose lines are all blank')),
2708 ] + walkopts,
2710 ] + walkopts,
2709 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2711 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2710 "^export":
2712 "^export":
2711 (export,
2713 (export,
2712 [('o', 'output', '', _('print output to file with formatted name')),
2714 [('o', 'output', '', _('print output to file with formatted name')),
2713 ('a', 'text', None, _('treat all files as text')),
2715 ('a', 'text', None, _('treat all files as text')),
2714 ('g', 'git', None, _('use git extended diff format')),
2716 ('g', 'git', None, _('use git extended diff format')),
2715 ('', 'nodates', None, _("don't include dates in diff headers")),
2717 ('', 'nodates', None, _("don't include dates in diff headers")),
2716 ('', 'switch-parent', None, _('diff against the second parent'))],
2718 ('', 'switch-parent', None, _('diff against the second parent'))],
2717 _('hg export [-a] [-o OUTFILESPEC] REV...')),
2719 _('hg export [-a] [-o OUTFILESPEC] REV...')),
2718 "grep":
2720 "grep":
2719 (grep,
2721 (grep,
2720 [('0', 'print0', None, _('end fields with NUL')),
2722 [('0', 'print0', None, _('end fields with NUL')),
2721 ('', 'all', None, _('print all revisions that match')),
2723 ('', 'all', None, _('print all revisions that match')),
2722 ('f', 'follow', None,
2724 ('f', 'follow', None,
2723 _('follow changeset history, or file history across copies and renames')),
2725 _('follow changeset history, or file history across copies and renames')),
2724 ('i', 'ignore-case', None, _('ignore case when matching')),
2726 ('i', 'ignore-case', None, _('ignore case when matching')),
2725 ('l', 'files-with-matches', None,
2727 ('l', 'files-with-matches', None,
2726 _('print only filenames and revs that match')),
2728 _('print only filenames and revs that match')),
2727 ('n', 'line-number', None, _('print matching line numbers')),
2729 ('n', 'line-number', None, _('print matching line numbers')),
2728 ('r', 'rev', [], _('search in given revision range')),
2730 ('r', 'rev', [], _('search in given revision range')),
2729 ('u', 'user', None, _('print user who committed change')),
2731 ('u', 'user', None, _('print user who committed change')),
2730 ] + walkopts,
2732 ] + walkopts,
2731 _('hg grep [OPTION]... PATTERN [FILE]...')),
2733 _('hg grep [OPTION]... PATTERN [FILE]...')),
2732 "heads":
2734 "heads":
2733 (heads,
2735 (heads,
2734 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2736 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2735 ('', 'style', '', _('display using template map file')),
2737 ('', 'style', '', _('display using template map file')),
2736 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2738 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2737 ('', 'template', '', _('display with template'))],
2739 ('', 'template', '', _('display with template'))],
2738 _('hg heads [-r REV]')),
2740 _('hg heads [-r REV]')),
2739 "help": (help_, [], _('hg help [COMMAND]')),
2741 "help": (help_, [], _('hg help [COMMAND]')),
2740 "identify|id": (identify, [], _('hg identify')),
2742 "identify|id": (identify, [], _('hg identify')),
2741 "import|patch":
2743 "import|patch":
2742 (import_,
2744 (import_,
2743 [('p', 'strip', 1,
2745 [('p', 'strip', 1,
2744 _('directory strip option for patch. This has the same\n'
2746 _('directory strip option for patch. This has the same\n'
2745 'meaning as the corresponding patch option')),
2747 'meaning as the corresponding patch option')),
2746 ('m', 'message', '', _('use <text> as commit message')),
2747 ('b', 'base', '', _('base path (DEPRECATED)')),
2748 ('b', 'base', '', _('base path (DEPRECATED)')),
2748 ('f', 'force', None,
2749 ('f', 'force', None,
2749 _('skip check for outstanding uncommitted changes'))],
2750 _('skip check for outstanding uncommitted changes'))] + commitopts,
2750 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2751 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2751 "incoming|in": (incoming,
2752 "incoming|in": (incoming,
2752 [('M', 'no-merges', None, _('do not show merges')),
2753 [('M', 'no-merges', None, _('do not show merges')),
2753 ('f', 'force', None,
2754 ('f', 'force', None,
2754 _('run even when remote repository is unrelated')),
2755 _('run even when remote repository is unrelated')),
2755 ('', 'style', '', _('display using template map file')),
2756 ('', 'style', '', _('display using template map file')),
2756 ('n', 'newest-first', None, _('show newest record first')),
2757 ('n', 'newest-first', None, _('show newest record first')),
2757 ('', 'bundle', '', _('file to store the bundles into')),
2758 ('', 'bundle', '', _('file to store the bundles into')),
2758 ('p', 'patch', None, _('show patch')),
2759 ('p', 'patch', None, _('show patch')),
2759 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2760 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2760 ('', 'template', '', _('display with template')),
2761 ('', 'template', '', _('display with template')),
2761 ] + remoteopts,
2762 ] + remoteopts,
2762 _('hg incoming [-p] [-n] [-M] [-r REV]...'
2763 _('hg incoming [-p] [-n] [-M] [-r REV]...'
2763 ' [--bundle FILENAME] [SOURCE]')),
2764 ' [--bundle FILENAME] [SOURCE]')),
2764 "^init":
2765 "^init":
2765 (init, remoteopts, _('hg init [-e FILE] [--remotecmd FILE] [DEST]')),
2766 (init, remoteopts, _('hg init [-e FILE] [--remotecmd FILE] [DEST]')),
2766 "locate":
2767 "locate":
2767 (locate,
2768 (locate,
2768 [('r', 'rev', '', _('search the repository as it stood at rev')),
2769 [('r', 'rev', '', _('search the repository as it stood at rev')),
2769 ('0', 'print0', None,
2770 ('0', 'print0', None,
2770 _('end filenames with NUL, for use with xargs')),
2771 _('end filenames with NUL, for use with xargs')),
2771 ('f', 'fullpath', None,
2772 ('f', 'fullpath', None,
2772 _('print complete paths from the filesystem root')),
2773 _('print complete paths from the filesystem root')),
2773 ] + walkopts,
2774 ] + walkopts,
2774 _('hg locate [OPTION]... [PATTERN]...')),
2775 _('hg locate [OPTION]... [PATTERN]...')),
2775 "^log|history":
2776 "^log|history":
2776 (log,
2777 (log,
2777 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2778 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2778 ('f', 'follow', None,
2779 ('f', 'follow', None,
2779 _('follow changeset history, or file history across copies and renames')),
2780 _('follow changeset history, or file history across copies and renames')),
2780 ('', 'follow-first', None,
2781 ('', 'follow-first', None,
2781 _('only follow the first parent of merge changesets')),
2782 _('only follow the first parent of merge changesets')),
2782 ('d', 'date', '', _('show revs matching date spec')),
2783 ('d', 'date', '', _('show revs matching date spec')),
2783 ('C', 'copies', None, _('show copied files')),
2784 ('C', 'copies', None, _('show copied files')),
2784 ('k', 'keyword', [], _('search for a keyword')),
2785 ('k', 'keyword', [], _('search for a keyword')),
2785 ('l', 'limit', '', _('limit number of changes displayed')),
2786 ('l', 'limit', '', _('limit number of changes displayed')),
2786 ('r', 'rev', [], _('show the specified revision or range')),
2787 ('r', 'rev', [], _('show the specified revision or range')),
2787 ('', 'removed', None, _('include revs where files were removed')),
2788 ('', 'removed', None, _('include revs where files were removed')),
2788 ('M', 'no-merges', None, _('do not show merges')),
2789 ('M', 'no-merges', None, _('do not show merges')),
2789 ('', 'style', '', _('display using template map file')),
2790 ('', 'style', '', _('display using template map file')),
2790 ('m', 'only-merges', None, _('show only merges')),
2791 ('m', 'only-merges', None, _('show only merges')),
2791 ('p', 'patch', None, _('show patch')),
2792 ('p', 'patch', None, _('show patch')),
2792 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2793 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2793 ('', 'template', '', _('display with template')),
2794 ('', 'template', '', _('display with template')),
2794 ] + walkopts,
2795 ] + walkopts,
2795 _('hg log [OPTION]... [FILE]')),
2796 _('hg log [OPTION]... [FILE]')),
2796 "manifest": (manifest, [], _('hg manifest [REV]')),
2797 "manifest": (manifest, [], _('hg manifest [REV]')),
2797 "merge":
2798 "merge":
2798 (merge,
2799 (merge,
2799 [('b', 'branch', '', _('merge with head of a specific branch (DEPRECATED)')),
2800 [('b', 'branch', '', _('merge with head of a specific branch (DEPRECATED)')),
2800 ('f', 'force', None, _('force a merge with outstanding changes'))],
2801 ('f', 'force', None, _('force a merge with outstanding changes'))],
2801 _('hg merge [-f] [REV]')),
2802 _('hg merge [-f] [REV]')),
2802 "outgoing|out": (outgoing,
2803 "outgoing|out": (outgoing,
2803 [('M', 'no-merges', None, _('do not show merges')),
2804 [('M', 'no-merges', None, _('do not show merges')),
2804 ('f', 'force', None,
2805 ('f', 'force', None,
2805 _('run even when remote repository is unrelated')),
2806 _('run even when remote repository is unrelated')),
2806 ('p', 'patch', None, _('show patch')),
2807 ('p', 'patch', None, _('show patch')),
2807 ('', 'style', '', _('display using template map file')),
2808 ('', 'style', '', _('display using template map file')),
2808 ('r', 'rev', [], _('a specific revision you would like to push')),
2809 ('r', 'rev', [], _('a specific revision you would like to push')),
2809 ('n', 'newest-first', None, _('show newest record first')),
2810 ('n', 'newest-first', None, _('show newest record first')),
2810 ('', 'template', '', _('display with template')),
2811 ('', 'template', '', _('display with template')),
2811 ] + remoteopts,
2812 ] + remoteopts,
2812 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
2813 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
2813 "^parents":
2814 "^parents":
2814 (parents,
2815 (parents,
2815 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2816 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2816 ('r', 'rev', '', _('show parents from the specified rev')),
2817 ('r', 'rev', '', _('show parents from the specified rev')),
2817 ('', 'style', '', _('display using template map file')),
2818 ('', 'style', '', _('display using template map file')),
2818 ('', 'template', '', _('display with template'))],
2819 ('', 'template', '', _('display with template'))],
2819 _('hg parents [-r REV] [FILE]')),
2820 _('hg parents [-r REV] [FILE]')),
2820 "paths": (paths, [], _('hg paths [NAME]')),
2821 "paths": (paths, [], _('hg paths [NAME]')),
2821 "^pull":
2822 "^pull":
2822 (pull,
2823 (pull,
2823 [('u', 'update', None,
2824 [('u', 'update', None,
2824 _('update to new tip if changesets were pulled')),
2825 _('update to new tip if changesets were pulled')),
2825 ('f', 'force', None,
2826 ('f', 'force', None,
2826 _('run even when remote repository is unrelated')),
2827 _('run even when remote repository is unrelated')),
2827 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2828 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2828 ] + remoteopts,
2829 ] + remoteopts,
2829 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
2830 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
2830 "^push":
2831 "^push":
2831 (push,
2832 (push,
2832 [('f', 'force', None, _('force push')),
2833 [('f', 'force', None, _('force push')),
2833 ('r', 'rev', [], _('a specific revision you would like to push')),
2834 ('r', 'rev', [], _('a specific revision you would like to push')),
2834 ] + remoteopts,
2835 ] + remoteopts,
2835 _('hg push [-f] [-r REV]... [-e FILE] [--remotecmd FILE] [DEST]')),
2836 _('hg push [-f] [-r REV]... [-e FILE] [--remotecmd FILE] [DEST]')),
2836 "debugrawcommit|rawcommit":
2837 "debugrawcommit|rawcommit":
2837 (rawcommit,
2838 (rawcommit,
2838 [('p', 'parent', [], _('parent')),
2839 [('p', 'parent', [], _('parent')),
2839 ('d', 'date', '', _('date code')),
2840 ('d', 'date', '', _('date code')),
2840 ('u', 'user', '', _('user')),
2841 ('u', 'user', '', _('user')),
2841 ('F', 'files', '', _('file list')),
2842 ('F', 'files', '', _('file list'))
2842 ('m', 'message', '', _('commit message')),
2843 ] + commitopts,
2843 ('l', 'logfile', '', _('commit message file'))],
2844 _('hg debugrawcommit [OPTION]... [FILE]...')),
2844 _('hg debugrawcommit [OPTION]... [FILE]...')),
2845 "recover": (recover, [], _('hg recover')),
2845 "recover": (recover, [], _('hg recover')),
2846 "^remove|rm":
2846 "^remove|rm":
2847 (remove,
2847 (remove,
2848 [('A', 'after', None, _('record remove that has already occurred')),
2848 [('A', 'after', None, _('record remove that has already occurred')),
2849 ('f', 'force', None, _('remove file even if modified')),
2849 ('f', 'force', None, _('remove file even if modified')),
2850 ] + walkopts,
2850 ] + walkopts,
2851 _('hg remove [OPTION]... FILE...')),
2851 _('hg remove [OPTION]... FILE...')),
2852 "rename|mv":
2852 "rename|mv":
2853 (rename,
2853 (rename,
2854 [('A', 'after', None, _('record a rename that has already occurred')),
2854 [('A', 'after', None, _('record a rename that has already occurred')),
2855 ('f', 'force', None,
2855 ('f', 'force', None,
2856 _('forcibly copy over an existing managed file')),
2856 _('forcibly copy over an existing managed file')),
2857 ] + walkopts + dryrunopts,
2857 ] + walkopts + dryrunopts,
2858 _('hg rename [OPTION]... SOURCE... DEST')),
2858 _('hg rename [OPTION]... SOURCE... DEST')),
2859 "^revert":
2859 "^revert":
2860 (revert,
2860 (revert,
2861 [('a', 'all', None, _('revert all changes when no arguments given')),
2861 [('a', 'all', None, _('revert all changes when no arguments given')),
2862 ('d', 'date', '', _('tipmost revision matching date')),
2862 ('d', 'date', '', _('tipmost revision matching date')),
2863 ('r', 'rev', '', _('revision to revert to')),
2863 ('r', 'rev', '', _('revision to revert to')),
2864 ('', 'no-backup', None, _('do not save backup copies of files')),
2864 ('', 'no-backup', None, _('do not save backup copies of files')),
2865 ] + walkopts + dryrunopts,
2865 ] + walkopts + dryrunopts,
2866 _('hg revert [-r REV] [NAME]...')),
2866 _('hg revert [-r REV] [NAME]...')),
2867 "rollback": (rollback, [], _('hg rollback')),
2867 "rollback": (rollback, [], _('hg rollback')),
2868 "root": (root, [], _('hg root')),
2868 "root": (root, [], _('hg root')),
2869 "showconfig|debugconfig":
2869 "showconfig|debugconfig":
2870 (showconfig,
2870 (showconfig,
2871 [('u', 'untrusted', None, _('show untrusted configuration options'))],
2871 [('u', 'untrusted', None, _('show untrusted configuration options'))],
2872 _('showconfig [-u] [NAME]...')),
2872 _('showconfig [-u] [NAME]...')),
2873 "^serve":
2873 "^serve":
2874 (serve,
2874 (serve,
2875 [('A', 'accesslog', '', _('name of access log file to write to')),
2875 [('A', 'accesslog', '', _('name of access log file to write to')),
2876 ('d', 'daemon', None, _('run server in background')),
2876 ('d', 'daemon', None, _('run server in background')),
2877 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2877 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2878 ('E', 'errorlog', '', _('name of error log file to write to')),
2878 ('E', 'errorlog', '', _('name of error log file to write to')),
2879 ('p', 'port', 0, _('port to use (default: 8000)')),
2879 ('p', 'port', 0, _('port to use (default: 8000)')),
2880 ('a', 'address', '', _('address to use')),
2880 ('a', 'address', '', _('address to use')),
2881 ('n', 'name', '',
2881 ('n', 'name', '',
2882 _('name to show in web pages (default: working dir)')),
2882 _('name to show in web pages (default: working dir)')),
2883 ('', 'webdir-conf', '', _('name of the webdir config file'
2883 ('', 'webdir-conf', '', _('name of the webdir config file'
2884 ' (serve more than one repo)')),
2884 ' (serve more than one repo)')),
2885 ('', 'pid-file', '', _('name of file to write process ID to')),
2885 ('', 'pid-file', '', _('name of file to write process ID to')),
2886 ('', 'stdio', None, _('for remote clients')),
2886 ('', 'stdio', None, _('for remote clients')),
2887 ('t', 'templates', '', _('web templates to use')),
2887 ('t', 'templates', '', _('web templates to use')),
2888 ('', 'style', '', _('template style to use')),
2888 ('', 'style', '', _('template style to use')),
2889 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2889 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2890 _('hg serve [OPTION]...')),
2890 _('hg serve [OPTION]...')),
2891 "^status|st":
2891 "^status|st":
2892 (status,
2892 (status,
2893 [('A', 'all', None, _('show status of all files')),
2893 [('A', 'all', None, _('show status of all files')),
2894 ('m', 'modified', None, _('show only modified files')),
2894 ('m', 'modified', None, _('show only modified files')),
2895 ('a', 'added', None, _('show only added files')),
2895 ('a', 'added', None, _('show only added files')),
2896 ('r', 'removed', None, _('show only removed files')),
2896 ('r', 'removed', None, _('show only removed files')),
2897 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2897 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2898 ('c', 'clean', None, _('show only files without changes')),
2898 ('c', 'clean', None, _('show only files without changes')),
2899 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2899 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2900 ('i', 'ignored', None, _('show ignored files')),
2900 ('i', 'ignored', None, _('show ignored files')),
2901 ('n', 'no-status', None, _('hide status prefix')),
2901 ('n', 'no-status', None, _('hide status prefix')),
2902 ('C', 'copies', None, _('show source of copied files')),
2902 ('C', 'copies', None, _('show source of copied files')),
2903 ('0', 'print0', None,
2903 ('0', 'print0', None,
2904 _('end filenames with NUL, for use with xargs')),
2904 _('end filenames with NUL, for use with xargs')),
2905 ('', 'rev', [], _('show difference from revision')),
2905 ('', 'rev', [], _('show difference from revision')),
2906 ] + walkopts,
2906 ] + walkopts,
2907 _('hg status [OPTION]... [FILE]...')),
2907 _('hg status [OPTION]... [FILE]...')),
2908 "tag":
2908 "tag":
2909 (tag,
2909 (tag,
2910 [('l', 'local', None, _('make the tag local')),
2910 [('l', 'local', None, _('make the tag local')),
2911 ('m', 'message', '', _('message for tag commit log entry')),
2911 ('m', 'message', '', _('message for tag commit log entry')),
2912 ('d', 'date', '', _('record datecode as commit date')),
2912 ('d', 'date', '', _('record datecode as commit date')),
2913 ('u', 'user', '', _('record user as commiter')),
2913 ('u', 'user', '', _('record user as commiter')),
2914 ('r', 'rev', '', _('revision to tag'))],
2914 ('r', 'rev', '', _('revision to tag'))],
2915 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
2915 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
2916 "tags": (tags, [], _('hg tags')),
2916 "tags": (tags, [], _('hg tags')),
2917 "tip":
2917 "tip":
2918 (tip,
2918 (tip,
2919 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2919 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2920 ('', 'style', '', _('display using template map file')),
2920 ('', 'style', '', _('display using template map file')),
2921 ('p', 'patch', None, _('show patch')),
2921 ('p', 'patch', None, _('show patch')),
2922 ('', 'template', '', _('display with template'))],
2922 ('', 'template', '', _('display with template'))],
2923 _('hg tip [-p]')),
2923 _('hg tip [-p]')),
2924 "unbundle":
2924 "unbundle":
2925 (unbundle,
2925 (unbundle,
2926 [('u', 'update', None,
2926 [('u', 'update', None,
2927 _('update to new tip if changesets were unbundled'))],
2927 _('update to new tip if changesets were unbundled'))],
2928 _('hg unbundle [-u] FILE')),
2928 _('hg unbundle [-u] FILE')),
2929 "^update|up|checkout|co":
2929 "^update|up|checkout|co":
2930 (update,
2930 (update,
2931 [('b', 'branch', '',
2931 [('b', 'branch', '',
2932 _('checkout the head of a specific branch (DEPRECATED)')),
2932 _('checkout the head of a specific branch (DEPRECATED)')),
2933 ('C', 'clean', None, _('overwrite locally modified files')),
2933 ('C', 'clean', None, _('overwrite locally modified files')),
2934 ('d', 'date', '', _('tipmost revision matching date'))],
2934 ('d', 'date', '', _('tipmost revision matching date'))],
2935 _('hg update [-C] [REV]')),
2935 _('hg update [-C] [REV]')),
2936 "verify": (verify, [], _('hg verify')),
2936 "verify": (verify, [], _('hg verify')),
2937 "version": (version_, [], _('hg version')),
2937 "version": (version_, [], _('hg version')),
2938 }
2938 }
2939
2939
2940 norepo = ("clone init version help debugancestor debugcomplete debugdata"
2940 norepo = ("clone init version help debugancestor debugcomplete debugdata"
2941 " debugindex debugindexdot debugdate debuginstall")
2941 " debugindex debugindexdot debugdate debuginstall")
2942 optionalrepo = ("paths serve showconfig")
2942 optionalrepo = ("paths serve showconfig")
2943
2943
2944 def findpossible(ui, cmd):
2944 def findpossible(ui, cmd):
2945 """
2945 """
2946 Return cmd -> (aliases, command table entry)
2946 Return cmd -> (aliases, command table entry)
2947 for each matching command.
2947 for each matching command.
2948 Return debug commands (or their aliases) only if no normal command matches.
2948 Return debug commands (or their aliases) only if no normal command matches.
2949 """
2949 """
2950 choice = {}
2950 choice = {}
2951 debugchoice = {}
2951 debugchoice = {}
2952 for e in table.keys():
2952 for e in table.keys():
2953 aliases = e.lstrip("^").split("|")
2953 aliases = e.lstrip("^").split("|")
2954 found = None
2954 found = None
2955 if cmd in aliases:
2955 if cmd in aliases:
2956 found = cmd
2956 found = cmd
2957 elif not ui.config("ui", "strict"):
2957 elif not ui.config("ui", "strict"):
2958 for a in aliases:
2958 for a in aliases:
2959 if a.startswith(cmd):
2959 if a.startswith(cmd):
2960 found = a
2960 found = a
2961 break
2961 break
2962 if found is not None:
2962 if found is not None:
2963 if aliases[0].startswith("debug") or found.startswith("debug"):
2963 if aliases[0].startswith("debug") or found.startswith("debug"):
2964 debugchoice[found] = (aliases, table[e])
2964 debugchoice[found] = (aliases, table[e])
2965 else:
2965 else:
2966 choice[found] = (aliases, table[e])
2966 choice[found] = (aliases, table[e])
2967
2967
2968 if not choice and debugchoice:
2968 if not choice and debugchoice:
2969 choice = debugchoice
2969 choice = debugchoice
2970
2970
2971 return choice
2971 return choice
2972
2972
2973 def findcmd(ui, cmd):
2973 def findcmd(ui, cmd):
2974 """Return (aliases, command table entry) for command string."""
2974 """Return (aliases, command table entry) for command string."""
2975 choice = findpossible(ui, cmd)
2975 choice = findpossible(ui, cmd)
2976
2976
2977 if choice.has_key(cmd):
2977 if choice.has_key(cmd):
2978 return choice[cmd]
2978 return choice[cmd]
2979
2979
2980 if len(choice) > 1:
2980 if len(choice) > 1:
2981 clist = choice.keys()
2981 clist = choice.keys()
2982 clist.sort()
2982 clist.sort()
2983 raise AmbiguousCommand(cmd, clist)
2983 raise AmbiguousCommand(cmd, clist)
2984
2984
2985 if choice:
2985 if choice:
2986 return choice.values()[0]
2986 return choice.values()[0]
2987
2987
2988 raise UnknownCommand(cmd)
2988 raise UnknownCommand(cmd)
2989
2989
2990 def catchterm(*args):
2990 def catchterm(*args):
2991 raise util.SignalInterrupt
2991 raise util.SignalInterrupt
2992
2992
2993 def run():
2993 def run():
2994 sys.exit(dispatch(sys.argv[1:]))
2994 sys.exit(dispatch(sys.argv[1:]))
2995
2995
2996 class ParseError(Exception):
2996 class ParseError(Exception):
2997 """Exception raised on errors in parsing the command line."""
2997 """Exception raised on errors in parsing the command line."""
2998
2998
2999 def parse(ui, args):
2999 def parse(ui, args):
3000 options = {}
3000 options = {}
3001 cmdoptions = {}
3001 cmdoptions = {}
3002
3002
3003 try:
3003 try:
3004 args = fancyopts.fancyopts(args, globalopts, options)
3004 args = fancyopts.fancyopts(args, globalopts, options)
3005 except fancyopts.getopt.GetoptError, inst:
3005 except fancyopts.getopt.GetoptError, inst:
3006 raise ParseError(None, inst)
3006 raise ParseError(None, inst)
3007
3007
3008 if args:
3008 if args:
3009 cmd, args = args[0], args[1:]
3009 cmd, args = args[0], args[1:]
3010 aliases, i = findcmd(ui, cmd)
3010 aliases, i = findcmd(ui, cmd)
3011 cmd = aliases[0]
3011 cmd = aliases[0]
3012 defaults = ui.config("defaults", cmd)
3012 defaults = ui.config("defaults", cmd)
3013 if defaults:
3013 if defaults:
3014 args = shlex.split(defaults) + args
3014 args = shlex.split(defaults) + args
3015 c = list(i[1])
3015 c = list(i[1])
3016 else:
3016 else:
3017 cmd = None
3017 cmd = None
3018 c = []
3018 c = []
3019
3019
3020 # combine global options into local
3020 # combine global options into local
3021 for o in globalopts:
3021 for o in globalopts:
3022 c.append((o[0], o[1], options[o[1]], o[3]))
3022 c.append((o[0], o[1], options[o[1]], o[3]))
3023
3023
3024 try:
3024 try:
3025 args = fancyopts.fancyopts(args, c, cmdoptions)
3025 args = fancyopts.fancyopts(args, c, cmdoptions)
3026 except fancyopts.getopt.GetoptError, inst:
3026 except fancyopts.getopt.GetoptError, inst:
3027 raise ParseError(cmd, inst)
3027 raise ParseError(cmd, inst)
3028
3028
3029 # separate global options back out
3029 # separate global options back out
3030 for o in globalopts:
3030 for o in globalopts:
3031 n = o[1]
3031 n = o[1]
3032 options[n] = cmdoptions[n]
3032 options[n] = cmdoptions[n]
3033 del cmdoptions[n]
3033 del cmdoptions[n]
3034
3034
3035 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3035 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3036
3036
3037 external = {}
3037 external = {}
3038
3038
3039 def findext(name):
3039 def findext(name):
3040 '''return module with given extension name'''
3040 '''return module with given extension name'''
3041 try:
3041 try:
3042 return sys.modules[external[name]]
3042 return sys.modules[external[name]]
3043 except KeyError:
3043 except KeyError:
3044 for k, v in external.iteritems():
3044 for k, v in external.iteritems():
3045 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3045 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3046 return sys.modules[v]
3046 return sys.modules[v]
3047 raise KeyError(name)
3047 raise KeyError(name)
3048
3048
3049 def load_extensions(ui):
3049 def load_extensions(ui):
3050 added = []
3050 added = []
3051 for ext_name, load_from_name in ui.extensions():
3051 for ext_name, load_from_name in ui.extensions():
3052 if ext_name in external:
3052 if ext_name in external:
3053 continue
3053 continue
3054 try:
3054 try:
3055 if load_from_name:
3055 if load_from_name:
3056 # the module will be loaded in sys.modules
3056 # the module will be loaded in sys.modules
3057 # choose an unique name so that it doesn't
3057 # choose an unique name so that it doesn't
3058 # conflicts with other modules
3058 # conflicts with other modules
3059 module_name = "hgext_%s" % ext_name.replace('.', '_')
3059 module_name = "hgext_%s" % ext_name.replace('.', '_')
3060 mod = imp.load_source(module_name, load_from_name)
3060 mod = imp.load_source(module_name, load_from_name)
3061 else:
3061 else:
3062 def importh(name):
3062 def importh(name):
3063 mod = __import__(name)
3063 mod = __import__(name)
3064 components = name.split('.')
3064 components = name.split('.')
3065 for comp in components[1:]:
3065 for comp in components[1:]:
3066 mod = getattr(mod, comp)
3066 mod = getattr(mod, comp)
3067 return mod
3067 return mod
3068 try:
3068 try:
3069 mod = importh("hgext.%s" % ext_name)
3069 mod = importh("hgext.%s" % ext_name)
3070 except ImportError:
3070 except ImportError:
3071 mod = importh(ext_name)
3071 mod = importh(ext_name)
3072 external[ext_name] = mod.__name__
3072 external[ext_name] = mod.__name__
3073 added.append((mod, ext_name))
3073 added.append((mod, ext_name))
3074 except (util.SignalInterrupt, KeyboardInterrupt):
3074 except (util.SignalInterrupt, KeyboardInterrupt):
3075 raise
3075 raise
3076 except Exception, inst:
3076 except Exception, inst:
3077 ui.warn(_("*** failed to import extension %s: %s\n") %
3077 ui.warn(_("*** failed to import extension %s: %s\n") %
3078 (ext_name, inst))
3078 (ext_name, inst))
3079 if ui.print_exc():
3079 if ui.print_exc():
3080 return 1
3080 return 1
3081
3081
3082 for mod, name in added:
3082 for mod, name in added:
3083 uisetup = getattr(mod, 'uisetup', None)
3083 uisetup = getattr(mod, 'uisetup', None)
3084 if uisetup:
3084 if uisetup:
3085 uisetup(ui)
3085 uisetup(ui)
3086 cmdtable = getattr(mod, 'cmdtable', {})
3086 cmdtable = getattr(mod, 'cmdtable', {})
3087 for t in cmdtable:
3087 for t in cmdtable:
3088 if t in table:
3088 if t in table:
3089 ui.warn(_("module %s overrides %s\n") % (name, t))
3089 ui.warn(_("module %s overrides %s\n") % (name, t))
3090 table.update(cmdtable)
3090 table.update(cmdtable)
3091
3091
3092 def parseconfig(config):
3092 def parseconfig(config):
3093 """parse the --config options from the command line"""
3093 """parse the --config options from the command line"""
3094 parsed = []
3094 parsed = []
3095 for cfg in config:
3095 for cfg in config:
3096 try:
3096 try:
3097 name, value = cfg.split('=', 1)
3097 name, value = cfg.split('=', 1)
3098 section, name = name.split('.', 1)
3098 section, name = name.split('.', 1)
3099 if not section or not name:
3099 if not section or not name:
3100 raise IndexError
3100 raise IndexError
3101 parsed.append((section, name, value))
3101 parsed.append((section, name, value))
3102 except (IndexError, ValueError):
3102 except (IndexError, ValueError):
3103 raise util.Abort(_('malformed --config option: %s') % cfg)
3103 raise util.Abort(_('malformed --config option: %s') % cfg)
3104 return parsed
3104 return parsed
3105
3105
3106 def dispatch(args):
3106 def dispatch(args):
3107 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3107 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3108 num = getattr(signal, name, None)
3108 num = getattr(signal, name, None)
3109 if num: signal.signal(num, catchterm)
3109 if num: signal.signal(num, catchterm)
3110
3110
3111 try:
3111 try:
3112 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3112 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3113 except util.Abort, inst:
3113 except util.Abort, inst:
3114 sys.stderr.write(_("abort: %s\n") % inst)
3114 sys.stderr.write(_("abort: %s\n") % inst)
3115 return -1
3115 return -1
3116
3116
3117 load_extensions(u)
3117 load_extensions(u)
3118 u.addreadhook(load_extensions)
3118 u.addreadhook(load_extensions)
3119
3119
3120 try:
3120 try:
3121 cmd, func, args, options, cmdoptions = parse(u, args)
3121 cmd, func, args, options, cmdoptions = parse(u, args)
3122 if options["encoding"]:
3122 if options["encoding"]:
3123 util._encoding = options["encoding"]
3123 util._encoding = options["encoding"]
3124 if options["encodingmode"]:
3124 if options["encodingmode"]:
3125 util._encodingmode = options["encodingmode"]
3125 util._encodingmode = options["encodingmode"]
3126 if options["time"]:
3126 if options["time"]:
3127 def get_times():
3127 def get_times():
3128 t = os.times()
3128 t = os.times()
3129 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3129 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3130 t = (t[0], t[1], t[2], t[3], time.clock())
3130 t = (t[0], t[1], t[2], t[3], time.clock())
3131 return t
3131 return t
3132 s = get_times()
3132 s = get_times()
3133 def print_time():
3133 def print_time():
3134 t = get_times()
3134 t = get_times()
3135 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3135 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3136 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3136 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3137 atexit.register(print_time)
3137 atexit.register(print_time)
3138
3138
3139 # enter the debugger before command execution
3139 # enter the debugger before command execution
3140 if options['debugger']:
3140 if options['debugger']:
3141 pdb.set_trace()
3141 pdb.set_trace()
3142
3142
3143 try:
3143 try:
3144 if options['cwd']:
3144 if options['cwd']:
3145 os.chdir(options['cwd'])
3145 os.chdir(options['cwd'])
3146
3146
3147 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3147 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3148 not options["noninteractive"], options["traceback"],
3148 not options["noninteractive"], options["traceback"],
3149 parseconfig(options["config"]))
3149 parseconfig(options["config"]))
3150
3150
3151 path = u.expandpath(options["repository"]) or ""
3151 path = u.expandpath(options["repository"]) or ""
3152 repo = path and hg.repository(u, path=path) or None
3152 repo = path and hg.repository(u, path=path) or None
3153 if repo and not repo.local():
3153 if repo and not repo.local():
3154 raise util.Abort(_("repository '%s' is not local") % path)
3154 raise util.Abort(_("repository '%s' is not local") % path)
3155
3155
3156 if options['help']:
3156 if options['help']:
3157 return help_(u, cmd, options['version'])
3157 return help_(u, cmd, options['version'])
3158 elif options['version']:
3158 elif options['version']:
3159 return version_(u)
3159 return version_(u)
3160 elif not cmd:
3160 elif not cmd:
3161 return help_(u, 'shortlist')
3161 return help_(u, 'shortlist')
3162
3162
3163 if cmd not in norepo.split():
3163 if cmd not in norepo.split():
3164 try:
3164 try:
3165 if not repo:
3165 if not repo:
3166 repo = hg.repository(u, path=path)
3166 repo = hg.repository(u, path=path)
3167 u = repo.ui
3167 u = repo.ui
3168 for name in external.itervalues():
3168 for name in external.itervalues():
3169 mod = sys.modules[name]
3169 mod = sys.modules[name]
3170 if hasattr(mod, 'reposetup'):
3170 if hasattr(mod, 'reposetup'):
3171 mod.reposetup(u, repo)
3171 mod.reposetup(u, repo)
3172 hg.repo_setup_hooks.append(mod.reposetup)
3172 hg.repo_setup_hooks.append(mod.reposetup)
3173 except hg.RepoError:
3173 except hg.RepoError:
3174 if cmd not in optionalrepo.split():
3174 if cmd not in optionalrepo.split():
3175 raise
3175 raise
3176 d = lambda: func(u, repo, *args, **cmdoptions)
3176 d = lambda: func(u, repo, *args, **cmdoptions)
3177 else:
3177 else:
3178 d = lambda: func(u, *args, **cmdoptions)
3178 d = lambda: func(u, *args, **cmdoptions)
3179
3179
3180 try:
3180 try:
3181 if options['profile']:
3181 if options['profile']:
3182 import hotshot, hotshot.stats
3182 import hotshot, hotshot.stats
3183 prof = hotshot.Profile("hg.prof")
3183 prof = hotshot.Profile("hg.prof")
3184 try:
3184 try:
3185 try:
3185 try:
3186 return prof.runcall(d)
3186 return prof.runcall(d)
3187 except:
3187 except:
3188 try:
3188 try:
3189 u.warn(_('exception raised - generating '
3189 u.warn(_('exception raised - generating '
3190 'profile anyway\n'))
3190 'profile anyway\n'))
3191 except:
3191 except:
3192 pass
3192 pass
3193 raise
3193 raise
3194 finally:
3194 finally:
3195 prof.close()
3195 prof.close()
3196 stats = hotshot.stats.load("hg.prof")
3196 stats = hotshot.stats.load("hg.prof")
3197 stats.strip_dirs()
3197 stats.strip_dirs()
3198 stats.sort_stats('time', 'calls')
3198 stats.sort_stats('time', 'calls')
3199 stats.print_stats(40)
3199 stats.print_stats(40)
3200 elif options['lsprof']:
3200 elif options['lsprof']:
3201 try:
3201 try:
3202 from mercurial import lsprof
3202 from mercurial import lsprof
3203 except ImportError:
3203 except ImportError:
3204 raise util.Abort(_(
3204 raise util.Abort(_(
3205 'lsprof not available - install from '
3205 'lsprof not available - install from '
3206 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3206 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3207 p = lsprof.Profiler()
3207 p = lsprof.Profiler()
3208 p.enable(subcalls=True)
3208 p.enable(subcalls=True)
3209 try:
3209 try:
3210 return d()
3210 return d()
3211 finally:
3211 finally:
3212 p.disable()
3212 p.disable()
3213 stats = lsprof.Stats(p.getstats())
3213 stats = lsprof.Stats(p.getstats())
3214 stats.sort()
3214 stats.sort()
3215 stats.pprint(top=10, file=sys.stderr, climit=5)
3215 stats.pprint(top=10, file=sys.stderr, climit=5)
3216 else:
3216 else:
3217 return d()
3217 return d()
3218 finally:
3218 finally:
3219 u.flush()
3219 u.flush()
3220 except:
3220 except:
3221 # enter the debugger when we hit an exception
3221 # enter the debugger when we hit an exception
3222 if options['debugger']:
3222 if options['debugger']:
3223 pdb.post_mortem(sys.exc_info()[2])
3223 pdb.post_mortem(sys.exc_info()[2])
3224 u.print_exc()
3224 u.print_exc()
3225 raise
3225 raise
3226 except ParseError, inst:
3226 except ParseError, inst:
3227 if inst.args[0]:
3227 if inst.args[0]:
3228 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3228 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3229 help_(u, inst.args[0])
3229 help_(u, inst.args[0])
3230 else:
3230 else:
3231 u.warn(_("hg: %s\n") % inst.args[1])
3231 u.warn(_("hg: %s\n") % inst.args[1])
3232 help_(u, 'shortlist')
3232 help_(u, 'shortlist')
3233 except AmbiguousCommand, inst:
3233 except AmbiguousCommand, inst:
3234 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3234 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3235 (inst.args[0], " ".join(inst.args[1])))
3235 (inst.args[0], " ".join(inst.args[1])))
3236 except UnknownCommand, inst:
3236 except UnknownCommand, inst:
3237 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3237 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3238 help_(u, 'shortlist')
3238 help_(u, 'shortlist')
3239 except hg.RepoError, inst:
3239 except hg.RepoError, inst:
3240 u.warn(_("abort: %s!\n") % inst)
3240 u.warn(_("abort: %s!\n") % inst)
3241 except lock.LockHeld, inst:
3241 except lock.LockHeld, inst:
3242 if inst.errno == errno.ETIMEDOUT:
3242 if inst.errno == errno.ETIMEDOUT:
3243 reason = _('timed out waiting for lock held by %s') % inst.locker
3243 reason = _('timed out waiting for lock held by %s') % inst.locker
3244 else:
3244 else:
3245 reason = _('lock held by %s') % inst.locker
3245 reason = _('lock held by %s') % inst.locker
3246 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3246 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3247 except lock.LockUnavailable, inst:
3247 except lock.LockUnavailable, inst:
3248 u.warn(_("abort: could not lock %s: %s\n") %
3248 u.warn(_("abort: could not lock %s: %s\n") %
3249 (inst.desc or inst.filename, inst.strerror))
3249 (inst.desc or inst.filename, inst.strerror))
3250 except revlog.RevlogError, inst:
3250 except revlog.RevlogError, inst:
3251 u.warn(_("abort: %s!\n") % inst)
3251 u.warn(_("abort: %s!\n") % inst)
3252 except util.SignalInterrupt:
3252 except util.SignalInterrupt:
3253 u.warn(_("killed!\n"))
3253 u.warn(_("killed!\n"))
3254 except KeyboardInterrupt:
3254 except KeyboardInterrupt:
3255 try:
3255 try:
3256 u.warn(_("interrupted!\n"))
3256 u.warn(_("interrupted!\n"))
3257 except IOError, inst:
3257 except IOError, inst:
3258 if inst.errno == errno.EPIPE:
3258 if inst.errno == errno.EPIPE:
3259 if u.debugflag:
3259 if u.debugflag:
3260 u.warn(_("\nbroken pipe\n"))
3260 u.warn(_("\nbroken pipe\n"))
3261 else:
3261 else:
3262 raise
3262 raise
3263 except IOError, inst:
3263 except IOError, inst:
3264 if hasattr(inst, "code"):
3264 if hasattr(inst, "code"):
3265 u.warn(_("abort: %s\n") % inst)
3265 u.warn(_("abort: %s\n") % inst)
3266 elif hasattr(inst, "reason"):
3266 elif hasattr(inst, "reason"):
3267 u.warn(_("abort: error: %s\n") % inst.reason[1])
3267 u.warn(_("abort: error: %s\n") % inst.reason[1])
3268 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3268 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3269 if u.debugflag:
3269 if u.debugflag:
3270 u.warn(_("broken pipe\n"))
3270 u.warn(_("broken pipe\n"))
3271 elif getattr(inst, "strerror", None):
3271 elif getattr(inst, "strerror", None):
3272 if getattr(inst, "filename", None):
3272 if getattr(inst, "filename", None):
3273 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3273 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3274 else:
3274 else:
3275 u.warn(_("abort: %s\n") % inst.strerror)
3275 u.warn(_("abort: %s\n") % inst.strerror)
3276 else:
3276 else:
3277 raise
3277 raise
3278 except OSError, inst:
3278 except OSError, inst:
3279 if getattr(inst, "filename", None):
3279 if getattr(inst, "filename", None):
3280 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3280 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3281 else:
3281 else:
3282 u.warn(_("abort: %s\n") % inst.strerror)
3282 u.warn(_("abort: %s\n") % inst.strerror)
3283 except util.UnexpectedOutput, inst:
3283 except util.UnexpectedOutput, inst:
3284 u.warn(_("abort: %s") % inst[0])
3284 u.warn(_("abort: %s") % inst[0])
3285 if not isinstance(inst[1], basestring):
3285 if not isinstance(inst[1], basestring):
3286 u.warn(" %r\n" % (inst[1],))
3286 u.warn(" %r\n" % (inst[1],))
3287 elif not inst[1]:
3287 elif not inst[1]:
3288 u.warn(_(" empty string\n"))
3288 u.warn(_(" empty string\n"))
3289 else:
3289 else:
3290 u.warn("\n%r\n" % util.ellipsis(inst[1]))
3290 u.warn("\n%r\n" % util.ellipsis(inst[1]))
3291 except util.Abort, inst:
3291 except util.Abort, inst:
3292 u.warn(_("abort: %s\n") % inst)
3292 u.warn(_("abort: %s\n") % inst)
3293 except TypeError, inst:
3293 except TypeError, inst:
3294 # was this an argument error?
3294 # was this an argument error?
3295 tb = traceback.extract_tb(sys.exc_info()[2])
3295 tb = traceback.extract_tb(sys.exc_info()[2])
3296 if len(tb) > 2: # no
3296 if len(tb) > 2: # no
3297 raise
3297 raise
3298 u.debug(inst, "\n")
3298 u.debug(inst, "\n")
3299 u.warn(_("%s: invalid arguments\n") % cmd)
3299 u.warn(_("%s: invalid arguments\n") % cmd)
3300 help_(u, cmd)
3300 help_(u, cmd)
3301 except SystemExit, inst:
3301 except SystemExit, inst:
3302 # Commands shouldn't sys.exit directly, but give a return code.
3302 # Commands shouldn't sys.exit directly, but give a return code.
3303 # Just in case catch this and and pass exit code to caller.
3303 # Just in case catch this and and pass exit code to caller.
3304 return inst.code
3304 return inst.code
3305 except:
3305 except:
3306 u.warn(_("** unknown exception encountered, details follow\n"))
3306 u.warn(_("** unknown exception encountered, details follow\n"))
3307 u.warn(_("** report bug details to "
3307 u.warn(_("** report bug details to "
3308 "http://www.selenic.com/mercurial/bts\n"))
3308 "http://www.selenic.com/mercurial/bts\n"))
3309 u.warn(_("** or mercurial@selenic.com\n"))
3309 u.warn(_("** or mercurial@selenic.com\n"))
3310 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3310 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3311 % version.get_version())
3311 % version.get_version())
3312 raise
3312 raise
3313
3313
3314 return -1
3314 return -1
General Comments 0
You need to be logged in to leave comments. Login now