##// END OF EJS Templates
dispatch: move dispatching code to cmdutil
Matt Mackall -
r4549:0c61124a default
parent child Browse files
Show More
@@ -1,98 +1,98 b''
1 # fetch.py - pull and merge remote changes
1 # fetch.py - pull and merge remote changes
2 #
2 #
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.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 mercurial.i18n import _
8 from mercurial.i18n import _
9 from mercurial.node import *
9 from mercurial.node import *
10 from mercurial import commands, hg, node, util
10 from mercurial import commands, cmdutil, hg, node, util
11
11
12 def fetch(ui, repo, source='default', **opts):
12 def fetch(ui, repo, source='default', **opts):
13 '''Pull changes from a remote repository, merge new changes if needed.
13 '''Pull changes from a remote repository, merge new changes if needed.
14
14
15 This finds all changes from the repository at the specified path
15 This finds all changes from the repository at the specified path
16 or URL and adds them to the local repository.
16 or URL and adds them to the local repository.
17
17
18 If the pulled changes add a new head, the head is automatically
18 If the pulled changes add a new head, the head is automatically
19 merged, and the result of the merge is committed. Otherwise, the
19 merged, and the result of the merge is committed. Otherwise, the
20 working directory is updated.'''
20 working directory is updated.'''
21
21
22 def postincoming(other, modheads):
22 def postincoming(other, modheads):
23 if modheads == 0:
23 if modheads == 0:
24 return 0
24 return 0
25 if modheads == 1:
25 if modheads == 1:
26 return hg.clean(repo, repo.changelog.tip(), wlock=wlock)
26 return hg.clean(repo, repo.changelog.tip(), wlock=wlock)
27 newheads = repo.heads(parent)
27 newheads = repo.heads(parent)
28 newchildren = [n for n in repo.heads(parent) if n != parent]
28 newchildren = [n for n in repo.heads(parent) if n != parent]
29 newparent = parent
29 newparent = parent
30 if newchildren:
30 if newchildren:
31 newparent = newchildren[0]
31 newparent = newchildren[0]
32 hg.clean(repo, newparent, wlock=wlock)
32 hg.clean(repo, newparent, wlock=wlock)
33 newheads = [n for n in repo.heads() if n != newparent]
33 newheads = [n for n in repo.heads() if n != newparent]
34 err = False
34 err = False
35 if newheads:
35 if newheads:
36 ui.status(_('merging with new head %d:%s\n') %
36 ui.status(_('merging with new head %d:%s\n') %
37 (repo.changelog.rev(newheads[0]), short(newheads[0])))
37 (repo.changelog.rev(newheads[0]), short(newheads[0])))
38 err = hg.merge(repo, newheads[0], remind=False, wlock=wlock)
38 err = hg.merge(repo, newheads[0], remind=False, wlock=wlock)
39 if not err and len(newheads) > 1:
39 if not err and len(newheads) > 1:
40 ui.status(_('not merging with %d other new heads '
40 ui.status(_('not merging with %d other new heads '
41 '(use "hg heads" and "hg merge" to merge them)') %
41 '(use "hg heads" and "hg merge" to merge them)') %
42 (len(newheads) - 1))
42 (len(newheads) - 1))
43 if not err:
43 if not err:
44 mod, add, rem = repo.status(wlock=wlock)[:3]
44 mod, add, rem = repo.status(wlock=wlock)[:3]
45 message = (commands.logmessage(opts) or
45 message = (cmdutil.logmessage(opts) or
46 (_('Automated merge with %s') % other.url()))
46 (_('Automated merge with %s') % other.url()))
47 n = repo.commit(mod + add + rem, message,
47 n = repo.commit(mod + add + rem, message,
48 opts['user'], opts['date'], lock=lock, wlock=wlock,
48 opts['user'], opts['date'], lock=lock, wlock=wlock,
49 force_editor=opts.get('force_editor'))
49 force_editor=opts.get('force_editor'))
50 ui.status(_('new changeset %d:%s merges remote changes '
50 ui.status(_('new changeset %d:%s merges remote changes '
51 'with local\n') % (repo.changelog.rev(n),
51 'with local\n') % (repo.changelog.rev(n),
52 short(n)))
52 short(n)))
53 def pull():
53 def pull():
54 commands.setremoteconfig(ui, opts)
54 cmdutil.setremoteconfig(ui, opts)
55
55
56 other = hg.repository(ui, ui.expandpath(source))
56 other = hg.repository(ui, ui.expandpath(source))
57 ui.status(_('pulling from %s\n') % ui.expandpath(source))
57 ui.status(_('pulling from %s\n') % ui.expandpath(source))
58 revs = None
58 revs = None
59 if opts['rev'] and not other.local():
59 if opts['rev'] and not other.local():
60 raise util.Abort(_("fetch -r doesn't work for remote repositories yet"))
60 raise util.Abort(_("fetch -r doesn't work for remote repositories yet"))
61 elif opts['rev']:
61 elif opts['rev']:
62 revs = [other.lookup(rev) for rev in opts['rev']]
62 revs = [other.lookup(rev) for rev in opts['rev']]
63 modheads = repo.pull(other, heads=revs, lock=lock)
63 modheads = repo.pull(other, heads=revs, lock=lock)
64 return postincoming(other, modheads)
64 return postincoming(other, modheads)
65
65
66 parent, p2 = repo.dirstate.parents()
66 parent, p2 = repo.dirstate.parents()
67 if parent != repo.changelog.tip():
67 if parent != repo.changelog.tip():
68 raise util.Abort(_('working dir not at tip '
68 raise util.Abort(_('working dir not at tip '
69 '(use "hg update" to check out tip)'))
69 '(use "hg update" to check out tip)'))
70 if p2 != nullid:
70 if p2 != nullid:
71 raise util.Abort(_('outstanding uncommitted merge'))
71 raise util.Abort(_('outstanding uncommitted merge'))
72 wlock = repo.wlock()
72 wlock = repo.wlock()
73 lock = repo.lock()
73 lock = repo.lock()
74 try:
74 try:
75 mod, add, rem = repo.status(wlock=wlock)[:3]
75 mod, add, rem = repo.status(wlock=wlock)[:3]
76 if mod or add or rem:
76 if mod or add or rem:
77 raise util.Abort(_('outstanding uncommitted changes'))
77 raise util.Abort(_('outstanding uncommitted changes'))
78 if len(repo.heads()) > 1:
78 if len(repo.heads()) > 1:
79 raise util.Abort(_('multiple heads in this repository '
79 raise util.Abort(_('multiple heads in this repository '
80 '(use "hg heads" and "hg merge" to merge)'))
80 '(use "hg heads" and "hg merge" to merge)'))
81 return pull()
81 return pull()
82 finally:
82 finally:
83 lock.release()
83 lock.release()
84 wlock.release()
84 wlock.release()
85
85
86 cmdtable = {
86 cmdtable = {
87 'fetch':
87 'fetch':
88 (fetch,
88 (fetch,
89 [('e', 'ssh', '', _('specify ssh command to use')),
89 [('e', 'ssh', '', _('specify ssh command to use')),
90 ('m', 'message', '', _('use <text> as commit message')),
90 ('m', 'message', '', _('use <text> as commit message')),
91 ('l', 'logfile', '', _('read the commit message from <file>')),
91 ('l', 'logfile', '', _('read the commit message from <file>')),
92 ('d', 'date', '', _('record datecode as commit date')),
92 ('d', 'date', '', _('record datecode as commit date')),
93 ('u', 'user', '', _('record user as commiter')),
93 ('u', 'user', '', _('record user as commiter')),
94 ('r', 'rev', [], _('a specific revision you would like to pull')),
94 ('r', 'rev', [], _('a specific revision you would like to pull')),
95 ('f', 'force-editor', None, _('edit commit message')),
95 ('f', 'force-editor', None, _('edit commit message')),
96 ('', 'remotecmd', '', _('hg command to run on the remote side'))],
96 ('', 'remotecmd', '', _('hg command to run on the remote side'))],
97 'hg fetch [SOURCE]'),
97 'hg fetch [SOURCE]'),
98 }
98 }
@@ -1,2300 +1,2300 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.i18n import _
32 from mercurial.i18n import _
33 from mercurial import commands, cmdutil, hg, patch, revlog, util, changegroup
33 from mercurial import commands, cmdutil, hg, patch, revlog, util, changegroup
34 import os, sys, re, errno
34 import os, sys, re, errno
35
35
36 commands.norepo += " qclone qversion"
36 commands.norepo += " qclone qversion"
37
37
38 # Patch names looks like unix-file names.
38 # Patch names looks like unix-file names.
39 # They must be joinable with queue directory and result in the patch path.
39 # They must be joinable with queue directory and result in the patch path.
40 normname = util.normpath
40 normname = util.normpath
41
41
42 class statusentry:
42 class statusentry:
43 def __init__(self, rev, name=None):
43 def __init__(self, rev, name=None):
44 if not name:
44 if not name:
45 fields = rev.split(':', 1)
45 fields = rev.split(':', 1)
46 if len(fields) == 2:
46 if len(fields) == 2:
47 self.rev, self.name = fields
47 self.rev, self.name = fields
48 else:
48 else:
49 self.rev, self.name = None, None
49 self.rev, self.name = None, None
50 else:
50 else:
51 self.rev, self.name = rev, name
51 self.rev, self.name = rev, name
52
52
53 def __str__(self):
53 def __str__(self):
54 return self.rev + ':' + self.name
54 return self.rev + ':' + self.name
55
55
56 class queue:
56 class queue:
57 def __init__(self, ui, path, patchdir=None):
57 def __init__(self, ui, path, patchdir=None):
58 self.basepath = path
58 self.basepath = path
59 self.path = patchdir or os.path.join(path, "patches")
59 self.path = patchdir or os.path.join(path, "patches")
60 self.opener = util.opener(self.path)
60 self.opener = util.opener(self.path)
61 self.ui = ui
61 self.ui = ui
62 self.applied = []
62 self.applied = []
63 self.full_series = []
63 self.full_series = []
64 self.applied_dirty = 0
64 self.applied_dirty = 0
65 self.series_dirty = 0
65 self.series_dirty = 0
66 self.series_path = "series"
66 self.series_path = "series"
67 self.status_path = "status"
67 self.status_path = "status"
68 self.guards_path = "guards"
68 self.guards_path = "guards"
69 self.active_guards = None
69 self.active_guards = None
70 self.guards_dirty = False
70 self.guards_dirty = False
71 self._diffopts = None
71 self._diffopts = None
72
72
73 if os.path.exists(self.join(self.series_path)):
73 if os.path.exists(self.join(self.series_path)):
74 self.full_series = self.opener(self.series_path).read().splitlines()
74 self.full_series = self.opener(self.series_path).read().splitlines()
75 self.parse_series()
75 self.parse_series()
76
76
77 if os.path.exists(self.join(self.status_path)):
77 if os.path.exists(self.join(self.status_path)):
78 lines = self.opener(self.status_path).read().splitlines()
78 lines = self.opener(self.status_path).read().splitlines()
79 self.applied = [statusentry(l) for l in lines]
79 self.applied = [statusentry(l) for l in lines]
80
80
81 def diffopts(self):
81 def diffopts(self):
82 if self._diffopts is None:
82 if self._diffopts is None:
83 self._diffopts = patch.diffopts(self.ui)
83 self._diffopts = patch.diffopts(self.ui)
84 return self._diffopts
84 return self._diffopts
85
85
86 def join(self, *p):
86 def join(self, *p):
87 return os.path.join(self.path, *p)
87 return os.path.join(self.path, *p)
88
88
89 def find_series(self, patch):
89 def find_series(self, patch):
90 pre = re.compile("(\s*)([^#]+)")
90 pre = re.compile("(\s*)([^#]+)")
91 index = 0
91 index = 0
92 for l in self.full_series:
92 for l in self.full_series:
93 m = pre.match(l)
93 m = pre.match(l)
94 if m:
94 if m:
95 s = m.group(2)
95 s = m.group(2)
96 s = s.rstrip()
96 s = s.rstrip()
97 if s == patch:
97 if s == patch:
98 return index
98 return index
99 index += 1
99 index += 1
100 return None
100 return None
101
101
102 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
102 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
103
103
104 def parse_series(self):
104 def parse_series(self):
105 self.series = []
105 self.series = []
106 self.series_guards = []
106 self.series_guards = []
107 for l in self.full_series:
107 for l in self.full_series:
108 h = l.find('#')
108 h = l.find('#')
109 if h == -1:
109 if h == -1:
110 patch = l
110 patch = l
111 comment = ''
111 comment = ''
112 elif h == 0:
112 elif h == 0:
113 continue
113 continue
114 else:
114 else:
115 patch = l[:h]
115 patch = l[:h]
116 comment = l[h:]
116 comment = l[h:]
117 patch = patch.strip()
117 patch = patch.strip()
118 if patch:
118 if patch:
119 if patch in self.series:
119 if patch in self.series:
120 raise util.Abort(_('%s appears more than once in %s') %
120 raise util.Abort(_('%s appears more than once in %s') %
121 (patch, self.join(self.series_path)))
121 (patch, self.join(self.series_path)))
122 self.series.append(patch)
122 self.series.append(patch)
123 self.series_guards.append(self.guard_re.findall(comment))
123 self.series_guards.append(self.guard_re.findall(comment))
124
124
125 def check_guard(self, guard):
125 def check_guard(self, guard):
126 bad_chars = '# \t\r\n\f'
126 bad_chars = '# \t\r\n\f'
127 first = guard[0]
127 first = guard[0]
128 for c in '-+':
128 for c in '-+':
129 if first == c:
129 if first == c:
130 return (_('guard %r starts with invalid character: %r') %
130 return (_('guard %r starts with invalid character: %r') %
131 (guard, c))
131 (guard, c))
132 for c in bad_chars:
132 for c in bad_chars:
133 if c in guard:
133 if c in guard:
134 return _('invalid character in guard %r: %r') % (guard, c)
134 return _('invalid character in guard %r: %r') % (guard, c)
135
135
136 def set_active(self, guards):
136 def set_active(self, guards):
137 for guard in guards:
137 for guard in guards:
138 bad = self.check_guard(guard)
138 bad = self.check_guard(guard)
139 if bad:
139 if bad:
140 raise util.Abort(bad)
140 raise util.Abort(bad)
141 guards = dict.fromkeys(guards).keys()
141 guards = dict.fromkeys(guards).keys()
142 guards.sort()
142 guards.sort()
143 self.ui.debug('active guards: %s\n' % ' '.join(guards))
143 self.ui.debug('active guards: %s\n' % ' '.join(guards))
144 self.active_guards = guards
144 self.active_guards = guards
145 self.guards_dirty = True
145 self.guards_dirty = True
146
146
147 def active(self):
147 def active(self):
148 if self.active_guards is None:
148 if self.active_guards is None:
149 self.active_guards = []
149 self.active_guards = []
150 try:
150 try:
151 guards = self.opener(self.guards_path).read().split()
151 guards = self.opener(self.guards_path).read().split()
152 except IOError, err:
152 except IOError, err:
153 if err.errno != errno.ENOENT: raise
153 if err.errno != errno.ENOENT: raise
154 guards = []
154 guards = []
155 for i, guard in enumerate(guards):
155 for i, guard in enumerate(guards):
156 bad = self.check_guard(guard)
156 bad = self.check_guard(guard)
157 if bad:
157 if bad:
158 self.ui.warn('%s:%d: %s\n' %
158 self.ui.warn('%s:%d: %s\n' %
159 (self.join(self.guards_path), i + 1, bad))
159 (self.join(self.guards_path), i + 1, bad))
160 else:
160 else:
161 self.active_guards.append(guard)
161 self.active_guards.append(guard)
162 return self.active_guards
162 return self.active_guards
163
163
164 def set_guards(self, idx, guards):
164 def set_guards(self, idx, guards):
165 for g in guards:
165 for g in guards:
166 if len(g) < 2:
166 if len(g) < 2:
167 raise util.Abort(_('guard %r too short') % g)
167 raise util.Abort(_('guard %r too short') % g)
168 if g[0] not in '-+':
168 if g[0] not in '-+':
169 raise util.Abort(_('guard %r starts with invalid char') % g)
169 raise util.Abort(_('guard %r starts with invalid char') % g)
170 bad = self.check_guard(g[1:])
170 bad = self.check_guard(g[1:])
171 if bad:
171 if bad:
172 raise util.Abort(bad)
172 raise util.Abort(bad)
173 drop = self.guard_re.sub('', self.full_series[idx])
173 drop = self.guard_re.sub('', self.full_series[idx])
174 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
174 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
175 self.parse_series()
175 self.parse_series()
176 self.series_dirty = True
176 self.series_dirty = True
177
177
178 def pushable(self, idx):
178 def pushable(self, idx):
179 if isinstance(idx, str):
179 if isinstance(idx, str):
180 idx = self.series.index(idx)
180 idx = self.series.index(idx)
181 patchguards = self.series_guards[idx]
181 patchguards = self.series_guards[idx]
182 if not patchguards:
182 if not patchguards:
183 return True, None
183 return True, None
184 default = False
184 default = False
185 guards = self.active()
185 guards = self.active()
186 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
186 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
187 if exactneg:
187 if exactneg:
188 return False, exactneg[0]
188 return False, exactneg[0]
189 pos = [g for g in patchguards if g[0] == '+']
189 pos = [g for g in patchguards if g[0] == '+']
190 exactpos = [g for g in pos if g[1:] in guards]
190 exactpos = [g for g in pos if g[1:] in guards]
191 if pos:
191 if pos:
192 if exactpos:
192 if exactpos:
193 return True, exactpos[0]
193 return True, exactpos[0]
194 return False, pos
194 return False, pos
195 return True, ''
195 return True, ''
196
196
197 def explain_pushable(self, idx, all_patches=False):
197 def explain_pushable(self, idx, all_patches=False):
198 write = all_patches and self.ui.write or self.ui.warn
198 write = all_patches and self.ui.write or self.ui.warn
199 if all_patches or self.ui.verbose:
199 if all_patches or self.ui.verbose:
200 if isinstance(idx, str):
200 if isinstance(idx, str):
201 idx = self.series.index(idx)
201 idx = self.series.index(idx)
202 pushable, why = self.pushable(idx)
202 pushable, why = self.pushable(idx)
203 if all_patches and pushable:
203 if all_patches and pushable:
204 if why is None:
204 if why is None:
205 write(_('allowing %s - no guards in effect\n') %
205 write(_('allowing %s - no guards in effect\n') %
206 self.series[idx])
206 self.series[idx])
207 else:
207 else:
208 if not why:
208 if not why:
209 write(_('allowing %s - no matching negative guards\n') %
209 write(_('allowing %s - no matching negative guards\n') %
210 self.series[idx])
210 self.series[idx])
211 else:
211 else:
212 write(_('allowing %s - guarded by %r\n') %
212 write(_('allowing %s - guarded by %r\n') %
213 (self.series[idx], why))
213 (self.series[idx], why))
214 if not pushable:
214 if not pushable:
215 if why:
215 if why:
216 write(_('skipping %s - guarded by %r\n') %
216 write(_('skipping %s - guarded by %r\n') %
217 (self.series[idx], why))
217 (self.series[idx], why))
218 else:
218 else:
219 write(_('skipping %s - no matching guards\n') %
219 write(_('skipping %s - no matching guards\n') %
220 self.series[idx])
220 self.series[idx])
221
221
222 def save_dirty(self):
222 def save_dirty(self):
223 def write_list(items, path):
223 def write_list(items, path):
224 fp = self.opener(path, 'w')
224 fp = self.opener(path, 'w')
225 for i in items:
225 for i in items:
226 print >> fp, i
226 print >> fp, i
227 fp.close()
227 fp.close()
228 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
228 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
229 if self.series_dirty: write_list(self.full_series, self.series_path)
229 if self.series_dirty: write_list(self.full_series, self.series_path)
230 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
230 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
231
231
232 def readheaders(self, patch):
232 def readheaders(self, patch):
233 def eatdiff(lines):
233 def eatdiff(lines):
234 while lines:
234 while lines:
235 l = lines[-1]
235 l = lines[-1]
236 if (l.startswith("diff -") or
236 if (l.startswith("diff -") or
237 l.startswith("Index:") or
237 l.startswith("Index:") or
238 l.startswith("===========")):
238 l.startswith("===========")):
239 del lines[-1]
239 del lines[-1]
240 else:
240 else:
241 break
241 break
242 def eatempty(lines):
242 def eatempty(lines):
243 while lines:
243 while lines:
244 l = lines[-1]
244 l = lines[-1]
245 if re.match('\s*$', l):
245 if re.match('\s*$', l):
246 del lines[-1]
246 del lines[-1]
247 else:
247 else:
248 break
248 break
249
249
250 pf = self.join(patch)
250 pf = self.join(patch)
251 message = []
251 message = []
252 comments = []
252 comments = []
253 user = None
253 user = None
254 date = None
254 date = None
255 format = None
255 format = None
256 subject = None
256 subject = None
257 diffstart = 0
257 diffstart = 0
258
258
259 for line in file(pf):
259 for line in file(pf):
260 line = line.rstrip()
260 line = line.rstrip()
261 if line.startswith('diff --git'):
261 if line.startswith('diff --git'):
262 diffstart = 2
262 diffstart = 2
263 break
263 break
264 if diffstart:
264 if diffstart:
265 if line.startswith('+++ '):
265 if line.startswith('+++ '):
266 diffstart = 2
266 diffstart = 2
267 break
267 break
268 if line.startswith("--- "):
268 if line.startswith("--- "):
269 diffstart = 1
269 diffstart = 1
270 continue
270 continue
271 elif format == "hgpatch":
271 elif format == "hgpatch":
272 # parse values when importing the result of an hg export
272 # parse values when importing the result of an hg export
273 if line.startswith("# User "):
273 if line.startswith("# User "):
274 user = line[7:]
274 user = line[7:]
275 elif line.startswith("# Date "):
275 elif line.startswith("# Date "):
276 date = line[7:]
276 date = line[7:]
277 elif not line.startswith("# ") and line:
277 elif not line.startswith("# ") and line:
278 message.append(line)
278 message.append(line)
279 format = None
279 format = None
280 elif line == '# HG changeset patch':
280 elif line == '# HG changeset patch':
281 format = "hgpatch"
281 format = "hgpatch"
282 elif (format != "tagdone" and (line.startswith("Subject: ") or
282 elif (format != "tagdone" and (line.startswith("Subject: ") or
283 line.startswith("subject: "))):
283 line.startswith("subject: "))):
284 subject = line[9:]
284 subject = line[9:]
285 format = "tag"
285 format = "tag"
286 elif (format != "tagdone" and (line.startswith("From: ") or
286 elif (format != "tagdone" and (line.startswith("From: ") or
287 line.startswith("from: "))):
287 line.startswith("from: "))):
288 user = line[6:]
288 user = line[6:]
289 format = "tag"
289 format = "tag"
290 elif format == "tag" and line == "":
290 elif format == "tag" and line == "":
291 # when looking for tags (subject: from: etc) they
291 # when looking for tags (subject: from: etc) they
292 # end once you find a blank line in the source
292 # end once you find a blank line in the source
293 format = "tagdone"
293 format = "tagdone"
294 elif message or line:
294 elif message or line:
295 message.append(line)
295 message.append(line)
296 comments.append(line)
296 comments.append(line)
297
297
298 eatdiff(message)
298 eatdiff(message)
299 eatdiff(comments)
299 eatdiff(comments)
300 eatempty(message)
300 eatempty(message)
301 eatempty(comments)
301 eatempty(comments)
302
302
303 # make sure message isn't empty
303 # make sure message isn't empty
304 if format and format.startswith("tag") and subject:
304 if format and format.startswith("tag") and subject:
305 message.insert(0, "")
305 message.insert(0, "")
306 message.insert(0, subject)
306 message.insert(0, subject)
307 return (message, comments, user, date, diffstart > 1)
307 return (message, comments, user, date, diffstart > 1)
308
308
309 def removeundo(self, repo):
309 def removeundo(self, repo):
310 undo = repo.sjoin('undo')
310 undo = repo.sjoin('undo')
311 if not os.path.exists(undo):
311 if not os.path.exists(undo):
312 return
312 return
313 try:
313 try:
314 os.unlink(undo)
314 os.unlink(undo)
315 except OSError, inst:
315 except OSError, inst:
316 self.ui.warn('error removing undo: %s\n' % str(inst))
316 self.ui.warn('error removing undo: %s\n' % str(inst))
317
317
318 def printdiff(self, repo, node1, node2=None, files=None,
318 def printdiff(self, repo, node1, node2=None, files=None,
319 fp=None, changes=None, opts={}):
319 fp=None, changes=None, opts={}):
320 fns, matchfn, anypats = cmdutil.matchpats(repo, files, opts)
320 fns, matchfn, anypats = cmdutil.matchpats(repo, files, opts)
321
321
322 patch.diff(repo, node1, node2, fns, match=matchfn,
322 patch.diff(repo, node1, node2, fns, match=matchfn,
323 fp=fp, changes=changes, opts=self.diffopts())
323 fp=fp, changes=changes, opts=self.diffopts())
324
324
325 def mergeone(self, repo, mergeq, head, patch, rev, wlock):
325 def mergeone(self, repo, mergeq, head, patch, rev, wlock):
326 # first try just applying the patch
326 # first try just applying the patch
327 (err, n) = self.apply(repo, [ patch ], update_status=False,
327 (err, n) = self.apply(repo, [ patch ], update_status=False,
328 strict=True, merge=rev, wlock=wlock)
328 strict=True, merge=rev, wlock=wlock)
329
329
330 if err == 0:
330 if err == 0:
331 return (err, n)
331 return (err, n)
332
332
333 if n is None:
333 if n is None:
334 raise util.Abort(_("apply failed for patch %s") % patch)
334 raise util.Abort(_("apply failed for patch %s") % patch)
335
335
336 self.ui.warn("patch didn't work out, merging %s\n" % patch)
336 self.ui.warn("patch didn't work out, merging %s\n" % patch)
337
337
338 # apply failed, strip away that rev and merge.
338 # apply failed, strip away that rev and merge.
339 hg.clean(repo, head, wlock=wlock)
339 hg.clean(repo, head, wlock=wlock)
340 self.strip(repo, n, update=False, backup='strip', wlock=wlock)
340 self.strip(repo, n, update=False, backup='strip', wlock=wlock)
341
341
342 ctx = repo.changectx(rev)
342 ctx = repo.changectx(rev)
343 ret = hg.merge(repo, rev, wlock=wlock)
343 ret = hg.merge(repo, rev, wlock=wlock)
344 if ret:
344 if ret:
345 raise util.Abort(_("update returned %d") % ret)
345 raise util.Abort(_("update returned %d") % ret)
346 n = repo.commit(None, ctx.description(), ctx.user(),
346 n = repo.commit(None, ctx.description(), ctx.user(),
347 force=1, wlock=wlock)
347 force=1, wlock=wlock)
348 if n == None:
348 if n == None:
349 raise util.Abort(_("repo commit failed"))
349 raise util.Abort(_("repo commit failed"))
350 try:
350 try:
351 message, comments, user, date, patchfound = mergeq.readheaders(patch)
351 message, comments, user, date, patchfound = mergeq.readheaders(patch)
352 except:
352 except:
353 raise util.Abort(_("unable to read %s") % patch)
353 raise util.Abort(_("unable to read %s") % patch)
354
354
355 patchf = self.opener(patch, "w")
355 patchf = self.opener(patch, "w")
356 if comments:
356 if comments:
357 comments = "\n".join(comments) + '\n\n'
357 comments = "\n".join(comments) + '\n\n'
358 patchf.write(comments)
358 patchf.write(comments)
359 self.printdiff(repo, head, n, fp=patchf)
359 self.printdiff(repo, head, n, fp=patchf)
360 patchf.close()
360 patchf.close()
361 self.removeundo(repo)
361 self.removeundo(repo)
362 return (0, n)
362 return (0, n)
363
363
364 def qparents(self, repo, rev=None):
364 def qparents(self, repo, rev=None):
365 if rev is None:
365 if rev is None:
366 (p1, p2) = repo.dirstate.parents()
366 (p1, p2) = repo.dirstate.parents()
367 if p2 == revlog.nullid:
367 if p2 == revlog.nullid:
368 return p1
368 return p1
369 if len(self.applied) == 0:
369 if len(self.applied) == 0:
370 return None
370 return None
371 return revlog.bin(self.applied[-1].rev)
371 return revlog.bin(self.applied[-1].rev)
372 pp = repo.changelog.parents(rev)
372 pp = repo.changelog.parents(rev)
373 if pp[1] != revlog.nullid:
373 if pp[1] != revlog.nullid:
374 arevs = [ x.rev for x in self.applied ]
374 arevs = [ x.rev for x in self.applied ]
375 p0 = revlog.hex(pp[0])
375 p0 = revlog.hex(pp[0])
376 p1 = revlog.hex(pp[1])
376 p1 = revlog.hex(pp[1])
377 if p0 in arevs:
377 if p0 in arevs:
378 return pp[0]
378 return pp[0]
379 if p1 in arevs:
379 if p1 in arevs:
380 return pp[1]
380 return pp[1]
381 return pp[0]
381 return pp[0]
382
382
383 def mergepatch(self, repo, mergeq, series, wlock):
383 def mergepatch(self, repo, mergeq, series, wlock):
384 if len(self.applied) == 0:
384 if len(self.applied) == 0:
385 # each of the patches merged in will have two parents. This
385 # each of the patches merged in will have two parents. This
386 # can confuse the qrefresh, qdiff, and strip code because it
386 # can confuse the qrefresh, qdiff, and strip code because it
387 # needs to know which parent is actually in the patch queue.
387 # needs to know which parent is actually in the patch queue.
388 # so, we insert a merge marker with only one parent. This way
388 # so, we insert a merge marker with only one parent. This way
389 # the first patch in the queue is never a merge patch
389 # the first patch in the queue is never a merge patch
390 #
390 #
391 pname = ".hg.patches.merge.marker"
391 pname = ".hg.patches.merge.marker"
392 n = repo.commit(None, '[mq]: merge marker', user=None, force=1,
392 n = repo.commit(None, '[mq]: merge marker', user=None, force=1,
393 wlock=wlock)
393 wlock=wlock)
394 self.removeundo(repo)
394 self.removeundo(repo)
395 self.applied.append(statusentry(revlog.hex(n), pname))
395 self.applied.append(statusentry(revlog.hex(n), pname))
396 self.applied_dirty = 1
396 self.applied_dirty = 1
397
397
398 head = self.qparents(repo)
398 head = self.qparents(repo)
399
399
400 for patch in series:
400 for patch in series:
401 patch = mergeq.lookup(patch, strict=True)
401 patch = mergeq.lookup(patch, strict=True)
402 if not patch:
402 if not patch:
403 self.ui.warn("patch %s does not exist\n" % patch)
403 self.ui.warn("patch %s does not exist\n" % patch)
404 return (1, None)
404 return (1, None)
405 pushable, reason = self.pushable(patch)
405 pushable, reason = self.pushable(patch)
406 if not pushable:
406 if not pushable:
407 self.explain_pushable(patch, all_patches=True)
407 self.explain_pushable(patch, all_patches=True)
408 continue
408 continue
409 info = mergeq.isapplied(patch)
409 info = mergeq.isapplied(patch)
410 if not info:
410 if not info:
411 self.ui.warn("patch %s is not applied\n" % patch)
411 self.ui.warn("patch %s is not applied\n" % patch)
412 return (1, None)
412 return (1, None)
413 rev = revlog.bin(info[1])
413 rev = revlog.bin(info[1])
414 (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock)
414 (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock)
415 if head:
415 if head:
416 self.applied.append(statusentry(revlog.hex(head), patch))
416 self.applied.append(statusentry(revlog.hex(head), patch))
417 self.applied_dirty = 1
417 self.applied_dirty = 1
418 if err:
418 if err:
419 return (err, head)
419 return (err, head)
420 self.save_dirty()
420 self.save_dirty()
421 return (0, head)
421 return (0, head)
422
422
423 def patch(self, repo, patchfile):
423 def patch(self, repo, patchfile):
424 '''Apply patchfile to the working directory.
424 '''Apply patchfile to the working directory.
425 patchfile: file name of patch'''
425 patchfile: file name of patch'''
426 files = {}
426 files = {}
427 try:
427 try:
428 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
428 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
429 files=files)
429 files=files)
430 except Exception, inst:
430 except Exception, inst:
431 self.ui.note(str(inst) + '\n')
431 self.ui.note(str(inst) + '\n')
432 if not self.ui.verbose:
432 if not self.ui.verbose:
433 self.ui.warn("patch failed, unable to continue (try -v)\n")
433 self.ui.warn("patch failed, unable to continue (try -v)\n")
434 return (False, files, False)
434 return (False, files, False)
435
435
436 return (True, files, fuzz)
436 return (True, files, fuzz)
437
437
438 def apply(self, repo, series, list=False, update_status=True,
438 def apply(self, repo, series, list=False, update_status=True,
439 strict=False, patchdir=None, merge=None, wlock=None,
439 strict=False, patchdir=None, merge=None, wlock=None,
440 all_files={}):
440 all_files={}):
441 tr = repo.transaction()
441 tr = repo.transaction()
442 try:
442 try:
443 ret = self._apply(tr, repo, series, list, update_status,
443 ret = self._apply(tr, repo, series, list, update_status,
444 strict, patchdir, merge, wlock,
444 strict, patchdir, merge, wlock,
445 all_files=all_files)
445 all_files=all_files)
446 tr.close()
446 tr.close()
447 self.save_dirty()
447 self.save_dirty()
448 return ret
448 return ret
449 except:
449 except:
450 try:
450 try:
451 tr.abort()
451 tr.abort()
452 finally:
452 finally:
453 repo.reload()
453 repo.reload()
454 repo.wreload()
454 repo.wreload()
455 raise
455 raise
456
456
457 def _apply(self, tr, repo, series, list=False, update_status=True,
457 def _apply(self, tr, repo, series, list=False, update_status=True,
458 strict=False, patchdir=None, merge=None, wlock=None,
458 strict=False, patchdir=None, merge=None, wlock=None,
459 all_files={}):
459 all_files={}):
460 # TODO unify with commands.py
460 # TODO unify with commands.py
461 if not patchdir:
461 if not patchdir:
462 patchdir = self.path
462 patchdir = self.path
463 err = 0
463 err = 0
464 if not wlock:
464 if not wlock:
465 wlock = repo.wlock()
465 wlock = repo.wlock()
466 lock = repo.lock()
466 lock = repo.lock()
467 n = None
467 n = None
468 for patchname in series:
468 for patchname in series:
469 pushable, reason = self.pushable(patchname)
469 pushable, reason = self.pushable(patchname)
470 if not pushable:
470 if not pushable:
471 self.explain_pushable(patchname, all_patches=True)
471 self.explain_pushable(patchname, all_patches=True)
472 continue
472 continue
473 self.ui.warn("applying %s\n" % patchname)
473 self.ui.warn("applying %s\n" % patchname)
474 pf = os.path.join(patchdir, patchname)
474 pf = os.path.join(patchdir, patchname)
475
475
476 try:
476 try:
477 message, comments, user, date, patchfound = self.readheaders(patchname)
477 message, comments, user, date, patchfound = self.readheaders(patchname)
478 except:
478 except:
479 self.ui.warn("Unable to read %s\n" % patchname)
479 self.ui.warn("Unable to read %s\n" % patchname)
480 err = 1
480 err = 1
481 break
481 break
482
482
483 if not message:
483 if not message:
484 message = "imported patch %s\n" % patchname
484 message = "imported patch %s\n" % patchname
485 else:
485 else:
486 if list:
486 if list:
487 message.append("\nimported patch %s" % patchname)
487 message.append("\nimported patch %s" % patchname)
488 message = '\n'.join(message)
488 message = '\n'.join(message)
489
489
490 (patcherr, files, fuzz) = self.patch(repo, pf)
490 (patcherr, files, fuzz) = self.patch(repo, pf)
491 all_files.update(files)
491 all_files.update(files)
492 patcherr = not patcherr
492 patcherr = not patcherr
493
493
494 if merge and files:
494 if merge and files:
495 # Mark as removed/merged and update dirstate parent info
495 # Mark as removed/merged and update dirstate parent info
496 removed = []
496 removed = []
497 merged = []
497 merged = []
498 for f in files:
498 for f in files:
499 if os.path.exists(repo.dirstate.wjoin(f)):
499 if os.path.exists(repo.dirstate.wjoin(f)):
500 merged.append(f)
500 merged.append(f)
501 else:
501 else:
502 removed.append(f)
502 removed.append(f)
503 repo.dirstate.update(repo.dirstate.filterfiles(removed), 'r')
503 repo.dirstate.update(repo.dirstate.filterfiles(removed), 'r')
504 repo.dirstate.update(repo.dirstate.filterfiles(merged), 'm')
504 repo.dirstate.update(repo.dirstate.filterfiles(merged), 'm')
505 p1, p2 = repo.dirstate.parents()
505 p1, p2 = repo.dirstate.parents()
506 repo.dirstate.setparents(p1, merge)
506 repo.dirstate.setparents(p1, merge)
507 files = patch.updatedir(self.ui, repo, files, wlock=wlock)
507 files = patch.updatedir(self.ui, repo, files, wlock=wlock)
508 n = repo.commit(files, message, user, date, force=1, lock=lock,
508 n = repo.commit(files, message, user, date, force=1, lock=lock,
509 wlock=wlock)
509 wlock=wlock)
510
510
511 if n == None:
511 if n == None:
512 raise util.Abort(_("repo commit failed"))
512 raise util.Abort(_("repo commit failed"))
513
513
514 if update_status:
514 if update_status:
515 self.applied.append(statusentry(revlog.hex(n), patchname))
515 self.applied.append(statusentry(revlog.hex(n), patchname))
516
516
517 if patcherr:
517 if patcherr:
518 if not patchfound:
518 if not patchfound:
519 self.ui.warn("patch %s is empty\n" % patchname)
519 self.ui.warn("patch %s is empty\n" % patchname)
520 err = 0
520 err = 0
521 else:
521 else:
522 self.ui.warn("patch failed, rejects left in working dir\n")
522 self.ui.warn("patch failed, rejects left in working dir\n")
523 err = 1
523 err = 1
524 break
524 break
525
525
526 if fuzz and strict:
526 if fuzz and strict:
527 self.ui.warn("fuzz found when applying patch, stopping\n")
527 self.ui.warn("fuzz found when applying patch, stopping\n")
528 err = 1
528 err = 1
529 break
529 break
530 self.removeundo(repo)
530 self.removeundo(repo)
531 return (err, n)
531 return (err, n)
532
532
533 def delete(self, repo, patches, opts):
533 def delete(self, repo, patches, opts):
534 realpatches = []
534 realpatches = []
535 for patch in patches:
535 for patch in patches:
536 patch = self.lookup(patch, strict=True)
536 patch = self.lookup(patch, strict=True)
537 info = self.isapplied(patch)
537 info = self.isapplied(patch)
538 if info:
538 if info:
539 raise util.Abort(_("cannot delete applied patch %s") % patch)
539 raise util.Abort(_("cannot delete applied patch %s") % patch)
540 if patch not in self.series:
540 if patch not in self.series:
541 raise util.Abort(_("patch %s not in series file") % patch)
541 raise util.Abort(_("patch %s not in series file") % patch)
542 realpatches.append(patch)
542 realpatches.append(patch)
543
543
544 appliedbase = 0
544 appliedbase = 0
545 if opts.get('rev'):
545 if opts.get('rev'):
546 if not self.applied:
546 if not self.applied:
547 raise util.Abort(_('no patches applied'))
547 raise util.Abort(_('no patches applied'))
548 revs = cmdutil.revrange(repo, opts['rev'])
548 revs = cmdutil.revrange(repo, opts['rev'])
549 if len(revs) > 1 and revs[0] > revs[1]:
549 if len(revs) > 1 and revs[0] > revs[1]:
550 revs.reverse()
550 revs.reverse()
551 for rev in revs:
551 for rev in revs:
552 if appliedbase >= len(self.applied):
552 if appliedbase >= len(self.applied):
553 raise util.Abort(_("revision %d is not managed") % rev)
553 raise util.Abort(_("revision %d is not managed") % rev)
554
554
555 base = revlog.bin(self.applied[appliedbase].rev)
555 base = revlog.bin(self.applied[appliedbase].rev)
556 node = repo.changelog.node(rev)
556 node = repo.changelog.node(rev)
557 if node != base:
557 if node != base:
558 raise util.Abort(_("cannot delete revision %d above "
558 raise util.Abort(_("cannot delete revision %d above "
559 "applied patches") % rev)
559 "applied patches") % rev)
560 realpatches.append(self.applied[appliedbase].name)
560 realpatches.append(self.applied[appliedbase].name)
561 appliedbase += 1
561 appliedbase += 1
562
562
563 if not opts.get('keep'):
563 if not opts.get('keep'):
564 r = self.qrepo()
564 r = self.qrepo()
565 if r:
565 if r:
566 r.remove(realpatches, True)
566 r.remove(realpatches, True)
567 else:
567 else:
568 for p in realpatches:
568 for p in realpatches:
569 os.unlink(self.join(p))
569 os.unlink(self.join(p))
570
570
571 if appliedbase:
571 if appliedbase:
572 del self.applied[:appliedbase]
572 del self.applied[:appliedbase]
573 self.applied_dirty = 1
573 self.applied_dirty = 1
574 indices = [self.find_series(p) for p in realpatches]
574 indices = [self.find_series(p) for p in realpatches]
575 indices.sort()
575 indices.sort()
576 for i in indices[-1::-1]:
576 for i in indices[-1::-1]:
577 del self.full_series[i]
577 del self.full_series[i]
578 self.parse_series()
578 self.parse_series()
579 self.series_dirty = 1
579 self.series_dirty = 1
580
580
581 def check_toppatch(self, repo):
581 def check_toppatch(self, repo):
582 if len(self.applied) > 0:
582 if len(self.applied) > 0:
583 top = revlog.bin(self.applied[-1].rev)
583 top = revlog.bin(self.applied[-1].rev)
584 pp = repo.dirstate.parents()
584 pp = repo.dirstate.parents()
585 if top not in pp:
585 if top not in pp:
586 raise util.Abort(_("queue top not at same revision as working directory"))
586 raise util.Abort(_("queue top not at same revision as working directory"))
587 return top
587 return top
588 return None
588 return None
589 def check_localchanges(self, repo, force=False, refresh=True):
589 def check_localchanges(self, repo, force=False, refresh=True):
590 m, a, r, d = repo.status()[:4]
590 m, a, r, d = repo.status()[:4]
591 if m or a or r or d:
591 if m or a or r or d:
592 if not force:
592 if not force:
593 if refresh:
593 if refresh:
594 raise util.Abort(_("local changes found, refresh first"))
594 raise util.Abort(_("local changes found, refresh first"))
595 else:
595 else:
596 raise util.Abort(_("local changes found"))
596 raise util.Abort(_("local changes found"))
597 return m, a, r, d
597 return m, a, r, d
598 def new(self, repo, patch, msg=None, force=None):
598 def new(self, repo, patch, msg=None, force=None):
599 if os.path.exists(self.join(patch)):
599 if os.path.exists(self.join(patch)):
600 raise util.Abort(_('patch "%s" already exists') % patch)
600 raise util.Abort(_('patch "%s" already exists') % patch)
601 m, a, r, d = self.check_localchanges(repo, force)
601 m, a, r, d = self.check_localchanges(repo, force)
602 commitfiles = m + a + r
602 commitfiles = m + a + r
603 self.check_toppatch(repo)
603 self.check_toppatch(repo)
604 wlock = repo.wlock()
604 wlock = repo.wlock()
605 insert = self.full_series_end()
605 insert = self.full_series_end()
606 if msg:
606 if msg:
607 n = repo.commit(commitfiles, "[mq]: %s" % msg, force=True,
607 n = repo.commit(commitfiles, "[mq]: %s" % msg, force=True,
608 wlock=wlock)
608 wlock=wlock)
609 else:
609 else:
610 n = repo.commit(commitfiles,
610 n = repo.commit(commitfiles,
611 "New patch: %s" % patch, force=True, wlock=wlock)
611 "New patch: %s" % patch, force=True, wlock=wlock)
612 if n == None:
612 if n == None:
613 raise util.Abort(_("repo commit failed"))
613 raise util.Abort(_("repo commit failed"))
614 self.full_series[insert:insert] = [patch]
614 self.full_series[insert:insert] = [patch]
615 self.applied.append(statusentry(revlog.hex(n), patch))
615 self.applied.append(statusentry(revlog.hex(n), patch))
616 self.parse_series()
616 self.parse_series()
617 self.series_dirty = 1
617 self.series_dirty = 1
618 self.applied_dirty = 1
618 self.applied_dirty = 1
619 p = self.opener(patch, "w")
619 p = self.opener(patch, "w")
620 if msg:
620 if msg:
621 msg = msg + "\n"
621 msg = msg + "\n"
622 p.write(msg)
622 p.write(msg)
623 p.close()
623 p.close()
624 wlock = None
624 wlock = None
625 r = self.qrepo()
625 r = self.qrepo()
626 if r: r.add([patch])
626 if r: r.add([patch])
627 if commitfiles:
627 if commitfiles:
628 self.refresh(repo, short=True)
628 self.refresh(repo, short=True)
629 self.removeundo(repo)
629 self.removeundo(repo)
630
630
631 def strip(self, repo, rev, update=True, backup="all", wlock=None):
631 def strip(self, repo, rev, update=True, backup="all", wlock=None):
632 def limitheads(chlog, stop):
632 def limitheads(chlog, stop):
633 """return the list of all nodes that have no children"""
633 """return the list of all nodes that have no children"""
634 p = {}
634 p = {}
635 h = []
635 h = []
636 stoprev = 0
636 stoprev = 0
637 if stop in chlog.nodemap:
637 if stop in chlog.nodemap:
638 stoprev = chlog.rev(stop)
638 stoprev = chlog.rev(stop)
639
639
640 for r in xrange(chlog.count() - 1, -1, -1):
640 for r in xrange(chlog.count() - 1, -1, -1):
641 n = chlog.node(r)
641 n = chlog.node(r)
642 if n not in p:
642 if n not in p:
643 h.append(n)
643 h.append(n)
644 if n == stop:
644 if n == stop:
645 break
645 break
646 if r < stoprev:
646 if r < stoprev:
647 break
647 break
648 for pn in chlog.parents(n):
648 for pn in chlog.parents(n):
649 p[pn] = 1
649 p[pn] = 1
650 return h
650 return h
651
651
652 def bundle(cg):
652 def bundle(cg):
653 backupdir = repo.join("strip-backup")
653 backupdir = repo.join("strip-backup")
654 if not os.path.isdir(backupdir):
654 if not os.path.isdir(backupdir):
655 os.mkdir(backupdir)
655 os.mkdir(backupdir)
656 name = os.path.join(backupdir, "%s" % revlog.short(rev))
656 name = os.path.join(backupdir, "%s" % revlog.short(rev))
657 name = savename(name)
657 name = savename(name)
658 self.ui.warn("saving bundle to %s\n" % name)
658 self.ui.warn("saving bundle to %s\n" % name)
659 return changegroup.writebundle(cg, name, "HG10BZ")
659 return changegroup.writebundle(cg, name, "HG10BZ")
660
660
661 def stripall(revnum):
661 def stripall(revnum):
662 mm = repo.changectx(rev).manifest()
662 mm = repo.changectx(rev).manifest()
663 seen = {}
663 seen = {}
664
664
665 for x in xrange(revnum, repo.changelog.count()):
665 for x in xrange(revnum, repo.changelog.count()):
666 for f in repo.changectx(x).files():
666 for f in repo.changectx(x).files():
667 if f in seen:
667 if f in seen:
668 continue
668 continue
669 seen[f] = 1
669 seen[f] = 1
670 if f in mm:
670 if f in mm:
671 filerev = mm[f]
671 filerev = mm[f]
672 else:
672 else:
673 filerev = 0
673 filerev = 0
674 seen[f] = filerev
674 seen[f] = filerev
675 # we go in two steps here so the strip loop happens in a
675 # we go in two steps here so the strip loop happens in a
676 # sensible order. When stripping many files, this helps keep
676 # sensible order. When stripping many files, this helps keep
677 # our disk access patterns under control.
677 # our disk access patterns under control.
678 seen_list = seen.keys()
678 seen_list = seen.keys()
679 seen_list.sort()
679 seen_list.sort()
680 for f in seen_list:
680 for f in seen_list:
681 ff = repo.file(f)
681 ff = repo.file(f)
682 filerev = seen[f]
682 filerev = seen[f]
683 if filerev != 0:
683 if filerev != 0:
684 if filerev in ff.nodemap:
684 if filerev in ff.nodemap:
685 filerev = ff.rev(filerev)
685 filerev = ff.rev(filerev)
686 else:
686 else:
687 filerev = 0
687 filerev = 0
688 ff.strip(filerev, revnum)
688 ff.strip(filerev, revnum)
689
689
690 if not wlock:
690 if not wlock:
691 wlock = repo.wlock()
691 wlock = repo.wlock()
692 lock = repo.lock()
692 lock = repo.lock()
693 chlog = repo.changelog
693 chlog = repo.changelog
694 # TODO delete the undo files, and handle undo of merge sets
694 # TODO delete the undo files, and handle undo of merge sets
695 pp = chlog.parents(rev)
695 pp = chlog.parents(rev)
696 revnum = chlog.rev(rev)
696 revnum = chlog.rev(rev)
697
697
698 if update:
698 if update:
699 self.check_localchanges(repo, refresh=False)
699 self.check_localchanges(repo, refresh=False)
700 urev = self.qparents(repo, rev)
700 urev = self.qparents(repo, rev)
701 hg.clean(repo, urev, wlock=wlock)
701 hg.clean(repo, urev, wlock=wlock)
702 repo.dirstate.write()
702 repo.dirstate.write()
703
703
704 # save is a list of all the branches we are truncating away
704 # save is a list of all the branches we are truncating away
705 # that we actually want to keep. changegroup will be used
705 # that we actually want to keep. changegroup will be used
706 # to preserve them and add them back after the truncate
706 # to preserve them and add them back after the truncate
707 saveheads = []
707 saveheads = []
708 savebases = {}
708 savebases = {}
709
709
710 heads = limitheads(chlog, rev)
710 heads = limitheads(chlog, rev)
711 seen = {}
711 seen = {}
712
712
713 # search through all the heads, finding those where the revision
713 # search through all the heads, finding those where the revision
714 # we want to strip away is an ancestor. Also look for merges
714 # we want to strip away is an ancestor. Also look for merges
715 # that might be turned into new heads by the strip.
715 # that might be turned into new heads by the strip.
716 while heads:
716 while heads:
717 h = heads.pop()
717 h = heads.pop()
718 n = h
718 n = h
719 while True:
719 while True:
720 seen[n] = 1
720 seen[n] = 1
721 pp = chlog.parents(n)
721 pp = chlog.parents(n)
722 if pp[1] != revlog.nullid:
722 if pp[1] != revlog.nullid:
723 for p in pp:
723 for p in pp:
724 if chlog.rev(p) > revnum and p not in seen:
724 if chlog.rev(p) > revnum and p not in seen:
725 heads.append(p)
725 heads.append(p)
726 if pp[0] == revlog.nullid:
726 if pp[0] == revlog.nullid:
727 break
727 break
728 if chlog.rev(pp[0]) < revnum:
728 if chlog.rev(pp[0]) < revnum:
729 break
729 break
730 n = pp[0]
730 n = pp[0]
731 if n == rev:
731 if n == rev:
732 break
732 break
733 r = chlog.reachable(h, rev)
733 r = chlog.reachable(h, rev)
734 if rev not in r:
734 if rev not in r:
735 saveheads.append(h)
735 saveheads.append(h)
736 for x in r:
736 for x in r:
737 if chlog.rev(x) > revnum:
737 if chlog.rev(x) > revnum:
738 savebases[x] = 1
738 savebases[x] = 1
739
739
740 # create a changegroup for all the branches we need to keep
740 # create a changegroup for all the branches we need to keep
741 if backup == "all":
741 if backup == "all":
742 backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip')
742 backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip')
743 bundle(backupch)
743 bundle(backupch)
744 if saveheads:
744 if saveheads:
745 backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip')
745 backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip')
746 chgrpfile = bundle(backupch)
746 chgrpfile = bundle(backupch)
747
747
748 stripall(revnum)
748 stripall(revnum)
749
749
750 change = chlog.read(rev)
750 change = chlog.read(rev)
751 chlog.strip(revnum, revnum)
751 chlog.strip(revnum, revnum)
752 repo.manifest.strip(repo.manifest.rev(change[0]), revnum)
752 repo.manifest.strip(repo.manifest.rev(change[0]), revnum)
753 self.removeundo(repo)
753 self.removeundo(repo)
754 if saveheads:
754 if saveheads:
755 self.ui.status("adding branch\n")
755 self.ui.status("adding branch\n")
756 commands.unbundle(self.ui, repo, "file:%s" % chgrpfile,
756 commands.unbundle(self.ui, repo, "file:%s" % chgrpfile,
757 update=False)
757 update=False)
758 if backup != "strip":
758 if backup != "strip":
759 os.unlink(chgrpfile)
759 os.unlink(chgrpfile)
760
760
761 def isapplied(self, patch):
761 def isapplied(self, patch):
762 """returns (index, rev, patch)"""
762 """returns (index, rev, patch)"""
763 for i in xrange(len(self.applied)):
763 for i in xrange(len(self.applied)):
764 a = self.applied[i]
764 a = self.applied[i]
765 if a.name == patch:
765 if a.name == patch:
766 return (i, a.rev, a.name)
766 return (i, a.rev, a.name)
767 return None
767 return None
768
768
769 # if the exact patch name does not exist, we try a few
769 # if the exact patch name does not exist, we try a few
770 # variations. If strict is passed, we try only #1
770 # variations. If strict is passed, we try only #1
771 #
771 #
772 # 1) a number to indicate an offset in the series file
772 # 1) a number to indicate an offset in the series file
773 # 2) a unique substring of the patch name was given
773 # 2) a unique substring of the patch name was given
774 # 3) patchname[-+]num to indicate an offset in the series file
774 # 3) patchname[-+]num to indicate an offset in the series file
775 def lookup(self, patch, strict=False):
775 def lookup(self, patch, strict=False):
776 patch = patch and str(patch)
776 patch = patch and str(patch)
777
777
778 def partial_name(s):
778 def partial_name(s):
779 if s in self.series:
779 if s in self.series:
780 return s
780 return s
781 matches = [x for x in self.series if s in x]
781 matches = [x for x in self.series if s in x]
782 if len(matches) > 1:
782 if len(matches) > 1:
783 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
783 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
784 for m in matches:
784 for m in matches:
785 self.ui.warn(' %s\n' % m)
785 self.ui.warn(' %s\n' % m)
786 return None
786 return None
787 if matches:
787 if matches:
788 return matches[0]
788 return matches[0]
789 if len(self.series) > 0 and len(self.applied) > 0:
789 if len(self.series) > 0 and len(self.applied) > 0:
790 if s == 'qtip':
790 if s == 'qtip':
791 return self.series[self.series_end(True)-1]
791 return self.series[self.series_end(True)-1]
792 if s == 'qbase':
792 if s == 'qbase':
793 return self.series[0]
793 return self.series[0]
794 return None
794 return None
795 if patch == None:
795 if patch == None:
796 return None
796 return None
797
797
798 # we don't want to return a partial match until we make
798 # we don't want to return a partial match until we make
799 # sure the file name passed in does not exist (checked below)
799 # sure the file name passed in does not exist (checked below)
800 res = partial_name(patch)
800 res = partial_name(patch)
801 if res and res == patch:
801 if res and res == patch:
802 return res
802 return res
803
803
804 if not os.path.isfile(self.join(patch)):
804 if not os.path.isfile(self.join(patch)):
805 try:
805 try:
806 sno = int(patch)
806 sno = int(patch)
807 except(ValueError, OverflowError):
807 except(ValueError, OverflowError):
808 pass
808 pass
809 else:
809 else:
810 if sno < len(self.series):
810 if sno < len(self.series):
811 return self.series[sno]
811 return self.series[sno]
812 if not strict:
812 if not strict:
813 # return any partial match made above
813 # return any partial match made above
814 if res:
814 if res:
815 return res
815 return res
816 minus = patch.rfind('-')
816 minus = patch.rfind('-')
817 if minus >= 0:
817 if minus >= 0:
818 res = partial_name(patch[:minus])
818 res = partial_name(patch[:minus])
819 if res:
819 if res:
820 i = self.series.index(res)
820 i = self.series.index(res)
821 try:
821 try:
822 off = int(patch[minus+1:] or 1)
822 off = int(patch[minus+1:] or 1)
823 except(ValueError, OverflowError):
823 except(ValueError, OverflowError):
824 pass
824 pass
825 else:
825 else:
826 if i - off >= 0:
826 if i - off >= 0:
827 return self.series[i - off]
827 return self.series[i - off]
828 plus = patch.rfind('+')
828 plus = patch.rfind('+')
829 if plus >= 0:
829 if plus >= 0:
830 res = partial_name(patch[:plus])
830 res = partial_name(patch[:plus])
831 if res:
831 if res:
832 i = self.series.index(res)
832 i = self.series.index(res)
833 try:
833 try:
834 off = int(patch[plus+1:] or 1)
834 off = int(patch[plus+1:] or 1)
835 except(ValueError, OverflowError):
835 except(ValueError, OverflowError):
836 pass
836 pass
837 else:
837 else:
838 if i + off < len(self.series):
838 if i + off < len(self.series):
839 return self.series[i + off]
839 return self.series[i + off]
840 raise util.Abort(_("patch %s not in series") % patch)
840 raise util.Abort(_("patch %s not in series") % patch)
841
841
842 def push(self, repo, patch=None, force=False, list=False,
842 def push(self, repo, patch=None, force=False, list=False,
843 mergeq=None, wlock=None):
843 mergeq=None, wlock=None):
844 if not wlock:
844 if not wlock:
845 wlock = repo.wlock()
845 wlock = repo.wlock()
846 patch = self.lookup(patch)
846 patch = self.lookup(patch)
847 # Suppose our series file is: A B C and the current 'top' patch is B.
847 # Suppose our series file is: A B C and the current 'top' patch is B.
848 # qpush C should be performed (moving forward)
848 # qpush C should be performed (moving forward)
849 # qpush B is a NOP (no change)
849 # qpush B is a NOP (no change)
850 # qpush A is an error (can't go backwards with qpush)
850 # qpush A is an error (can't go backwards with qpush)
851 if patch:
851 if patch:
852 info = self.isapplied(patch)
852 info = self.isapplied(patch)
853 if info:
853 if info:
854 if info[0] < len(self.applied) - 1:
854 if info[0] < len(self.applied) - 1:
855 raise util.Abort(_("cannot push to a previous patch: %s") %
855 raise util.Abort(_("cannot push to a previous patch: %s") %
856 patch)
856 patch)
857 if info[0] < len(self.series) - 1:
857 if info[0] < len(self.series) - 1:
858 self.ui.warn(_('qpush: %s is already at the top\n') % patch)
858 self.ui.warn(_('qpush: %s is already at the top\n') % patch)
859 else:
859 else:
860 self.ui.warn(_('all patches are currently applied\n'))
860 self.ui.warn(_('all patches are currently applied\n'))
861 return
861 return
862
862
863 # Following the above example, starting at 'top' of B:
863 # Following the above example, starting at 'top' of B:
864 # qpush should be performed (pushes C), but a subsequent qpush without
864 # qpush should be performed (pushes C), but a subsequent qpush without
865 # an argument is an error (nothing to apply). This allows a loop
865 # an argument is an error (nothing to apply). This allows a loop
866 # of "...while hg qpush..." to work as it detects an error when done
866 # of "...while hg qpush..." to work as it detects an error when done
867 if self.series_end() == len(self.series):
867 if self.series_end() == len(self.series):
868 self.ui.warn(_('patch series already fully applied\n'))
868 self.ui.warn(_('patch series already fully applied\n'))
869 return 1
869 return 1
870 if not force:
870 if not force:
871 self.check_localchanges(repo)
871 self.check_localchanges(repo)
872
872
873 self.applied_dirty = 1;
873 self.applied_dirty = 1;
874 start = self.series_end()
874 start = self.series_end()
875 if start > 0:
875 if start > 0:
876 self.check_toppatch(repo)
876 self.check_toppatch(repo)
877 if not patch:
877 if not patch:
878 patch = self.series[start]
878 patch = self.series[start]
879 end = start + 1
879 end = start + 1
880 else:
880 else:
881 end = self.series.index(patch, start) + 1
881 end = self.series.index(patch, start) + 1
882 s = self.series[start:end]
882 s = self.series[start:end]
883 all_files = {}
883 all_files = {}
884 try:
884 try:
885 if mergeq:
885 if mergeq:
886 ret = self.mergepatch(repo, mergeq, s, wlock)
886 ret = self.mergepatch(repo, mergeq, s, wlock)
887 else:
887 else:
888 ret = self.apply(repo, s, list, wlock=wlock,
888 ret = self.apply(repo, s, list, wlock=wlock,
889 all_files=all_files)
889 all_files=all_files)
890 except:
890 except:
891 self.ui.warn(_('cleaning up working directory...'))
891 self.ui.warn(_('cleaning up working directory...'))
892 node = repo.dirstate.parents()[0]
892 node = repo.dirstate.parents()[0]
893 hg.revert(repo, node, None, wlock)
893 hg.revert(repo, node, None, wlock)
894 unknown = repo.status(wlock=wlock)[4]
894 unknown = repo.status(wlock=wlock)[4]
895 # only remove unknown files that we know we touched or
895 # only remove unknown files that we know we touched or
896 # created while patching
896 # created while patching
897 for f in unknown:
897 for f in unknown:
898 if f in all_files:
898 if f in all_files:
899 util.unlink(repo.wjoin(f))
899 util.unlink(repo.wjoin(f))
900 self.ui.warn(_('done\n'))
900 self.ui.warn(_('done\n'))
901 raise
901 raise
902 top = self.applied[-1].name
902 top = self.applied[-1].name
903 if ret[0]:
903 if ret[0]:
904 self.ui.write("Errors during apply, please fix and refresh %s\n" %
904 self.ui.write("Errors during apply, please fix and refresh %s\n" %
905 top)
905 top)
906 else:
906 else:
907 self.ui.write("Now at: %s\n" % top)
907 self.ui.write("Now at: %s\n" % top)
908 return ret[0]
908 return ret[0]
909
909
910 def pop(self, repo, patch=None, force=False, update=True, all=False,
910 def pop(self, repo, patch=None, force=False, update=True, all=False,
911 wlock=None):
911 wlock=None):
912 def getfile(f, rev):
912 def getfile(f, rev):
913 t = repo.file(f).read(rev)
913 t = repo.file(f).read(rev)
914 repo.wfile(f, "w").write(t)
914 repo.wfile(f, "w").write(t)
915
915
916 if not wlock:
916 if not wlock:
917 wlock = repo.wlock()
917 wlock = repo.wlock()
918 if patch:
918 if patch:
919 # index, rev, patch
919 # index, rev, patch
920 info = self.isapplied(patch)
920 info = self.isapplied(patch)
921 if not info:
921 if not info:
922 patch = self.lookup(patch)
922 patch = self.lookup(patch)
923 info = self.isapplied(patch)
923 info = self.isapplied(patch)
924 if not info:
924 if not info:
925 raise util.Abort(_("patch %s is not applied") % patch)
925 raise util.Abort(_("patch %s is not applied") % patch)
926
926
927 if len(self.applied) == 0:
927 if len(self.applied) == 0:
928 # Allow qpop -a to work repeatedly,
928 # Allow qpop -a to work repeatedly,
929 # but not qpop without an argument
929 # but not qpop without an argument
930 self.ui.warn(_("no patches applied\n"))
930 self.ui.warn(_("no patches applied\n"))
931 return not all
931 return not all
932
932
933 if not update:
933 if not update:
934 parents = repo.dirstate.parents()
934 parents = repo.dirstate.parents()
935 rr = [ revlog.bin(x.rev) for x in self.applied ]
935 rr = [ revlog.bin(x.rev) for x in self.applied ]
936 for p in parents:
936 for p in parents:
937 if p in rr:
937 if p in rr:
938 self.ui.warn("qpop: forcing dirstate update\n")
938 self.ui.warn("qpop: forcing dirstate update\n")
939 update = True
939 update = True
940
940
941 if not force and update:
941 if not force and update:
942 self.check_localchanges(repo)
942 self.check_localchanges(repo)
943
943
944 self.applied_dirty = 1;
944 self.applied_dirty = 1;
945 end = len(self.applied)
945 end = len(self.applied)
946 if not patch:
946 if not patch:
947 if all:
947 if all:
948 popi = 0
948 popi = 0
949 else:
949 else:
950 popi = len(self.applied) - 1
950 popi = len(self.applied) - 1
951 else:
951 else:
952 popi = info[0] + 1
952 popi = info[0] + 1
953 if popi >= end:
953 if popi >= end:
954 self.ui.warn("qpop: %s is already at the top\n" % patch)
954 self.ui.warn("qpop: %s is already at the top\n" % patch)
955 return
955 return
956 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
956 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
957
957
958 start = info[0]
958 start = info[0]
959 rev = revlog.bin(info[1])
959 rev = revlog.bin(info[1])
960
960
961 # we know there are no local changes, so we can make a simplified
961 # we know there are no local changes, so we can make a simplified
962 # form of hg.update.
962 # form of hg.update.
963 if update:
963 if update:
964 top = self.check_toppatch(repo)
964 top = self.check_toppatch(repo)
965 qp = self.qparents(repo, rev)
965 qp = self.qparents(repo, rev)
966 changes = repo.changelog.read(qp)
966 changes = repo.changelog.read(qp)
967 mmap = repo.manifest.read(changes[0])
967 mmap = repo.manifest.read(changes[0])
968 m, a, r, d, u = repo.status(qp, top)[:5]
968 m, a, r, d, u = repo.status(qp, top)[:5]
969 if d:
969 if d:
970 raise util.Abort("deletions found between repo revs")
970 raise util.Abort("deletions found between repo revs")
971 for f in m:
971 for f in m:
972 getfile(f, mmap[f])
972 getfile(f, mmap[f])
973 for f in r:
973 for f in r:
974 getfile(f, mmap[f])
974 getfile(f, mmap[f])
975 util.set_exec(repo.wjoin(f), mmap.execf(f))
975 util.set_exec(repo.wjoin(f), mmap.execf(f))
976 repo.dirstate.update(m + r, 'n')
976 repo.dirstate.update(m + r, 'n')
977 for f in a:
977 for f in a:
978 try:
978 try:
979 os.unlink(repo.wjoin(f))
979 os.unlink(repo.wjoin(f))
980 except OSError, e:
980 except OSError, e:
981 if e.errno != errno.ENOENT:
981 if e.errno != errno.ENOENT:
982 raise
982 raise
983 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
983 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
984 except: pass
984 except: pass
985 if a:
985 if a:
986 repo.dirstate.forget(a)
986 repo.dirstate.forget(a)
987 repo.dirstate.setparents(qp, revlog.nullid)
987 repo.dirstate.setparents(qp, revlog.nullid)
988 self.strip(repo, rev, update=False, backup='strip', wlock=wlock)
988 self.strip(repo, rev, update=False, backup='strip', wlock=wlock)
989 del self.applied[start:end]
989 del self.applied[start:end]
990 if len(self.applied):
990 if len(self.applied):
991 self.ui.write("Now at: %s\n" % self.applied[-1].name)
991 self.ui.write("Now at: %s\n" % self.applied[-1].name)
992 else:
992 else:
993 self.ui.write("Patch queue now empty\n")
993 self.ui.write("Patch queue now empty\n")
994
994
995 def diff(self, repo, pats, opts):
995 def diff(self, repo, pats, opts):
996 top = self.check_toppatch(repo)
996 top = self.check_toppatch(repo)
997 if not top:
997 if not top:
998 self.ui.write("No patches applied\n")
998 self.ui.write("No patches applied\n")
999 return
999 return
1000 qp = self.qparents(repo, top)
1000 qp = self.qparents(repo, top)
1001 if opts.get('git'):
1001 if opts.get('git'):
1002 self.diffopts().git = True
1002 self.diffopts().git = True
1003 self.printdiff(repo, qp, files=pats, opts=opts)
1003 self.printdiff(repo, qp, files=pats, opts=opts)
1004
1004
1005 def refresh(self, repo, pats=None, **opts):
1005 def refresh(self, repo, pats=None, **opts):
1006 if len(self.applied) == 0:
1006 if len(self.applied) == 0:
1007 self.ui.write("No patches applied\n")
1007 self.ui.write("No patches applied\n")
1008 return 1
1008 return 1
1009 wlock = repo.wlock()
1009 wlock = repo.wlock()
1010 self.check_toppatch(repo)
1010 self.check_toppatch(repo)
1011 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
1011 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
1012 top = revlog.bin(top)
1012 top = revlog.bin(top)
1013 cparents = repo.changelog.parents(top)
1013 cparents = repo.changelog.parents(top)
1014 patchparent = self.qparents(repo, top)
1014 patchparent = self.qparents(repo, top)
1015 message, comments, user, date, patchfound = self.readheaders(patchfn)
1015 message, comments, user, date, patchfound = self.readheaders(patchfn)
1016
1016
1017 patchf = self.opener(patchfn, "w")
1017 patchf = self.opener(patchfn, "w")
1018 msg = opts.get('msg', '').rstrip()
1018 msg = opts.get('msg', '').rstrip()
1019 if msg:
1019 if msg:
1020 if comments:
1020 if comments:
1021 # Remove existing message.
1021 # Remove existing message.
1022 ci = 0
1022 ci = 0
1023 subj = None
1023 subj = None
1024 for mi in xrange(len(message)):
1024 for mi in xrange(len(message)):
1025 if comments[ci].lower().startswith('subject: '):
1025 if comments[ci].lower().startswith('subject: '):
1026 subj = comments[ci][9:]
1026 subj = comments[ci][9:]
1027 while message[mi] != comments[ci] and message[mi] != subj:
1027 while message[mi] != comments[ci] and message[mi] != subj:
1028 ci += 1
1028 ci += 1
1029 del comments[ci]
1029 del comments[ci]
1030 comments.append(msg)
1030 comments.append(msg)
1031 if comments:
1031 if comments:
1032 comments = "\n".join(comments) + '\n\n'
1032 comments = "\n".join(comments) + '\n\n'
1033 patchf.write(comments)
1033 patchf.write(comments)
1034
1034
1035 if opts.get('git'):
1035 if opts.get('git'):
1036 self.diffopts().git = True
1036 self.diffopts().git = True
1037 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1037 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1038 tip = repo.changelog.tip()
1038 tip = repo.changelog.tip()
1039 if top == tip:
1039 if top == tip:
1040 # if the top of our patch queue is also the tip, there is an
1040 # if the top of our patch queue is also the tip, there is an
1041 # optimization here. We update the dirstate in place and strip
1041 # optimization here. We update the dirstate in place and strip
1042 # off the tip commit. Then just commit the current directory
1042 # off the tip commit. Then just commit the current directory
1043 # tree. We can also send repo.commit the list of files
1043 # tree. We can also send repo.commit the list of files
1044 # changed to speed up the diff
1044 # changed to speed up the diff
1045 #
1045 #
1046 # in short mode, we only diff the files included in the
1046 # in short mode, we only diff the files included in the
1047 # patch already
1047 # patch already
1048 #
1048 #
1049 # this should really read:
1049 # this should really read:
1050 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
1050 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
1051 # but we do it backwards to take advantage of manifest/chlog
1051 # but we do it backwards to take advantage of manifest/chlog
1052 # caching against the next repo.status call
1052 # caching against the next repo.status call
1053 #
1053 #
1054 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
1054 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
1055 changes = repo.changelog.read(tip)
1055 changes = repo.changelog.read(tip)
1056 man = repo.manifest.read(changes[0])
1056 man = repo.manifest.read(changes[0])
1057 aaa = aa[:]
1057 aaa = aa[:]
1058 if opts.get('short'):
1058 if opts.get('short'):
1059 filelist = mm + aa + dd
1059 filelist = mm + aa + dd
1060 else:
1060 else:
1061 filelist = None
1061 filelist = None
1062 m, a, r, d, u = repo.status(files=filelist)[:5]
1062 m, a, r, d, u = repo.status(files=filelist)[:5]
1063
1063
1064 # we might end up with files that were added between tip and
1064 # we might end up with files that were added between tip and
1065 # the dirstate parent, but then changed in the local dirstate.
1065 # the dirstate parent, but then changed in the local dirstate.
1066 # in this case, we want them to only show up in the added section
1066 # in this case, we want them to only show up in the added section
1067 for x in m:
1067 for x in m:
1068 if x not in aa:
1068 if x not in aa:
1069 mm.append(x)
1069 mm.append(x)
1070 # we might end up with files added by the local dirstate that
1070 # we might end up with files added by the local dirstate that
1071 # were deleted by the patch. In this case, they should only
1071 # were deleted by the patch. In this case, they should only
1072 # show up in the changed section.
1072 # show up in the changed section.
1073 for x in a:
1073 for x in a:
1074 if x in dd:
1074 if x in dd:
1075 del dd[dd.index(x)]
1075 del dd[dd.index(x)]
1076 mm.append(x)
1076 mm.append(x)
1077 else:
1077 else:
1078 aa.append(x)
1078 aa.append(x)
1079 # make sure any files deleted in the local dirstate
1079 # make sure any files deleted in the local dirstate
1080 # are not in the add or change column of the patch
1080 # are not in the add or change column of the patch
1081 forget = []
1081 forget = []
1082 for x in d + r:
1082 for x in d + r:
1083 if x in aa:
1083 if x in aa:
1084 del aa[aa.index(x)]
1084 del aa[aa.index(x)]
1085 forget.append(x)
1085 forget.append(x)
1086 continue
1086 continue
1087 elif x in mm:
1087 elif x in mm:
1088 del mm[mm.index(x)]
1088 del mm[mm.index(x)]
1089 dd.append(x)
1089 dd.append(x)
1090
1090
1091 m = util.unique(mm)
1091 m = util.unique(mm)
1092 r = util.unique(dd)
1092 r = util.unique(dd)
1093 a = util.unique(aa)
1093 a = util.unique(aa)
1094 c = [filter(matchfn, l) for l in (m, a, r, [], u)]
1094 c = [filter(matchfn, l) for l in (m, a, r, [], u)]
1095 filelist = util.unique(c[0] + c[1] + c[2])
1095 filelist = util.unique(c[0] + c[1] + c[2])
1096 patch.diff(repo, patchparent, files=filelist, match=matchfn,
1096 patch.diff(repo, patchparent, files=filelist, match=matchfn,
1097 fp=patchf, changes=c, opts=self.diffopts())
1097 fp=patchf, changes=c, opts=self.diffopts())
1098 patchf.close()
1098 patchf.close()
1099
1099
1100 repo.dirstate.setparents(*cparents)
1100 repo.dirstate.setparents(*cparents)
1101 copies = {}
1101 copies = {}
1102 for dst in a:
1102 for dst in a:
1103 src = repo.dirstate.copied(dst)
1103 src = repo.dirstate.copied(dst)
1104 if src is None:
1104 if src is None:
1105 continue
1105 continue
1106 copies.setdefault(src, []).append(dst)
1106 copies.setdefault(src, []).append(dst)
1107 repo.dirstate.update(a, 'a')
1107 repo.dirstate.update(a, 'a')
1108 # remember the copies between patchparent and tip
1108 # remember the copies between patchparent and tip
1109 # this may be slow, so don't do it if we're not tracking copies
1109 # this may be slow, so don't do it if we're not tracking copies
1110 if self.diffopts().git:
1110 if self.diffopts().git:
1111 for dst in aaa:
1111 for dst in aaa:
1112 f = repo.file(dst)
1112 f = repo.file(dst)
1113 src = f.renamed(man[dst])
1113 src = f.renamed(man[dst])
1114 if src:
1114 if src:
1115 copies[src[0]] = copies.get(dst, [])
1115 copies[src[0]] = copies.get(dst, [])
1116 if dst in a:
1116 if dst in a:
1117 copies[src[0]].append(dst)
1117 copies[src[0]].append(dst)
1118 # we can't copy a file created by the patch itself
1118 # we can't copy a file created by the patch itself
1119 if dst in copies:
1119 if dst in copies:
1120 del copies[dst]
1120 del copies[dst]
1121 for src, dsts in copies.iteritems():
1121 for src, dsts in copies.iteritems():
1122 for dst in dsts:
1122 for dst in dsts:
1123 repo.dirstate.copy(src, dst)
1123 repo.dirstate.copy(src, dst)
1124 repo.dirstate.update(r, 'r')
1124 repo.dirstate.update(r, 'r')
1125 # if the patch excludes a modified file, mark that file with mtime=0
1125 # if the patch excludes a modified file, mark that file with mtime=0
1126 # so status can see it.
1126 # so status can see it.
1127 mm = []
1127 mm = []
1128 for i in xrange(len(m)-1, -1, -1):
1128 for i in xrange(len(m)-1, -1, -1):
1129 if not matchfn(m[i]):
1129 if not matchfn(m[i]):
1130 mm.append(m[i])
1130 mm.append(m[i])
1131 del m[i]
1131 del m[i]
1132 repo.dirstate.update(m, 'n')
1132 repo.dirstate.update(m, 'n')
1133 repo.dirstate.update(mm, 'n', st_mtime=-1, st_size=-1)
1133 repo.dirstate.update(mm, 'n', st_mtime=-1, st_size=-1)
1134 repo.dirstate.forget(forget)
1134 repo.dirstate.forget(forget)
1135
1135
1136 if not msg:
1136 if not msg:
1137 if not message:
1137 if not message:
1138 message = "patch queue: %s\n" % patchfn
1138 message = "patch queue: %s\n" % patchfn
1139 else:
1139 else:
1140 message = "\n".join(message)
1140 message = "\n".join(message)
1141 else:
1141 else:
1142 message = msg
1142 message = msg
1143
1143
1144 self.strip(repo, top, update=False, backup='strip', wlock=wlock)
1144 self.strip(repo, top, update=False, backup='strip', wlock=wlock)
1145 n = repo.commit(filelist, message, changes[1], match=matchfn,
1145 n = repo.commit(filelist, message, changes[1], match=matchfn,
1146 force=1, wlock=wlock)
1146 force=1, wlock=wlock)
1147 self.applied[-1] = statusentry(revlog.hex(n), patchfn)
1147 self.applied[-1] = statusentry(revlog.hex(n), patchfn)
1148 self.applied_dirty = 1
1148 self.applied_dirty = 1
1149 self.removeundo(repo)
1149 self.removeundo(repo)
1150 else:
1150 else:
1151 self.printdiff(repo, patchparent, fp=patchf)
1151 self.printdiff(repo, patchparent, fp=patchf)
1152 patchf.close()
1152 patchf.close()
1153 added = repo.status()[1]
1153 added = repo.status()[1]
1154 for a in added:
1154 for a in added:
1155 f = repo.wjoin(a)
1155 f = repo.wjoin(a)
1156 try:
1156 try:
1157 os.unlink(f)
1157 os.unlink(f)
1158 except OSError, e:
1158 except OSError, e:
1159 if e.errno != errno.ENOENT:
1159 if e.errno != errno.ENOENT:
1160 raise
1160 raise
1161 try: os.removedirs(os.path.dirname(f))
1161 try: os.removedirs(os.path.dirname(f))
1162 except: pass
1162 except: pass
1163 # forget the file copies in the dirstate
1163 # forget the file copies in the dirstate
1164 # push should readd the files later on
1164 # push should readd the files later on
1165 repo.dirstate.forget(added)
1165 repo.dirstate.forget(added)
1166 self.pop(repo, force=True, wlock=wlock)
1166 self.pop(repo, force=True, wlock=wlock)
1167 self.push(repo, force=True, wlock=wlock)
1167 self.push(repo, force=True, wlock=wlock)
1168
1168
1169 def init(self, repo, create=False):
1169 def init(self, repo, create=False):
1170 if not create and os.path.isdir(self.path):
1170 if not create and os.path.isdir(self.path):
1171 raise util.Abort(_("patch queue directory already exists"))
1171 raise util.Abort(_("patch queue directory already exists"))
1172 try:
1172 try:
1173 os.mkdir(self.path)
1173 os.mkdir(self.path)
1174 except OSError, inst:
1174 except OSError, inst:
1175 if inst.errno != errno.EEXIST or not create:
1175 if inst.errno != errno.EEXIST or not create:
1176 raise
1176 raise
1177 if create:
1177 if create:
1178 return self.qrepo(create=True)
1178 return self.qrepo(create=True)
1179
1179
1180 def unapplied(self, repo, patch=None):
1180 def unapplied(self, repo, patch=None):
1181 if patch and patch not in self.series:
1181 if patch and patch not in self.series:
1182 raise util.Abort(_("patch %s is not in series file") % patch)
1182 raise util.Abort(_("patch %s is not in series file") % patch)
1183 if not patch:
1183 if not patch:
1184 start = self.series_end()
1184 start = self.series_end()
1185 else:
1185 else:
1186 start = self.series.index(patch) + 1
1186 start = self.series.index(patch) + 1
1187 unapplied = []
1187 unapplied = []
1188 for i in xrange(start, len(self.series)):
1188 for i in xrange(start, len(self.series)):
1189 pushable, reason = self.pushable(i)
1189 pushable, reason = self.pushable(i)
1190 if pushable:
1190 if pushable:
1191 unapplied.append((i, self.series[i]))
1191 unapplied.append((i, self.series[i]))
1192 self.explain_pushable(i)
1192 self.explain_pushable(i)
1193 return unapplied
1193 return unapplied
1194
1194
1195 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1195 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1196 summary=False):
1196 summary=False):
1197 def displayname(patchname):
1197 def displayname(patchname):
1198 if summary:
1198 if summary:
1199 msg = self.readheaders(patchname)[0]
1199 msg = self.readheaders(patchname)[0]
1200 msg = msg and ': ' + msg[0] or ': '
1200 msg = msg and ': ' + msg[0] or ': '
1201 else:
1201 else:
1202 msg = ''
1202 msg = ''
1203 return '%s%s' % (patchname, msg)
1203 return '%s%s' % (patchname, msg)
1204
1204
1205 applied = dict.fromkeys([p.name for p in self.applied])
1205 applied = dict.fromkeys([p.name for p in self.applied])
1206 if length is None:
1206 if length is None:
1207 length = len(self.series) - start
1207 length = len(self.series) - start
1208 if not missing:
1208 if not missing:
1209 for i in xrange(start, start+length):
1209 for i in xrange(start, start+length):
1210 patch = self.series[i]
1210 patch = self.series[i]
1211 if patch in applied:
1211 if patch in applied:
1212 stat = 'A'
1212 stat = 'A'
1213 elif self.pushable(i)[0]:
1213 elif self.pushable(i)[0]:
1214 stat = 'U'
1214 stat = 'U'
1215 else:
1215 else:
1216 stat = 'G'
1216 stat = 'G'
1217 pfx = ''
1217 pfx = ''
1218 if self.ui.verbose:
1218 if self.ui.verbose:
1219 pfx = '%d %s ' % (i, stat)
1219 pfx = '%d %s ' % (i, stat)
1220 elif status and status != stat:
1220 elif status and status != stat:
1221 continue
1221 continue
1222 self.ui.write('%s%s\n' % (pfx, displayname(patch)))
1222 self.ui.write('%s%s\n' % (pfx, displayname(patch)))
1223 else:
1223 else:
1224 msng_list = []
1224 msng_list = []
1225 for root, dirs, files in os.walk(self.path):
1225 for root, dirs, files in os.walk(self.path):
1226 d = root[len(self.path) + 1:]
1226 d = root[len(self.path) + 1:]
1227 for f in files:
1227 for f in files:
1228 fl = os.path.join(d, f)
1228 fl = os.path.join(d, f)
1229 if (fl not in self.series and
1229 if (fl not in self.series and
1230 fl not in (self.status_path, self.series_path,
1230 fl not in (self.status_path, self.series_path,
1231 self.guards_path)
1231 self.guards_path)
1232 and not fl.startswith('.')):
1232 and not fl.startswith('.')):
1233 msng_list.append(fl)
1233 msng_list.append(fl)
1234 msng_list.sort()
1234 msng_list.sort()
1235 for x in msng_list:
1235 for x in msng_list:
1236 pfx = self.ui.verbose and ('D ') or ''
1236 pfx = self.ui.verbose and ('D ') or ''
1237 self.ui.write("%s%s\n" % (pfx, displayname(x)))
1237 self.ui.write("%s%s\n" % (pfx, displayname(x)))
1238
1238
1239 def issaveline(self, l):
1239 def issaveline(self, l):
1240 if l.name == '.hg.patches.save.line':
1240 if l.name == '.hg.patches.save.line':
1241 return True
1241 return True
1242
1242
1243 def qrepo(self, create=False):
1243 def qrepo(self, create=False):
1244 if create or os.path.isdir(self.join(".hg")):
1244 if create or os.path.isdir(self.join(".hg")):
1245 return hg.repository(self.ui, path=self.path, create=create)
1245 return hg.repository(self.ui, path=self.path, create=create)
1246
1246
1247 def restore(self, repo, rev, delete=None, qupdate=None):
1247 def restore(self, repo, rev, delete=None, qupdate=None):
1248 c = repo.changelog.read(rev)
1248 c = repo.changelog.read(rev)
1249 desc = c[4].strip()
1249 desc = c[4].strip()
1250 lines = desc.splitlines()
1250 lines = desc.splitlines()
1251 i = 0
1251 i = 0
1252 datastart = None
1252 datastart = None
1253 series = []
1253 series = []
1254 applied = []
1254 applied = []
1255 qpp = None
1255 qpp = None
1256 for i in xrange(0, len(lines)):
1256 for i in xrange(0, len(lines)):
1257 if lines[i] == 'Patch Data:':
1257 if lines[i] == 'Patch Data:':
1258 datastart = i + 1
1258 datastart = i + 1
1259 elif lines[i].startswith('Dirstate:'):
1259 elif lines[i].startswith('Dirstate:'):
1260 l = lines[i].rstrip()
1260 l = lines[i].rstrip()
1261 l = l[10:].split(' ')
1261 l = l[10:].split(' ')
1262 qpp = [ hg.bin(x) for x in l ]
1262 qpp = [ hg.bin(x) for x in l ]
1263 elif datastart != None:
1263 elif datastart != None:
1264 l = lines[i].rstrip()
1264 l = lines[i].rstrip()
1265 se = statusentry(l)
1265 se = statusentry(l)
1266 file_ = se.name
1266 file_ = se.name
1267 if se.rev:
1267 if se.rev:
1268 applied.append(se)
1268 applied.append(se)
1269 else:
1269 else:
1270 series.append(file_)
1270 series.append(file_)
1271 if datastart == None:
1271 if datastart == None:
1272 self.ui.warn("No saved patch data found\n")
1272 self.ui.warn("No saved patch data found\n")
1273 return 1
1273 return 1
1274 self.ui.warn("restoring status: %s\n" % lines[0])
1274 self.ui.warn("restoring status: %s\n" % lines[0])
1275 self.full_series = series
1275 self.full_series = series
1276 self.applied = applied
1276 self.applied = applied
1277 self.parse_series()
1277 self.parse_series()
1278 self.series_dirty = 1
1278 self.series_dirty = 1
1279 self.applied_dirty = 1
1279 self.applied_dirty = 1
1280 heads = repo.changelog.heads()
1280 heads = repo.changelog.heads()
1281 if delete:
1281 if delete:
1282 if rev not in heads:
1282 if rev not in heads:
1283 self.ui.warn("save entry has children, leaving it alone\n")
1283 self.ui.warn("save entry has children, leaving it alone\n")
1284 else:
1284 else:
1285 self.ui.warn("removing save entry %s\n" % hg.short(rev))
1285 self.ui.warn("removing save entry %s\n" % hg.short(rev))
1286 pp = repo.dirstate.parents()
1286 pp = repo.dirstate.parents()
1287 if rev in pp:
1287 if rev in pp:
1288 update = True
1288 update = True
1289 else:
1289 else:
1290 update = False
1290 update = False
1291 self.strip(repo, rev, update=update, backup='strip')
1291 self.strip(repo, rev, update=update, backup='strip')
1292 if qpp:
1292 if qpp:
1293 self.ui.warn("saved queue repository parents: %s %s\n" %
1293 self.ui.warn("saved queue repository parents: %s %s\n" %
1294 (hg.short(qpp[0]), hg.short(qpp[1])))
1294 (hg.short(qpp[0]), hg.short(qpp[1])))
1295 if qupdate:
1295 if qupdate:
1296 print "queue directory updating"
1296 print "queue directory updating"
1297 r = self.qrepo()
1297 r = self.qrepo()
1298 if not r:
1298 if not r:
1299 self.ui.warn("Unable to load queue repository\n")
1299 self.ui.warn("Unable to load queue repository\n")
1300 return 1
1300 return 1
1301 hg.clean(r, qpp[0])
1301 hg.clean(r, qpp[0])
1302
1302
1303 def save(self, repo, msg=None):
1303 def save(self, repo, msg=None):
1304 if len(self.applied) == 0:
1304 if len(self.applied) == 0:
1305 self.ui.warn("save: no patches applied, exiting\n")
1305 self.ui.warn("save: no patches applied, exiting\n")
1306 return 1
1306 return 1
1307 if self.issaveline(self.applied[-1]):
1307 if self.issaveline(self.applied[-1]):
1308 self.ui.warn("status is already saved\n")
1308 self.ui.warn("status is already saved\n")
1309 return 1
1309 return 1
1310
1310
1311 ar = [ ':' + x for x in self.full_series ]
1311 ar = [ ':' + x for x in self.full_series ]
1312 if not msg:
1312 if not msg:
1313 msg = "hg patches saved state"
1313 msg = "hg patches saved state"
1314 else:
1314 else:
1315 msg = "hg patches: " + msg.rstrip('\r\n')
1315 msg = "hg patches: " + msg.rstrip('\r\n')
1316 r = self.qrepo()
1316 r = self.qrepo()
1317 if r:
1317 if r:
1318 pp = r.dirstate.parents()
1318 pp = r.dirstate.parents()
1319 msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1]))
1319 msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1]))
1320 msg += "\n\nPatch Data:\n"
1320 msg += "\n\nPatch Data:\n"
1321 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1321 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1322 "\n".join(ar) + '\n' or "")
1322 "\n".join(ar) + '\n' or "")
1323 n = repo.commit(None, text, user=None, force=1)
1323 n = repo.commit(None, text, user=None, force=1)
1324 if not n:
1324 if not n:
1325 self.ui.warn("repo commit failed\n")
1325 self.ui.warn("repo commit failed\n")
1326 return 1
1326 return 1
1327 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1327 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1328 self.applied_dirty = 1
1328 self.applied_dirty = 1
1329 self.removeundo(repo)
1329 self.removeundo(repo)
1330
1330
1331 def full_series_end(self):
1331 def full_series_end(self):
1332 if len(self.applied) > 0:
1332 if len(self.applied) > 0:
1333 p = self.applied[-1].name
1333 p = self.applied[-1].name
1334 end = self.find_series(p)
1334 end = self.find_series(p)
1335 if end == None:
1335 if end == None:
1336 return len(self.full_series)
1336 return len(self.full_series)
1337 return end + 1
1337 return end + 1
1338 return 0
1338 return 0
1339
1339
1340 def series_end(self, all_patches=False):
1340 def series_end(self, all_patches=False):
1341 """If all_patches is False, return the index of the next pushable patch
1341 """If all_patches is False, return the index of the next pushable patch
1342 in the series, or the series length. If all_patches is True, return the
1342 in the series, or the series length. If all_patches is True, return the
1343 index of the first patch past the last applied one.
1343 index of the first patch past the last applied one.
1344 """
1344 """
1345 end = 0
1345 end = 0
1346 def next(start):
1346 def next(start):
1347 if all_patches:
1347 if all_patches:
1348 return start
1348 return start
1349 i = start
1349 i = start
1350 while i < len(self.series):
1350 while i < len(self.series):
1351 p, reason = self.pushable(i)
1351 p, reason = self.pushable(i)
1352 if p:
1352 if p:
1353 break
1353 break
1354 self.explain_pushable(i)
1354 self.explain_pushable(i)
1355 i += 1
1355 i += 1
1356 return i
1356 return i
1357 if len(self.applied) > 0:
1357 if len(self.applied) > 0:
1358 p = self.applied[-1].name
1358 p = self.applied[-1].name
1359 try:
1359 try:
1360 end = self.series.index(p)
1360 end = self.series.index(p)
1361 except ValueError:
1361 except ValueError:
1362 return 0
1362 return 0
1363 return next(end + 1)
1363 return next(end + 1)
1364 return next(end)
1364 return next(end)
1365
1365
1366 def appliedname(self, index):
1366 def appliedname(self, index):
1367 pname = self.applied[index].name
1367 pname = self.applied[index].name
1368 if not self.ui.verbose:
1368 if not self.ui.verbose:
1369 p = pname
1369 p = pname
1370 else:
1370 else:
1371 p = str(self.series.index(pname)) + " " + pname
1371 p = str(self.series.index(pname)) + " " + pname
1372 return p
1372 return p
1373
1373
1374 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1374 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1375 force=None, git=False):
1375 force=None, git=False):
1376 def checkseries(patchname):
1376 def checkseries(patchname):
1377 if patchname in self.series:
1377 if patchname in self.series:
1378 raise util.Abort(_('patch %s is already in the series file')
1378 raise util.Abort(_('patch %s is already in the series file')
1379 % patchname)
1379 % patchname)
1380 def checkfile(patchname):
1380 def checkfile(patchname):
1381 if not force and os.path.exists(self.join(patchname)):
1381 if not force and os.path.exists(self.join(patchname)):
1382 raise util.Abort(_('patch "%s" already exists')
1382 raise util.Abort(_('patch "%s" already exists')
1383 % patchname)
1383 % patchname)
1384
1384
1385 if rev:
1385 if rev:
1386 if files:
1386 if files:
1387 raise util.Abort(_('option "-r" not valid when importing '
1387 raise util.Abort(_('option "-r" not valid when importing '
1388 'files'))
1388 'files'))
1389 rev = cmdutil.revrange(repo, rev)
1389 rev = cmdutil.revrange(repo, rev)
1390 rev.sort(lambda x, y: cmp(y, x))
1390 rev.sort(lambda x, y: cmp(y, x))
1391 if (len(files) > 1 or len(rev) > 1) and patchname:
1391 if (len(files) > 1 or len(rev) > 1) and patchname:
1392 raise util.Abort(_('option "-n" not valid when importing multiple '
1392 raise util.Abort(_('option "-n" not valid when importing multiple '
1393 'patches'))
1393 'patches'))
1394 i = 0
1394 i = 0
1395 added = []
1395 added = []
1396 if rev:
1396 if rev:
1397 # If mq patches are applied, we can only import revisions
1397 # If mq patches are applied, we can only import revisions
1398 # that form a linear path to qbase.
1398 # that form a linear path to qbase.
1399 # Otherwise, they should form a linear path to a head.
1399 # Otherwise, they should form a linear path to a head.
1400 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1400 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1401 if len(heads) > 1:
1401 if len(heads) > 1:
1402 raise util.Abort(_('revision %d is the root of more than one '
1402 raise util.Abort(_('revision %d is the root of more than one '
1403 'branch') % rev[-1])
1403 'branch') % rev[-1])
1404 if self.applied:
1404 if self.applied:
1405 base = revlog.hex(repo.changelog.node(rev[0]))
1405 base = revlog.hex(repo.changelog.node(rev[0]))
1406 if base in [n.rev for n in self.applied]:
1406 if base in [n.rev for n in self.applied]:
1407 raise util.Abort(_('revision %d is already managed')
1407 raise util.Abort(_('revision %d is already managed')
1408 % rev[0])
1408 % rev[0])
1409 if heads != [revlog.bin(self.applied[-1].rev)]:
1409 if heads != [revlog.bin(self.applied[-1].rev)]:
1410 raise util.Abort(_('revision %d is not the parent of '
1410 raise util.Abort(_('revision %d is not the parent of '
1411 'the queue') % rev[0])
1411 'the queue') % rev[0])
1412 base = repo.changelog.rev(revlog.bin(self.applied[0].rev))
1412 base = repo.changelog.rev(revlog.bin(self.applied[0].rev))
1413 lastparent = repo.changelog.parentrevs(base)[0]
1413 lastparent = repo.changelog.parentrevs(base)[0]
1414 else:
1414 else:
1415 if heads != [repo.changelog.node(rev[0])]:
1415 if heads != [repo.changelog.node(rev[0])]:
1416 raise util.Abort(_('revision %d has unmanaged children')
1416 raise util.Abort(_('revision %d has unmanaged children')
1417 % rev[0])
1417 % rev[0])
1418 lastparent = None
1418 lastparent = None
1419
1419
1420 if git:
1420 if git:
1421 self.diffopts().git = True
1421 self.diffopts().git = True
1422
1422
1423 for r in rev:
1423 for r in rev:
1424 p1, p2 = repo.changelog.parentrevs(r)
1424 p1, p2 = repo.changelog.parentrevs(r)
1425 n = repo.changelog.node(r)
1425 n = repo.changelog.node(r)
1426 if p2 != revlog.nullrev:
1426 if p2 != revlog.nullrev:
1427 raise util.Abort(_('cannot import merge revision %d') % r)
1427 raise util.Abort(_('cannot import merge revision %d') % r)
1428 if lastparent and lastparent != r:
1428 if lastparent and lastparent != r:
1429 raise util.Abort(_('revision %d is not the parent of %d')
1429 raise util.Abort(_('revision %d is not the parent of %d')
1430 % (r, lastparent))
1430 % (r, lastparent))
1431 lastparent = p1
1431 lastparent = p1
1432
1432
1433 if not patchname:
1433 if not patchname:
1434 patchname = normname('%d.diff' % r)
1434 patchname = normname('%d.diff' % r)
1435 checkseries(patchname)
1435 checkseries(patchname)
1436 checkfile(patchname)
1436 checkfile(patchname)
1437 self.full_series.insert(0, patchname)
1437 self.full_series.insert(0, patchname)
1438
1438
1439 patchf = self.opener(patchname, "w")
1439 patchf = self.opener(patchname, "w")
1440 patch.export(repo, [n], fp=patchf, opts=self.diffopts())
1440 patch.export(repo, [n], fp=patchf, opts=self.diffopts())
1441 patchf.close()
1441 patchf.close()
1442
1442
1443 se = statusentry(revlog.hex(n), patchname)
1443 se = statusentry(revlog.hex(n), patchname)
1444 self.applied.insert(0, se)
1444 self.applied.insert(0, se)
1445
1445
1446 added.append(patchname)
1446 added.append(patchname)
1447 patchname = None
1447 patchname = None
1448 self.parse_series()
1448 self.parse_series()
1449 self.applied_dirty = 1
1449 self.applied_dirty = 1
1450
1450
1451 for filename in files:
1451 for filename in files:
1452 if existing:
1452 if existing:
1453 if filename == '-':
1453 if filename == '-':
1454 raise util.Abort(_('-e is incompatible with import from -'))
1454 raise util.Abort(_('-e is incompatible with import from -'))
1455 if not patchname:
1455 if not patchname:
1456 patchname = normname(filename)
1456 patchname = normname(filename)
1457 if not os.path.isfile(self.join(patchname)):
1457 if not os.path.isfile(self.join(patchname)):
1458 raise util.Abort(_("patch %s does not exist") % patchname)
1458 raise util.Abort(_("patch %s does not exist") % patchname)
1459 else:
1459 else:
1460 try:
1460 try:
1461 if filename == '-':
1461 if filename == '-':
1462 if not patchname:
1462 if not patchname:
1463 raise util.Abort(_('need --name to import a patch from -'))
1463 raise util.Abort(_('need --name to import a patch from -'))
1464 text = sys.stdin.read()
1464 text = sys.stdin.read()
1465 else:
1465 else:
1466 text = file(filename).read()
1466 text = file(filename).read()
1467 except IOError:
1467 except IOError:
1468 raise util.Abort(_("unable to read %s") % patchname)
1468 raise util.Abort(_("unable to read %s") % patchname)
1469 if not patchname:
1469 if not patchname:
1470 patchname = normname(os.path.basename(filename))
1470 patchname = normname(os.path.basename(filename))
1471 checkfile(patchname)
1471 checkfile(patchname)
1472 patchf = self.opener(patchname, "w")
1472 patchf = self.opener(patchname, "w")
1473 patchf.write(text)
1473 patchf.write(text)
1474 checkseries(patchname)
1474 checkseries(patchname)
1475 index = self.full_series_end() + i
1475 index = self.full_series_end() + i
1476 self.full_series[index:index] = [patchname]
1476 self.full_series[index:index] = [patchname]
1477 self.parse_series()
1477 self.parse_series()
1478 self.ui.warn("adding %s to series file\n" % patchname)
1478 self.ui.warn("adding %s to series file\n" % patchname)
1479 i += 1
1479 i += 1
1480 added.append(patchname)
1480 added.append(patchname)
1481 patchname = None
1481 patchname = None
1482 self.series_dirty = 1
1482 self.series_dirty = 1
1483 qrepo = self.qrepo()
1483 qrepo = self.qrepo()
1484 if qrepo:
1484 if qrepo:
1485 qrepo.add(added)
1485 qrepo.add(added)
1486
1486
1487 def delete(ui, repo, *patches, **opts):
1487 def delete(ui, repo, *patches, **opts):
1488 """remove patches from queue
1488 """remove patches from queue
1489
1489
1490 With --rev, mq will stop managing the named revisions. The
1490 With --rev, mq will stop managing the named revisions. The
1491 patches must be applied and at the base of the stack. This option
1491 patches must be applied and at the base of the stack. This option
1492 is useful when the patches have been applied upstream.
1492 is useful when the patches have been applied upstream.
1493
1493
1494 Otherwise, the patches must not be applied.
1494 Otherwise, the patches must not be applied.
1495
1495
1496 With --keep, the patch files are preserved in the patch directory."""
1496 With --keep, the patch files are preserved in the patch directory."""
1497 q = repo.mq
1497 q = repo.mq
1498 q.delete(repo, patches, opts)
1498 q.delete(repo, patches, opts)
1499 q.save_dirty()
1499 q.save_dirty()
1500 return 0
1500 return 0
1501
1501
1502 def applied(ui, repo, patch=None, **opts):
1502 def applied(ui, repo, patch=None, **opts):
1503 """print the patches already applied"""
1503 """print the patches already applied"""
1504 q = repo.mq
1504 q = repo.mq
1505 if patch:
1505 if patch:
1506 if patch not in q.series:
1506 if patch not in q.series:
1507 raise util.Abort(_("patch %s is not in series file") % patch)
1507 raise util.Abort(_("patch %s is not in series file") % patch)
1508 end = q.series.index(patch) + 1
1508 end = q.series.index(patch) + 1
1509 else:
1509 else:
1510 end = q.series_end(True)
1510 end = q.series_end(True)
1511 return q.qseries(repo, length=end, status='A', summary=opts.get('summary'))
1511 return q.qseries(repo, length=end, status='A', summary=opts.get('summary'))
1512
1512
1513 def unapplied(ui, repo, patch=None, **opts):
1513 def unapplied(ui, repo, patch=None, **opts):
1514 """print the patches not yet applied"""
1514 """print the patches not yet applied"""
1515 q = repo.mq
1515 q = repo.mq
1516 if patch:
1516 if patch:
1517 if patch not in q.series:
1517 if patch not in q.series:
1518 raise util.Abort(_("patch %s is not in series file") % patch)
1518 raise util.Abort(_("patch %s is not in series file") % patch)
1519 start = q.series.index(patch) + 1
1519 start = q.series.index(patch) + 1
1520 else:
1520 else:
1521 start = q.series_end(True)
1521 start = q.series_end(True)
1522 q.qseries(repo, start=start, status='U', summary=opts.get('summary'))
1522 q.qseries(repo, start=start, status='U', summary=opts.get('summary'))
1523
1523
1524 def qimport(ui, repo, *filename, **opts):
1524 def qimport(ui, repo, *filename, **opts):
1525 """import a patch
1525 """import a patch
1526
1526
1527 The patch will have the same name as its source file unless you
1527 The patch will have the same name as its source file unless you
1528 give it a new one with --name.
1528 give it a new one with --name.
1529
1529
1530 You can register an existing patch inside the patch directory
1530 You can register an existing patch inside the patch directory
1531 with the --existing flag.
1531 with the --existing flag.
1532
1532
1533 With --force, an existing patch of the same name will be overwritten.
1533 With --force, an existing patch of the same name will be overwritten.
1534
1534
1535 An existing changeset may be placed under mq control with --rev
1535 An existing changeset may be placed under mq control with --rev
1536 (e.g. qimport --rev tip -n patch will place tip under mq control).
1536 (e.g. qimport --rev tip -n patch will place tip under mq control).
1537 With --git, patches imported with --rev will use the git diff
1537 With --git, patches imported with --rev will use the git diff
1538 format.
1538 format.
1539 """
1539 """
1540 q = repo.mq
1540 q = repo.mq
1541 q.qimport(repo, filename, patchname=opts['name'],
1541 q.qimport(repo, filename, patchname=opts['name'],
1542 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1542 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1543 git=opts['git'])
1543 git=opts['git'])
1544 q.save_dirty()
1544 q.save_dirty()
1545 return 0
1545 return 0
1546
1546
1547 def init(ui, repo, **opts):
1547 def init(ui, repo, **opts):
1548 """init a new queue repository
1548 """init a new queue repository
1549
1549
1550 The queue repository is unversioned by default. If -c is
1550 The queue repository is unversioned by default. If -c is
1551 specified, qinit will create a separate nested repository
1551 specified, qinit will create a separate nested repository
1552 for patches. Use qcommit to commit changes to this queue
1552 for patches. Use qcommit to commit changes to this queue
1553 repository."""
1553 repository."""
1554 q = repo.mq
1554 q = repo.mq
1555 r = q.init(repo, create=opts['create_repo'])
1555 r = q.init(repo, create=opts['create_repo'])
1556 q.save_dirty()
1556 q.save_dirty()
1557 if r:
1557 if r:
1558 if not os.path.exists(r.wjoin('.hgignore')):
1558 if not os.path.exists(r.wjoin('.hgignore')):
1559 fp = r.wopener('.hgignore', 'w')
1559 fp = r.wopener('.hgignore', 'w')
1560 fp.write('syntax: glob\n')
1560 fp.write('syntax: glob\n')
1561 fp.write('status\n')
1561 fp.write('status\n')
1562 fp.write('guards\n')
1562 fp.write('guards\n')
1563 fp.close()
1563 fp.close()
1564 if not os.path.exists(r.wjoin('series')):
1564 if not os.path.exists(r.wjoin('series')):
1565 r.wopener('series', 'w').close()
1565 r.wopener('series', 'w').close()
1566 r.add(['.hgignore', 'series'])
1566 r.add(['.hgignore', 'series'])
1567 commands.add(ui, r)
1567 commands.add(ui, r)
1568 return 0
1568 return 0
1569
1569
1570 def clone(ui, source, dest=None, **opts):
1570 def clone(ui, source, dest=None, **opts):
1571 '''clone main and patch repository at same time
1571 '''clone main and patch repository at same time
1572
1572
1573 If source is local, destination will have no patches applied. If
1573 If source is local, destination will have no patches applied. If
1574 source is remote, this command can not check if patches are
1574 source is remote, this command can not check if patches are
1575 applied in source, so cannot guarantee that patches are not
1575 applied in source, so cannot guarantee that patches are not
1576 applied in destination. If you clone remote repository, be sure
1576 applied in destination. If you clone remote repository, be sure
1577 before that it has no patches applied.
1577 before that it has no patches applied.
1578
1578
1579 Source patch repository is looked for in <src>/.hg/patches by
1579 Source patch repository is looked for in <src>/.hg/patches by
1580 default. Use -p <url> to change.
1580 default. Use -p <url> to change.
1581 '''
1581 '''
1582 commands.setremoteconfig(ui, opts)
1582 cmdutil.setremoteconfig(ui, opts)
1583 if dest is None:
1583 if dest is None:
1584 dest = hg.defaultdest(source)
1584 dest = hg.defaultdest(source)
1585 sr = hg.repository(ui, ui.expandpath(source))
1585 sr = hg.repository(ui, ui.expandpath(source))
1586 qbase, destrev = None, None
1586 qbase, destrev = None, None
1587 if sr.local():
1587 if sr.local():
1588 if sr.mq.applied:
1588 if sr.mq.applied:
1589 qbase = revlog.bin(sr.mq.applied[0].rev)
1589 qbase = revlog.bin(sr.mq.applied[0].rev)
1590 if not hg.islocal(dest):
1590 if not hg.islocal(dest):
1591 heads = dict.fromkeys(sr.heads())
1591 heads = dict.fromkeys(sr.heads())
1592 for h in sr.heads(qbase):
1592 for h in sr.heads(qbase):
1593 del heads[h]
1593 del heads[h]
1594 destrev = heads.keys()
1594 destrev = heads.keys()
1595 destrev.append(sr.changelog.parents(qbase)[0])
1595 destrev.append(sr.changelog.parents(qbase)[0])
1596 ui.note(_('cloning main repo\n'))
1596 ui.note(_('cloning main repo\n'))
1597 sr, dr = hg.clone(ui, sr.url(), dest,
1597 sr, dr = hg.clone(ui, sr.url(), dest,
1598 pull=opts['pull'],
1598 pull=opts['pull'],
1599 rev=destrev,
1599 rev=destrev,
1600 update=False,
1600 update=False,
1601 stream=opts['uncompressed'])
1601 stream=opts['uncompressed'])
1602 ui.note(_('cloning patch repo\n'))
1602 ui.note(_('cloning patch repo\n'))
1603 spr, dpr = hg.clone(ui, opts['patches'] or (sr.url() + '/.hg/patches'),
1603 spr, dpr = hg.clone(ui, opts['patches'] or (sr.url() + '/.hg/patches'),
1604 dr.url() + '/.hg/patches',
1604 dr.url() + '/.hg/patches',
1605 pull=opts['pull'],
1605 pull=opts['pull'],
1606 update=not opts['noupdate'],
1606 update=not opts['noupdate'],
1607 stream=opts['uncompressed'])
1607 stream=opts['uncompressed'])
1608 if dr.local():
1608 if dr.local():
1609 if qbase:
1609 if qbase:
1610 ui.note(_('stripping applied patches from destination repo\n'))
1610 ui.note(_('stripping applied patches from destination repo\n'))
1611 dr.mq.strip(dr, qbase, update=False, backup=None)
1611 dr.mq.strip(dr, qbase, update=False, backup=None)
1612 if not opts['noupdate']:
1612 if not opts['noupdate']:
1613 ui.note(_('updating destination repo\n'))
1613 ui.note(_('updating destination repo\n'))
1614 hg.update(dr, dr.changelog.tip())
1614 hg.update(dr, dr.changelog.tip())
1615
1615
1616 def commit(ui, repo, *pats, **opts):
1616 def commit(ui, repo, *pats, **opts):
1617 """commit changes in the queue repository"""
1617 """commit changes in the queue repository"""
1618 q = repo.mq
1618 q = repo.mq
1619 r = q.qrepo()
1619 r = q.qrepo()
1620 if not r: raise util.Abort('no queue repository')
1620 if not r: raise util.Abort('no queue repository')
1621 commands.commit(r.ui, r, *pats, **opts)
1621 commands.commit(r.ui, r, *pats, **opts)
1622
1622
1623 def series(ui, repo, **opts):
1623 def series(ui, repo, **opts):
1624 """print the entire series file"""
1624 """print the entire series file"""
1625 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1625 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1626 return 0
1626 return 0
1627
1627
1628 def top(ui, repo, **opts):
1628 def top(ui, repo, **opts):
1629 """print the name of the current patch"""
1629 """print the name of the current patch"""
1630 q = repo.mq
1630 q = repo.mq
1631 t = q.applied and q.series_end(True) or 0
1631 t = q.applied and q.series_end(True) or 0
1632 if t:
1632 if t:
1633 return q.qseries(repo, start=t-1, length=1, status='A',
1633 return q.qseries(repo, start=t-1, length=1, status='A',
1634 summary=opts.get('summary'))
1634 summary=opts.get('summary'))
1635 else:
1635 else:
1636 ui.write("No patches applied\n")
1636 ui.write("No patches applied\n")
1637 return 1
1637 return 1
1638
1638
1639 def next(ui, repo, **opts):
1639 def next(ui, repo, **opts):
1640 """print the name of the next patch"""
1640 """print the name of the next patch"""
1641 q = repo.mq
1641 q = repo.mq
1642 end = q.series_end()
1642 end = q.series_end()
1643 if end == len(q.series):
1643 if end == len(q.series):
1644 ui.write("All patches applied\n")
1644 ui.write("All patches applied\n")
1645 return 1
1645 return 1
1646 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1646 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1647
1647
1648 def prev(ui, repo, **opts):
1648 def prev(ui, repo, **opts):
1649 """print the name of the previous patch"""
1649 """print the name of the previous patch"""
1650 q = repo.mq
1650 q = repo.mq
1651 l = len(q.applied)
1651 l = len(q.applied)
1652 if l == 1:
1652 if l == 1:
1653 ui.write("Only one patch applied\n")
1653 ui.write("Only one patch applied\n")
1654 return 1
1654 return 1
1655 if not l:
1655 if not l:
1656 ui.write("No patches applied\n")
1656 ui.write("No patches applied\n")
1657 return 1
1657 return 1
1658 return q.qseries(repo, start=l-2, length=1, status='A',
1658 return q.qseries(repo, start=l-2, length=1, status='A',
1659 summary=opts.get('summary'))
1659 summary=opts.get('summary'))
1660
1660
1661 def new(ui, repo, patch, **opts):
1661 def new(ui, repo, patch, **opts):
1662 """create a new patch
1662 """create a new patch
1663
1663
1664 qnew creates a new patch on top of the currently-applied patch
1664 qnew creates a new patch on top of the currently-applied patch
1665 (if any). It will refuse to run if there are any outstanding
1665 (if any). It will refuse to run if there are any outstanding
1666 changes unless -f is specified, in which case the patch will
1666 changes unless -f is specified, in which case the patch will
1667 be initialised with them.
1667 be initialised with them.
1668
1668
1669 -e, -m or -l set the patch header as well as the commit message.
1669 -e, -m or -l set the patch header as well as the commit message.
1670 If none is specified, the patch header is empty and the
1670 If none is specified, the patch header is empty and the
1671 commit message is 'New patch: PATCH'"""
1671 commit message is 'New patch: PATCH'"""
1672 q = repo.mq
1672 q = repo.mq
1673 message = commands.logmessage(opts)
1673 message = cmdutil.logmessage(opts)
1674 if opts['edit']:
1674 if opts['edit']:
1675 message = ui.edit(message, ui.username())
1675 message = ui.edit(message, ui.username())
1676 q.new(repo, patch, msg=message, force=opts['force'])
1676 q.new(repo, patch, msg=message, force=opts['force'])
1677 q.save_dirty()
1677 q.save_dirty()
1678 return 0
1678 return 0
1679
1679
1680 def refresh(ui, repo, *pats, **opts):
1680 def refresh(ui, repo, *pats, **opts):
1681 """update the current patch
1681 """update the current patch
1682
1682
1683 If any file patterns are provided, the refreshed patch will contain only
1683 If any file patterns are provided, the refreshed patch will contain only
1684 the modifications that match those patterns; the remaining modifications
1684 the modifications that match those patterns; the remaining modifications
1685 will remain in the working directory.
1685 will remain in the working directory.
1686
1686
1687 hg add/remove/copy/rename work as usual, though you might want to use
1687 hg add/remove/copy/rename work as usual, though you might want to use
1688 git-style patches (--git or [diff] git=1) to track copies and renames.
1688 git-style patches (--git or [diff] git=1) to track copies and renames.
1689 """
1689 """
1690 q = repo.mq
1690 q = repo.mq
1691 message = commands.logmessage(opts)
1691 message = cmdutil.logmessage(opts)
1692 if opts['edit']:
1692 if opts['edit']:
1693 if message:
1693 if message:
1694 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1694 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1695 patch = q.applied[-1].name
1695 patch = q.applied[-1].name
1696 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1696 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1697 message = ui.edit('\n'.join(message), user or ui.username())
1697 message = ui.edit('\n'.join(message), user or ui.username())
1698 ret = q.refresh(repo, pats, msg=message, **opts)
1698 ret = q.refresh(repo, pats, msg=message, **opts)
1699 q.save_dirty()
1699 q.save_dirty()
1700 return ret
1700 return ret
1701
1701
1702 def diff(ui, repo, *pats, **opts):
1702 def diff(ui, repo, *pats, **opts):
1703 """diff of the current patch"""
1703 """diff of the current patch"""
1704 repo.mq.diff(repo, pats, opts)
1704 repo.mq.diff(repo, pats, opts)
1705 return 0
1705 return 0
1706
1706
1707 def fold(ui, repo, *files, **opts):
1707 def fold(ui, repo, *files, **opts):
1708 """fold the named patches into the current patch
1708 """fold the named patches into the current patch
1709
1709
1710 Patches must not yet be applied. Each patch will be successively
1710 Patches must not yet be applied. Each patch will be successively
1711 applied to the current patch in the order given. If all the
1711 applied to the current patch in the order given. If all the
1712 patches apply successfully, the current patch will be refreshed
1712 patches apply successfully, the current patch will be refreshed
1713 with the new cumulative patch, and the folded patches will
1713 with the new cumulative patch, and the folded patches will
1714 be deleted. With -k/--keep, the folded patch files will not
1714 be deleted. With -k/--keep, the folded patch files will not
1715 be removed afterwards.
1715 be removed afterwards.
1716
1716
1717 The header for each folded patch will be concatenated with
1717 The header for each folded patch will be concatenated with
1718 the current patch header, separated by a line of '* * *'."""
1718 the current patch header, separated by a line of '* * *'."""
1719
1719
1720 q = repo.mq
1720 q = repo.mq
1721
1721
1722 if not files:
1722 if not files:
1723 raise util.Abort(_('qfold requires at least one patch name'))
1723 raise util.Abort(_('qfold requires at least one patch name'))
1724 if not q.check_toppatch(repo):
1724 if not q.check_toppatch(repo):
1725 raise util.Abort(_('No patches applied'))
1725 raise util.Abort(_('No patches applied'))
1726
1726
1727 message = commands.logmessage(opts)
1727 message = cmdutil.logmessage(opts)
1728 if opts['edit']:
1728 if opts['edit']:
1729 if message:
1729 if message:
1730 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1730 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1731
1731
1732 parent = q.lookup('qtip')
1732 parent = q.lookup('qtip')
1733 patches = []
1733 patches = []
1734 messages = []
1734 messages = []
1735 for f in files:
1735 for f in files:
1736 p = q.lookup(f)
1736 p = q.lookup(f)
1737 if p in patches or p == parent:
1737 if p in patches or p == parent:
1738 ui.warn(_('Skipping already folded patch %s') % p)
1738 ui.warn(_('Skipping already folded patch %s') % p)
1739 if q.isapplied(p):
1739 if q.isapplied(p):
1740 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1740 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1741 patches.append(p)
1741 patches.append(p)
1742
1742
1743 for p in patches:
1743 for p in patches:
1744 if not message:
1744 if not message:
1745 messages.append(q.readheaders(p)[0])
1745 messages.append(q.readheaders(p)[0])
1746 pf = q.join(p)
1746 pf = q.join(p)
1747 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1747 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1748 if not patchsuccess:
1748 if not patchsuccess:
1749 raise util.Abort(_('Error folding patch %s') % p)
1749 raise util.Abort(_('Error folding patch %s') % p)
1750 patch.updatedir(ui, repo, files)
1750 patch.updatedir(ui, repo, files)
1751
1751
1752 if not message:
1752 if not message:
1753 message, comments, user = q.readheaders(parent)[0:3]
1753 message, comments, user = q.readheaders(parent)[0:3]
1754 for msg in messages:
1754 for msg in messages:
1755 message.append('* * *')
1755 message.append('* * *')
1756 message.extend(msg)
1756 message.extend(msg)
1757 message = '\n'.join(message)
1757 message = '\n'.join(message)
1758
1758
1759 if opts['edit']:
1759 if opts['edit']:
1760 message = ui.edit(message, user or ui.username())
1760 message = ui.edit(message, user or ui.username())
1761
1761
1762 q.refresh(repo, msg=message)
1762 q.refresh(repo, msg=message)
1763 q.delete(repo, patches, opts)
1763 q.delete(repo, patches, opts)
1764 q.save_dirty()
1764 q.save_dirty()
1765
1765
1766 def goto(ui, repo, patch, **opts):
1766 def goto(ui, repo, patch, **opts):
1767 '''push or pop patches until named patch is at top of stack'''
1767 '''push or pop patches until named patch is at top of stack'''
1768 q = repo.mq
1768 q = repo.mq
1769 patch = q.lookup(patch)
1769 patch = q.lookup(patch)
1770 if q.isapplied(patch):
1770 if q.isapplied(patch):
1771 ret = q.pop(repo, patch, force=opts['force'])
1771 ret = q.pop(repo, patch, force=opts['force'])
1772 else:
1772 else:
1773 ret = q.push(repo, patch, force=opts['force'])
1773 ret = q.push(repo, patch, force=opts['force'])
1774 q.save_dirty()
1774 q.save_dirty()
1775 return ret
1775 return ret
1776
1776
1777 def guard(ui, repo, *args, **opts):
1777 def guard(ui, repo, *args, **opts):
1778 '''set or print guards for a patch
1778 '''set or print guards for a patch
1779
1779
1780 Guards control whether a patch can be pushed. A patch with no
1780 Guards control whether a patch can be pushed. A patch with no
1781 guards is always pushed. A patch with a positive guard ("+foo") is
1781 guards is always pushed. A patch with a positive guard ("+foo") is
1782 pushed only if the qselect command has activated it. A patch with
1782 pushed only if the qselect command has activated it. A patch with
1783 a negative guard ("-foo") is never pushed if the qselect command
1783 a negative guard ("-foo") is never pushed if the qselect command
1784 has activated it.
1784 has activated it.
1785
1785
1786 With no arguments, print the currently active guards.
1786 With no arguments, print the currently active guards.
1787 With arguments, set guards for the named patch.
1787 With arguments, set guards for the named patch.
1788
1788
1789 To set a negative guard "-foo" on topmost patch ("--" is needed so
1789 To set a negative guard "-foo" on topmost patch ("--" is needed so
1790 hg will not interpret "-foo" as an option):
1790 hg will not interpret "-foo" as an option):
1791 hg qguard -- -foo
1791 hg qguard -- -foo
1792
1792
1793 To set guards on another patch:
1793 To set guards on another patch:
1794 hg qguard other.patch +2.6.17 -stable
1794 hg qguard other.patch +2.6.17 -stable
1795 '''
1795 '''
1796 def status(idx):
1796 def status(idx):
1797 guards = q.series_guards[idx] or ['unguarded']
1797 guards = q.series_guards[idx] or ['unguarded']
1798 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1798 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1799 q = repo.mq
1799 q = repo.mq
1800 patch = None
1800 patch = None
1801 args = list(args)
1801 args = list(args)
1802 if opts['list']:
1802 if opts['list']:
1803 if args or opts['none']:
1803 if args or opts['none']:
1804 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1804 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1805 for i in xrange(len(q.series)):
1805 for i in xrange(len(q.series)):
1806 status(i)
1806 status(i)
1807 return
1807 return
1808 if not args or args[0][0:1] in '-+':
1808 if not args or args[0][0:1] in '-+':
1809 if not q.applied:
1809 if not q.applied:
1810 raise util.Abort(_('no patches applied'))
1810 raise util.Abort(_('no patches applied'))
1811 patch = q.applied[-1].name
1811 patch = q.applied[-1].name
1812 if patch is None and args[0][0:1] not in '-+':
1812 if patch is None and args[0][0:1] not in '-+':
1813 patch = args.pop(0)
1813 patch = args.pop(0)
1814 if patch is None:
1814 if patch is None:
1815 raise util.Abort(_('no patch to work with'))
1815 raise util.Abort(_('no patch to work with'))
1816 if args or opts['none']:
1816 if args or opts['none']:
1817 idx = q.find_series(patch)
1817 idx = q.find_series(patch)
1818 if idx is None:
1818 if idx is None:
1819 raise util.Abort(_('no patch named %s') % patch)
1819 raise util.Abort(_('no patch named %s') % patch)
1820 q.set_guards(idx, args)
1820 q.set_guards(idx, args)
1821 q.save_dirty()
1821 q.save_dirty()
1822 else:
1822 else:
1823 status(q.series.index(q.lookup(patch)))
1823 status(q.series.index(q.lookup(patch)))
1824
1824
1825 def header(ui, repo, patch=None):
1825 def header(ui, repo, patch=None):
1826 """Print the header of the topmost or specified patch"""
1826 """Print the header of the topmost or specified patch"""
1827 q = repo.mq
1827 q = repo.mq
1828
1828
1829 if patch:
1829 if patch:
1830 patch = q.lookup(patch)
1830 patch = q.lookup(patch)
1831 else:
1831 else:
1832 if not q.applied:
1832 if not q.applied:
1833 ui.write('No patches applied\n')
1833 ui.write('No patches applied\n')
1834 return 1
1834 return 1
1835 patch = q.lookup('qtip')
1835 patch = q.lookup('qtip')
1836 message = repo.mq.readheaders(patch)[0]
1836 message = repo.mq.readheaders(patch)[0]
1837
1837
1838 ui.write('\n'.join(message) + '\n')
1838 ui.write('\n'.join(message) + '\n')
1839
1839
1840 def lastsavename(path):
1840 def lastsavename(path):
1841 (directory, base) = os.path.split(path)
1841 (directory, base) = os.path.split(path)
1842 names = os.listdir(directory)
1842 names = os.listdir(directory)
1843 namere = re.compile("%s.([0-9]+)" % base)
1843 namere = re.compile("%s.([0-9]+)" % base)
1844 maxindex = None
1844 maxindex = None
1845 maxname = None
1845 maxname = None
1846 for f in names:
1846 for f in names:
1847 m = namere.match(f)
1847 m = namere.match(f)
1848 if m:
1848 if m:
1849 index = int(m.group(1))
1849 index = int(m.group(1))
1850 if maxindex == None or index > maxindex:
1850 if maxindex == None or index > maxindex:
1851 maxindex = index
1851 maxindex = index
1852 maxname = f
1852 maxname = f
1853 if maxname:
1853 if maxname:
1854 return (os.path.join(directory, maxname), maxindex)
1854 return (os.path.join(directory, maxname), maxindex)
1855 return (None, None)
1855 return (None, None)
1856
1856
1857 def savename(path):
1857 def savename(path):
1858 (last, index) = lastsavename(path)
1858 (last, index) = lastsavename(path)
1859 if last is None:
1859 if last is None:
1860 index = 0
1860 index = 0
1861 newpath = path + ".%d" % (index + 1)
1861 newpath = path + ".%d" % (index + 1)
1862 return newpath
1862 return newpath
1863
1863
1864 def push(ui, repo, patch=None, **opts):
1864 def push(ui, repo, patch=None, **opts):
1865 """push the next patch onto the stack"""
1865 """push the next patch onto the stack"""
1866 q = repo.mq
1866 q = repo.mq
1867 mergeq = None
1867 mergeq = None
1868
1868
1869 if opts['all']:
1869 if opts['all']:
1870 if not q.series:
1870 if not q.series:
1871 ui.warn(_('no patches in series\n'))
1871 ui.warn(_('no patches in series\n'))
1872 return 0
1872 return 0
1873 patch = q.series[-1]
1873 patch = q.series[-1]
1874 if opts['merge']:
1874 if opts['merge']:
1875 if opts['name']:
1875 if opts['name']:
1876 newpath = opts['name']
1876 newpath = opts['name']
1877 else:
1877 else:
1878 newpath, i = lastsavename(q.path)
1878 newpath, i = lastsavename(q.path)
1879 if not newpath:
1879 if not newpath:
1880 ui.warn("no saved queues found, please use -n\n")
1880 ui.warn("no saved queues found, please use -n\n")
1881 return 1
1881 return 1
1882 mergeq = queue(ui, repo.join(""), newpath)
1882 mergeq = queue(ui, repo.join(""), newpath)
1883 ui.warn("merging with queue at: %s\n" % mergeq.path)
1883 ui.warn("merging with queue at: %s\n" % mergeq.path)
1884 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
1884 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
1885 mergeq=mergeq)
1885 mergeq=mergeq)
1886 return ret
1886 return ret
1887
1887
1888 def pop(ui, repo, patch=None, **opts):
1888 def pop(ui, repo, patch=None, **opts):
1889 """pop the current patch off the stack"""
1889 """pop the current patch off the stack"""
1890 localupdate = True
1890 localupdate = True
1891 if opts['name']:
1891 if opts['name']:
1892 q = queue(ui, repo.join(""), repo.join(opts['name']))
1892 q = queue(ui, repo.join(""), repo.join(opts['name']))
1893 ui.warn('using patch queue: %s\n' % q.path)
1893 ui.warn('using patch queue: %s\n' % q.path)
1894 localupdate = False
1894 localupdate = False
1895 else:
1895 else:
1896 q = repo.mq
1896 q = repo.mq
1897 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
1897 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
1898 all=opts['all'])
1898 all=opts['all'])
1899 q.save_dirty()
1899 q.save_dirty()
1900 return ret
1900 return ret
1901
1901
1902 def rename(ui, repo, patch, name=None, **opts):
1902 def rename(ui, repo, patch, name=None, **opts):
1903 """rename a patch
1903 """rename a patch
1904
1904
1905 With one argument, renames the current patch to PATCH1.
1905 With one argument, renames the current patch to PATCH1.
1906 With two arguments, renames PATCH1 to PATCH2."""
1906 With two arguments, renames PATCH1 to PATCH2."""
1907
1907
1908 q = repo.mq
1908 q = repo.mq
1909
1909
1910 if not name:
1910 if not name:
1911 name = patch
1911 name = patch
1912 patch = None
1912 patch = None
1913
1913
1914 if patch:
1914 if patch:
1915 patch = q.lookup(patch)
1915 patch = q.lookup(patch)
1916 else:
1916 else:
1917 if not q.applied:
1917 if not q.applied:
1918 ui.write(_('No patches applied\n'))
1918 ui.write(_('No patches applied\n'))
1919 return
1919 return
1920 patch = q.lookup('qtip')
1920 patch = q.lookup('qtip')
1921 absdest = q.join(name)
1921 absdest = q.join(name)
1922 if os.path.isdir(absdest):
1922 if os.path.isdir(absdest):
1923 name = normname(os.path.join(name, os.path.basename(patch)))
1923 name = normname(os.path.join(name, os.path.basename(patch)))
1924 absdest = q.join(name)
1924 absdest = q.join(name)
1925 if os.path.exists(absdest):
1925 if os.path.exists(absdest):
1926 raise util.Abort(_('%s already exists') % absdest)
1926 raise util.Abort(_('%s already exists') % absdest)
1927
1927
1928 if name in q.series:
1928 if name in q.series:
1929 raise util.Abort(_('A patch named %s already exists in the series file') % name)
1929 raise util.Abort(_('A patch named %s already exists in the series file') % name)
1930
1930
1931 if ui.verbose:
1931 if ui.verbose:
1932 ui.write('Renaming %s to %s\n' % (patch, name))
1932 ui.write('Renaming %s to %s\n' % (patch, name))
1933 i = q.find_series(patch)
1933 i = q.find_series(patch)
1934 guards = q.guard_re.findall(q.full_series[i])
1934 guards = q.guard_re.findall(q.full_series[i])
1935 q.full_series[i] = name + ''.join([' #' + g for g in guards])
1935 q.full_series[i] = name + ''.join([' #' + g for g in guards])
1936 q.parse_series()
1936 q.parse_series()
1937 q.series_dirty = 1
1937 q.series_dirty = 1
1938
1938
1939 info = q.isapplied(patch)
1939 info = q.isapplied(patch)
1940 if info:
1940 if info:
1941 q.applied[info[0]] = statusentry(info[1], name)
1941 q.applied[info[0]] = statusentry(info[1], name)
1942 q.applied_dirty = 1
1942 q.applied_dirty = 1
1943
1943
1944 util.rename(q.join(patch), absdest)
1944 util.rename(q.join(patch), absdest)
1945 r = q.qrepo()
1945 r = q.qrepo()
1946 if r:
1946 if r:
1947 wlock = r.wlock()
1947 wlock = r.wlock()
1948 if r.dirstate.state(name) == 'r':
1948 if r.dirstate.state(name) == 'r':
1949 r.undelete([name], wlock)
1949 r.undelete([name], wlock)
1950 r.copy(patch, name, wlock)
1950 r.copy(patch, name, wlock)
1951 r.remove([patch], False, wlock)
1951 r.remove([patch], False, wlock)
1952
1952
1953 q.save_dirty()
1953 q.save_dirty()
1954
1954
1955 def restore(ui, repo, rev, **opts):
1955 def restore(ui, repo, rev, **opts):
1956 """restore the queue state saved by a rev"""
1956 """restore the queue state saved by a rev"""
1957 rev = repo.lookup(rev)
1957 rev = repo.lookup(rev)
1958 q = repo.mq
1958 q = repo.mq
1959 q.restore(repo, rev, delete=opts['delete'],
1959 q.restore(repo, rev, delete=opts['delete'],
1960 qupdate=opts['update'])
1960 qupdate=opts['update'])
1961 q.save_dirty()
1961 q.save_dirty()
1962 return 0
1962 return 0
1963
1963
1964 def save(ui, repo, **opts):
1964 def save(ui, repo, **opts):
1965 """save current queue state"""
1965 """save current queue state"""
1966 q = repo.mq
1966 q = repo.mq
1967 message = commands.logmessage(opts)
1967 message = cmdutil.logmessage(opts)
1968 ret = q.save(repo, msg=message)
1968 ret = q.save(repo, msg=message)
1969 if ret:
1969 if ret:
1970 return ret
1970 return ret
1971 q.save_dirty()
1971 q.save_dirty()
1972 if opts['copy']:
1972 if opts['copy']:
1973 path = q.path
1973 path = q.path
1974 if opts['name']:
1974 if opts['name']:
1975 newpath = os.path.join(q.basepath, opts['name'])
1975 newpath = os.path.join(q.basepath, opts['name'])
1976 if os.path.exists(newpath):
1976 if os.path.exists(newpath):
1977 if not os.path.isdir(newpath):
1977 if not os.path.isdir(newpath):
1978 raise util.Abort(_('destination %s exists and is not '
1978 raise util.Abort(_('destination %s exists and is not '
1979 'a directory') % newpath)
1979 'a directory') % newpath)
1980 if not opts['force']:
1980 if not opts['force']:
1981 raise util.Abort(_('destination %s exists, '
1981 raise util.Abort(_('destination %s exists, '
1982 'use -f to force') % newpath)
1982 'use -f to force') % newpath)
1983 else:
1983 else:
1984 newpath = savename(path)
1984 newpath = savename(path)
1985 ui.warn("copy %s to %s\n" % (path, newpath))
1985 ui.warn("copy %s to %s\n" % (path, newpath))
1986 util.copyfiles(path, newpath)
1986 util.copyfiles(path, newpath)
1987 if opts['empty']:
1987 if opts['empty']:
1988 try:
1988 try:
1989 os.unlink(q.join(q.status_path))
1989 os.unlink(q.join(q.status_path))
1990 except:
1990 except:
1991 pass
1991 pass
1992 return 0
1992 return 0
1993
1993
1994 def strip(ui, repo, rev, **opts):
1994 def strip(ui, repo, rev, **opts):
1995 """strip a revision and all later revs on the same branch"""
1995 """strip a revision and all later revs on the same branch"""
1996 rev = repo.lookup(rev)
1996 rev = repo.lookup(rev)
1997 backup = 'all'
1997 backup = 'all'
1998 if opts['backup']:
1998 if opts['backup']:
1999 backup = 'strip'
1999 backup = 'strip'
2000 elif opts['nobackup']:
2000 elif opts['nobackup']:
2001 backup = 'none'
2001 backup = 'none'
2002 update = repo.dirstate.parents()[0] != revlog.nullid
2002 update = repo.dirstate.parents()[0] != revlog.nullid
2003 repo.mq.strip(repo, rev, backup=backup, update=update)
2003 repo.mq.strip(repo, rev, backup=backup, update=update)
2004 return 0
2004 return 0
2005
2005
2006 def select(ui, repo, *args, **opts):
2006 def select(ui, repo, *args, **opts):
2007 '''set or print guarded patches to push
2007 '''set or print guarded patches to push
2008
2008
2009 Use the qguard command to set or print guards on patch, then use
2009 Use the qguard command to set or print guards on patch, then use
2010 qselect to tell mq which guards to use. A patch will be pushed if it
2010 qselect to tell mq which guards to use. A patch will be pushed if it
2011 has no guards or any positive guards match the currently selected guard,
2011 has no guards or any positive guards match the currently selected guard,
2012 but will not be pushed if any negative guards match the current guard.
2012 but will not be pushed if any negative guards match the current guard.
2013 For example:
2013 For example:
2014
2014
2015 qguard foo.patch -stable (negative guard)
2015 qguard foo.patch -stable (negative guard)
2016 qguard bar.patch +stable (positive guard)
2016 qguard bar.patch +stable (positive guard)
2017 qselect stable
2017 qselect stable
2018
2018
2019 This activates the "stable" guard. mq will skip foo.patch (because
2019 This activates the "stable" guard. mq will skip foo.patch (because
2020 it has a negative match) but push bar.patch (because it
2020 it has a negative match) but push bar.patch (because it
2021 has a positive match).
2021 has a positive match).
2022
2022
2023 With no arguments, prints the currently active guards.
2023 With no arguments, prints the currently active guards.
2024 With one argument, sets the active guard.
2024 With one argument, sets the active guard.
2025
2025
2026 Use -n/--none to deactivate guards (no other arguments needed).
2026 Use -n/--none to deactivate guards (no other arguments needed).
2027 When no guards are active, patches with positive guards are skipped
2027 When no guards are active, patches with positive guards are skipped
2028 and patches with negative guards are pushed.
2028 and patches with negative guards are pushed.
2029
2029
2030 qselect can change the guards on applied patches. It does not pop
2030 qselect can change the guards on applied patches. It does not pop
2031 guarded patches by default. Use --pop to pop back to the last applied
2031 guarded patches by default. Use --pop to pop back to the last applied
2032 patch that is not guarded. Use --reapply (which implies --pop) to push
2032 patch that is not guarded. Use --reapply (which implies --pop) to push
2033 back to the current patch afterwards, but skip guarded patches.
2033 back to the current patch afterwards, but skip guarded patches.
2034
2034
2035 Use -s/--series to print a list of all guards in the series file (no
2035 Use -s/--series to print a list of all guards in the series file (no
2036 other arguments needed). Use -v for more information.'''
2036 other arguments needed). Use -v for more information.'''
2037
2037
2038 q = repo.mq
2038 q = repo.mq
2039 guards = q.active()
2039 guards = q.active()
2040 if args or opts['none']:
2040 if args or opts['none']:
2041 old_unapplied = q.unapplied(repo)
2041 old_unapplied = q.unapplied(repo)
2042 old_guarded = [i for i in xrange(len(q.applied)) if
2042 old_guarded = [i for i in xrange(len(q.applied)) if
2043 not q.pushable(i)[0]]
2043 not q.pushable(i)[0]]
2044 q.set_active(args)
2044 q.set_active(args)
2045 q.save_dirty()
2045 q.save_dirty()
2046 if not args:
2046 if not args:
2047 ui.status(_('guards deactivated\n'))
2047 ui.status(_('guards deactivated\n'))
2048 if not opts['pop'] and not opts['reapply']:
2048 if not opts['pop'] and not opts['reapply']:
2049 unapplied = q.unapplied(repo)
2049 unapplied = q.unapplied(repo)
2050 guarded = [i for i in xrange(len(q.applied))
2050 guarded = [i for i in xrange(len(q.applied))
2051 if not q.pushable(i)[0]]
2051 if not q.pushable(i)[0]]
2052 if len(unapplied) != len(old_unapplied):
2052 if len(unapplied) != len(old_unapplied):
2053 ui.status(_('number of unguarded, unapplied patches has '
2053 ui.status(_('number of unguarded, unapplied patches has '
2054 'changed from %d to %d\n') %
2054 'changed from %d to %d\n') %
2055 (len(old_unapplied), len(unapplied)))
2055 (len(old_unapplied), len(unapplied)))
2056 if len(guarded) != len(old_guarded):
2056 if len(guarded) != len(old_guarded):
2057 ui.status(_('number of guarded, applied patches has changed '
2057 ui.status(_('number of guarded, applied patches has changed '
2058 'from %d to %d\n') %
2058 'from %d to %d\n') %
2059 (len(old_guarded), len(guarded)))
2059 (len(old_guarded), len(guarded)))
2060 elif opts['series']:
2060 elif opts['series']:
2061 guards = {}
2061 guards = {}
2062 noguards = 0
2062 noguards = 0
2063 for gs in q.series_guards:
2063 for gs in q.series_guards:
2064 if not gs:
2064 if not gs:
2065 noguards += 1
2065 noguards += 1
2066 for g in gs:
2066 for g in gs:
2067 guards.setdefault(g, 0)
2067 guards.setdefault(g, 0)
2068 guards[g] += 1
2068 guards[g] += 1
2069 if ui.verbose:
2069 if ui.verbose:
2070 guards['NONE'] = noguards
2070 guards['NONE'] = noguards
2071 guards = guards.items()
2071 guards = guards.items()
2072 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
2072 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
2073 if guards:
2073 if guards:
2074 ui.note(_('guards in series file:\n'))
2074 ui.note(_('guards in series file:\n'))
2075 for guard, count in guards:
2075 for guard, count in guards:
2076 ui.note('%2d ' % count)
2076 ui.note('%2d ' % count)
2077 ui.write(guard, '\n')
2077 ui.write(guard, '\n')
2078 else:
2078 else:
2079 ui.note(_('no guards in series file\n'))
2079 ui.note(_('no guards in series file\n'))
2080 else:
2080 else:
2081 if guards:
2081 if guards:
2082 ui.note(_('active guards:\n'))
2082 ui.note(_('active guards:\n'))
2083 for g in guards:
2083 for g in guards:
2084 ui.write(g, '\n')
2084 ui.write(g, '\n')
2085 else:
2085 else:
2086 ui.write(_('no active guards\n'))
2086 ui.write(_('no active guards\n'))
2087 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2087 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2088 popped = False
2088 popped = False
2089 if opts['pop'] or opts['reapply']:
2089 if opts['pop'] or opts['reapply']:
2090 for i in xrange(len(q.applied)):
2090 for i in xrange(len(q.applied)):
2091 pushable, reason = q.pushable(i)
2091 pushable, reason = q.pushable(i)
2092 if not pushable:
2092 if not pushable:
2093 ui.status(_('popping guarded patches\n'))
2093 ui.status(_('popping guarded patches\n'))
2094 popped = True
2094 popped = True
2095 if i == 0:
2095 if i == 0:
2096 q.pop(repo, all=True)
2096 q.pop(repo, all=True)
2097 else:
2097 else:
2098 q.pop(repo, i-1)
2098 q.pop(repo, i-1)
2099 break
2099 break
2100 if popped:
2100 if popped:
2101 try:
2101 try:
2102 if reapply:
2102 if reapply:
2103 ui.status(_('reapplying unguarded patches\n'))
2103 ui.status(_('reapplying unguarded patches\n'))
2104 q.push(repo, reapply)
2104 q.push(repo, reapply)
2105 finally:
2105 finally:
2106 q.save_dirty()
2106 q.save_dirty()
2107
2107
2108 def reposetup(ui, repo):
2108 def reposetup(ui, repo):
2109 class mqrepo(repo.__class__):
2109 class mqrepo(repo.__class__):
2110 def abort_if_wdir_patched(self, errmsg, force=False):
2110 def abort_if_wdir_patched(self, errmsg, force=False):
2111 if self.mq.applied and not force:
2111 if self.mq.applied and not force:
2112 parent = revlog.hex(self.dirstate.parents()[0])
2112 parent = revlog.hex(self.dirstate.parents()[0])
2113 if parent in [s.rev for s in self.mq.applied]:
2113 if parent in [s.rev for s in self.mq.applied]:
2114 raise util.Abort(errmsg)
2114 raise util.Abort(errmsg)
2115
2115
2116 def commit(self, *args, **opts):
2116 def commit(self, *args, **opts):
2117 if len(args) >= 6:
2117 if len(args) >= 6:
2118 force = args[5]
2118 force = args[5]
2119 else:
2119 else:
2120 force = opts.get('force')
2120 force = opts.get('force')
2121 self.abort_if_wdir_patched(
2121 self.abort_if_wdir_patched(
2122 _('cannot commit over an applied mq patch'),
2122 _('cannot commit over an applied mq patch'),
2123 force)
2123 force)
2124
2124
2125 return super(mqrepo, self).commit(*args, **opts)
2125 return super(mqrepo, self).commit(*args, **opts)
2126
2126
2127 def push(self, remote, force=False, revs=None):
2127 def push(self, remote, force=False, revs=None):
2128 if self.mq.applied and not force and not revs:
2128 if self.mq.applied and not force and not revs:
2129 raise util.Abort(_('source has mq patches applied'))
2129 raise util.Abort(_('source has mq patches applied'))
2130 return super(mqrepo, self).push(remote, force, revs)
2130 return super(mqrepo, self).push(remote, force, revs)
2131
2131
2132 def tags(self):
2132 def tags(self):
2133 if self.tagscache:
2133 if self.tagscache:
2134 return self.tagscache
2134 return self.tagscache
2135
2135
2136 tagscache = super(mqrepo, self).tags()
2136 tagscache = super(mqrepo, self).tags()
2137
2137
2138 q = self.mq
2138 q = self.mq
2139 if not q.applied:
2139 if not q.applied:
2140 return tagscache
2140 return tagscache
2141
2141
2142 mqtags = [(revlog.bin(patch.rev), patch.name) for patch in q.applied]
2142 mqtags = [(revlog.bin(patch.rev), patch.name) for patch in q.applied]
2143 mqtags.append((mqtags[-1][0], 'qtip'))
2143 mqtags.append((mqtags[-1][0], 'qtip'))
2144 mqtags.append((mqtags[0][0], 'qbase'))
2144 mqtags.append((mqtags[0][0], 'qbase'))
2145 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2145 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2146 for patch in mqtags:
2146 for patch in mqtags:
2147 if patch[1] in tagscache:
2147 if patch[1] in tagscache:
2148 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1])
2148 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1])
2149 else:
2149 else:
2150 tagscache[patch[1]] = patch[0]
2150 tagscache[patch[1]] = patch[0]
2151
2151
2152 return tagscache
2152 return tagscache
2153
2153
2154 def _branchtags(self):
2154 def _branchtags(self):
2155 q = self.mq
2155 q = self.mq
2156 if not q.applied:
2156 if not q.applied:
2157 return super(mqrepo, self)._branchtags()
2157 return super(mqrepo, self)._branchtags()
2158
2158
2159 self.branchcache = {} # avoid recursion in changectx
2159 self.branchcache = {} # avoid recursion in changectx
2160 cl = self.changelog
2160 cl = self.changelog
2161 partial, last, lrev = self._readbranchcache()
2161 partial, last, lrev = self._readbranchcache()
2162
2162
2163 qbase = cl.rev(revlog.bin(q.applied[0].rev))
2163 qbase = cl.rev(revlog.bin(q.applied[0].rev))
2164 start = lrev + 1
2164 start = lrev + 1
2165 if start < qbase:
2165 if start < qbase:
2166 # update the cache (excluding the patches) and save it
2166 # update the cache (excluding the patches) and save it
2167 self._updatebranchcache(partial, lrev+1, qbase)
2167 self._updatebranchcache(partial, lrev+1, qbase)
2168 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2168 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2169 start = qbase
2169 start = qbase
2170 # if start = qbase, the cache is as updated as it should be.
2170 # if start = qbase, the cache is as updated as it should be.
2171 # if start > qbase, the cache includes (part of) the patches.
2171 # if start > qbase, the cache includes (part of) the patches.
2172 # we might as well use it, but we won't save it.
2172 # we might as well use it, but we won't save it.
2173
2173
2174 # update the cache up to the tip
2174 # update the cache up to the tip
2175 self._updatebranchcache(partial, start, cl.count())
2175 self._updatebranchcache(partial, start, cl.count())
2176
2176
2177 return partial
2177 return partial
2178
2178
2179 if repo.local():
2179 if repo.local():
2180 repo.__class__ = mqrepo
2180 repo.__class__ = mqrepo
2181 repo.mq = queue(ui, repo.join(""))
2181 repo.mq = queue(ui, repo.join(""))
2182
2182
2183 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2183 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2184
2184
2185 cmdtable = {
2185 cmdtable = {
2186 "qapplied": (applied, [] + seriesopts, 'hg qapplied [-s] [PATCH]'),
2186 "qapplied": (applied, [] + seriesopts, 'hg qapplied [-s] [PATCH]'),
2187 "qclone": (clone,
2187 "qclone": (clone,
2188 [('', 'pull', None, _('use pull protocol to copy metadata')),
2188 [('', 'pull', None, _('use pull protocol to copy metadata')),
2189 ('U', 'noupdate', None, _('do not update the new working directories')),
2189 ('U', 'noupdate', None, _('do not update the new working directories')),
2190 ('', 'uncompressed', None,
2190 ('', 'uncompressed', None,
2191 _('use uncompressed transfer (fast over LAN)')),
2191 _('use uncompressed transfer (fast over LAN)')),
2192 ('e', 'ssh', '', _('specify ssh command to use')),
2192 ('e', 'ssh', '', _('specify ssh command to use')),
2193 ('p', 'patches', '', _('location of source patch repo')),
2193 ('p', 'patches', '', _('location of source patch repo')),
2194 ('', 'remotecmd', '',
2194 ('', 'remotecmd', '',
2195 _('specify hg command to run on the remote side'))],
2195 _('specify hg command to run on the remote side'))],
2196 'hg qclone [OPTION]... SOURCE [DEST]'),
2196 'hg qclone [OPTION]... SOURCE [DEST]'),
2197 "qcommit|qci":
2197 "qcommit|qci":
2198 (commit,
2198 (commit,
2199 commands.table["^commit|ci"][1],
2199 commands.table["^commit|ci"][1],
2200 'hg qcommit [OPTION]... [FILE]...'),
2200 'hg qcommit [OPTION]... [FILE]...'),
2201 "^qdiff": (diff,
2201 "^qdiff": (diff,
2202 [('g', 'git', None, _('use git extended diff format')),
2202 [('g', 'git', None, _('use git extended diff format')),
2203 ('I', 'include', [], _('include names matching the given patterns')),
2203 ('I', 'include', [], _('include names matching the given patterns')),
2204 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2204 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2205 'hg qdiff [-I] [-X] [FILE]...'),
2205 'hg qdiff [-I] [-X] [FILE]...'),
2206 "qdelete|qremove|qrm":
2206 "qdelete|qremove|qrm":
2207 (delete,
2207 (delete,
2208 [('k', 'keep', None, _('keep patch file')),
2208 [('k', 'keep', None, _('keep patch file')),
2209 ('r', 'rev', [], _('stop managing a revision'))],
2209 ('r', 'rev', [], _('stop managing a revision'))],
2210 'hg qdelete [-k] [-r REV]... PATCH...'),
2210 'hg qdelete [-k] [-r REV]... PATCH...'),
2211 'qfold':
2211 'qfold':
2212 (fold,
2212 (fold,
2213 [('e', 'edit', None, _('edit patch header')),
2213 [('e', 'edit', None, _('edit patch header')),
2214 ('k', 'keep', None, _('keep folded patch files'))
2214 ('k', 'keep', None, _('keep folded patch files'))
2215 ] + commands.commitopts,
2215 ] + commands.commitopts,
2216 'hg qfold [-e] [-m <text>] [-l <file] PATCH...'),
2216 'hg qfold [-e] [-m <text>] [-l <file] PATCH...'),
2217 'qgoto': (goto, [('f', 'force', None, _('overwrite any local changes'))],
2217 'qgoto': (goto, [('f', 'force', None, _('overwrite any local changes'))],
2218 'hg qgoto [OPT]... PATCH'),
2218 'hg qgoto [OPT]... PATCH'),
2219 'qguard': (guard, [('l', 'list', None, _('list all patches and guards')),
2219 'qguard': (guard, [('l', 'list', None, _('list all patches and guards')),
2220 ('n', 'none', None, _('drop all guards'))],
2220 ('n', 'none', None, _('drop all guards'))],
2221 'hg qguard [PATCH] [+GUARD]... [-GUARD]...'),
2221 'hg qguard [PATCH] [+GUARD]... [-GUARD]...'),
2222 'qheader': (header, [],
2222 'qheader': (header, [],
2223 _('hg qheader [PATCH]')),
2223 _('hg qheader [PATCH]')),
2224 "^qimport":
2224 "^qimport":
2225 (qimport,
2225 (qimport,
2226 [('e', 'existing', None, 'import file in patch dir'),
2226 [('e', 'existing', None, 'import file in patch dir'),
2227 ('n', 'name', '', 'patch file name'),
2227 ('n', 'name', '', 'patch file name'),
2228 ('f', 'force', None, 'overwrite existing files'),
2228 ('f', 'force', None, 'overwrite existing files'),
2229 ('r', 'rev', [], 'place existing revisions under mq control'),
2229 ('r', 'rev', [], 'place existing revisions under mq control'),
2230 ('g', 'git', None, _('use git extended diff format'))],
2230 ('g', 'git', None, _('use git extended diff format'))],
2231 'hg qimport [-e] [-n NAME] [-f] [-g] [-r REV]... FILE...'),
2231 'hg qimport [-e] [-n NAME] [-f] [-g] [-r REV]... FILE...'),
2232 "^qinit":
2232 "^qinit":
2233 (init,
2233 (init,
2234 [('c', 'create-repo', None, 'create queue repository')],
2234 [('c', 'create-repo', None, 'create queue repository')],
2235 'hg qinit [-c]'),
2235 'hg qinit [-c]'),
2236 "qnew":
2236 "qnew":
2237 (new,
2237 (new,
2238 [('e', 'edit', None, _('edit commit message')),
2238 [('e', 'edit', None, _('edit commit message')),
2239 ('f', 'force', None, _('import uncommitted changes into patch'))
2239 ('f', 'force', None, _('import uncommitted changes into patch'))
2240 ] + commands.commitopts,
2240 ] + commands.commitopts,
2241 'hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH'),
2241 'hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH'),
2242 "qnext": (next, [] + seriesopts, 'hg qnext [-s]'),
2242 "qnext": (next, [] + seriesopts, 'hg qnext [-s]'),
2243 "qprev": (prev, [] + seriesopts, 'hg qprev [-s]'),
2243 "qprev": (prev, [] + seriesopts, 'hg qprev [-s]'),
2244 "^qpop":
2244 "^qpop":
2245 (pop,
2245 (pop,
2246 [('a', 'all', None, 'pop all patches'),
2246 [('a', 'all', None, 'pop all patches'),
2247 ('n', 'name', '', 'queue name to pop'),
2247 ('n', 'name', '', 'queue name to pop'),
2248 ('f', 'force', None, 'forget any local changes')],
2248 ('f', 'force', None, 'forget any local changes')],
2249 'hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]'),
2249 'hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]'),
2250 "^qpush":
2250 "^qpush":
2251 (push,
2251 (push,
2252 [('f', 'force', None, 'apply if the patch has rejects'),
2252 [('f', 'force', None, 'apply if the patch has rejects'),
2253 ('l', 'list', None, 'list patch name in commit text'),
2253 ('l', 'list', None, 'list patch name in commit text'),
2254 ('a', 'all', None, 'apply all patches'),
2254 ('a', 'all', None, 'apply all patches'),
2255 ('m', 'merge', None, 'merge from another queue'),
2255 ('m', 'merge', None, 'merge from another queue'),
2256 ('n', 'name', '', 'merge queue name')],
2256 ('n', 'name', '', 'merge queue name')],
2257 'hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]'),
2257 'hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]'),
2258 "^qrefresh":
2258 "^qrefresh":
2259 (refresh,
2259 (refresh,
2260 [('e', 'edit', None, _('edit commit message')),
2260 [('e', 'edit', None, _('edit commit message')),
2261 ('g', 'git', None, _('use git extended diff format')),
2261 ('g', 'git', None, _('use git extended diff format')),
2262 ('s', 'short', None, 'refresh only files already in the patch'),
2262 ('s', 'short', None, 'refresh only files already in the patch'),
2263 ('I', 'include', [], _('include names matching the given patterns')),
2263 ('I', 'include', [], _('include names matching the given patterns')),
2264 ('X', 'exclude', [], _('exclude names matching the given patterns'))
2264 ('X', 'exclude', [], _('exclude names matching the given patterns'))
2265 ] + commands.commitopts,
2265 ] + commands.commitopts,
2266 'hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...'),
2266 'hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...'),
2267 'qrename|qmv':
2267 'qrename|qmv':
2268 (rename, [], 'hg qrename PATCH1 [PATCH2]'),
2268 (rename, [], 'hg qrename PATCH1 [PATCH2]'),
2269 "qrestore":
2269 "qrestore":
2270 (restore,
2270 (restore,
2271 [('d', 'delete', None, 'delete save entry'),
2271 [('d', 'delete', None, 'delete save entry'),
2272 ('u', 'update', None, 'update queue working dir')],
2272 ('u', 'update', None, 'update queue working dir')],
2273 'hg qrestore [-d] [-u] REV'),
2273 'hg qrestore [-d] [-u] REV'),
2274 "qsave":
2274 "qsave":
2275 (save,
2275 (save,
2276 [('c', 'copy', None, 'copy patch directory'),
2276 [('c', 'copy', None, 'copy patch directory'),
2277 ('n', 'name', '', 'copy directory name'),
2277 ('n', 'name', '', 'copy directory name'),
2278 ('e', 'empty', None, 'clear queue status file'),
2278 ('e', 'empty', None, 'clear queue status file'),
2279 ('f', 'force', None, 'force copy')] + commands.commitopts,
2279 ('f', 'force', None, 'force copy')] + commands.commitopts,
2280 'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
2280 'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
2281 "qselect": (select,
2281 "qselect": (select,
2282 [('n', 'none', None, _('disable all guards')),
2282 [('n', 'none', None, _('disable all guards')),
2283 ('s', 'series', None, _('list all guards in series file')),
2283 ('s', 'series', None, _('list all guards in series file')),
2284 ('', 'pop', None,
2284 ('', 'pop', None,
2285 _('pop to before first guarded applied patch')),
2285 _('pop to before first guarded applied patch')),
2286 ('', 'reapply', None, _('pop, then reapply patches'))],
2286 ('', 'reapply', None, _('pop, then reapply patches'))],
2287 'hg qselect [OPTION]... [GUARD]...'),
2287 'hg qselect [OPTION]... [GUARD]...'),
2288 "qseries":
2288 "qseries":
2289 (series,
2289 (series,
2290 [('m', 'missing', None, 'print patches not in series')] + seriesopts,
2290 [('m', 'missing', None, 'print patches not in series')] + seriesopts,
2291 'hg qseries [-ms]'),
2291 'hg qseries [-ms]'),
2292 "^strip":
2292 "^strip":
2293 (strip,
2293 (strip,
2294 [('f', 'force', None, 'force multi-head removal'),
2294 [('f', 'force', None, 'force multi-head removal'),
2295 ('b', 'backup', None, 'bundle unrelated changesets'),
2295 ('b', 'backup', None, 'bundle unrelated changesets'),
2296 ('n', 'nobackup', None, 'no backups')],
2296 ('n', 'nobackup', None, 'no backups')],
2297 'hg strip [-f] [-b] [-n] REV'),
2297 'hg strip [-f] [-b] [-n] REV'),
2298 "qtop": (top, [] + seriesopts, 'hg qtop [-s]'),
2298 "qtop": (top, [] + seriesopts, 'hg qtop [-s]'),
2299 "qunapplied": (unapplied, [] + seriesopts, 'hg qunapplied [-s] [PATCH]'),
2299 "qunapplied": (unapplied, [] + seriesopts, 'hg qunapplied [-s] [PATCH]'),
2300 }
2300 }
@@ -1,876 +1,1176 b''
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in 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 node import *
8 from node import *
9 from i18n import _
9 from i18n import _
10 import os, sys, mdiff, bdiff, util, templater, patch
10 import os, sys, mdiff, bdiff, util, templater, patch, commands
11 import atexit, signal, pdb, hg, lock, fancyopts, traceback
12 import socket, revlog, version, extensions, errno
11
13
12 revrangesep = ':'
14 revrangesep = ':'
13
15
16 class UnknownCommand(Exception):
17 """Exception raised if command is not in the command table."""
18 class AmbiguousCommand(Exception):
19 """Exception raised if command shortcut matches more than one command."""
20 class ParseError(Exception):
21 """Exception raised on errors in parsing the command line."""
22
23 def runcatch(u, args):
24 def catchterm(*args):
25 raise util.SignalInterrupt
26
27 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
28 num = getattr(signal, name, None)
29 if num: signal.signal(num, catchterm)
30
31 try:
32 return dispatch(u, args)
33 except ParseError, inst:
34 if inst.args[0]:
35 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
36 commands.help_(u, inst.args[0])
37 else:
38 u.warn(_("hg: %s\n") % inst.args[1])
39 commands.help_(u, 'shortlist')
40 except AmbiguousCommand, inst:
41 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
42 (inst.args[0], " ".join(inst.args[1])))
43 except UnknownCommand, inst:
44 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
45 commands.help_(u, 'shortlist')
46 except hg.RepoError, inst:
47 u.warn(_("abort: %s!\n") % inst)
48 except lock.LockHeld, inst:
49 if inst.errno == errno.ETIMEDOUT:
50 reason = _('timed out waiting for lock held by %s') % inst.locker
51 else:
52 reason = _('lock held by %s') % inst.locker
53 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
54 except lock.LockUnavailable, inst:
55 u.warn(_("abort: could not lock %s: %s\n") %
56 (inst.desc or inst.filename, inst.strerror))
57 except revlog.RevlogError, inst:
58 u.warn(_("abort: %s!\n") % inst)
59 except util.SignalInterrupt:
60 u.warn(_("killed!\n"))
61 except KeyboardInterrupt:
62 try:
63 u.warn(_("interrupted!\n"))
64 except IOError, inst:
65 if inst.errno == errno.EPIPE:
66 if u.debugflag:
67 u.warn(_("\nbroken pipe\n"))
68 else:
69 raise
70 except socket.error, inst:
71 u.warn(_("abort: %s\n") % inst[1])
72 except IOError, inst:
73 if hasattr(inst, "code"):
74 u.warn(_("abort: %s\n") % inst)
75 elif hasattr(inst, "reason"):
76 try: # usually it is in the form (errno, strerror)
77 reason = inst.reason.args[1]
78 except: # it might be anything, for example a string
79 reason = inst.reason
80 u.warn(_("abort: error: %s\n") % reason)
81 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
82 if u.debugflag:
83 u.warn(_("broken pipe\n"))
84 elif getattr(inst, "strerror", None):
85 if getattr(inst, "filename", None):
86 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
87 else:
88 u.warn(_("abort: %s\n") % inst.strerror)
89 else:
90 raise
91 except OSError, inst:
92 if getattr(inst, "filename", None):
93 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
94 else:
95 u.warn(_("abort: %s\n") % inst.strerror)
96 except util.UnexpectedOutput, inst:
97 u.warn(_("abort: %s") % inst[0])
98 if not isinstance(inst[1], basestring):
99 u.warn(" %r\n" % (inst[1],))
100 elif not inst[1]:
101 u.warn(_(" empty string\n"))
102 else:
103 u.warn("\n%r\n" % util.ellipsis(inst[1]))
104 except util.Abort, inst:
105 u.warn(_("abort: %s\n") % inst)
106 except TypeError, inst:
107 # was this an argument error?
108 tb = traceback.extract_tb(sys.exc_info()[2])
109 if len(tb) > 2: # no
110 raise
111 u.debug(inst, "\n")
112 u.warn(_("%s: invalid arguments\n") % cmd)
113 commands.help_(u, cmd)
114 except SystemExit, inst:
115 # Commands shouldn't sys.exit directly, but give a return code.
116 # Just in case catch this and and pass exit code to caller.
117 return inst.code
118 except:
119 u.warn(_("** unknown exception encountered, details follow\n"))
120 u.warn(_("** report bug details to "
121 "http://www.selenic.com/mercurial/bts\n"))
122 u.warn(_("** or mercurial@selenic.com\n"))
123 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
124 % version.get_version())
125 raise
126
127 return -1
128
129 def findpossible(ui, cmd):
130 """
131 Return cmd -> (aliases, command table entry)
132 for each matching command.
133 Return debug commands (or their aliases) only if no normal command matches.
134 """
135 choice = {}
136 debugchoice = {}
137 for e in commands.table.keys():
138 aliases = e.lstrip("^").split("|")
139 found = None
140 if cmd in aliases:
141 found = cmd
142 elif not ui.config("ui", "strict"):
143 for a in aliases:
144 if a.startswith(cmd):
145 found = a
146 break
147 if found is not None:
148 if aliases[0].startswith("debug") or found.startswith("debug"):
149 debugchoice[found] = (aliases, commands.table[e])
150 else:
151 choice[found] = (aliases, commands.table[e])
152
153 if not choice and debugchoice:
154 choice = debugchoice
155
156 return choice
157
158 def findcmd(ui, cmd):
159 """Return (aliases, command table entry) for command string."""
160 choice = findpossible(ui, cmd)
161
162 if choice.has_key(cmd):
163 return choice[cmd]
164
165 if len(choice) > 1:
166 clist = choice.keys()
167 clist.sort()
168 raise AmbiguousCommand(cmd, clist)
169
170 if choice:
171 return choice.values()[0]
172
173 raise UnknownCommand(cmd)
174
175 def parse(ui, args):
176 options = {}
177 cmdoptions = {}
178
179 try:
180 args = fancyopts.fancyopts(args, commands.globalopts, options)
181 except fancyopts.getopt.GetoptError, inst:
182 raise ParseError(None, inst)
183
184 if args:
185 cmd, args = args[0], args[1:]
186 aliases, i = findcmd(ui, cmd)
187 cmd = aliases[0]
188 defaults = ui.config("defaults", cmd)
189 if defaults:
190 args = shlex.split(defaults) + args
191 c = list(i[1])
192 else:
193 cmd = None
194 c = []
195
196 # combine global options into local
197 for o in commands.globalopts:
198 c.append((o[0], o[1], options[o[1]], o[3]))
199
200 try:
201 args = fancyopts.fancyopts(args, c, cmdoptions)
202 except fancyopts.getopt.GetoptError, inst:
203 raise ParseError(cmd, inst)
204
205 # separate global options back out
206 for o in commands.globalopts:
207 n = o[1]
208 options[n] = cmdoptions[n]
209 del cmdoptions[n]
210
211 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
212
213 def parseconfig(config):
214 """parse the --config options from the command line"""
215 parsed = []
216 for cfg in config:
217 try:
218 name, value = cfg.split('=', 1)
219 section, name = name.split('.', 1)
220 if not section or not name:
221 raise IndexError
222 parsed.append((section, name, value))
223 except (IndexError, ValueError):
224 raise util.Abort(_('malformed --config option: %s') % cfg)
225 return parsed
226
227 def dispatch(u, args):
228 extensions.loadall(u)
229 u.addreadhook(extensions.loadall)
230
231 cmd, func, args, options, cmdoptions = parse(u, args)
232
233 if options["encoding"]:
234 util._encoding = options["encoding"]
235 if options["encodingmode"]:
236 util._encodingmode = options["encodingmode"]
237 if options["time"]:
238 def get_times():
239 t = os.times()
240 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
241 t = (t[0], t[1], t[2], t[3], time.clock())
242 return t
243 s = get_times()
244 def print_time():
245 t = get_times()
246 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
247 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
248 atexit.register(print_time)
249
250 if options['cwd']:
251 os.chdir(options['cwd'])
252
253 u.updateopts(options["verbose"], options["debug"], options["quiet"],
254 not options["noninteractive"], options["traceback"],
255 parseconfig(options["config"]))
256
257 path = u.expandpath(options["repository"]) or ""
258 repo = path and hg.repository(u, path=path) or None
259 if repo and not repo.local():
260 raise util.Abort(_("repository '%s' is not local") % path)
261
262 if options['help']:
263 return commands.help_(u, cmd, options['version'])
264 elif options['version']:
265 return commands.version_(u)
266 elif not cmd:
267 return commands.help_(u, 'shortlist')
268
269 if cmd not in commands.norepo.split():
270 try:
271 if not repo:
272 repo = hg.repository(u, path=path)
273 u = repo.ui
274 except hg.RepoError:
275 if cmd not in commands.optionalrepo.split():
276 raise
277 d = lambda: func(u, repo, *args, **cmdoptions)
278 else:
279 d = lambda: func(u, *args, **cmdoptions)
280
281 return runcommand(u, options, d)
282
14 def runcommand(u, options, d):
283 def runcommand(u, options, d):
15 # enter the debugger before command execution
284 # enter the debugger before command execution
16 if options['debugger']:
285 if options['debugger']:
17 pdb.set_trace()
286 pdb.set_trace()
18
287
19 try:
288 try:
20 try:
289 try:
21 if options['profile']:
290 if options['profile']:
22 import hotshot, hotshot.stats
291 import hotshot, hotshot.stats
23 prof = hotshot.Profile("hg.prof")
292 prof = hotshot.Profile("hg.prof")
24 try:
293 try:
25 try:
294 try:
26 return prof.runcall(d)
295 return prof.runcall(d)
27 except:
296 except:
28 try:
297 try:
29 u.warn(_('exception raised - generating '
298 u.warn(_('exception raised - generating '
30 'profile anyway\n'))
299 'profile anyway\n'))
31 except:
300 except:
32 pass
301 pass
33 raise
302 raise
34 finally:
303 finally:
35 prof.close()
304 prof.close()
36 stats = hotshot.stats.load("hg.prof")
305 stats = hotshot.stats.load("hg.prof")
37 stats.strip_dirs()
306 stats.strip_dirs()
38 stats.sort_stats('time', 'calls')
307 stats.sort_stats('time', 'calls')
39 stats.print_stats(40)
308 stats.print_stats(40)
40 elif options['lsprof']:
309 elif options['lsprof']:
41 try:
310 try:
42 from mercurial import lsprof
311 from mercurial import lsprof
43 except ImportError:
312 except ImportError:
44 raise util.Abort(_(
313 raise util.Abort(_(
45 'lsprof not available - install from '
314 'lsprof not available - install from '
46 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
315 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
47 p = lsprof.Profiler()
316 p = lsprof.Profiler()
48 p.enable(subcalls=True)
317 p.enable(subcalls=True)
49 try:
318 try:
50 return d()
319 return d()
51 finally:
320 finally:
52 p.disable()
321 p.disable()
53 stats = lsprof.Stats(p.getstats())
322 stats = lsprof.Stats(p.getstats())
54 stats.sort()
323 stats.sort()
55 stats.pprint(top=10, file=sys.stderr, climit=5)
324 stats.pprint(top=10, file=sys.stderr, climit=5)
56 else:
325 else:
57 return d()
326 return d()
58 finally:
327 finally:
59 u.flush()
328 u.flush()
60 except:
329 except:
61 # enter the debugger when we hit an exception
330 # enter the debugger when we hit an exception
62 if options['debugger']:
331 if options['debugger']:
63 pdb.post_mortem(sys.exc_info()[2])
332 pdb.post_mortem(sys.exc_info()[2])
64 u.print_exc()
333 u.print_exc()
65 raise
334 raise
66
335
336 def bail_if_changed(repo):
337 modified, added, removed, deleted = repo.status()[:4]
338 if modified or added or removed or deleted:
339 raise util.Abort(_("outstanding uncommitted changes"))
340
341 def logmessage(opts):
342 """ get the log message according to -m and -l option """
343 message = opts['message']
344 logfile = opts['logfile']
345
346 if message and logfile:
347 raise util.Abort(_('options --message and --logfile are mutually '
348 'exclusive'))
349 if not message and logfile:
350 try:
351 if logfile == '-':
352 message = sys.stdin.read()
353 else:
354 message = open(logfile).read()
355 except IOError, inst:
356 raise util.Abort(_("can't read commit message '%s': %s") %
357 (logfile, inst.strerror))
358 return message
359
360 def setremoteconfig(ui, opts):
361 "copy remote options to ui tree"
362 if opts.get('ssh'):
363 ui.setconfig("ui", "ssh", opts['ssh'])
364 if opts.get('remotecmd'):
365 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
366
67 def parseurl(url, revs):
367 def parseurl(url, revs):
68 '''parse url#branch, returning url, branch + revs'''
368 '''parse url#branch, returning url, branch + revs'''
69
369
70 if '#' not in url:
370 if '#' not in url:
71 return url, (revs or None)
371 return url, (revs or None)
72
372
73 url, rev = url.split('#', 1)
373 url, rev = url.split('#', 1)
74 return url, revs + [rev]
374 return url, revs + [rev]
75
375
76 def revpair(repo, revs):
376 def revpair(repo, revs):
77 '''return pair of nodes, given list of revisions. second item can
377 '''return pair of nodes, given list of revisions. second item can
78 be None, meaning use working dir.'''
378 be None, meaning use working dir.'''
79
379
80 def revfix(repo, val, defval):
380 def revfix(repo, val, defval):
81 if not val and val != 0 and defval is not None:
381 if not val and val != 0 and defval is not None:
82 val = defval
382 val = defval
83 return repo.lookup(val)
383 return repo.lookup(val)
84
384
85 if not revs:
385 if not revs:
86 return repo.dirstate.parents()[0], None
386 return repo.dirstate.parents()[0], None
87 end = None
387 end = None
88 if len(revs) == 1:
388 if len(revs) == 1:
89 if revrangesep in revs[0]:
389 if revrangesep in revs[0]:
90 start, end = revs[0].split(revrangesep, 1)
390 start, end = revs[0].split(revrangesep, 1)
91 start = revfix(repo, start, 0)
391 start = revfix(repo, start, 0)
92 end = revfix(repo, end, repo.changelog.count() - 1)
392 end = revfix(repo, end, repo.changelog.count() - 1)
93 else:
393 else:
94 start = revfix(repo, revs[0], None)
394 start = revfix(repo, revs[0], None)
95 elif len(revs) == 2:
395 elif len(revs) == 2:
96 if revrangesep in revs[0] or revrangesep in revs[1]:
396 if revrangesep in revs[0] or revrangesep in revs[1]:
97 raise util.Abort(_('too many revisions specified'))
397 raise util.Abort(_('too many revisions specified'))
98 start = revfix(repo, revs[0], None)
398 start = revfix(repo, revs[0], None)
99 end = revfix(repo, revs[1], None)
399 end = revfix(repo, revs[1], None)
100 else:
400 else:
101 raise util.Abort(_('too many revisions specified'))
401 raise util.Abort(_('too many revisions specified'))
102 return start, end
402 return start, end
103
403
104 def revrange(repo, revs):
404 def revrange(repo, revs):
105 """Yield revision as strings from a list of revision specifications."""
405 """Yield revision as strings from a list of revision specifications."""
106
406
107 def revfix(repo, val, defval):
407 def revfix(repo, val, defval):
108 if not val and val != 0 and defval is not None:
408 if not val and val != 0 and defval is not None:
109 return defval
409 return defval
110 return repo.changelog.rev(repo.lookup(val))
410 return repo.changelog.rev(repo.lookup(val))
111
411
112 seen, l = {}, []
412 seen, l = {}, []
113 for spec in revs:
413 for spec in revs:
114 if revrangesep in spec:
414 if revrangesep in spec:
115 start, end = spec.split(revrangesep, 1)
415 start, end = spec.split(revrangesep, 1)
116 start = revfix(repo, start, 0)
416 start = revfix(repo, start, 0)
117 end = revfix(repo, end, repo.changelog.count() - 1)
417 end = revfix(repo, end, repo.changelog.count() - 1)
118 step = start > end and -1 or 1
418 step = start > end and -1 or 1
119 for rev in xrange(start, end+step, step):
419 for rev in xrange(start, end+step, step):
120 if rev in seen:
420 if rev in seen:
121 continue
421 continue
122 seen[rev] = 1
422 seen[rev] = 1
123 l.append(rev)
423 l.append(rev)
124 else:
424 else:
125 rev = revfix(repo, spec, None)
425 rev = revfix(repo, spec, None)
126 if rev in seen:
426 if rev in seen:
127 continue
427 continue
128 seen[rev] = 1
428 seen[rev] = 1
129 l.append(rev)
429 l.append(rev)
130
430
131 return l
431 return l
132
432
133 def make_filename(repo, pat, node,
433 def make_filename(repo, pat, node,
134 total=None, seqno=None, revwidth=None, pathname=None):
434 total=None, seqno=None, revwidth=None, pathname=None):
135 node_expander = {
435 node_expander = {
136 'H': lambda: hex(node),
436 'H': lambda: hex(node),
137 'R': lambda: str(repo.changelog.rev(node)),
437 'R': lambda: str(repo.changelog.rev(node)),
138 'h': lambda: short(node),
438 'h': lambda: short(node),
139 }
439 }
140 expander = {
440 expander = {
141 '%': lambda: '%',
441 '%': lambda: '%',
142 'b': lambda: os.path.basename(repo.root),
442 'b': lambda: os.path.basename(repo.root),
143 }
443 }
144
444
145 try:
445 try:
146 if node:
446 if node:
147 expander.update(node_expander)
447 expander.update(node_expander)
148 if node and revwidth is not None:
448 if node and revwidth is not None:
149 expander['r'] = (lambda:
449 expander['r'] = (lambda:
150 str(repo.changelog.rev(node)).zfill(revwidth))
450 str(repo.changelog.rev(node)).zfill(revwidth))
151 if total is not None:
451 if total is not None:
152 expander['N'] = lambda: str(total)
452 expander['N'] = lambda: str(total)
153 if seqno is not None:
453 if seqno is not None:
154 expander['n'] = lambda: str(seqno)
454 expander['n'] = lambda: str(seqno)
155 if total is not None and seqno is not None:
455 if total is not None and seqno is not None:
156 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
456 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
157 if pathname is not None:
457 if pathname is not None:
158 expander['s'] = lambda: os.path.basename(pathname)
458 expander['s'] = lambda: os.path.basename(pathname)
159 expander['d'] = lambda: os.path.dirname(pathname) or '.'
459 expander['d'] = lambda: os.path.dirname(pathname) or '.'
160 expander['p'] = lambda: pathname
460 expander['p'] = lambda: pathname
161
461
162 newname = []
462 newname = []
163 patlen = len(pat)
463 patlen = len(pat)
164 i = 0
464 i = 0
165 while i < patlen:
465 while i < patlen:
166 c = pat[i]
466 c = pat[i]
167 if c == '%':
467 if c == '%':
168 i += 1
468 i += 1
169 c = pat[i]
469 c = pat[i]
170 c = expander[c]()
470 c = expander[c]()
171 newname.append(c)
471 newname.append(c)
172 i += 1
472 i += 1
173 return ''.join(newname)
473 return ''.join(newname)
174 except KeyError, inst:
474 except KeyError, inst:
175 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
475 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
176 inst.args[0])
476 inst.args[0])
177
477
178 def make_file(repo, pat, node=None,
478 def make_file(repo, pat, node=None,
179 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
479 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
180 if not pat or pat == '-':
480 if not pat or pat == '-':
181 return 'w' in mode and sys.stdout or sys.stdin
481 return 'w' in mode and sys.stdout or sys.stdin
182 if hasattr(pat, 'write') and 'w' in mode:
482 if hasattr(pat, 'write') and 'w' in mode:
183 return pat
483 return pat
184 if hasattr(pat, 'read') and 'r' in mode:
484 if hasattr(pat, 'read') and 'r' in mode:
185 return pat
485 return pat
186 return open(make_filename(repo, pat, node, total, seqno, revwidth,
486 return open(make_filename(repo, pat, node, total, seqno, revwidth,
187 pathname),
487 pathname),
188 mode)
488 mode)
189
489
190 def matchpats(repo, pats=[], opts={}, globbed=False, default=None):
490 def matchpats(repo, pats=[], opts={}, globbed=False, default=None):
191 cwd = repo.getcwd()
491 cwd = repo.getcwd()
192 return util.cmdmatcher(repo.root, cwd, pats or [], opts.get('include'),
492 return util.cmdmatcher(repo.root, cwd, pats or [], opts.get('include'),
193 opts.get('exclude'), globbed=globbed,
493 opts.get('exclude'), globbed=globbed,
194 default=default)
494 default=default)
195
495
196 def walk(repo, pats=[], opts={}, node=None, badmatch=None, globbed=False,
496 def walk(repo, pats=[], opts={}, node=None, badmatch=None, globbed=False,
197 default=None):
497 default=None):
198 files, matchfn, anypats = matchpats(repo, pats, opts, globbed=globbed,
498 files, matchfn, anypats = matchpats(repo, pats, opts, globbed=globbed,
199 default=default)
499 default=default)
200 exact = dict.fromkeys(files)
500 exact = dict.fromkeys(files)
201 cwd = repo.getcwd()
501 cwd = repo.getcwd()
202 for src, fn in repo.walk(node=node, files=files, match=matchfn,
502 for src, fn in repo.walk(node=node, files=files, match=matchfn,
203 badmatch=badmatch):
503 badmatch=badmatch):
204 yield src, fn, repo.pathto(fn, cwd), fn in exact
504 yield src, fn, repo.pathto(fn, cwd), fn in exact
205
505
206 def findrenames(repo, added=None, removed=None, threshold=0.5):
506 def findrenames(repo, added=None, removed=None, threshold=0.5):
207 '''find renamed files -- yields (before, after, score) tuples'''
507 '''find renamed files -- yields (before, after, score) tuples'''
208 if added is None or removed is None:
508 if added is None or removed is None:
209 added, removed = repo.status()[1:3]
509 added, removed = repo.status()[1:3]
210 ctx = repo.changectx()
510 ctx = repo.changectx()
211 for a in added:
511 for a in added:
212 aa = repo.wread(a)
512 aa = repo.wread(a)
213 bestname, bestscore = None, threshold
513 bestname, bestscore = None, threshold
214 for r in removed:
514 for r in removed:
215 rr = ctx.filectx(r).data()
515 rr = ctx.filectx(r).data()
216
516
217 # bdiff.blocks() returns blocks of matching lines
517 # bdiff.blocks() returns blocks of matching lines
218 # count the number of bytes in each
518 # count the number of bytes in each
219 equal = 0
519 equal = 0
220 alines = mdiff.splitnewlines(aa)
520 alines = mdiff.splitnewlines(aa)
221 matches = bdiff.blocks(aa, rr)
521 matches = bdiff.blocks(aa, rr)
222 for x1,x2,y1,y2 in matches:
522 for x1,x2,y1,y2 in matches:
223 for line in alines[x1:x2]:
523 for line in alines[x1:x2]:
224 equal += len(line)
524 equal += len(line)
225
525
226 lengths = len(aa) + len(rr)
526 lengths = len(aa) + len(rr)
227 if lengths:
527 if lengths:
228 myscore = equal*2.0 / lengths
528 myscore = equal*2.0 / lengths
229 if myscore >= bestscore:
529 if myscore >= bestscore:
230 bestname, bestscore = r, myscore
530 bestname, bestscore = r, myscore
231 if bestname:
531 if bestname:
232 yield bestname, a, bestscore
532 yield bestname, a, bestscore
233
533
234 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
534 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
235 similarity=None):
535 similarity=None):
236 if dry_run is None:
536 if dry_run is None:
237 dry_run = opts.get('dry_run')
537 dry_run = opts.get('dry_run')
238 if similarity is None:
538 if similarity is None:
239 similarity = float(opts.get('similarity') or 0)
539 similarity = float(opts.get('similarity') or 0)
240 add, remove = [], []
540 add, remove = [], []
241 mapping = {}
541 mapping = {}
242 for src, abs, rel, exact in walk(repo, pats, opts):
542 for src, abs, rel, exact in walk(repo, pats, opts):
243 target = repo.wjoin(abs)
543 target = repo.wjoin(abs)
244 if src == 'f' and repo.dirstate.state(abs) == '?':
544 if src == 'f' and repo.dirstate.state(abs) == '?':
245 add.append(abs)
545 add.append(abs)
246 mapping[abs] = rel, exact
546 mapping[abs] = rel, exact
247 if repo.ui.verbose or not exact:
547 if repo.ui.verbose or not exact:
248 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
548 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
249 islink = os.path.islink(target)
549 islink = os.path.islink(target)
250 if (repo.dirstate.state(abs) != 'r' and not islink
550 if (repo.dirstate.state(abs) != 'r' and not islink
251 and not os.path.exists(target)):
551 and not os.path.exists(target)):
252 remove.append(abs)
552 remove.append(abs)
253 mapping[abs] = rel, exact
553 mapping[abs] = rel, exact
254 if repo.ui.verbose or not exact:
554 if repo.ui.verbose or not exact:
255 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
555 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
256 if not dry_run:
556 if not dry_run:
257 repo.add(add, wlock=wlock)
557 repo.add(add, wlock=wlock)
258 repo.remove(remove, wlock=wlock)
558 repo.remove(remove, wlock=wlock)
259 if similarity > 0:
559 if similarity > 0:
260 for old, new, score in findrenames(repo, add, remove, similarity):
560 for old, new, score in findrenames(repo, add, remove, similarity):
261 oldrel, oldexact = mapping[old]
561 oldrel, oldexact = mapping[old]
262 newrel, newexact = mapping[new]
562 newrel, newexact = mapping[new]
263 if repo.ui.verbose or not oldexact or not newexact:
563 if repo.ui.verbose or not oldexact or not newexact:
264 repo.ui.status(_('recording removal of %s as rename to %s '
564 repo.ui.status(_('recording removal of %s as rename to %s '
265 '(%d%% similar)\n') %
565 '(%d%% similar)\n') %
266 (oldrel, newrel, score * 100))
566 (oldrel, newrel, score * 100))
267 if not dry_run:
567 if not dry_run:
268 repo.copy(old, new, wlock=wlock)
568 repo.copy(old, new, wlock=wlock)
269
569
270 def service(opts, parentfn=None, initfn=None, runfn=None):
570 def service(opts, parentfn=None, initfn=None, runfn=None):
271 '''Run a command as a service.'''
571 '''Run a command as a service.'''
272
572
273 if opts['daemon'] and not opts['daemon_pipefds']:
573 if opts['daemon'] and not opts['daemon_pipefds']:
274 rfd, wfd = os.pipe()
574 rfd, wfd = os.pipe()
275 args = sys.argv[:]
575 args = sys.argv[:]
276 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
576 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
277 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
577 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
278 args[0], args)
578 args[0], args)
279 os.close(wfd)
579 os.close(wfd)
280 os.read(rfd, 1)
580 os.read(rfd, 1)
281 if parentfn:
581 if parentfn:
282 return parentfn(pid)
582 return parentfn(pid)
283 else:
583 else:
284 os._exit(0)
584 os._exit(0)
285
585
286 if initfn:
586 if initfn:
287 initfn()
587 initfn()
288
588
289 if opts['pid_file']:
589 if opts['pid_file']:
290 fp = open(opts['pid_file'], 'w')
590 fp = open(opts['pid_file'], 'w')
291 fp.write(str(os.getpid()) + '\n')
591 fp.write(str(os.getpid()) + '\n')
292 fp.close()
592 fp.close()
293
593
294 if opts['daemon_pipefds']:
594 if opts['daemon_pipefds']:
295 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
595 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
296 os.close(rfd)
596 os.close(rfd)
297 try:
597 try:
298 os.setsid()
598 os.setsid()
299 except AttributeError:
599 except AttributeError:
300 pass
600 pass
301 os.write(wfd, 'y')
601 os.write(wfd, 'y')
302 os.close(wfd)
602 os.close(wfd)
303 sys.stdout.flush()
603 sys.stdout.flush()
304 sys.stderr.flush()
604 sys.stderr.flush()
305 fd = os.open(util.nulldev, os.O_RDWR)
605 fd = os.open(util.nulldev, os.O_RDWR)
306 if fd != 0: os.dup2(fd, 0)
606 if fd != 0: os.dup2(fd, 0)
307 if fd != 1: os.dup2(fd, 1)
607 if fd != 1: os.dup2(fd, 1)
308 if fd != 2: os.dup2(fd, 2)
608 if fd != 2: os.dup2(fd, 2)
309 if fd not in (0, 1, 2): os.close(fd)
609 if fd not in (0, 1, 2): os.close(fd)
310
610
311 if runfn:
611 if runfn:
312 return runfn()
612 return runfn()
313
613
314 class changeset_printer(object):
614 class changeset_printer(object):
315 '''show changeset information when templating not requested.'''
615 '''show changeset information when templating not requested.'''
316
616
317 def __init__(self, ui, repo, patch, buffered):
617 def __init__(self, ui, repo, patch, buffered):
318 self.ui = ui
618 self.ui = ui
319 self.repo = repo
619 self.repo = repo
320 self.buffered = buffered
620 self.buffered = buffered
321 self.patch = patch
621 self.patch = patch
322 self.header = {}
622 self.header = {}
323 self.hunk = {}
623 self.hunk = {}
324 self.lastheader = None
624 self.lastheader = None
325
625
326 def flush(self, rev):
626 def flush(self, rev):
327 if rev in self.header:
627 if rev in self.header:
328 h = self.header[rev]
628 h = self.header[rev]
329 if h != self.lastheader:
629 if h != self.lastheader:
330 self.lastheader = h
630 self.lastheader = h
331 self.ui.write(h)
631 self.ui.write(h)
332 del self.header[rev]
632 del self.header[rev]
333 if rev in self.hunk:
633 if rev in self.hunk:
334 self.ui.write(self.hunk[rev])
634 self.ui.write(self.hunk[rev])
335 del self.hunk[rev]
635 del self.hunk[rev]
336 return 1
636 return 1
337 return 0
637 return 0
338
638
339 def show(self, rev=0, changenode=None, copies=(), **props):
639 def show(self, rev=0, changenode=None, copies=(), **props):
340 if self.buffered:
640 if self.buffered:
341 self.ui.pushbuffer()
641 self.ui.pushbuffer()
342 self._show(rev, changenode, copies, props)
642 self._show(rev, changenode, copies, props)
343 self.hunk[rev] = self.ui.popbuffer()
643 self.hunk[rev] = self.ui.popbuffer()
344 else:
644 else:
345 self._show(rev, changenode, copies, props)
645 self._show(rev, changenode, copies, props)
346
646
347 def _show(self, rev, changenode, copies, props):
647 def _show(self, rev, changenode, copies, props):
348 '''show a single changeset or file revision'''
648 '''show a single changeset or file revision'''
349 log = self.repo.changelog
649 log = self.repo.changelog
350 if changenode is None:
650 if changenode is None:
351 changenode = log.node(rev)
651 changenode = log.node(rev)
352 elif not rev:
652 elif not rev:
353 rev = log.rev(changenode)
653 rev = log.rev(changenode)
354
654
355 if self.ui.quiet:
655 if self.ui.quiet:
356 self.ui.write("%d:%s\n" % (rev, short(changenode)))
656 self.ui.write("%d:%s\n" % (rev, short(changenode)))
357 return
657 return
358
658
359 changes = log.read(changenode)
659 changes = log.read(changenode)
360 date = util.datestr(changes[2])
660 date = util.datestr(changes[2])
361 extra = changes[5]
661 extra = changes[5]
362 branch = extra.get("branch")
662 branch = extra.get("branch")
363
663
364 hexfunc = self.ui.debugflag and hex or short
664 hexfunc = self.ui.debugflag and hex or short
365
665
366 parents = log.parentrevs(rev)
666 parents = log.parentrevs(rev)
367 if not self.ui.debugflag:
667 if not self.ui.debugflag:
368 if parents[1] == nullrev:
668 if parents[1] == nullrev:
369 if parents[0] >= rev - 1:
669 if parents[0] >= rev - 1:
370 parents = []
670 parents = []
371 else:
671 else:
372 parents = [parents[0]]
672 parents = [parents[0]]
373 parents = [(p, hexfunc(log.node(p))) for p in parents]
673 parents = [(p, hexfunc(log.node(p))) for p in parents]
374
674
375 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
675 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
376
676
377 # don't show the default branch name
677 # don't show the default branch name
378 if branch != 'default':
678 if branch != 'default':
379 branch = util.tolocal(branch)
679 branch = util.tolocal(branch)
380 self.ui.write(_("branch: %s\n") % branch)
680 self.ui.write(_("branch: %s\n") % branch)
381 for tag in self.repo.nodetags(changenode):
681 for tag in self.repo.nodetags(changenode):
382 self.ui.write(_("tag: %s\n") % tag)
682 self.ui.write(_("tag: %s\n") % tag)
383 for parent in parents:
683 for parent in parents:
384 self.ui.write(_("parent: %d:%s\n") % parent)
684 self.ui.write(_("parent: %d:%s\n") % parent)
385
685
386 if self.ui.debugflag:
686 if self.ui.debugflag:
387 self.ui.write(_("manifest: %d:%s\n") %
687 self.ui.write(_("manifest: %d:%s\n") %
388 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
688 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
389 self.ui.write(_("user: %s\n") % changes[1])
689 self.ui.write(_("user: %s\n") % changes[1])
390 self.ui.write(_("date: %s\n") % date)
690 self.ui.write(_("date: %s\n") % date)
391
691
392 if self.ui.debugflag:
692 if self.ui.debugflag:
393 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
693 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
394 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
694 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
395 files):
695 files):
396 if value:
696 if value:
397 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
697 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
398 elif changes[3] and self.ui.verbose:
698 elif changes[3] and self.ui.verbose:
399 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
699 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
400 if copies and self.ui.verbose:
700 if copies and self.ui.verbose:
401 copies = ['%s (%s)' % c for c in copies]
701 copies = ['%s (%s)' % c for c in copies]
402 self.ui.write(_("copies: %s\n") % ' '.join(copies))
702 self.ui.write(_("copies: %s\n") % ' '.join(copies))
403
703
404 if extra and self.ui.debugflag:
704 if extra and self.ui.debugflag:
405 extraitems = extra.items()
705 extraitems = extra.items()
406 extraitems.sort()
706 extraitems.sort()
407 for key, value in extraitems:
707 for key, value in extraitems:
408 self.ui.write(_("extra: %s=%s\n")
708 self.ui.write(_("extra: %s=%s\n")
409 % (key, value.encode('string_escape')))
709 % (key, value.encode('string_escape')))
410
710
411 description = changes[4].strip()
711 description = changes[4].strip()
412 if description:
712 if description:
413 if self.ui.verbose:
713 if self.ui.verbose:
414 self.ui.write(_("description:\n"))
714 self.ui.write(_("description:\n"))
415 self.ui.write(description)
715 self.ui.write(description)
416 self.ui.write("\n\n")
716 self.ui.write("\n\n")
417 else:
717 else:
418 self.ui.write(_("summary: %s\n") %
718 self.ui.write(_("summary: %s\n") %
419 description.splitlines()[0])
719 description.splitlines()[0])
420 self.ui.write("\n")
720 self.ui.write("\n")
421
721
422 self.showpatch(changenode)
722 self.showpatch(changenode)
423
723
424 def showpatch(self, node):
724 def showpatch(self, node):
425 if self.patch:
725 if self.patch:
426 prev = self.repo.changelog.parents(node)[0]
726 prev = self.repo.changelog.parents(node)[0]
427 patch.diff(self.repo, prev, node, match=self.patch, fp=self.ui)
727 patch.diff(self.repo, prev, node, match=self.patch, fp=self.ui)
428 self.ui.write("\n")
728 self.ui.write("\n")
429
729
430 class changeset_templater(changeset_printer):
730 class changeset_templater(changeset_printer):
431 '''format changeset information.'''
731 '''format changeset information.'''
432
732
433 def __init__(self, ui, repo, patch, mapfile, buffered):
733 def __init__(self, ui, repo, patch, mapfile, buffered):
434 changeset_printer.__init__(self, ui, repo, patch, buffered)
734 changeset_printer.__init__(self, ui, repo, patch, buffered)
435 filters = templater.common_filters.copy()
735 filters = templater.common_filters.copy()
436 filters['formatnode'] = (ui.debugflag and (lambda x: x)
736 filters['formatnode'] = (ui.debugflag and (lambda x: x)
437 or (lambda x: x[:12]))
737 or (lambda x: x[:12]))
438 self.t = templater.templater(mapfile, filters,
738 self.t = templater.templater(mapfile, filters,
439 cache={
739 cache={
440 'parent': '{rev}:{node|formatnode} ',
740 'parent': '{rev}:{node|formatnode} ',
441 'manifest': '{rev}:{node|formatnode}',
741 'manifest': '{rev}:{node|formatnode}',
442 'filecopy': '{name} ({source})'})
742 'filecopy': '{name} ({source})'})
443
743
444 def use_template(self, t):
744 def use_template(self, t):
445 '''set template string to use'''
745 '''set template string to use'''
446 self.t.cache['changeset'] = t
746 self.t.cache['changeset'] = t
447
747
448 def _show(self, rev, changenode, copies, props):
748 def _show(self, rev, changenode, copies, props):
449 '''show a single changeset or file revision'''
749 '''show a single changeset or file revision'''
450 log = self.repo.changelog
750 log = self.repo.changelog
451 if changenode is None:
751 if changenode is None:
452 changenode = log.node(rev)
752 changenode = log.node(rev)
453 elif not rev:
753 elif not rev:
454 rev = log.rev(changenode)
754 rev = log.rev(changenode)
455
755
456 changes = log.read(changenode)
756 changes = log.read(changenode)
457
757
458 def showlist(name, values, plural=None, **args):
758 def showlist(name, values, plural=None, **args):
459 '''expand set of values.
759 '''expand set of values.
460 name is name of key in template map.
760 name is name of key in template map.
461 values is list of strings or dicts.
761 values is list of strings or dicts.
462 plural is plural of name, if not simply name + 's'.
762 plural is plural of name, if not simply name + 's'.
463
763
464 expansion works like this, given name 'foo'.
764 expansion works like this, given name 'foo'.
465
765
466 if values is empty, expand 'no_foos'.
766 if values is empty, expand 'no_foos'.
467
767
468 if 'foo' not in template map, return values as a string,
768 if 'foo' not in template map, return values as a string,
469 joined by space.
769 joined by space.
470
770
471 expand 'start_foos'.
771 expand 'start_foos'.
472
772
473 for each value, expand 'foo'. if 'last_foo' in template
773 for each value, expand 'foo'. if 'last_foo' in template
474 map, expand it instead of 'foo' for last key.
774 map, expand it instead of 'foo' for last key.
475
775
476 expand 'end_foos'.
776 expand 'end_foos'.
477 '''
777 '''
478 if plural: names = plural
778 if plural: names = plural
479 else: names = name + 's'
779 else: names = name + 's'
480 if not values:
780 if not values:
481 noname = 'no_' + names
781 noname = 'no_' + names
482 if noname in self.t:
782 if noname in self.t:
483 yield self.t(noname, **args)
783 yield self.t(noname, **args)
484 return
784 return
485 if name not in self.t:
785 if name not in self.t:
486 if isinstance(values[0], str):
786 if isinstance(values[0], str):
487 yield ' '.join(values)
787 yield ' '.join(values)
488 else:
788 else:
489 for v in values:
789 for v in values:
490 yield dict(v, **args)
790 yield dict(v, **args)
491 return
791 return
492 startname = 'start_' + names
792 startname = 'start_' + names
493 if startname in self.t:
793 if startname in self.t:
494 yield self.t(startname, **args)
794 yield self.t(startname, **args)
495 vargs = args.copy()
795 vargs = args.copy()
496 def one(v, tag=name):
796 def one(v, tag=name):
497 try:
797 try:
498 vargs.update(v)
798 vargs.update(v)
499 except (AttributeError, ValueError):
799 except (AttributeError, ValueError):
500 try:
800 try:
501 for a, b in v:
801 for a, b in v:
502 vargs[a] = b
802 vargs[a] = b
503 except ValueError:
803 except ValueError:
504 vargs[name] = v
804 vargs[name] = v
505 return self.t(tag, **vargs)
805 return self.t(tag, **vargs)
506 lastname = 'last_' + name
806 lastname = 'last_' + name
507 if lastname in self.t:
807 if lastname in self.t:
508 last = values.pop()
808 last = values.pop()
509 else:
809 else:
510 last = None
810 last = None
511 for v in values:
811 for v in values:
512 yield one(v)
812 yield one(v)
513 if last is not None:
813 if last is not None:
514 yield one(last, tag=lastname)
814 yield one(last, tag=lastname)
515 endname = 'end_' + names
815 endname = 'end_' + names
516 if endname in self.t:
816 if endname in self.t:
517 yield self.t(endname, **args)
817 yield self.t(endname, **args)
518
818
519 def showbranches(**args):
819 def showbranches(**args):
520 branch = changes[5].get("branch")
820 branch = changes[5].get("branch")
521 if branch != 'default':
821 if branch != 'default':
522 branch = util.tolocal(branch)
822 branch = util.tolocal(branch)
523 return showlist('branch', [branch], plural='branches', **args)
823 return showlist('branch', [branch], plural='branches', **args)
524
824
525 def showparents(**args):
825 def showparents(**args):
526 parents = [[('rev', log.rev(p)), ('node', hex(p))]
826 parents = [[('rev', log.rev(p)), ('node', hex(p))]
527 for p in log.parents(changenode)
827 for p in log.parents(changenode)
528 if self.ui.debugflag or p != nullid]
828 if self.ui.debugflag or p != nullid]
529 if (not self.ui.debugflag and len(parents) == 1 and
829 if (not self.ui.debugflag and len(parents) == 1 and
530 parents[0][0][1] == rev - 1):
830 parents[0][0][1] == rev - 1):
531 return
831 return
532 return showlist('parent', parents, **args)
832 return showlist('parent', parents, **args)
533
833
534 def showtags(**args):
834 def showtags(**args):
535 return showlist('tag', self.repo.nodetags(changenode), **args)
835 return showlist('tag', self.repo.nodetags(changenode), **args)
536
836
537 def showextras(**args):
837 def showextras(**args):
538 extras = changes[5].items()
838 extras = changes[5].items()
539 extras.sort()
839 extras.sort()
540 for key, value in extras:
840 for key, value in extras:
541 args = args.copy()
841 args = args.copy()
542 args.update(dict(key=key, value=value))
842 args.update(dict(key=key, value=value))
543 yield self.t('extra', **args)
843 yield self.t('extra', **args)
544
844
545 def showcopies(**args):
845 def showcopies(**args):
546 c = [{'name': x[0], 'source': x[1]} for x in copies]
846 c = [{'name': x[0], 'source': x[1]} for x in copies]
547 return showlist('file_copy', c, plural='file_copies', **args)
847 return showlist('file_copy', c, plural='file_copies', **args)
548
848
549 if self.ui.debugflag:
849 if self.ui.debugflag:
550 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
850 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
551 def showfiles(**args):
851 def showfiles(**args):
552 return showlist('file', files[0], **args)
852 return showlist('file', files[0], **args)
553 def showadds(**args):
853 def showadds(**args):
554 return showlist('file_add', files[1], **args)
854 return showlist('file_add', files[1], **args)
555 def showdels(**args):
855 def showdels(**args):
556 return showlist('file_del', files[2], **args)
856 return showlist('file_del', files[2], **args)
557 def showmanifest(**args):
857 def showmanifest(**args):
558 args = args.copy()
858 args = args.copy()
559 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
859 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
560 node=hex(changes[0])))
860 node=hex(changes[0])))
561 return self.t('manifest', **args)
861 return self.t('manifest', **args)
562 else:
862 else:
563 def showfiles(**args):
863 def showfiles(**args):
564 return showlist('file', changes[3], **args)
864 return showlist('file', changes[3], **args)
565 showadds = ''
865 showadds = ''
566 showdels = ''
866 showdels = ''
567 showmanifest = ''
867 showmanifest = ''
568
868
569 defprops = {
869 defprops = {
570 'author': changes[1],
870 'author': changes[1],
571 'branches': showbranches,
871 'branches': showbranches,
572 'date': changes[2],
872 'date': changes[2],
573 'desc': changes[4],
873 'desc': changes[4],
574 'file_adds': showadds,
874 'file_adds': showadds,
575 'file_dels': showdels,
875 'file_dels': showdels,
576 'files': showfiles,
876 'files': showfiles,
577 'file_copies': showcopies,
877 'file_copies': showcopies,
578 'manifest': showmanifest,
878 'manifest': showmanifest,
579 'node': hex(changenode),
879 'node': hex(changenode),
580 'parents': showparents,
880 'parents': showparents,
581 'rev': rev,
881 'rev': rev,
582 'tags': showtags,
882 'tags': showtags,
583 'extras': showextras,
883 'extras': showextras,
584 }
884 }
585 props = props.copy()
885 props = props.copy()
586 props.update(defprops)
886 props.update(defprops)
587
887
588 try:
888 try:
589 if self.ui.debugflag and 'header_debug' in self.t:
889 if self.ui.debugflag and 'header_debug' in self.t:
590 key = 'header_debug'
890 key = 'header_debug'
591 elif self.ui.quiet and 'header_quiet' in self.t:
891 elif self.ui.quiet and 'header_quiet' in self.t:
592 key = 'header_quiet'
892 key = 'header_quiet'
593 elif self.ui.verbose and 'header_verbose' in self.t:
893 elif self.ui.verbose and 'header_verbose' in self.t:
594 key = 'header_verbose'
894 key = 'header_verbose'
595 elif 'header' in self.t:
895 elif 'header' in self.t:
596 key = 'header'
896 key = 'header'
597 else:
897 else:
598 key = ''
898 key = ''
599 if key:
899 if key:
600 h = templater.stringify(self.t(key, **props))
900 h = templater.stringify(self.t(key, **props))
601 if self.buffered:
901 if self.buffered:
602 self.header[rev] = h
902 self.header[rev] = h
603 else:
903 else:
604 self.ui.write(h)
904 self.ui.write(h)
605 if self.ui.debugflag and 'changeset_debug' in self.t:
905 if self.ui.debugflag and 'changeset_debug' in self.t:
606 key = 'changeset_debug'
906 key = 'changeset_debug'
607 elif self.ui.quiet and 'changeset_quiet' in self.t:
907 elif self.ui.quiet and 'changeset_quiet' in self.t:
608 key = 'changeset_quiet'
908 key = 'changeset_quiet'
609 elif self.ui.verbose and 'changeset_verbose' in self.t:
909 elif self.ui.verbose and 'changeset_verbose' in self.t:
610 key = 'changeset_verbose'
910 key = 'changeset_verbose'
611 else:
911 else:
612 key = 'changeset'
912 key = 'changeset'
613 self.ui.write(templater.stringify(self.t(key, **props)))
913 self.ui.write(templater.stringify(self.t(key, **props)))
614 self.showpatch(changenode)
914 self.showpatch(changenode)
615 except KeyError, inst:
915 except KeyError, inst:
616 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
916 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
617 inst.args[0]))
917 inst.args[0]))
618 except SyntaxError, inst:
918 except SyntaxError, inst:
619 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
919 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
620
920
621 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
921 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
622 """show one changeset using template or regular display.
922 """show one changeset using template or regular display.
623
923
624 Display format will be the first non-empty hit of:
924 Display format will be the first non-empty hit of:
625 1. option 'template'
925 1. option 'template'
626 2. option 'style'
926 2. option 'style'
627 3. [ui] setting 'logtemplate'
927 3. [ui] setting 'logtemplate'
628 4. [ui] setting 'style'
928 4. [ui] setting 'style'
629 If all of these values are either the unset or the empty string,
929 If all of these values are either the unset or the empty string,
630 regular display via changeset_printer() is done.
930 regular display via changeset_printer() is done.
631 """
931 """
632 # options
932 # options
633 patch = False
933 patch = False
634 if opts.get('patch'):
934 if opts.get('patch'):
635 patch = matchfn or util.always
935 patch = matchfn or util.always
636
936
637 tmpl = opts.get('template')
937 tmpl = opts.get('template')
638 mapfile = None
938 mapfile = None
639 if tmpl:
939 if tmpl:
640 tmpl = templater.parsestring(tmpl, quoted=False)
940 tmpl = templater.parsestring(tmpl, quoted=False)
641 else:
941 else:
642 mapfile = opts.get('style')
942 mapfile = opts.get('style')
643 # ui settings
943 # ui settings
644 if not mapfile:
944 if not mapfile:
645 tmpl = ui.config('ui', 'logtemplate')
945 tmpl = ui.config('ui', 'logtemplate')
646 if tmpl:
946 if tmpl:
647 tmpl = templater.parsestring(tmpl)
947 tmpl = templater.parsestring(tmpl)
648 else:
948 else:
649 mapfile = ui.config('ui', 'style')
949 mapfile = ui.config('ui', 'style')
650
950
651 if tmpl or mapfile:
951 if tmpl or mapfile:
652 if mapfile:
952 if mapfile:
653 if not os.path.split(mapfile)[0]:
953 if not os.path.split(mapfile)[0]:
654 mapname = (templater.templatepath('map-cmdline.' + mapfile)
954 mapname = (templater.templatepath('map-cmdline.' + mapfile)
655 or templater.templatepath(mapfile))
955 or templater.templatepath(mapfile))
656 if mapname: mapfile = mapname
956 if mapname: mapfile = mapname
657 try:
957 try:
658 t = changeset_templater(ui, repo, patch, mapfile, buffered)
958 t = changeset_templater(ui, repo, patch, mapfile, buffered)
659 except SyntaxError, inst:
959 except SyntaxError, inst:
660 raise util.Abort(inst.args[0])
960 raise util.Abort(inst.args[0])
661 if tmpl: t.use_template(tmpl)
961 if tmpl: t.use_template(tmpl)
662 return t
962 return t
663 return changeset_printer(ui, repo, patch, buffered)
963 return changeset_printer(ui, repo, patch, buffered)
664
964
665 def finddate(ui, repo, date):
965 def finddate(ui, repo, date):
666 """Find the tipmost changeset that matches the given date spec"""
966 """Find the tipmost changeset that matches the given date spec"""
667 df = util.matchdate(date + " to " + date)
967 df = util.matchdate(date + " to " + date)
668 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
968 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
669 changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None})
969 changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None})
670 results = {}
970 results = {}
671 for st, rev, fns in changeiter:
971 for st, rev, fns in changeiter:
672 if st == 'add':
972 if st == 'add':
673 d = get(rev)[2]
973 d = get(rev)[2]
674 if df(d[0]):
974 if df(d[0]):
675 results[rev] = d
975 results[rev] = d
676 elif st == 'iter':
976 elif st == 'iter':
677 if rev in results:
977 if rev in results:
678 ui.status("Found revision %s from %s\n" %
978 ui.status("Found revision %s from %s\n" %
679 (rev, util.datestr(results[rev])))
979 (rev, util.datestr(results[rev])))
680 return str(rev)
980 return str(rev)
681
981
682 raise util.Abort(_("revision matching date not found"))
982 raise util.Abort(_("revision matching date not found"))
683
983
684 def walkchangerevs(ui, repo, pats, change, opts):
984 def walkchangerevs(ui, repo, pats, change, opts):
685 '''Iterate over files and the revs they changed in.
985 '''Iterate over files and the revs they changed in.
686
986
687 Callers most commonly need to iterate backwards over the history
987 Callers most commonly need to iterate backwards over the history
688 it is interested in. Doing so has awful (quadratic-looking)
988 it is interested in. Doing so has awful (quadratic-looking)
689 performance, so we use iterators in a "windowed" way.
989 performance, so we use iterators in a "windowed" way.
690
990
691 We walk a window of revisions in the desired order. Within the
991 We walk a window of revisions in the desired order. Within the
692 window, we first walk forwards to gather data, then in the desired
992 window, we first walk forwards to gather data, then in the desired
693 order (usually backwards) to display it.
993 order (usually backwards) to display it.
694
994
695 This function returns an (iterator, matchfn) tuple. The iterator
995 This function returns an (iterator, matchfn) tuple. The iterator
696 yields 3-tuples. They will be of one of the following forms:
996 yields 3-tuples. They will be of one of the following forms:
697
997
698 "window", incrementing, lastrev: stepping through a window,
998 "window", incrementing, lastrev: stepping through a window,
699 positive if walking forwards through revs, last rev in the
999 positive if walking forwards through revs, last rev in the
700 sequence iterated over - use to reset state for the current window
1000 sequence iterated over - use to reset state for the current window
701
1001
702 "add", rev, fns: out-of-order traversal of the given file names
1002 "add", rev, fns: out-of-order traversal of the given file names
703 fns, which changed during revision rev - use to gather data for
1003 fns, which changed during revision rev - use to gather data for
704 possible display
1004 possible display
705
1005
706 "iter", rev, None: in-order traversal of the revs earlier iterated
1006 "iter", rev, None: in-order traversal of the revs earlier iterated
707 over with "add" - use to display data'''
1007 over with "add" - use to display data'''
708
1008
709 def increasing_windows(start, end, windowsize=8, sizelimit=512):
1009 def increasing_windows(start, end, windowsize=8, sizelimit=512):
710 if start < end:
1010 if start < end:
711 while start < end:
1011 while start < end:
712 yield start, min(windowsize, end-start)
1012 yield start, min(windowsize, end-start)
713 start += windowsize
1013 start += windowsize
714 if windowsize < sizelimit:
1014 if windowsize < sizelimit:
715 windowsize *= 2
1015 windowsize *= 2
716 else:
1016 else:
717 while start > end:
1017 while start > end:
718 yield start, min(windowsize, start-end-1)
1018 yield start, min(windowsize, start-end-1)
719 start -= windowsize
1019 start -= windowsize
720 if windowsize < sizelimit:
1020 if windowsize < sizelimit:
721 windowsize *= 2
1021 windowsize *= 2
722
1022
723 files, matchfn, anypats = matchpats(repo, pats, opts)
1023 files, matchfn, anypats = matchpats(repo, pats, opts)
724 follow = opts.get('follow') or opts.get('follow_first')
1024 follow = opts.get('follow') or opts.get('follow_first')
725
1025
726 if repo.changelog.count() == 0:
1026 if repo.changelog.count() == 0:
727 return [], matchfn
1027 return [], matchfn
728
1028
729 if follow:
1029 if follow:
730 defrange = '%s:0' % repo.changectx().rev()
1030 defrange = '%s:0' % repo.changectx().rev()
731 else:
1031 else:
732 defrange = 'tip:0'
1032 defrange = 'tip:0'
733 revs = revrange(repo, opts['rev'] or [defrange])
1033 revs = revrange(repo, opts['rev'] or [defrange])
734 wanted = {}
1034 wanted = {}
735 slowpath = anypats or opts.get('removed')
1035 slowpath = anypats or opts.get('removed')
736 fncache = {}
1036 fncache = {}
737
1037
738 if not slowpath and not files:
1038 if not slowpath and not files:
739 # No files, no patterns. Display all revs.
1039 # No files, no patterns. Display all revs.
740 wanted = dict.fromkeys(revs)
1040 wanted = dict.fromkeys(revs)
741 copies = []
1041 copies = []
742 if not slowpath:
1042 if not slowpath:
743 # Only files, no patterns. Check the history of each file.
1043 # Only files, no patterns. Check the history of each file.
744 def filerevgen(filelog, node):
1044 def filerevgen(filelog, node):
745 cl_count = repo.changelog.count()
1045 cl_count = repo.changelog.count()
746 if node is None:
1046 if node is None:
747 last = filelog.count() - 1
1047 last = filelog.count() - 1
748 else:
1048 else:
749 last = filelog.rev(node)
1049 last = filelog.rev(node)
750 for i, window in increasing_windows(last, nullrev):
1050 for i, window in increasing_windows(last, nullrev):
751 revs = []
1051 revs = []
752 for j in xrange(i - window, i + 1):
1052 for j in xrange(i - window, i + 1):
753 n = filelog.node(j)
1053 n = filelog.node(j)
754 revs.append((filelog.linkrev(n),
1054 revs.append((filelog.linkrev(n),
755 follow and filelog.renamed(n)))
1055 follow and filelog.renamed(n)))
756 revs.reverse()
1056 revs.reverse()
757 for rev in revs:
1057 for rev in revs:
758 # only yield rev for which we have the changelog, it can
1058 # only yield rev for which we have the changelog, it can
759 # happen while doing "hg log" during a pull or commit
1059 # happen while doing "hg log" during a pull or commit
760 if rev[0] < cl_count:
1060 if rev[0] < cl_count:
761 yield rev
1061 yield rev
762 def iterfiles():
1062 def iterfiles():
763 for filename in files:
1063 for filename in files:
764 yield filename, None
1064 yield filename, None
765 for filename_node in copies:
1065 for filename_node in copies:
766 yield filename_node
1066 yield filename_node
767 minrev, maxrev = min(revs), max(revs)
1067 minrev, maxrev = min(revs), max(revs)
768 for file_, node in iterfiles():
1068 for file_, node in iterfiles():
769 filelog = repo.file(file_)
1069 filelog = repo.file(file_)
770 # A zero count may be a directory or deleted file, so
1070 # A zero count may be a directory or deleted file, so
771 # try to find matching entries on the slow path.
1071 # try to find matching entries on the slow path.
772 if filelog.count() == 0:
1072 if filelog.count() == 0:
773 slowpath = True
1073 slowpath = True
774 break
1074 break
775 for rev, copied in filerevgen(filelog, node):
1075 for rev, copied in filerevgen(filelog, node):
776 if rev <= maxrev:
1076 if rev <= maxrev:
777 if rev < minrev:
1077 if rev < minrev:
778 break
1078 break
779 fncache.setdefault(rev, [])
1079 fncache.setdefault(rev, [])
780 fncache[rev].append(file_)
1080 fncache[rev].append(file_)
781 wanted[rev] = 1
1081 wanted[rev] = 1
782 if follow and copied:
1082 if follow and copied:
783 copies.append(copied)
1083 copies.append(copied)
784 if slowpath:
1084 if slowpath:
785 if follow:
1085 if follow:
786 raise util.Abort(_('can only follow copies/renames for explicit '
1086 raise util.Abort(_('can only follow copies/renames for explicit '
787 'file names'))
1087 'file names'))
788
1088
789 # The slow path checks files modified in every changeset.
1089 # The slow path checks files modified in every changeset.
790 def changerevgen():
1090 def changerevgen():
791 for i, window in increasing_windows(repo.changelog.count()-1,
1091 for i, window in increasing_windows(repo.changelog.count()-1,
792 nullrev):
1092 nullrev):
793 for j in xrange(i - window, i + 1):
1093 for j in xrange(i - window, i + 1):
794 yield j, change(j)[3]
1094 yield j, change(j)[3]
795
1095
796 for rev, changefiles in changerevgen():
1096 for rev, changefiles in changerevgen():
797 matches = filter(matchfn, changefiles)
1097 matches = filter(matchfn, changefiles)
798 if matches:
1098 if matches:
799 fncache[rev] = matches
1099 fncache[rev] = matches
800 wanted[rev] = 1
1100 wanted[rev] = 1
801
1101
802 class followfilter:
1102 class followfilter:
803 def __init__(self, onlyfirst=False):
1103 def __init__(self, onlyfirst=False):
804 self.startrev = nullrev
1104 self.startrev = nullrev
805 self.roots = []
1105 self.roots = []
806 self.onlyfirst = onlyfirst
1106 self.onlyfirst = onlyfirst
807
1107
808 def match(self, rev):
1108 def match(self, rev):
809 def realparents(rev):
1109 def realparents(rev):
810 if self.onlyfirst:
1110 if self.onlyfirst:
811 return repo.changelog.parentrevs(rev)[0:1]
1111 return repo.changelog.parentrevs(rev)[0:1]
812 else:
1112 else:
813 return filter(lambda x: x != nullrev,
1113 return filter(lambda x: x != nullrev,
814 repo.changelog.parentrevs(rev))
1114 repo.changelog.parentrevs(rev))
815
1115
816 if self.startrev == nullrev:
1116 if self.startrev == nullrev:
817 self.startrev = rev
1117 self.startrev = rev
818 return True
1118 return True
819
1119
820 if rev > self.startrev:
1120 if rev > self.startrev:
821 # forward: all descendants
1121 # forward: all descendants
822 if not self.roots:
1122 if not self.roots:
823 self.roots.append(self.startrev)
1123 self.roots.append(self.startrev)
824 for parent in realparents(rev):
1124 for parent in realparents(rev):
825 if parent in self.roots:
1125 if parent in self.roots:
826 self.roots.append(rev)
1126 self.roots.append(rev)
827 return True
1127 return True
828 else:
1128 else:
829 # backwards: all parents
1129 # backwards: all parents
830 if not self.roots:
1130 if not self.roots:
831 self.roots.extend(realparents(self.startrev))
1131 self.roots.extend(realparents(self.startrev))
832 if rev in self.roots:
1132 if rev in self.roots:
833 self.roots.remove(rev)
1133 self.roots.remove(rev)
834 self.roots.extend(realparents(rev))
1134 self.roots.extend(realparents(rev))
835 return True
1135 return True
836
1136
837 return False
1137 return False
838
1138
839 # it might be worthwhile to do this in the iterator if the rev range
1139 # it might be worthwhile to do this in the iterator if the rev range
840 # is descending and the prune args are all within that range
1140 # is descending and the prune args are all within that range
841 for rev in opts.get('prune', ()):
1141 for rev in opts.get('prune', ()):
842 rev = repo.changelog.rev(repo.lookup(rev))
1142 rev = repo.changelog.rev(repo.lookup(rev))
843 ff = followfilter()
1143 ff = followfilter()
844 stop = min(revs[0], revs[-1])
1144 stop = min(revs[0], revs[-1])
845 for x in xrange(rev, stop-1, -1):
1145 for x in xrange(rev, stop-1, -1):
846 if ff.match(x) and x in wanted:
1146 if ff.match(x) and x in wanted:
847 del wanted[x]
1147 del wanted[x]
848
1148
849 def iterate():
1149 def iterate():
850 if follow and not files:
1150 if follow and not files:
851 ff = followfilter(onlyfirst=opts.get('follow_first'))
1151 ff = followfilter(onlyfirst=opts.get('follow_first'))
852 def want(rev):
1152 def want(rev):
853 if ff.match(rev) and rev in wanted:
1153 if ff.match(rev) and rev in wanted:
854 return True
1154 return True
855 return False
1155 return False
856 else:
1156 else:
857 def want(rev):
1157 def want(rev):
858 return rev in wanted
1158 return rev in wanted
859
1159
860 for i, window in increasing_windows(0, len(revs)):
1160 for i, window in increasing_windows(0, len(revs)):
861 yield 'window', revs[0] < revs[-1], revs[-1]
1161 yield 'window', revs[0] < revs[-1], revs[-1]
862 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
1162 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
863 srevs = list(nrevs)
1163 srevs = list(nrevs)
864 srevs.sort()
1164 srevs.sort()
865 for rev in srevs:
1165 for rev in srevs:
866 fns = fncache.get(rev)
1166 fns = fncache.get(rev)
867 if not fns:
1167 if not fns:
868 def fns_generator():
1168 def fns_generator():
869 for f in change(rev)[3]:
1169 for f in change(rev)[3]:
870 if matchfn(f):
1170 if matchfn(f):
871 yield f
1171 yield f
872 fns = fns_generator()
1172 fns = fns_generator()
873 yield 'add', rev, fns
1173 yield 'add', rev, fns
874 for rev in nrevs:
1174 for rev in nrevs:
875 yield 'iter', rev, None
1175 yield 'iter', rev, None
876 return iterate(), matchfn
1176 return iterate(), matchfn
@@ -1,3310 +1,3007 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 import demandimport; demandimport.enable()
8 import demandimport; demandimport.enable()
9 from node import *
9 from node import *
10 from i18n import _
10 from i18n import _
11 import bisect, os, re, sys, signal, urllib, pdb, shlex, stat
11 import bisect, os, re, sys, urllib, shlex, stat
12 import fancyopts, ui, hg, util, lock, revlog, bundlerepo, extensions
12 import ui, hg, util, revlog, bundlerepo, extensions
13 import difflib, patch, time, help, mdiff, tempfile
13 import difflib, patch, time, help, mdiff, tempfile
14 import traceback, errno, version, atexit, socket
14 import errno, version, socket
15 import archival, changegroup, cmdutil, hgweb.server, sshserver
15 import archival, changegroup, cmdutil, hgweb.server, sshserver
16
16
17 class UnknownCommand(Exception):
18 """Exception raised if command is not in the command table."""
19 class AmbiguousCommand(Exception):
20 """Exception raised if command shortcut matches more than one command."""
21
22 def bail_if_changed(repo):
23 modified, added, removed, deleted = repo.status()[:4]
24 if modified or added or removed or deleted:
25 raise util.Abort(_("outstanding uncommitted changes"))
26
27 def logmessage(opts):
28 """ get the log message according to -m and -l option """
29 message = opts['message']
30 logfile = opts['logfile']
31
32 if message and logfile:
33 raise util.Abort(_('options --message and --logfile are mutually '
34 'exclusive'))
35 if not message and logfile:
36 try:
37 if logfile == '-':
38 message = sys.stdin.read()
39 else:
40 message = open(logfile).read()
41 except IOError, inst:
42 raise util.Abort(_("can't read commit message '%s': %s") %
43 (logfile, inst.strerror))
44 return message
45
46 def setremoteconfig(ui, opts):
47 "copy remote options to ui tree"
48 if opts.get('ssh'):
49 ui.setconfig("ui", "ssh", opts['ssh'])
50 if opts.get('remotecmd'):
51 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
52
53 # Commands start here, listed alphabetically
17 # Commands start here, listed alphabetically
54
18
55 def add(ui, repo, *pats, **opts):
19 def add(ui, repo, *pats, **opts):
56 """add the specified files on the next commit
20 """add the specified files on the next commit
57
21
58 Schedule files to be version controlled and added to the repository.
22 Schedule files to be version controlled and added to the repository.
59
23
60 The files will be added to the repository at the next commit. To
24 The files will be added to the repository at the next commit. To
61 undo an add before that, see hg revert.
25 undo an add before that, see hg revert.
62
26
63 If no names are given, add all files in the repository.
27 If no names are given, add all files in the repository.
64 """
28 """
65
29
66 names = []
30 names = []
67 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
31 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
68 if exact:
32 if exact:
69 if ui.verbose:
33 if ui.verbose:
70 ui.status(_('adding %s\n') % rel)
34 ui.status(_('adding %s\n') % rel)
71 names.append(abs)
35 names.append(abs)
72 elif repo.dirstate.state(abs) == '?':
36 elif repo.dirstate.state(abs) == '?':
73 ui.status(_('adding %s\n') % rel)
37 ui.status(_('adding %s\n') % rel)
74 names.append(abs)
38 names.append(abs)
75 if not opts.get('dry_run'):
39 if not opts.get('dry_run'):
76 repo.add(names)
40 repo.add(names)
77
41
78 def addremove(ui, repo, *pats, **opts):
42 def addremove(ui, repo, *pats, **opts):
79 """add all new files, delete all missing files
43 """add all new files, delete all missing files
80
44
81 Add all new files and remove all missing files from the repository.
45 Add all new files and remove all missing files from the repository.
82
46
83 New files are ignored if they match any of the patterns in .hgignore. As
47 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.
48 with add, these changes take effect at the next commit.
85
49
86 Use the -s option to detect renamed files. With a parameter > 0,
50 Use the -s option to detect renamed files. With a parameter > 0,
87 this compares every removed file with every added file and records
51 this compares every removed file with every added file and records
88 those similar enough as renames. This option takes a percentage
52 those similar enough as renames. This option takes a percentage
89 between 0 (disabled) and 100 (files must be identical) as its
53 between 0 (disabled) and 100 (files must be identical) as its
90 parameter. Detecting renamed files this way can be expensive.
54 parameter. Detecting renamed files this way can be expensive.
91 """
55 """
92 sim = float(opts.get('similarity') or 0)
56 sim = float(opts.get('similarity') or 0)
93 if sim < 0 or sim > 100:
57 if sim < 0 or sim > 100:
94 raise util.Abort(_('similarity must be between 0 and 100'))
58 raise util.Abort(_('similarity must be between 0 and 100'))
95 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
59 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
96
60
97 def annotate(ui, repo, *pats, **opts):
61 def annotate(ui, repo, *pats, **opts):
98 """show changeset information per file line
62 """show changeset information per file line
99
63
100 List changes in files, showing the revision id responsible for each line
64 List changes in files, showing the revision id responsible for each line
101
65
102 This command is useful to discover who did a change or when a change took
66 This command is useful to discover who did a change or when a change took
103 place.
67 place.
104
68
105 Without the -a option, annotate will avoid processing files it
69 Without the -a option, annotate will avoid processing files it
106 detects as binary. With -a, annotate will generate an annotation
70 detects as binary. With -a, annotate will generate an annotation
107 anyway, probably with undesirable results.
71 anyway, probably with undesirable results.
108 """
72 """
109 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
73 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
110
74
111 if not pats:
75 if not pats:
112 raise util.Abort(_('at least one file name or pattern required'))
76 raise util.Abort(_('at least one file name or pattern required'))
113
77
114 opmap = [['user', lambda x: ui.shortuser(x.user())],
78 opmap = [['user', lambda x: ui.shortuser(x.user())],
115 ['number', lambda x: str(x.rev())],
79 ['number', lambda x: str(x.rev())],
116 ['changeset', lambda x: short(x.node())],
80 ['changeset', lambda x: short(x.node())],
117 ['date', getdate], ['follow', lambda x: x.path()]]
81 ['date', getdate], ['follow', lambda x: x.path()]]
118 if (not opts['user'] and not opts['changeset'] and not opts['date']
82 if (not opts['user'] and not opts['changeset'] and not opts['date']
119 and not opts['follow']):
83 and not opts['follow']):
120 opts['number'] = 1
84 opts['number'] = 1
121
85
122 ctx = repo.changectx(opts['rev'])
86 ctx = repo.changectx(opts['rev'])
123
87
124 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
88 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
125 node=ctx.node()):
89 node=ctx.node()):
126 fctx = ctx.filectx(abs)
90 fctx = ctx.filectx(abs)
127 if not opts['text'] and util.binary(fctx.data()):
91 if not opts['text'] and util.binary(fctx.data()):
128 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
92 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
129 continue
93 continue
130
94
131 lines = fctx.annotate(follow=opts.get('follow'))
95 lines = fctx.annotate(follow=opts.get('follow'))
132 pieces = []
96 pieces = []
133
97
134 for o, f in opmap:
98 for o, f in opmap:
135 if opts[o]:
99 if opts[o]:
136 l = [f(n) for n, dummy in lines]
100 l = [f(n) for n, dummy in lines]
137 if l:
101 if l:
138 m = max(map(len, l))
102 m = max(map(len, l))
139 pieces.append(["%*s" % (m, x) for x in l])
103 pieces.append(["%*s" % (m, x) for x in l])
140
104
141 if pieces:
105 if pieces:
142 for p, l in zip(zip(*pieces), lines):
106 for p, l in zip(zip(*pieces), lines):
143 ui.write("%s: %s" % (" ".join(p), l[1]))
107 ui.write("%s: %s" % (" ".join(p), l[1]))
144
108
145 def archive(ui, repo, dest, **opts):
109 def archive(ui, repo, dest, **opts):
146 '''create unversioned archive of a repository revision
110 '''create unversioned archive of a repository revision
147
111
148 By default, the revision used is the parent of the working
112 By default, the revision used is the parent of the working
149 directory; use "-r" to specify a different revision.
113 directory; use "-r" to specify a different revision.
150
114
151 To specify the type of archive to create, use "-t". Valid
115 To specify the type of archive to create, use "-t". Valid
152 types are:
116 types are:
153
117
154 "files" (default): a directory full of files
118 "files" (default): a directory full of files
155 "tar": tar archive, uncompressed
119 "tar": tar archive, uncompressed
156 "tbz2": tar archive, compressed using bzip2
120 "tbz2": tar archive, compressed using bzip2
157 "tgz": tar archive, compressed using gzip
121 "tgz": tar archive, compressed using gzip
158 "uzip": zip archive, uncompressed
122 "uzip": zip archive, uncompressed
159 "zip": zip archive, compressed using deflate
123 "zip": zip archive, compressed using deflate
160
124
161 The exact name of the destination archive or directory is given
125 The exact name of the destination archive or directory is given
162 using a format string; see "hg help export" for details.
126 using a format string; see "hg help export" for details.
163
127
164 Each member added to an archive file has a directory prefix
128 Each member added to an archive file has a directory prefix
165 prepended. Use "-p" to specify a format string for the prefix.
129 prepended. Use "-p" to specify a format string for the prefix.
166 The default is the basename of the archive, with suffixes removed.
130 The default is the basename of the archive, with suffixes removed.
167 '''
131 '''
168
132
169 node = repo.changectx(opts['rev']).node()
133 node = repo.changectx(opts['rev']).node()
170 dest = cmdutil.make_filename(repo, dest, node)
134 dest = cmdutil.make_filename(repo, dest, node)
171 if os.path.realpath(dest) == repo.root:
135 if os.path.realpath(dest) == repo.root:
172 raise util.Abort(_('repository root cannot be destination'))
136 raise util.Abort(_('repository root cannot be destination'))
173 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
137 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
174 kind = opts.get('type') or 'files'
138 kind = opts.get('type') or 'files'
175 prefix = opts['prefix']
139 prefix = opts['prefix']
176 if dest == '-':
140 if dest == '-':
177 if kind == 'files':
141 if kind == 'files':
178 raise util.Abort(_('cannot archive plain files to stdout'))
142 raise util.Abort(_('cannot archive plain files to stdout'))
179 dest = sys.stdout
143 dest = sys.stdout
180 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
144 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
181 prefix = cmdutil.make_filename(repo, prefix, node)
145 prefix = cmdutil.make_filename(repo, prefix, node)
182 archival.archive(repo, dest, node, kind, not opts['no_decode'],
146 archival.archive(repo, dest, node, kind, not opts['no_decode'],
183 matchfn, prefix)
147 matchfn, prefix)
184
148
185 def backout(ui, repo, node=None, rev=None, **opts):
149 def backout(ui, repo, node=None, rev=None, **opts):
186 '''reverse effect of earlier changeset
150 '''reverse effect of earlier changeset
187
151
188 Commit the backed out changes as a new changeset. The new
152 Commit the backed out changes as a new changeset. The new
189 changeset is a child of the backed out changeset.
153 changeset is a child of the backed out changeset.
190
154
191 If you back out a changeset other than the tip, a new head is
155 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
156 created. This head is the parent of the working directory. If
193 you back out an old changeset, your working directory will appear
157 you back out an old changeset, your working directory will appear
194 old after the backout. You should merge the backout changeset
158 old after the backout. You should merge the backout changeset
195 with another head.
159 with another head.
196
160
197 The --merge option remembers the parent of the working directory
161 The --merge option remembers the parent of the working directory
198 before starting the backout, then merges the new head with that
162 before starting the backout, then merges the new head with that
199 changeset afterwards. This saves you from doing the merge by
163 changeset afterwards. This saves you from doing the merge by
200 hand. The result of this merge is not committed, as for a normal
164 hand. The result of this merge is not committed, as for a normal
201 merge.'''
165 merge.'''
202 if rev and node:
166 if rev and node:
203 raise util.Abort(_("please specify just one revision"))
167 raise util.Abort(_("please specify just one revision"))
204
168
205 if not rev:
169 if not rev:
206 rev = node
170 rev = node
207
171
208 bail_if_changed(repo)
172 cmdutil.bail_if_changed(repo)
209 op1, op2 = repo.dirstate.parents()
173 op1, op2 = repo.dirstate.parents()
210 if op2 != nullid:
174 if op2 != nullid:
211 raise util.Abort(_('outstanding uncommitted merge'))
175 raise util.Abort(_('outstanding uncommitted merge'))
212 node = repo.lookup(rev)
176 node = repo.lookup(rev)
213 p1, p2 = repo.changelog.parents(node)
177 p1, p2 = repo.changelog.parents(node)
214 if p1 == nullid:
178 if p1 == nullid:
215 raise util.Abort(_('cannot back out a change with no parents'))
179 raise util.Abort(_('cannot back out a change with no parents'))
216 if p2 != nullid:
180 if p2 != nullid:
217 if not opts['parent']:
181 if not opts['parent']:
218 raise util.Abort(_('cannot back out a merge changeset without '
182 raise util.Abort(_('cannot back out a merge changeset without '
219 '--parent'))
183 '--parent'))
220 p = repo.lookup(opts['parent'])
184 p = repo.lookup(opts['parent'])
221 if p not in (p1, p2):
185 if p not in (p1, p2):
222 raise util.Abort(_('%s is not a parent of %s') %
186 raise util.Abort(_('%s is not a parent of %s') %
223 (short(p), short(node)))
187 (short(p), short(node)))
224 parent = p
188 parent = p
225 else:
189 else:
226 if opts['parent']:
190 if opts['parent']:
227 raise util.Abort(_('cannot use --parent on non-merge changeset'))
191 raise util.Abort(_('cannot use --parent on non-merge changeset'))
228 parent = p1
192 parent = p1
229 hg.clean(repo, node, show_stats=False)
193 hg.clean(repo, node, show_stats=False)
230 revert_opts = opts.copy()
194 revert_opts = opts.copy()
231 revert_opts['date'] = None
195 revert_opts['date'] = None
232 revert_opts['all'] = True
196 revert_opts['all'] = True
233 revert_opts['rev'] = hex(parent)
197 revert_opts['rev'] = hex(parent)
234 revert(ui, repo, **revert_opts)
198 revert(ui, repo, **revert_opts)
235 commit_opts = opts.copy()
199 commit_opts = opts.copy()
236 commit_opts['addremove'] = False
200 commit_opts['addremove'] = False
237 if not commit_opts['message'] and not commit_opts['logfile']:
201 if not commit_opts['message'] and not commit_opts['logfile']:
238 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
202 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
239 commit_opts['force_editor'] = True
203 commit_opts['force_editor'] = True
240 commit(ui, repo, **commit_opts)
204 commit(ui, repo, **commit_opts)
241 def nice(node):
205 def nice(node):
242 return '%d:%s' % (repo.changelog.rev(node), short(node))
206 return '%d:%s' % (repo.changelog.rev(node), short(node))
243 ui.status(_('changeset %s backs out changeset %s\n') %
207 ui.status(_('changeset %s backs out changeset %s\n') %
244 (nice(repo.changelog.tip()), nice(node)))
208 (nice(repo.changelog.tip()), nice(node)))
245 if op1 != node:
209 if op1 != node:
246 if opts['merge']:
210 if opts['merge']:
247 ui.status(_('merging with changeset %s\n') % nice(op1))
211 ui.status(_('merging with changeset %s\n') % nice(op1))
248 hg.merge(repo, hex(op1))
212 hg.merge(repo, hex(op1))
249 else:
213 else:
250 ui.status(_('the backout changeset is a new head - '
214 ui.status(_('the backout changeset is a new head - '
251 'do not forget to merge\n'))
215 'do not forget to merge\n'))
252 ui.status(_('(use "backout --merge" '
216 ui.status(_('(use "backout --merge" '
253 'if you want to auto-merge)\n'))
217 'if you want to auto-merge)\n'))
254
218
255 def branch(ui, repo, label=None, **opts):
219 def branch(ui, repo, label=None, **opts):
256 """set or show the current branch name
220 """set or show the current branch name
257
221
258 With <name>, set the current branch name. Otherwise, show the
222 With <name>, set the current branch name. Otherwise, show the
259 current branch name.
223 current branch name.
260
224
261 Unless --force is specified, branch will not let you set a
225 Unless --force is specified, branch will not let you set a
262 branch name that shadows an existing branch.
226 branch name that shadows an existing branch.
263 """
227 """
264
228
265 if label:
229 if label:
266 if not opts.get('force') and label in repo.branchtags():
230 if not opts.get('force') and label in repo.branchtags():
267 if label not in [p.branch() for p in repo.workingctx().parents()]:
231 if label not in [p.branch() for p in repo.workingctx().parents()]:
268 raise util.Abort(_('a branch of the same name already exists'
232 raise util.Abort(_('a branch of the same name already exists'
269 ' (use --force to override)'))
233 ' (use --force to override)'))
270 repo.dirstate.setbranch(util.fromlocal(label))
234 repo.dirstate.setbranch(util.fromlocal(label))
271 else:
235 else:
272 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
236 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
273
237
274 def branches(ui, repo):
238 def branches(ui, repo):
275 """list repository named branches
239 """list repository named branches
276
240
277 List the repository's named branches.
241 List the repository's named branches.
278 """
242 """
279 b = repo.branchtags()
243 b = repo.branchtags()
280 l = [(-repo.changelog.rev(n), n, t) for t, n in b.items()]
244 l = [(-repo.changelog.rev(n), n, t) for t, n in b.items()]
281 l.sort()
245 l.sort()
282 for r, n, t in l:
246 for r, n, t in l:
283 hexfunc = ui.debugflag and hex or short
247 hexfunc = ui.debugflag and hex or short
284 if ui.quiet:
248 if ui.quiet:
285 ui.write("%s\n" % t)
249 ui.write("%s\n" % t)
286 else:
250 else:
287 spaces = " " * (30 - util.locallen(t))
251 spaces = " " * (30 - util.locallen(t))
288 ui.write("%s%s %s:%s\n" % (t, spaces, -r, hexfunc(n)))
252 ui.write("%s%s %s:%s\n" % (t, spaces, -r, hexfunc(n)))
289
253
290 def bundle(ui, repo, fname, dest=None, **opts):
254 def bundle(ui, repo, fname, dest=None, **opts):
291 """create a changegroup file
255 """create a changegroup file
292
256
293 Generate a compressed changegroup file collecting changesets not
257 Generate a compressed changegroup file collecting changesets not
294 found in the other repository.
258 found in the other repository.
295
259
296 If no destination repository is specified the destination is assumed
260 If no destination repository is specified the destination is assumed
297 to have all the nodes specified by one or more --base parameters.
261 to have all the nodes specified by one or more --base parameters.
298
262
299 The bundle file can then be transferred using conventional means and
263 The bundle file can then be transferred using conventional means and
300 applied to another repository with the unbundle or pull command.
264 applied to another repository with the unbundle or pull command.
301 This is useful when direct push and pull are not available or when
265 This is useful when direct push and pull are not available or when
302 exporting an entire repository is undesirable.
266 exporting an entire repository is undesirable.
303
267
304 Applying bundles preserves all changeset contents including
268 Applying bundles preserves all changeset contents including
305 permissions, copy/rename information, and revision history.
269 permissions, copy/rename information, and revision history.
306 """
270 """
307 revs = opts.get('rev') or None
271 revs = opts.get('rev') or None
308 if revs:
272 if revs:
309 revs = [repo.lookup(rev) for rev in revs]
273 revs = [repo.lookup(rev) for rev in revs]
310 base = opts.get('base')
274 base = opts.get('base')
311 if base:
275 if base:
312 if dest:
276 if dest:
313 raise util.Abort(_("--base is incompatible with specifiying "
277 raise util.Abort(_("--base is incompatible with specifiying "
314 "a destination"))
278 "a destination"))
315 base = [repo.lookup(rev) for rev in base]
279 base = [repo.lookup(rev) for rev in base]
316 # create the right base
280 # create the right base
317 # XXX: nodesbetween / changegroup* should be "fixed" instead
281 # XXX: nodesbetween / changegroup* should be "fixed" instead
318 o = []
282 o = []
319 has = {nullid: None}
283 has = {nullid: None}
320 for n in base:
284 for n in base:
321 has.update(repo.changelog.reachable(n))
285 has.update(repo.changelog.reachable(n))
322 if revs:
286 if revs:
323 visit = list(revs)
287 visit = list(revs)
324 else:
288 else:
325 visit = repo.changelog.heads()
289 visit = repo.changelog.heads()
326 seen = {}
290 seen = {}
327 while visit:
291 while visit:
328 n = visit.pop(0)
292 n = visit.pop(0)
329 parents = [p for p in repo.changelog.parents(n) if p not in has]
293 parents = [p for p in repo.changelog.parents(n) if p not in has]
330 if len(parents) == 0:
294 if len(parents) == 0:
331 o.insert(0, n)
295 o.insert(0, n)
332 else:
296 else:
333 for p in parents:
297 for p in parents:
334 if p not in seen:
298 if p not in seen:
335 seen[p] = 1
299 seen[p] = 1
336 visit.append(p)
300 visit.append(p)
337 else:
301 else:
338 setremoteconfig(ui, opts)
302 cmdutil.setremoteconfig(ui, opts)
339 dest, revs = cmdutil.parseurl(
303 dest, revs = cmdutil.parseurl(
340 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
304 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
341 other = hg.repository(ui, dest)
305 other = hg.repository(ui, dest)
342 o = repo.findoutgoing(other, force=opts['force'])
306 o = repo.findoutgoing(other, force=opts['force'])
343
307
344 if revs:
308 if revs:
345 cg = repo.changegroupsubset(o, revs, 'bundle')
309 cg = repo.changegroupsubset(o, revs, 'bundle')
346 else:
310 else:
347 cg = repo.changegroup(o, 'bundle')
311 cg = repo.changegroup(o, 'bundle')
348 changegroup.writebundle(cg, fname, "HG10BZ")
312 changegroup.writebundle(cg, fname, "HG10BZ")
349
313
350 def cat(ui, repo, file1, *pats, **opts):
314 def cat(ui, repo, file1, *pats, **opts):
351 """output the current or given revision of files
315 """output the current or given revision of files
352
316
353 Print the specified files as they were at the given revision.
317 Print the specified files as they were at the given revision.
354 If no revision is given, the parent of the working directory is used,
318 If no revision is given, the parent of the working directory is used,
355 or tip if no revision is checked out.
319 or tip if no revision is checked out.
356
320
357 Output may be to a file, in which case the name of the file is
321 Output may be to a file, in which case the name of the file is
358 given using a format string. The formatting rules are the same as
322 given using a format string. The formatting rules are the same as
359 for the export command, with the following additions:
323 for the export command, with the following additions:
360
324
361 %s basename of file being printed
325 %s basename of file being printed
362 %d dirname of file being printed, or '.' if in repo root
326 %d dirname of file being printed, or '.' if in repo root
363 %p root-relative path name of file being printed
327 %p root-relative path name of file being printed
364 """
328 """
365 ctx = repo.changectx(opts['rev'])
329 ctx = repo.changectx(opts['rev'])
366 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
330 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
367 ctx.node()):
331 ctx.node()):
368 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
332 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
369 fp.write(ctx.filectx(abs).data())
333 fp.write(ctx.filectx(abs).data())
370
334
371 def clone(ui, source, dest=None, **opts):
335 def clone(ui, source, dest=None, **opts):
372 """make a copy of an existing repository
336 """make a copy of an existing repository
373
337
374 Create a copy of an existing repository in a new directory.
338 Create a copy of an existing repository in a new directory.
375
339
376 If no destination directory name is specified, it defaults to the
340 If no destination directory name is specified, it defaults to the
377 basename of the source.
341 basename of the source.
378
342
379 The location of the source is added to the new repository's
343 The location of the source is added to the new repository's
380 .hg/hgrc file, as the default to be used for future pulls.
344 .hg/hgrc file, as the default to be used for future pulls.
381
345
382 For efficiency, hardlinks are used for cloning whenever the source
346 For efficiency, hardlinks are used for cloning whenever the source
383 and destination are on the same filesystem (note this applies only
347 and destination are on the same filesystem (note this applies only
384 to the repository data, not to the checked out files). Some
348 to the repository data, not to the checked out files). Some
385 filesystems, such as AFS, implement hardlinking incorrectly, but
349 filesystems, such as AFS, implement hardlinking incorrectly, but
386 do not report errors. In these cases, use the --pull option to
350 do not report errors. In these cases, use the --pull option to
387 avoid hardlinking.
351 avoid hardlinking.
388
352
389 You can safely clone repositories and checked out files using full
353 You can safely clone repositories and checked out files using full
390 hardlinks with
354 hardlinks with
391
355
392 $ cp -al REPO REPOCLONE
356 $ cp -al REPO REPOCLONE
393
357
394 which is the fastest way to clone. However, the operation is not
358 which is the fastest way to clone. However, the operation is not
395 atomic (making sure REPO is not modified during the operation is
359 atomic (making sure REPO is not modified during the operation is
396 up to you) and you have to make sure your editor breaks hardlinks
360 up to you) and you have to make sure your editor breaks hardlinks
397 (Emacs and most Linux Kernel tools do so).
361 (Emacs and most Linux Kernel tools do so).
398
362
399 If you use the -r option to clone up to a specific revision, no
363 If you use the -r option to clone up to a specific revision, no
400 subsequent revisions will be present in the cloned repository.
364 subsequent revisions will be present in the cloned repository.
401 This option implies --pull, even on local repositories.
365 This option implies --pull, even on local repositories.
402
366
403 See pull for valid source format details.
367 See pull for valid source format details.
404
368
405 It is possible to specify an ssh:// URL as the destination, but no
369 It is possible to specify an ssh:// URL as the destination, but no
406 .hg/hgrc and working directory will be created on the remote side.
370 .hg/hgrc and working directory will be created on the remote side.
407 Look at the help text for the pull command for important details
371 Look at the help text for the pull command for important details
408 about ssh:// URLs.
372 about ssh:// URLs.
409 """
373 """
410 setremoteconfig(ui, opts)
374 cmdutil.setremoteconfig(ui, opts)
411 hg.clone(ui, source, dest,
375 hg.clone(ui, source, dest,
412 pull=opts['pull'],
376 pull=opts['pull'],
413 stream=opts['uncompressed'],
377 stream=opts['uncompressed'],
414 rev=opts['rev'],
378 rev=opts['rev'],
415 update=not opts['noupdate'])
379 update=not opts['noupdate'])
416
380
417 def commit(ui, repo, *pats, **opts):
381 def commit(ui, repo, *pats, **opts):
418 """commit the specified files or all outstanding changes
382 """commit the specified files or all outstanding changes
419
383
420 Commit changes to the given files into the repository.
384 Commit changes to the given files into the repository.
421
385
422 If a list of files is omitted, all changes reported by "hg status"
386 If a list of files is omitted, all changes reported by "hg status"
423 will be committed.
387 will be committed.
424
388
425 If no commit message is specified, the editor configured in your hgrc
389 If no commit message is specified, the editor configured in your hgrc
426 or in the EDITOR environment variable is started to enter a message.
390 or in the EDITOR environment variable is started to enter a message.
427 """
391 """
428 message = logmessage(opts)
392 message = cmdutil.logmessage(opts)
429
393
430 if opts['addremove']:
394 if opts['addremove']:
431 cmdutil.addremove(repo, pats, opts)
395 cmdutil.addremove(repo, pats, opts)
432 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
396 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
433 if pats:
397 if pats:
434 status = repo.status(files=fns, match=match)
398 status = repo.status(files=fns, match=match)
435 modified, added, removed, deleted, unknown = status[:5]
399 modified, added, removed, deleted, unknown = status[:5]
436 files = modified + added + removed
400 files = modified + added + removed
437 slist = None
401 slist = None
438 for f in fns:
402 for f in fns:
439 if f == '.':
403 if f == '.':
440 continue
404 continue
441 if f not in files:
405 if f not in files:
442 rf = repo.wjoin(f)
406 rf = repo.wjoin(f)
443 if f in unknown:
407 if f in unknown:
444 raise util.Abort(_("file %s not tracked!") % rf)
408 raise util.Abort(_("file %s not tracked!") % rf)
445 try:
409 try:
446 mode = os.lstat(rf)[stat.ST_MODE]
410 mode = os.lstat(rf)[stat.ST_MODE]
447 except OSError:
411 except OSError:
448 raise util.Abort(_("file %s not found!") % rf)
412 raise util.Abort(_("file %s not found!") % rf)
449 if stat.S_ISDIR(mode):
413 if stat.S_ISDIR(mode):
450 name = f + '/'
414 name = f + '/'
451 if slist is None:
415 if slist is None:
452 slist = list(files)
416 slist = list(files)
453 slist.sort()
417 slist.sort()
454 i = bisect.bisect(slist, name)
418 i = bisect.bisect(slist, name)
455 if i >= len(slist) or not slist[i].startswith(name):
419 if i >= len(slist) or not slist[i].startswith(name):
456 raise util.Abort(_("no match under directory %s!")
420 raise util.Abort(_("no match under directory %s!")
457 % rf)
421 % rf)
458 elif not stat.S_ISREG(mode):
422 elif not stat.S_ISREG(mode):
459 raise util.Abort(_("can't commit %s: "
423 raise util.Abort(_("can't commit %s: "
460 "unsupported file type!") % rf)
424 "unsupported file type!") % rf)
461 else:
425 else:
462 files = []
426 files = []
463 try:
427 try:
464 repo.commit(files, message, opts['user'], opts['date'], match,
428 repo.commit(files, message, opts['user'], opts['date'], match,
465 force_editor=opts.get('force_editor'))
429 force_editor=opts.get('force_editor'))
466 except ValueError, inst:
430 except ValueError, inst:
467 raise util.Abort(str(inst))
431 raise util.Abort(str(inst))
468
432
469 def docopy(ui, repo, pats, opts, wlock):
433 def docopy(ui, repo, pats, opts, wlock):
470 # called with the repo lock held
434 # called with the repo lock held
471 #
435 #
472 # hgsep => pathname that uses "/" to separate directories
436 # hgsep => pathname that uses "/" to separate directories
473 # ossep => pathname that uses os.sep to separate directories
437 # ossep => pathname that uses os.sep to separate directories
474 cwd = repo.getcwd()
438 cwd = repo.getcwd()
475 errors = 0
439 errors = 0
476 copied = []
440 copied = []
477 targets = {}
441 targets = {}
478
442
479 # abs: hgsep
443 # abs: hgsep
480 # rel: ossep
444 # rel: ossep
481 # return: hgsep
445 # return: hgsep
482 def okaytocopy(abs, rel, exact):
446 def okaytocopy(abs, rel, exact):
483 reasons = {'?': _('is not managed'),
447 reasons = {'?': _('is not managed'),
484 'a': _('has been marked for add'),
448 'a': _('has been marked for add'),
485 'r': _('has been marked for remove')}
449 'r': _('has been marked for remove')}
486 state = repo.dirstate.state(abs)
450 state = repo.dirstate.state(abs)
487 reason = reasons.get(state)
451 reason = reasons.get(state)
488 if reason:
452 if reason:
489 if state == 'a':
453 if state == 'a':
490 origsrc = repo.dirstate.copied(abs)
454 origsrc = repo.dirstate.copied(abs)
491 if origsrc is not None:
455 if origsrc is not None:
492 return origsrc
456 return origsrc
493 if exact:
457 if exact:
494 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
458 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
495 else:
459 else:
496 return abs
460 return abs
497
461
498 # origsrc: hgsep
462 # origsrc: hgsep
499 # abssrc: hgsep
463 # abssrc: hgsep
500 # relsrc: ossep
464 # relsrc: ossep
501 # otarget: ossep
465 # otarget: ossep
502 def copy(origsrc, abssrc, relsrc, otarget, exact):
466 def copy(origsrc, abssrc, relsrc, otarget, exact):
503 abstarget = util.canonpath(repo.root, cwd, otarget)
467 abstarget = util.canonpath(repo.root, cwd, otarget)
504 reltarget = repo.pathto(abstarget, cwd)
468 reltarget = repo.pathto(abstarget, cwd)
505 prevsrc = targets.get(abstarget)
469 prevsrc = targets.get(abstarget)
506 src = repo.wjoin(abssrc)
470 src = repo.wjoin(abssrc)
507 target = repo.wjoin(abstarget)
471 target = repo.wjoin(abstarget)
508 if prevsrc is not None:
472 if prevsrc is not None:
509 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
473 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
510 (reltarget, repo.pathto(abssrc, cwd),
474 (reltarget, repo.pathto(abssrc, cwd),
511 repo.pathto(prevsrc, cwd)))
475 repo.pathto(prevsrc, cwd)))
512 return
476 return
513 if (not opts['after'] and os.path.exists(target) or
477 if (not opts['after'] and os.path.exists(target) or
514 opts['after'] and repo.dirstate.state(abstarget) not in '?ar'):
478 opts['after'] and repo.dirstate.state(abstarget) not in '?ar'):
515 if not opts['force']:
479 if not opts['force']:
516 ui.warn(_('%s: not overwriting - file exists\n') %
480 ui.warn(_('%s: not overwriting - file exists\n') %
517 reltarget)
481 reltarget)
518 return
482 return
519 if not opts['after'] and not opts.get('dry_run'):
483 if not opts['after'] and not opts.get('dry_run'):
520 os.unlink(target)
484 os.unlink(target)
521 if opts['after']:
485 if opts['after']:
522 if not os.path.exists(target):
486 if not os.path.exists(target):
523 return
487 return
524 else:
488 else:
525 targetdir = os.path.dirname(target) or '.'
489 targetdir = os.path.dirname(target) or '.'
526 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
490 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
527 os.makedirs(targetdir)
491 os.makedirs(targetdir)
528 try:
492 try:
529 restore = repo.dirstate.state(abstarget) == 'r'
493 restore = repo.dirstate.state(abstarget) == 'r'
530 if restore and not opts.get('dry_run'):
494 if restore and not opts.get('dry_run'):
531 repo.undelete([abstarget], wlock)
495 repo.undelete([abstarget], wlock)
532 try:
496 try:
533 if not opts.get('dry_run'):
497 if not opts.get('dry_run'):
534 util.copyfile(src, target)
498 util.copyfile(src, target)
535 restore = False
499 restore = False
536 finally:
500 finally:
537 if restore:
501 if restore:
538 repo.remove([abstarget], wlock=wlock)
502 repo.remove([abstarget], wlock=wlock)
539 except IOError, inst:
503 except IOError, inst:
540 if inst.errno == errno.ENOENT:
504 if inst.errno == errno.ENOENT:
541 ui.warn(_('%s: deleted in working copy\n') % relsrc)
505 ui.warn(_('%s: deleted in working copy\n') % relsrc)
542 else:
506 else:
543 ui.warn(_('%s: cannot copy - %s\n') %
507 ui.warn(_('%s: cannot copy - %s\n') %
544 (relsrc, inst.strerror))
508 (relsrc, inst.strerror))
545 errors += 1
509 errors += 1
546 return
510 return
547 if ui.verbose or not exact:
511 if ui.verbose or not exact:
548 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
512 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
549 targets[abstarget] = abssrc
513 targets[abstarget] = abssrc
550 if abstarget != origsrc and not opts.get('dry_run'):
514 if abstarget != origsrc and not opts.get('dry_run'):
551 repo.copy(origsrc, abstarget, wlock)
515 repo.copy(origsrc, abstarget, wlock)
552 copied.append((abssrc, relsrc, exact))
516 copied.append((abssrc, relsrc, exact))
553
517
554 # pat: ossep
518 # pat: ossep
555 # dest ossep
519 # dest ossep
556 # srcs: list of (hgsep, hgsep, ossep, bool)
520 # srcs: list of (hgsep, hgsep, ossep, bool)
557 # return: function that takes hgsep and returns ossep
521 # return: function that takes hgsep and returns ossep
558 def targetpathfn(pat, dest, srcs):
522 def targetpathfn(pat, dest, srcs):
559 if os.path.isdir(pat):
523 if os.path.isdir(pat):
560 abspfx = util.canonpath(repo.root, cwd, pat)
524 abspfx = util.canonpath(repo.root, cwd, pat)
561 abspfx = util.localpath(abspfx)
525 abspfx = util.localpath(abspfx)
562 if destdirexists:
526 if destdirexists:
563 striplen = len(os.path.split(abspfx)[0])
527 striplen = len(os.path.split(abspfx)[0])
564 else:
528 else:
565 striplen = len(abspfx)
529 striplen = len(abspfx)
566 if striplen:
530 if striplen:
567 striplen += len(os.sep)
531 striplen += len(os.sep)
568 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
532 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
569 elif destdirexists:
533 elif destdirexists:
570 res = lambda p: os.path.join(dest,
534 res = lambda p: os.path.join(dest,
571 os.path.basename(util.localpath(p)))
535 os.path.basename(util.localpath(p)))
572 else:
536 else:
573 res = lambda p: dest
537 res = lambda p: dest
574 return res
538 return res
575
539
576 # pat: ossep
540 # pat: ossep
577 # dest ossep
541 # dest ossep
578 # srcs: list of (hgsep, hgsep, ossep, bool)
542 # srcs: list of (hgsep, hgsep, ossep, bool)
579 # return: function that takes hgsep and returns ossep
543 # return: function that takes hgsep and returns ossep
580 def targetpathafterfn(pat, dest, srcs):
544 def targetpathafterfn(pat, dest, srcs):
581 if util.patkind(pat, None)[0]:
545 if util.patkind(pat, None)[0]:
582 # a mercurial pattern
546 # a mercurial pattern
583 res = lambda p: os.path.join(dest,
547 res = lambda p: os.path.join(dest,
584 os.path.basename(util.localpath(p)))
548 os.path.basename(util.localpath(p)))
585 else:
549 else:
586 abspfx = util.canonpath(repo.root, cwd, pat)
550 abspfx = util.canonpath(repo.root, cwd, pat)
587 if len(abspfx) < len(srcs[0][0]):
551 if len(abspfx) < len(srcs[0][0]):
588 # A directory. Either the target path contains the last
552 # A directory. Either the target path contains the last
589 # component of the source path or it does not.
553 # component of the source path or it does not.
590 def evalpath(striplen):
554 def evalpath(striplen):
591 score = 0
555 score = 0
592 for s in srcs:
556 for s in srcs:
593 t = os.path.join(dest, util.localpath(s[0])[striplen:])
557 t = os.path.join(dest, util.localpath(s[0])[striplen:])
594 if os.path.exists(t):
558 if os.path.exists(t):
595 score += 1
559 score += 1
596 return score
560 return score
597
561
598 abspfx = util.localpath(abspfx)
562 abspfx = util.localpath(abspfx)
599 striplen = len(abspfx)
563 striplen = len(abspfx)
600 if striplen:
564 if striplen:
601 striplen += len(os.sep)
565 striplen += len(os.sep)
602 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
566 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
603 score = evalpath(striplen)
567 score = evalpath(striplen)
604 striplen1 = len(os.path.split(abspfx)[0])
568 striplen1 = len(os.path.split(abspfx)[0])
605 if striplen1:
569 if striplen1:
606 striplen1 += len(os.sep)
570 striplen1 += len(os.sep)
607 if evalpath(striplen1) > score:
571 if evalpath(striplen1) > score:
608 striplen = striplen1
572 striplen = striplen1
609 res = lambda p: os.path.join(dest,
573 res = lambda p: os.path.join(dest,
610 util.localpath(p)[striplen:])
574 util.localpath(p)[striplen:])
611 else:
575 else:
612 # a file
576 # a file
613 if destdirexists:
577 if destdirexists:
614 res = lambda p: os.path.join(dest,
578 res = lambda p: os.path.join(dest,
615 os.path.basename(util.localpath(p)))
579 os.path.basename(util.localpath(p)))
616 else:
580 else:
617 res = lambda p: dest
581 res = lambda p: dest
618 return res
582 return res
619
583
620
584
621 pats = util.expand_glob(pats)
585 pats = util.expand_glob(pats)
622 if not pats:
586 if not pats:
623 raise util.Abort(_('no source or destination specified'))
587 raise util.Abort(_('no source or destination specified'))
624 if len(pats) == 1:
588 if len(pats) == 1:
625 raise util.Abort(_('no destination specified'))
589 raise util.Abort(_('no destination specified'))
626 dest = pats.pop()
590 dest = pats.pop()
627 destdirexists = os.path.isdir(dest)
591 destdirexists = os.path.isdir(dest)
628 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
592 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
629 raise util.Abort(_('with multiple sources, destination must be an '
593 raise util.Abort(_('with multiple sources, destination must be an '
630 'existing directory'))
594 'existing directory'))
631 if opts['after']:
595 if opts['after']:
632 tfn = targetpathafterfn
596 tfn = targetpathafterfn
633 else:
597 else:
634 tfn = targetpathfn
598 tfn = targetpathfn
635 copylist = []
599 copylist = []
636 for pat in pats:
600 for pat in pats:
637 srcs = []
601 srcs = []
638 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts,
602 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts,
639 globbed=True):
603 globbed=True):
640 origsrc = okaytocopy(abssrc, relsrc, exact)
604 origsrc = okaytocopy(abssrc, relsrc, exact)
641 if origsrc:
605 if origsrc:
642 srcs.append((origsrc, abssrc, relsrc, exact))
606 srcs.append((origsrc, abssrc, relsrc, exact))
643 if not srcs:
607 if not srcs:
644 continue
608 continue
645 copylist.append((tfn(pat, dest, srcs), srcs))
609 copylist.append((tfn(pat, dest, srcs), srcs))
646 if not copylist:
610 if not copylist:
647 raise util.Abort(_('no files to copy'))
611 raise util.Abort(_('no files to copy'))
648
612
649 for targetpath, srcs in copylist:
613 for targetpath, srcs in copylist:
650 for origsrc, abssrc, relsrc, exact in srcs:
614 for origsrc, abssrc, relsrc, exact in srcs:
651 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
615 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
652
616
653 if errors:
617 if errors:
654 ui.warn(_('(consider using --after)\n'))
618 ui.warn(_('(consider using --after)\n'))
655 return errors, copied
619 return errors, copied
656
620
657 def copy(ui, repo, *pats, **opts):
621 def copy(ui, repo, *pats, **opts):
658 """mark files as copied for the next commit
622 """mark files as copied for the next commit
659
623
660 Mark dest as having copies of source files. If dest is a
624 Mark dest as having copies of source files. If dest is a
661 directory, copies are put in that directory. If dest is a file,
625 directory, copies are put in that directory. If dest is a file,
662 there can only be one source.
626 there can only be one source.
663
627
664 By default, this command copies the contents of files as they
628 By default, this command copies the contents of files as they
665 stand in the working directory. If invoked with --after, the
629 stand in the working directory. If invoked with --after, the
666 operation is recorded, but no copying is performed.
630 operation is recorded, but no copying is performed.
667
631
668 This command takes effect in the next commit. To undo a copy
632 This command takes effect in the next commit. To undo a copy
669 before that, see hg revert.
633 before that, see hg revert.
670 """
634 """
671 wlock = repo.wlock(0)
635 wlock = repo.wlock(0)
672 errs, copied = docopy(ui, repo, pats, opts, wlock)
636 errs, copied = docopy(ui, repo, pats, opts, wlock)
673 return errs
637 return errs
674
638
675 def debugancestor(ui, index, rev1, rev2):
639 def debugancestor(ui, index, rev1, rev2):
676 """find the ancestor revision of two revisions in a given index"""
640 """find the ancestor revision of two revisions in a given index"""
677 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
641 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
678 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
642 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
679 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
643 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
680
644
681 def debugcomplete(ui, cmd='', **opts):
645 def debugcomplete(ui, cmd='', **opts):
682 """returns the completion list associated with the given command"""
646 """returns the completion list associated with the given command"""
683
647
684 if opts['options']:
648 if opts['options']:
685 options = []
649 options = []
686 otables = [globalopts]
650 otables = [globalopts]
687 if cmd:
651 if cmd:
688 aliases, entry = findcmd(ui, cmd)
652 aliases, entry = cmdutil.findcmd(ui, cmd)
689 otables.append(entry[1])
653 otables.append(entry[1])
690 for t in otables:
654 for t in otables:
691 for o in t:
655 for o in t:
692 if o[0]:
656 if o[0]:
693 options.append('-%s' % o[0])
657 options.append('-%s' % o[0])
694 options.append('--%s' % o[1])
658 options.append('--%s' % o[1])
695 ui.write("%s\n" % "\n".join(options))
659 ui.write("%s\n" % "\n".join(options))
696 return
660 return
697
661
698 clist = findpossible(ui, cmd).keys()
662 clist = cmdutil.findpossible(ui, cmd).keys()
699 clist.sort()
663 clist.sort()
700 ui.write("%s\n" % "\n".join(clist))
664 ui.write("%s\n" % "\n".join(clist))
701
665
702 def debugrebuildstate(ui, repo, rev=""):
666 def debugrebuildstate(ui, repo, rev=""):
703 """rebuild the dirstate as it would look like for the given revision"""
667 """rebuild the dirstate as it would look like for the given revision"""
704 if rev == "":
668 if rev == "":
705 rev = repo.changelog.tip()
669 rev = repo.changelog.tip()
706 ctx = repo.changectx(rev)
670 ctx = repo.changectx(rev)
707 files = ctx.manifest()
671 files = ctx.manifest()
708 wlock = repo.wlock()
672 wlock = repo.wlock()
709 repo.dirstate.rebuild(rev, files)
673 repo.dirstate.rebuild(rev, files)
710
674
711 def debugcheckstate(ui, repo):
675 def debugcheckstate(ui, repo):
712 """validate the correctness of the current dirstate"""
676 """validate the correctness of the current dirstate"""
713 parent1, parent2 = repo.dirstate.parents()
677 parent1, parent2 = repo.dirstate.parents()
714 repo.dirstate.read()
678 repo.dirstate.read()
715 dc = repo.dirstate.map
679 dc = repo.dirstate.map
716 keys = dc.keys()
680 keys = dc.keys()
717 keys.sort()
681 keys.sort()
718 m1 = repo.changectx(parent1).manifest()
682 m1 = repo.changectx(parent1).manifest()
719 m2 = repo.changectx(parent2).manifest()
683 m2 = repo.changectx(parent2).manifest()
720 errors = 0
684 errors = 0
721 for f in dc:
685 for f in dc:
722 state = repo.dirstate.state(f)
686 state = repo.dirstate.state(f)
723 if state in "nr" and f not in m1:
687 if state in "nr" and f not in m1:
724 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
688 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
725 errors += 1
689 errors += 1
726 if state in "a" and f in m1:
690 if state in "a" and f in m1:
727 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
691 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
728 errors += 1
692 errors += 1
729 if state in "m" and f not in m1 and f not in m2:
693 if state in "m" and f not in m1 and f not in m2:
730 ui.warn(_("%s in state %s, but not in either manifest\n") %
694 ui.warn(_("%s in state %s, but not in either manifest\n") %
731 (f, state))
695 (f, state))
732 errors += 1
696 errors += 1
733 for f in m1:
697 for f in m1:
734 state = repo.dirstate.state(f)
698 state = repo.dirstate.state(f)
735 if state not in "nrm":
699 if state not in "nrm":
736 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
700 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
737 errors += 1
701 errors += 1
738 if errors:
702 if errors:
739 error = _(".hg/dirstate inconsistent with current parent's manifest")
703 error = _(".hg/dirstate inconsistent with current parent's manifest")
740 raise util.Abort(error)
704 raise util.Abort(error)
741
705
742 def showconfig(ui, repo, *values, **opts):
706 def showconfig(ui, repo, *values, **opts):
743 """show combined config settings from all hgrc files
707 """show combined config settings from all hgrc files
744
708
745 With no args, print names and values of all config items.
709 With no args, print names and values of all config items.
746
710
747 With one arg of the form section.name, print just the value of
711 With one arg of the form section.name, print just the value of
748 that config item.
712 that config item.
749
713
750 With multiple args, print names and values of all config items
714 With multiple args, print names and values of all config items
751 with matching section names."""
715 with matching section names."""
752
716
753 untrusted = bool(opts.get('untrusted'))
717 untrusted = bool(opts.get('untrusted'))
754 if values:
718 if values:
755 if len([v for v in values if '.' in v]) > 1:
719 if len([v for v in values if '.' in v]) > 1:
756 raise util.Abort(_('only one config item permitted'))
720 raise util.Abort(_('only one config item permitted'))
757 for section, name, value in ui.walkconfig(untrusted=untrusted):
721 for section, name, value in ui.walkconfig(untrusted=untrusted):
758 sectname = section + '.' + name
722 sectname = section + '.' + name
759 if values:
723 if values:
760 for v in values:
724 for v in values:
761 if v == section:
725 if v == section:
762 ui.write('%s=%s\n' % (sectname, value))
726 ui.write('%s=%s\n' % (sectname, value))
763 elif v == sectname:
727 elif v == sectname:
764 ui.write(value, '\n')
728 ui.write(value, '\n')
765 else:
729 else:
766 ui.write('%s=%s\n' % (sectname, value))
730 ui.write('%s=%s\n' % (sectname, value))
767
731
768 def debugsetparents(ui, repo, rev1, rev2=None):
732 def debugsetparents(ui, repo, rev1, rev2=None):
769 """manually set the parents of the current working directory
733 """manually set the parents of the current working directory
770
734
771 This is useful for writing repository conversion tools, but should
735 This is useful for writing repository conversion tools, but should
772 be used with care.
736 be used with care.
773 """
737 """
774
738
775 if not rev2:
739 if not rev2:
776 rev2 = hex(nullid)
740 rev2 = hex(nullid)
777
741
778 wlock = repo.wlock()
742 wlock = repo.wlock()
779 try:
743 try:
780 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
744 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
781 finally:
745 finally:
782 wlock.release()
746 wlock.release()
783
747
784 def debugstate(ui, repo):
748 def debugstate(ui, repo):
785 """show the contents of the current dirstate"""
749 """show the contents of the current dirstate"""
786 repo.dirstate.read()
750 repo.dirstate.read()
787 dc = repo.dirstate.map
751 dc = repo.dirstate.map
788 keys = dc.keys()
752 keys = dc.keys()
789 keys.sort()
753 keys.sort()
790 for file_ in keys:
754 for file_ in keys:
791 if dc[file_][3] == -1:
755 if dc[file_][3] == -1:
792 # Pad or slice to locale representation
756 # Pad or slice to locale representation
793 locale_len = len(time.strftime("%x %X", time.localtime(0)))
757 locale_len = len(time.strftime("%x %X", time.localtime(0)))
794 timestr = 'unset'
758 timestr = 'unset'
795 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
759 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
796 else:
760 else:
797 timestr = time.strftime("%x %X", time.localtime(dc[file_][3]))
761 timestr = time.strftime("%x %X", time.localtime(dc[file_][3]))
798 ui.write("%c %3o %10d %s %s\n"
762 ui.write("%c %3o %10d %s %s\n"
799 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
763 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
800 timestr, file_))
764 timestr, file_))
801 for f in repo.dirstate.copies():
765 for f in repo.dirstate.copies():
802 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
766 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
803
767
804 def debugdata(ui, file_, rev):
768 def debugdata(ui, file_, rev):
805 """dump the contents of a data file revision"""
769 """dump the contents of a data file revision"""
806 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
770 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
807 try:
771 try:
808 ui.write(r.revision(r.lookup(rev)))
772 ui.write(r.revision(r.lookup(rev)))
809 except KeyError:
773 except KeyError:
810 raise util.Abort(_('invalid revision identifier %s') % rev)
774 raise util.Abort(_('invalid revision identifier %s') % rev)
811
775
812 def debugdate(ui, date, range=None, **opts):
776 def debugdate(ui, date, range=None, **opts):
813 """parse and display a date"""
777 """parse and display a date"""
814 if opts["extended"]:
778 if opts["extended"]:
815 d = util.parsedate(date, util.extendeddateformats)
779 d = util.parsedate(date, util.extendeddateformats)
816 else:
780 else:
817 d = util.parsedate(date)
781 d = util.parsedate(date)
818 ui.write("internal: %s %s\n" % d)
782 ui.write("internal: %s %s\n" % d)
819 ui.write("standard: %s\n" % util.datestr(d))
783 ui.write("standard: %s\n" % util.datestr(d))
820 if range:
784 if range:
821 m = util.matchdate(range)
785 m = util.matchdate(range)
822 ui.write("match: %s\n" % m(d[0]))
786 ui.write("match: %s\n" % m(d[0]))
823
787
824 def debugindex(ui, file_):
788 def debugindex(ui, file_):
825 """dump the contents of an index file"""
789 """dump the contents of an index file"""
826 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
790 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
827 ui.write(" rev offset length base linkrev" +
791 ui.write(" rev offset length base linkrev" +
828 " nodeid p1 p2\n")
792 " nodeid p1 p2\n")
829 for i in xrange(r.count()):
793 for i in xrange(r.count()):
830 node = r.node(i)
794 node = r.node(i)
831 pp = r.parents(node)
795 pp = r.parents(node)
832 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
796 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
833 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
797 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
834 short(node), short(pp[0]), short(pp[1])))
798 short(node), short(pp[0]), short(pp[1])))
835
799
836 def debugindexdot(ui, file_):
800 def debugindexdot(ui, file_):
837 """dump an index DAG as a .dot file"""
801 """dump an index DAG as a .dot file"""
838 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
802 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
839 ui.write("digraph G {\n")
803 ui.write("digraph G {\n")
840 for i in xrange(r.count()):
804 for i in xrange(r.count()):
841 node = r.node(i)
805 node = r.node(i)
842 pp = r.parents(node)
806 pp = r.parents(node)
843 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
807 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
844 if pp[1] != nullid:
808 if pp[1] != nullid:
845 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
809 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
846 ui.write("}\n")
810 ui.write("}\n")
847
811
848 def debuginstall(ui):
812 def debuginstall(ui):
849 '''test Mercurial installation'''
813 '''test Mercurial installation'''
850
814
851 def writetemp(contents):
815 def writetemp(contents):
852 (fd, name) = tempfile.mkstemp()
816 (fd, name) = tempfile.mkstemp()
853 f = os.fdopen(fd, "wb")
817 f = os.fdopen(fd, "wb")
854 f.write(contents)
818 f.write(contents)
855 f.close()
819 f.close()
856 return name
820 return name
857
821
858 problems = 0
822 problems = 0
859
823
860 # encoding
824 # encoding
861 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
825 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
862 try:
826 try:
863 util.fromlocal("test")
827 util.fromlocal("test")
864 except util.Abort, inst:
828 except util.Abort, inst:
865 ui.write(" %s\n" % inst)
829 ui.write(" %s\n" % inst)
866 ui.write(_(" (check that your locale is properly set)\n"))
830 ui.write(_(" (check that your locale is properly set)\n"))
867 problems += 1
831 problems += 1
868
832
869 # compiled modules
833 # compiled modules
870 ui.status(_("Checking extensions...\n"))
834 ui.status(_("Checking extensions...\n"))
871 try:
835 try:
872 import bdiff, mpatch, base85
836 import bdiff, mpatch, base85
873 except Exception, inst:
837 except Exception, inst:
874 ui.write(" %s\n" % inst)
838 ui.write(" %s\n" % inst)
875 ui.write(_(" One or more extensions could not be found"))
839 ui.write(_(" One or more extensions could not be found"))
876 ui.write(_(" (check that you compiled the extensions)\n"))
840 ui.write(_(" (check that you compiled the extensions)\n"))
877 problems += 1
841 problems += 1
878
842
879 # templates
843 # templates
880 ui.status(_("Checking templates...\n"))
844 ui.status(_("Checking templates...\n"))
881 try:
845 try:
882 import templater
846 import templater
883 t = templater.templater(templater.templatepath("map-cmdline.default"))
847 t = templater.templater(templater.templatepath("map-cmdline.default"))
884 except Exception, inst:
848 except Exception, inst:
885 ui.write(" %s\n" % inst)
849 ui.write(" %s\n" % inst)
886 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
850 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
887 problems += 1
851 problems += 1
888
852
889 # patch
853 # patch
890 ui.status(_("Checking patch...\n"))
854 ui.status(_("Checking patch...\n"))
891 patcher = ui.config('ui', 'patch')
855 patcher = ui.config('ui', 'patch')
892 patcher = ((patcher and util.find_exe(patcher)) or
856 patcher = ((patcher and util.find_exe(patcher)) or
893 util.find_exe('gpatch') or
857 util.find_exe('gpatch') or
894 util.find_exe('patch'))
858 util.find_exe('patch'))
895 if not patcher:
859 if not patcher:
896 ui.write(_(" Can't find patch or gpatch in PATH\n"))
860 ui.write(_(" Can't find patch or gpatch in PATH\n"))
897 ui.write(_(" (specify a patch utility in your .hgrc file)\n"))
861 ui.write(_(" (specify a patch utility in your .hgrc file)\n"))
898 problems += 1
862 problems += 1
899 else:
863 else:
900 # actually attempt a patch here
864 # actually attempt a patch here
901 a = "1\n2\n3\n4\n"
865 a = "1\n2\n3\n4\n"
902 b = "1\n2\n3\ninsert\n4\n"
866 b = "1\n2\n3\ninsert\n4\n"
903 fa = writetemp(a)
867 fa = writetemp(a)
904 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa))
868 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa))
905 fd = writetemp(d)
869 fd = writetemp(d)
906
870
907 files = {}
871 files = {}
908 try:
872 try:
909 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
873 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
910 except util.Abort, e:
874 except util.Abort, e:
911 ui.write(_(" patch call failed:\n"))
875 ui.write(_(" patch call failed:\n"))
912 ui.write(" " + str(e) + "\n")
876 ui.write(" " + str(e) + "\n")
913 problems += 1
877 problems += 1
914 else:
878 else:
915 if list(files) != [os.path.basename(fa)]:
879 if list(files) != [os.path.basename(fa)]:
916 ui.write(_(" unexpected patch output!"))
880 ui.write(_(" unexpected patch output!"))
917 ui.write(_(" (you may have an incompatible version of patch)\n"))
881 ui.write(_(" (you may have an incompatible version of patch)\n"))
918 problems += 1
882 problems += 1
919 a = file(fa).read()
883 a = file(fa).read()
920 if a != b:
884 if a != b:
921 ui.write(_(" patch test failed!"))
885 ui.write(_(" patch test failed!"))
922 ui.write(_(" (you may have an incompatible version of patch)\n"))
886 ui.write(_(" (you may have an incompatible version of patch)\n"))
923 problems += 1
887 problems += 1
924
888
925 os.unlink(fa)
889 os.unlink(fa)
926 os.unlink(fd)
890 os.unlink(fd)
927
891
928 # merge helper
892 # merge helper
929 ui.status(_("Checking merge helper...\n"))
893 ui.status(_("Checking merge helper...\n"))
930 cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge")
894 cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge")
931 or "hgmerge")
895 or "hgmerge")
932 cmdpath = util.find_exe(cmd) or util.find_exe(cmd.split()[0])
896 cmdpath = util.find_exe(cmd) or util.find_exe(cmd.split()[0])
933 if not cmdpath:
897 if not cmdpath:
934 if cmd == 'hgmerge':
898 if cmd == 'hgmerge':
935 ui.write(_(" No merge helper set and can't find default"
899 ui.write(_(" No merge helper set and can't find default"
936 " hgmerge script in PATH\n"))
900 " hgmerge script in PATH\n"))
937 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
901 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
938 else:
902 else:
939 ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd)
903 ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd)
940 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
904 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
941 problems += 1
905 problems += 1
942 else:
906 else:
943 # actually attempt a patch here
907 # actually attempt a patch here
944 fa = writetemp("1\n2\n3\n4\n")
908 fa = writetemp("1\n2\n3\n4\n")
945 fl = writetemp("1\n2\n3\ninsert\n4\n")
909 fl = writetemp("1\n2\n3\ninsert\n4\n")
946 fr = writetemp("begin\n1\n2\n3\n4\n")
910 fr = writetemp("begin\n1\n2\n3\n4\n")
947 r = os.system('%s %s %s %s' % (cmd, fl, fa, fr))
911 r = os.system('%s %s %s %s' % (cmd, fl, fa, fr))
948 if r:
912 if r:
949 ui.write(_(" got unexpected merge error %d!") % r)
913 ui.write(_(" got unexpected merge error %d!") % r)
950 problems += 1
914 problems += 1
951 m = file(fl).read()
915 m = file(fl).read()
952 if m != "begin\n1\n2\n3\ninsert\n4\n":
916 if m != "begin\n1\n2\n3\ninsert\n4\n":
953 ui.write(_(" got unexpected merge results!") % r)
917 ui.write(_(" got unexpected merge results!") % r)
954 ui.write(_(" (your merge helper may have the"
918 ui.write(_(" (your merge helper may have the"
955 " wrong argument order)\n"))
919 " wrong argument order)\n"))
956 ui.write(m)
920 ui.write(m)
957 os.unlink(fa)
921 os.unlink(fa)
958 os.unlink(fl)
922 os.unlink(fl)
959 os.unlink(fr)
923 os.unlink(fr)
960
924
961 # editor
925 # editor
962 ui.status(_("Checking commit editor...\n"))
926 ui.status(_("Checking commit editor...\n"))
963 editor = (os.environ.get("HGEDITOR") or
927 editor = (os.environ.get("HGEDITOR") or
964 ui.config("ui", "editor") or
928 ui.config("ui", "editor") or
965 os.environ.get("EDITOR", "vi"))
929 os.environ.get("EDITOR", "vi"))
966 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
930 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
967 if not cmdpath:
931 if not cmdpath:
968 if editor == 'vi':
932 if editor == 'vi':
969 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
933 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
970 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
934 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
971 else:
935 else:
972 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
936 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
973 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
937 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
974 problems += 1
938 problems += 1
975
939
976 # check username
940 # check username
977 ui.status(_("Checking username...\n"))
941 ui.status(_("Checking username...\n"))
978 user = os.environ.get("HGUSER")
942 user = os.environ.get("HGUSER")
979 if user is None:
943 if user is None:
980 user = ui.config("ui", "username")
944 user = ui.config("ui", "username")
981 if user is None:
945 if user is None:
982 user = os.environ.get("EMAIL")
946 user = os.environ.get("EMAIL")
983 if not user:
947 if not user:
984 ui.warn(" ")
948 ui.warn(" ")
985 ui.username()
949 ui.username()
986 ui.write(_(" (specify a username in your .hgrc file)\n"))
950 ui.write(_(" (specify a username in your .hgrc file)\n"))
987
951
988 if not problems:
952 if not problems:
989 ui.status(_("No problems detected\n"))
953 ui.status(_("No problems detected\n"))
990 else:
954 else:
991 ui.write(_("%s problems detected,"
955 ui.write(_("%s problems detected,"
992 " please check your install!\n") % problems)
956 " please check your install!\n") % problems)
993
957
994 return problems
958 return problems
995
959
996 def debugrename(ui, repo, file1, *pats, **opts):
960 def debugrename(ui, repo, file1, *pats, **opts):
997 """dump rename information"""
961 """dump rename information"""
998
962
999 ctx = repo.changectx(opts.get('rev', 'tip'))
963 ctx = repo.changectx(opts.get('rev', 'tip'))
1000 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
964 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
1001 ctx.node()):
965 ctx.node()):
1002 m = ctx.filectx(abs).renamed()
966 m = ctx.filectx(abs).renamed()
1003 if m:
967 if m:
1004 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
968 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
1005 else:
969 else:
1006 ui.write(_("%s not renamed\n") % rel)
970 ui.write(_("%s not renamed\n") % rel)
1007
971
1008 def debugwalk(ui, repo, *pats, **opts):
972 def debugwalk(ui, repo, *pats, **opts):
1009 """show how files match on given patterns"""
973 """show how files match on given patterns"""
1010 items = list(cmdutil.walk(repo, pats, opts))
974 items = list(cmdutil.walk(repo, pats, opts))
1011 if not items:
975 if not items:
1012 return
976 return
1013 fmt = '%%s %%-%ds %%-%ds %%s' % (
977 fmt = '%%s %%-%ds %%-%ds %%s' % (
1014 max([len(abs) for (src, abs, rel, exact) in items]),
978 max([len(abs) for (src, abs, rel, exact) in items]),
1015 max([len(rel) for (src, abs, rel, exact) in items]))
979 max([len(rel) for (src, abs, rel, exact) in items]))
1016 for src, abs, rel, exact in items:
980 for src, abs, rel, exact in items:
1017 line = fmt % (src, abs, rel, exact and 'exact' or '')
981 line = fmt % (src, abs, rel, exact and 'exact' or '')
1018 ui.write("%s\n" % line.rstrip())
982 ui.write("%s\n" % line.rstrip())
1019
983
1020 def diff(ui, repo, *pats, **opts):
984 def diff(ui, repo, *pats, **opts):
1021 """diff repository (or selected files)
985 """diff repository (or selected files)
1022
986
1023 Show differences between revisions for the specified files.
987 Show differences between revisions for the specified files.
1024
988
1025 Differences between files are shown using the unified diff format.
989 Differences between files are shown using the unified diff format.
1026
990
1027 NOTE: diff may generate unexpected results for merges, as it will
991 NOTE: diff may generate unexpected results for merges, as it will
1028 default to comparing against the working directory's first parent
992 default to comparing against the working directory's first parent
1029 changeset if no revisions are specified.
993 changeset if no revisions are specified.
1030
994
1031 When two revision arguments are given, then changes are shown
995 When two revision arguments are given, then changes are shown
1032 between those revisions. If only one revision is specified then
996 between those revisions. If only one revision is specified then
1033 that revision is compared to the working directory, and, when no
997 that revision is compared to the working directory, and, when no
1034 revisions are specified, the working directory files are compared
998 revisions are specified, the working directory files are compared
1035 to its parent.
999 to its parent.
1036
1000
1037 Without the -a option, diff will avoid generating diffs of files
1001 Without the -a option, diff will avoid generating diffs of files
1038 it detects as binary. With -a, diff will generate a diff anyway,
1002 it detects as binary. With -a, diff will generate a diff anyway,
1039 probably with undesirable results.
1003 probably with undesirable results.
1040 """
1004 """
1041 node1, node2 = cmdutil.revpair(repo, opts['rev'])
1005 node1, node2 = cmdutil.revpair(repo, opts['rev'])
1042
1006
1043 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1007 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1044
1008
1045 patch.diff(repo, node1, node2, fns, match=matchfn,
1009 patch.diff(repo, node1, node2, fns, match=matchfn,
1046 opts=patch.diffopts(ui, opts))
1010 opts=patch.diffopts(ui, opts))
1047
1011
1048 def export(ui, repo, *changesets, **opts):
1012 def export(ui, repo, *changesets, **opts):
1049 """dump the header and diffs for one or more changesets
1013 """dump the header and diffs for one or more changesets
1050
1014
1051 Print the changeset header and diffs for one or more revisions.
1015 Print the changeset header and diffs for one or more revisions.
1052
1016
1053 The information shown in the changeset header is: author,
1017 The information shown in the changeset header is: author,
1054 changeset hash, parent(s) and commit comment.
1018 changeset hash, parent(s) and commit comment.
1055
1019
1056 NOTE: export may generate unexpected diff output for merge changesets,
1020 NOTE: export may generate unexpected diff output for merge changesets,
1057 as it will compare the merge changeset against its first parent only.
1021 as it will compare the merge changeset against its first parent only.
1058
1022
1059 Output may be to a file, in which case the name of the file is
1023 Output may be to a file, in which case the name of the file is
1060 given using a format string. The formatting rules are as follows:
1024 given using a format string. The formatting rules are as follows:
1061
1025
1062 %% literal "%" character
1026 %% literal "%" character
1063 %H changeset hash (40 bytes of hexadecimal)
1027 %H changeset hash (40 bytes of hexadecimal)
1064 %N number of patches being generated
1028 %N number of patches being generated
1065 %R changeset revision number
1029 %R changeset revision number
1066 %b basename of the exporting repository
1030 %b basename of the exporting repository
1067 %h short-form changeset hash (12 bytes of hexadecimal)
1031 %h short-form changeset hash (12 bytes of hexadecimal)
1068 %n zero-padded sequence number, starting at 1
1032 %n zero-padded sequence number, starting at 1
1069 %r zero-padded changeset revision number
1033 %r zero-padded changeset revision number
1070
1034
1071 Without the -a option, export will avoid generating diffs of files
1035 Without the -a option, export will avoid generating diffs of files
1072 it detects as binary. With -a, export will generate a diff anyway,
1036 it detects as binary. With -a, export will generate a diff anyway,
1073 probably with undesirable results.
1037 probably with undesirable results.
1074
1038
1075 With the --switch-parent option, the diff will be against the second
1039 With the --switch-parent option, the diff will be against the second
1076 parent. It can be useful to review a merge.
1040 parent. It can be useful to review a merge.
1077 """
1041 """
1078 if not changesets:
1042 if not changesets:
1079 raise util.Abort(_("export requires at least one changeset"))
1043 raise util.Abort(_("export requires at least one changeset"))
1080 revs = cmdutil.revrange(repo, changesets)
1044 revs = cmdutil.revrange(repo, changesets)
1081 if len(revs) > 1:
1045 if len(revs) > 1:
1082 ui.note(_('exporting patches:\n'))
1046 ui.note(_('exporting patches:\n'))
1083 else:
1047 else:
1084 ui.note(_('exporting patch:\n'))
1048 ui.note(_('exporting patch:\n'))
1085 patch.export(repo, revs, template=opts['output'],
1049 patch.export(repo, revs, template=opts['output'],
1086 switch_parent=opts['switch_parent'],
1050 switch_parent=opts['switch_parent'],
1087 opts=patch.diffopts(ui, opts))
1051 opts=patch.diffopts(ui, opts))
1088
1052
1089 def grep(ui, repo, pattern, *pats, **opts):
1053 def grep(ui, repo, pattern, *pats, **opts):
1090 """search for a pattern in specified files and revisions
1054 """search for a pattern in specified files and revisions
1091
1055
1092 Search revisions of files for a regular expression.
1056 Search revisions of files for a regular expression.
1093
1057
1094 This command behaves differently than Unix grep. It only accepts
1058 This command behaves differently than Unix grep. It only accepts
1095 Python/Perl regexps. It searches repository history, not the
1059 Python/Perl regexps. It searches repository history, not the
1096 working directory. It always prints the revision number in which
1060 working directory. It always prints the revision number in which
1097 a match appears.
1061 a match appears.
1098
1062
1099 By default, grep only prints output for the first revision of a
1063 By default, grep only prints output for the first revision of a
1100 file in which it finds a match. To get it to print every revision
1064 file in which it finds a match. To get it to print every revision
1101 that contains a change in match status ("-" for a match that
1065 that contains a change in match status ("-" for a match that
1102 becomes a non-match, or "+" for a non-match that becomes a match),
1066 becomes a non-match, or "+" for a non-match that becomes a match),
1103 use the --all flag.
1067 use the --all flag.
1104 """
1068 """
1105 reflags = 0
1069 reflags = 0
1106 if opts['ignore_case']:
1070 if opts['ignore_case']:
1107 reflags |= re.I
1071 reflags |= re.I
1108 regexp = re.compile(pattern, reflags)
1072 regexp = re.compile(pattern, reflags)
1109 sep, eol = ':', '\n'
1073 sep, eol = ':', '\n'
1110 if opts['print0']:
1074 if opts['print0']:
1111 sep = eol = '\0'
1075 sep = eol = '\0'
1112
1076
1113 fcache = {}
1077 fcache = {}
1114 def getfile(fn):
1078 def getfile(fn):
1115 if fn not in fcache:
1079 if fn not in fcache:
1116 fcache[fn] = repo.file(fn)
1080 fcache[fn] = repo.file(fn)
1117 return fcache[fn]
1081 return fcache[fn]
1118
1082
1119 def matchlines(body):
1083 def matchlines(body):
1120 begin = 0
1084 begin = 0
1121 linenum = 0
1085 linenum = 0
1122 while True:
1086 while True:
1123 match = regexp.search(body, begin)
1087 match = regexp.search(body, begin)
1124 if not match:
1088 if not match:
1125 break
1089 break
1126 mstart, mend = match.span()
1090 mstart, mend = match.span()
1127 linenum += body.count('\n', begin, mstart) + 1
1091 linenum += body.count('\n', begin, mstart) + 1
1128 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1092 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1129 lend = body.find('\n', mend)
1093 lend = body.find('\n', mend)
1130 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1094 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1131 begin = lend + 1
1095 begin = lend + 1
1132
1096
1133 class linestate(object):
1097 class linestate(object):
1134 def __init__(self, line, linenum, colstart, colend):
1098 def __init__(self, line, linenum, colstart, colend):
1135 self.line = line
1099 self.line = line
1136 self.linenum = linenum
1100 self.linenum = linenum
1137 self.colstart = colstart
1101 self.colstart = colstart
1138 self.colend = colend
1102 self.colend = colend
1139
1103
1140 def __eq__(self, other):
1104 def __eq__(self, other):
1141 return self.line == other.line
1105 return self.line == other.line
1142
1106
1143 matches = {}
1107 matches = {}
1144 copies = {}
1108 copies = {}
1145 def grepbody(fn, rev, body):
1109 def grepbody(fn, rev, body):
1146 matches[rev].setdefault(fn, [])
1110 matches[rev].setdefault(fn, [])
1147 m = matches[rev][fn]
1111 m = matches[rev][fn]
1148 for lnum, cstart, cend, line in matchlines(body):
1112 for lnum, cstart, cend, line in matchlines(body):
1149 s = linestate(line, lnum, cstart, cend)
1113 s = linestate(line, lnum, cstart, cend)
1150 m.append(s)
1114 m.append(s)
1151
1115
1152 def difflinestates(a, b):
1116 def difflinestates(a, b):
1153 sm = difflib.SequenceMatcher(None, a, b)
1117 sm = difflib.SequenceMatcher(None, a, b)
1154 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1118 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1155 if tag == 'insert':
1119 if tag == 'insert':
1156 for i in xrange(blo, bhi):
1120 for i in xrange(blo, bhi):
1157 yield ('+', b[i])
1121 yield ('+', b[i])
1158 elif tag == 'delete':
1122 elif tag == 'delete':
1159 for i in xrange(alo, ahi):
1123 for i in xrange(alo, ahi):
1160 yield ('-', a[i])
1124 yield ('-', a[i])
1161 elif tag == 'replace':
1125 elif tag == 'replace':
1162 for i in xrange(alo, ahi):
1126 for i in xrange(alo, ahi):
1163 yield ('-', a[i])
1127 yield ('-', a[i])
1164 for i in xrange(blo, bhi):
1128 for i in xrange(blo, bhi):
1165 yield ('+', b[i])
1129 yield ('+', b[i])
1166
1130
1167 prev = {}
1131 prev = {}
1168 def display(fn, rev, states, prevstates):
1132 def display(fn, rev, states, prevstates):
1169 found = False
1133 found = False
1170 filerevmatches = {}
1134 filerevmatches = {}
1171 r = prev.get(fn, -1)
1135 r = prev.get(fn, -1)
1172 if opts['all']:
1136 if opts['all']:
1173 iter = difflinestates(states, prevstates)
1137 iter = difflinestates(states, prevstates)
1174 else:
1138 else:
1175 iter = [('', l) for l in prevstates]
1139 iter = [('', l) for l in prevstates]
1176 for change, l in iter:
1140 for change, l in iter:
1177 cols = [fn, str(r)]
1141 cols = [fn, str(r)]
1178 if opts['line_number']:
1142 if opts['line_number']:
1179 cols.append(str(l.linenum))
1143 cols.append(str(l.linenum))
1180 if opts['all']:
1144 if opts['all']:
1181 cols.append(change)
1145 cols.append(change)
1182 if opts['user']:
1146 if opts['user']:
1183 cols.append(ui.shortuser(get(r)[1]))
1147 cols.append(ui.shortuser(get(r)[1]))
1184 if opts['files_with_matches']:
1148 if opts['files_with_matches']:
1185 c = (fn, r)
1149 c = (fn, r)
1186 if c in filerevmatches:
1150 if c in filerevmatches:
1187 continue
1151 continue
1188 filerevmatches[c] = 1
1152 filerevmatches[c] = 1
1189 else:
1153 else:
1190 cols.append(l.line)
1154 cols.append(l.line)
1191 ui.write(sep.join(cols), eol)
1155 ui.write(sep.join(cols), eol)
1192 found = True
1156 found = True
1193 return found
1157 return found
1194
1158
1195 fstate = {}
1159 fstate = {}
1196 skip = {}
1160 skip = {}
1197 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1161 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1198 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1162 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1199 found = False
1163 found = False
1200 follow = opts.get('follow')
1164 follow = opts.get('follow')
1201 for st, rev, fns in changeiter:
1165 for st, rev, fns in changeiter:
1202 if st == 'window':
1166 if st == 'window':
1203 matches.clear()
1167 matches.clear()
1204 elif st == 'add':
1168 elif st == 'add':
1205 mf = repo.changectx(rev).manifest()
1169 mf = repo.changectx(rev).manifest()
1206 matches[rev] = {}
1170 matches[rev] = {}
1207 for fn in fns:
1171 for fn in fns:
1208 if fn in skip:
1172 if fn in skip:
1209 continue
1173 continue
1210 fstate.setdefault(fn, {})
1174 fstate.setdefault(fn, {})
1211 try:
1175 try:
1212 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1176 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1213 if follow:
1177 if follow:
1214 copied = getfile(fn).renamed(mf[fn])
1178 copied = getfile(fn).renamed(mf[fn])
1215 if copied:
1179 if copied:
1216 copies.setdefault(rev, {})[fn] = copied[0]
1180 copies.setdefault(rev, {})[fn] = copied[0]
1217 except KeyError:
1181 except KeyError:
1218 pass
1182 pass
1219 elif st == 'iter':
1183 elif st == 'iter':
1220 states = matches[rev].items()
1184 states = matches[rev].items()
1221 states.sort()
1185 states.sort()
1222 for fn, m in states:
1186 for fn, m in states:
1223 copy = copies.get(rev, {}).get(fn)
1187 copy = copies.get(rev, {}).get(fn)
1224 if fn in skip:
1188 if fn in skip:
1225 if copy:
1189 if copy:
1226 skip[copy] = True
1190 skip[copy] = True
1227 continue
1191 continue
1228 if fn in prev or fstate[fn]:
1192 if fn in prev or fstate[fn]:
1229 r = display(fn, rev, m, fstate[fn])
1193 r = display(fn, rev, m, fstate[fn])
1230 found = found or r
1194 found = found or r
1231 if r and not opts['all']:
1195 if r and not opts['all']:
1232 skip[fn] = True
1196 skip[fn] = True
1233 if copy:
1197 if copy:
1234 skip[copy] = True
1198 skip[copy] = True
1235 fstate[fn] = m
1199 fstate[fn] = m
1236 if copy:
1200 if copy:
1237 fstate[copy] = m
1201 fstate[copy] = m
1238 prev[fn] = rev
1202 prev[fn] = rev
1239
1203
1240 fstate = fstate.items()
1204 fstate = fstate.items()
1241 fstate.sort()
1205 fstate.sort()
1242 for fn, state in fstate:
1206 for fn, state in fstate:
1243 if fn in skip:
1207 if fn in skip:
1244 continue
1208 continue
1245 if fn not in copies.get(prev[fn], {}):
1209 if fn not in copies.get(prev[fn], {}):
1246 found = display(fn, rev, {}, state) or found
1210 found = display(fn, rev, {}, state) or found
1247 return (not found and 1) or 0
1211 return (not found and 1) or 0
1248
1212
1249 def heads(ui, repo, **opts):
1213 def heads(ui, repo, **opts):
1250 """show current repository heads
1214 """show current repository heads
1251
1215
1252 Show all repository head changesets.
1216 Show all repository head changesets.
1253
1217
1254 Repository "heads" are changesets that don't have children
1218 Repository "heads" are changesets that don't have children
1255 changesets. They are where development generally takes place and
1219 changesets. They are where development generally takes place and
1256 are the usual targets for update and merge operations.
1220 are the usual targets for update and merge operations.
1257 """
1221 """
1258 if opts['rev']:
1222 if opts['rev']:
1259 heads = repo.heads(repo.lookup(opts['rev']))
1223 heads = repo.heads(repo.lookup(opts['rev']))
1260 else:
1224 else:
1261 heads = repo.heads()
1225 heads = repo.heads()
1262 displayer = cmdutil.show_changeset(ui, repo, opts)
1226 displayer = cmdutil.show_changeset(ui, repo, opts)
1263 for n in heads:
1227 for n in heads:
1264 displayer.show(changenode=n)
1228 displayer.show(changenode=n)
1265
1229
1266 def help_(ui, name=None, with_version=False):
1230 def help_(ui, name=None, with_version=False):
1267 """show help for a command, extension, or list of commands
1231 """show help for a command, extension, or list of commands
1268
1232
1269 With no arguments, print a list of commands and short help.
1233 With no arguments, print a list of commands and short help.
1270
1234
1271 Given a command name, print help for that command.
1235 Given a command name, print help for that command.
1272
1236
1273 Given an extension name, print help for that extension, and the
1237 Given an extension name, print help for that extension, and the
1274 commands it provides."""
1238 commands it provides."""
1275 option_lists = []
1239 option_lists = []
1276
1240
1277 def addglobalopts(aliases):
1241 def addglobalopts(aliases):
1278 if ui.verbose:
1242 if ui.verbose:
1279 option_lists.append((_("global options:"), globalopts))
1243 option_lists.append((_("global options:"), globalopts))
1280 if name == 'shortlist':
1244 if name == 'shortlist':
1281 option_lists.append((_('use "hg help" for the full list '
1245 option_lists.append((_('use "hg help" for the full list '
1282 'of commands'), ()))
1246 'of commands'), ()))
1283 else:
1247 else:
1284 if name == 'shortlist':
1248 if name == 'shortlist':
1285 msg = _('use "hg help" for the full list of commands '
1249 msg = _('use "hg help" for the full list of commands '
1286 'or "hg -v" for details')
1250 'or "hg -v" for details')
1287 elif aliases:
1251 elif aliases:
1288 msg = _('use "hg -v help%s" to show aliases and '
1252 msg = _('use "hg -v help%s" to show aliases and '
1289 'global options') % (name and " " + name or "")
1253 'global options') % (name and " " + name or "")
1290 else:
1254 else:
1291 msg = _('use "hg -v help %s" to show global options') % name
1255 msg = _('use "hg -v help %s" to show global options') % name
1292 option_lists.append((msg, ()))
1256 option_lists.append((msg, ()))
1293
1257
1294 def helpcmd(name):
1258 def helpcmd(name):
1295 if with_version:
1259 if with_version:
1296 version_(ui)
1260 version_(ui)
1297 ui.write('\n')
1261 ui.write('\n')
1298 aliases, i = findcmd(ui, name)
1262 aliases, i = cmdutil.findcmd(ui, name)
1299 # synopsis
1263 # synopsis
1300 ui.write("%s\n\n" % i[2])
1264 ui.write("%s\n\n" % i[2])
1301
1265
1302 # description
1266 # description
1303 doc = i[0].__doc__
1267 doc = i[0].__doc__
1304 if not doc:
1268 if not doc:
1305 doc = _("(No help text available)")
1269 doc = _("(No help text available)")
1306 if ui.quiet:
1270 if ui.quiet:
1307 doc = doc.splitlines(0)[0]
1271 doc = doc.splitlines(0)[0]
1308 ui.write("%s\n" % doc.rstrip())
1272 ui.write("%s\n" % doc.rstrip())
1309
1273
1310 if not ui.quiet:
1274 if not ui.quiet:
1311 # aliases
1275 # aliases
1312 if len(aliases) > 1:
1276 if len(aliases) > 1:
1313 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1277 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1314
1278
1315 # options
1279 # options
1316 if i[1]:
1280 if i[1]:
1317 option_lists.append((_("options:\n"), i[1]))
1281 option_lists.append((_("options:\n"), i[1]))
1318
1282
1319 addglobalopts(False)
1283 addglobalopts(False)
1320
1284
1321 def helplist(select=None):
1285 def helplist(select=None):
1322 h = {}
1286 h = {}
1323 cmds = {}
1287 cmds = {}
1324 for c, e in table.items():
1288 for c, e in table.items():
1325 f = c.split("|", 1)[0]
1289 f = c.split("|", 1)[0]
1326 if select and not select(f):
1290 if select and not select(f):
1327 continue
1291 continue
1328 if name == "shortlist" and not f.startswith("^"):
1292 if name == "shortlist" and not f.startswith("^"):
1329 continue
1293 continue
1330 f = f.lstrip("^")
1294 f = f.lstrip("^")
1331 if not ui.debugflag and f.startswith("debug"):
1295 if not ui.debugflag and f.startswith("debug"):
1332 continue
1296 continue
1333 doc = e[0].__doc__
1297 doc = e[0].__doc__
1334 if not doc:
1298 if not doc:
1335 doc = _("(No help text available)")
1299 doc = _("(No help text available)")
1336 h[f] = doc.splitlines(0)[0].rstrip()
1300 h[f] = doc.splitlines(0)[0].rstrip()
1337 cmds[f] = c.lstrip("^")
1301 cmds[f] = c.lstrip("^")
1338
1302
1339 fns = h.keys()
1303 fns = h.keys()
1340 fns.sort()
1304 fns.sort()
1341 m = max(map(len, fns))
1305 m = max(map(len, fns))
1342 for f in fns:
1306 for f in fns:
1343 if ui.verbose:
1307 if ui.verbose:
1344 commands = cmds[f].replace("|",", ")
1308 commands = cmds[f].replace("|",", ")
1345 ui.write(" %s:\n %s\n"%(commands, h[f]))
1309 ui.write(" %s:\n %s\n"%(commands, h[f]))
1346 else:
1310 else:
1347 ui.write(' %-*s %s\n' % (m, f, h[f]))
1311 ui.write(' %-*s %s\n' % (m, f, h[f]))
1348
1312
1349 if not ui.quiet:
1313 if not ui.quiet:
1350 addglobalopts(True)
1314 addglobalopts(True)
1351
1315
1352 def helptopic(name):
1316 def helptopic(name):
1353 v = None
1317 v = None
1354 for i in help.helptable:
1318 for i in help.helptable:
1355 l = i.split('|')
1319 l = i.split('|')
1356 if name in l:
1320 if name in l:
1357 v = i
1321 v = i
1358 header = l[-1]
1322 header = l[-1]
1359 if not v:
1323 if not v:
1360 raise UnknownCommand(name)
1324 raise cmdutil.UnknownCommand(name)
1361
1325
1362 # description
1326 # description
1363 doc = help.helptable[v]
1327 doc = help.helptable[v]
1364 if not doc:
1328 if not doc:
1365 doc = _("(No help text available)")
1329 doc = _("(No help text available)")
1366 if callable(doc):
1330 if callable(doc):
1367 doc = doc()
1331 doc = doc()
1368
1332
1369 ui.write("%s\n" % header)
1333 ui.write("%s\n" % header)
1370 ui.write("%s\n" % doc.rstrip())
1334 ui.write("%s\n" % doc.rstrip())
1371
1335
1372 def helpext(name):
1336 def helpext(name):
1373 try:
1337 try:
1374 mod = extensions.find(name)
1338 mod = extensions.find(name)
1375 except KeyError:
1339 except KeyError:
1376 raise UnknownCommand(name)
1340 raise cmdutil.UnknownCommand(name)
1377
1341
1378 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1342 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1379 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1343 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1380 for d in doc[1:]:
1344 for d in doc[1:]:
1381 ui.write(d, '\n')
1345 ui.write(d, '\n')
1382
1346
1383 ui.status('\n')
1347 ui.status('\n')
1384
1348
1385 try:
1349 try:
1386 ct = mod.cmdtable
1350 ct = mod.cmdtable
1387 except AttributeError:
1351 except AttributeError:
1388 ui.status(_('no commands defined\n'))
1352 ui.status(_('no commands defined\n'))
1389 return
1353 return
1390
1354
1391 ui.status(_('list of commands:\n\n'))
1355 ui.status(_('list of commands:\n\n'))
1392 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1356 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1393 helplist(modcmds.has_key)
1357 helplist(modcmds.has_key)
1394
1358
1395 if name and name != 'shortlist':
1359 if name and name != 'shortlist':
1396 i = None
1360 i = None
1397 for f in (helpcmd, helptopic, helpext):
1361 for f in (helpcmd, helptopic, helpext):
1398 try:
1362 try:
1399 f(name)
1363 f(name)
1400 i = None
1364 i = None
1401 break
1365 break
1402 except UnknownCommand, inst:
1366 except cmdutil.UnknownCommand, inst:
1403 i = inst
1367 i = inst
1404 if i:
1368 if i:
1405 raise i
1369 raise i
1406
1370
1407 else:
1371 else:
1408 # program name
1372 # program name
1409 if ui.verbose or with_version:
1373 if ui.verbose or with_version:
1410 version_(ui)
1374 version_(ui)
1411 else:
1375 else:
1412 ui.status(_("Mercurial Distributed SCM\n"))
1376 ui.status(_("Mercurial Distributed SCM\n"))
1413 ui.status('\n')
1377 ui.status('\n')
1414
1378
1415 # list of commands
1379 # list of commands
1416 if name == "shortlist":
1380 if name == "shortlist":
1417 ui.status(_('basic commands:\n\n'))
1381 ui.status(_('basic commands:\n\n'))
1418 else:
1382 else:
1419 ui.status(_('list of commands:\n\n'))
1383 ui.status(_('list of commands:\n\n'))
1420
1384
1421 helplist()
1385 helplist()
1422
1386
1423 # list all option lists
1387 # list all option lists
1424 opt_output = []
1388 opt_output = []
1425 for title, options in option_lists:
1389 for title, options in option_lists:
1426 opt_output.append(("\n%s" % title, None))
1390 opt_output.append(("\n%s" % title, None))
1427 for shortopt, longopt, default, desc in options:
1391 for shortopt, longopt, default, desc in options:
1428 if "DEPRECATED" in desc and not ui.verbose: continue
1392 if "DEPRECATED" in desc and not ui.verbose: continue
1429 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1393 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1430 longopt and " --%s" % longopt),
1394 longopt and " --%s" % longopt),
1431 "%s%s" % (desc,
1395 "%s%s" % (desc,
1432 default
1396 default
1433 and _(" (default: %s)") % default
1397 and _(" (default: %s)") % default
1434 or "")))
1398 or "")))
1435
1399
1436 if opt_output:
1400 if opt_output:
1437 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1401 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1438 for first, second in opt_output:
1402 for first, second in opt_output:
1439 if second:
1403 if second:
1440 ui.write(" %-*s %s\n" % (opts_len, first, second))
1404 ui.write(" %-*s %s\n" % (opts_len, first, second))
1441 else:
1405 else:
1442 ui.write("%s\n" % first)
1406 ui.write("%s\n" % first)
1443
1407
1444 def identify(ui, repo):
1408 def identify(ui, repo):
1445 """print information about the working copy
1409 """print information about the working copy
1446
1410
1447 Print a short summary of the current state of the repo.
1411 Print a short summary of the current state of the repo.
1448
1412
1449 This summary identifies the repository state using one or two parent
1413 This summary identifies the repository state using one or two parent
1450 hash identifiers, followed by a "+" if there are uncommitted changes
1414 hash identifiers, followed by a "+" if there are uncommitted changes
1451 in the working directory, followed by a list of tags for this revision.
1415 in the working directory, followed by a list of tags for this revision.
1452 """
1416 """
1453 parents = [p for p in repo.dirstate.parents() if p != nullid]
1417 parents = [p for p in repo.dirstate.parents() if p != nullid]
1454 if not parents:
1418 if not parents:
1455 ui.write(_("unknown\n"))
1419 ui.write(_("unknown\n"))
1456 return
1420 return
1457
1421
1458 hexfunc = ui.debugflag and hex or short
1422 hexfunc = ui.debugflag and hex or short
1459 modified, added, removed, deleted = repo.status()[:4]
1423 modified, added, removed, deleted = repo.status()[:4]
1460 output = ["%s%s" %
1424 output = ["%s%s" %
1461 ('+'.join([hexfunc(parent) for parent in parents]),
1425 ('+'.join([hexfunc(parent) for parent in parents]),
1462 (modified or added or removed or deleted) and "+" or "")]
1426 (modified or added or removed or deleted) and "+" or "")]
1463
1427
1464 if not ui.quiet:
1428 if not ui.quiet:
1465
1429
1466 branch = util.tolocal(repo.workingctx().branch())
1430 branch = util.tolocal(repo.workingctx().branch())
1467 if branch != 'default':
1431 if branch != 'default':
1468 output.append("(%s)" % branch)
1432 output.append("(%s)" % branch)
1469
1433
1470 # multiple tags for a single parent separated by '/'
1434 # multiple tags for a single parent separated by '/'
1471 parenttags = ['/'.join(tags)
1435 parenttags = ['/'.join(tags)
1472 for tags in map(repo.nodetags, parents) if tags]
1436 for tags in map(repo.nodetags, parents) if tags]
1473 # tags for multiple parents separated by ' + '
1437 # tags for multiple parents separated by ' + '
1474 if parenttags:
1438 if parenttags:
1475 output.append(' + '.join(parenttags))
1439 output.append(' + '.join(parenttags))
1476
1440
1477 ui.write("%s\n" % ' '.join(output))
1441 ui.write("%s\n" % ' '.join(output))
1478
1442
1479 def import_(ui, repo, patch1, *patches, **opts):
1443 def import_(ui, repo, patch1, *patches, **opts):
1480 """import an ordered set of patches
1444 """import an ordered set of patches
1481
1445
1482 Import a list of patches and commit them individually.
1446 Import a list of patches and commit them individually.
1483
1447
1484 If there are outstanding changes in the working directory, import
1448 If there are outstanding changes in the working directory, import
1485 will abort unless given the -f flag.
1449 will abort unless given the -f flag.
1486
1450
1487 You can import a patch straight from a mail message. Even patches
1451 You can import a patch straight from a mail message. Even patches
1488 as attachments work (body part must be type text/plain or
1452 as attachments work (body part must be type text/plain or
1489 text/x-patch to be used). From and Subject headers of email
1453 text/x-patch to be used). From and Subject headers of email
1490 message are used as default committer and commit message. All
1454 message are used as default committer and commit message. All
1491 text/plain body parts before first diff are added to commit
1455 text/plain body parts before first diff are added to commit
1492 message.
1456 message.
1493
1457
1494 If the imported patch was generated by hg export, user and description
1458 If the imported patch was generated by hg export, user and description
1495 from patch override values from message headers and body. Values
1459 from patch override values from message headers and body. Values
1496 given on command line with -m and -u override these.
1460 given on command line with -m and -u override these.
1497
1461
1498 If --exact is specified, import will set the working directory
1462 If --exact is specified, import will set the working directory
1499 to the parent of each patch before applying it, and will abort
1463 to the parent of each patch before applying it, and will abort
1500 if the resulting changeset has a different ID than the one
1464 if the resulting changeset has a different ID than the one
1501 recorded in the patch. This may happen due to character set
1465 recorded in the patch. This may happen due to character set
1502 problems or other deficiencies in the text patch format.
1466 problems or other deficiencies in the text patch format.
1503
1467
1504 To read a patch from standard input, use patch name "-".
1468 To read a patch from standard input, use patch name "-".
1505 """
1469 """
1506 patches = (patch1,) + patches
1470 patches = (patch1,) + patches
1507
1471
1508 if opts.get('exact') or not opts['force']:
1472 if opts.get('exact') or not opts['force']:
1509 bail_if_changed(repo)
1473 cmdutil.bail_if_changed(repo)
1510
1474
1511 d = opts["base"]
1475 d = opts["base"]
1512 strip = opts["strip"]
1476 strip = opts["strip"]
1513
1477
1514 wlock = repo.wlock()
1478 wlock = repo.wlock()
1515 lock = repo.lock()
1479 lock = repo.lock()
1516
1480
1517 for p in patches:
1481 for p in patches:
1518 pf = os.path.join(d, p)
1482 pf = os.path.join(d, p)
1519
1483
1520 if pf == '-':
1484 if pf == '-':
1521 ui.status(_("applying patch from stdin\n"))
1485 ui.status(_("applying patch from stdin\n"))
1522 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, sys.stdin)
1486 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, sys.stdin)
1523 else:
1487 else:
1524 ui.status(_("applying %s\n") % p)
1488 ui.status(_("applying %s\n") % p)
1525 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, file(pf))
1489 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, file(pf))
1526
1490
1527 if tmpname is None:
1491 if tmpname is None:
1528 raise util.Abort(_('no diffs found'))
1492 raise util.Abort(_('no diffs found'))
1529
1493
1530 try:
1494 try:
1531 cmdline_message = logmessage(opts)
1495 cmdline_message = cmdutil.logmessage(opts)
1532 if cmdline_message:
1496 if cmdline_message:
1533 # pickup the cmdline msg
1497 # pickup the cmdline msg
1534 message = cmdline_message
1498 message = cmdline_message
1535 elif message:
1499 elif message:
1536 # pickup the patch msg
1500 # pickup the patch msg
1537 message = message.strip()
1501 message = message.strip()
1538 else:
1502 else:
1539 # launch the editor
1503 # launch the editor
1540 message = None
1504 message = None
1541 ui.debug(_('message:\n%s\n') % message)
1505 ui.debug(_('message:\n%s\n') % message)
1542
1506
1543 wp = repo.workingctx().parents()
1507 wp = repo.workingctx().parents()
1544 if opts.get('exact'):
1508 if opts.get('exact'):
1545 if not nodeid or not p1:
1509 if not nodeid or not p1:
1546 raise util.Abort(_('not a mercurial patch'))
1510 raise util.Abort(_('not a mercurial patch'))
1547 p1 = repo.lookup(p1)
1511 p1 = repo.lookup(p1)
1548 p2 = repo.lookup(p2 or hex(nullid))
1512 p2 = repo.lookup(p2 or hex(nullid))
1549
1513
1550 if p1 != wp[0].node():
1514 if p1 != wp[0].node():
1551 hg.clean(repo, p1, wlock=wlock)
1515 hg.clean(repo, p1, wlock=wlock)
1552 repo.dirstate.setparents(p1, p2)
1516 repo.dirstate.setparents(p1, p2)
1553 repo.dirstate.setbranch(branch or 'default')
1517 repo.dirstate.setbranch(branch or 'default')
1554 elif p2:
1518 elif p2:
1555 try:
1519 try:
1556 p1 = repo.lookup(p1)
1520 p1 = repo.lookup(p1)
1557 p2 = repo.lookup(p2)
1521 p2 = repo.lookup(p2)
1558 if p1 == wp[0].node():
1522 if p1 == wp[0].node():
1559 repo.dirstate.setparents(p1, p2)
1523 repo.dirstate.setparents(p1, p2)
1560 except hg.RepoError:
1524 except hg.RepoError:
1561 pass
1525 pass
1562
1526
1563 files = {}
1527 files = {}
1564 try:
1528 try:
1565 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1529 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1566 files=files)
1530 files=files)
1567 finally:
1531 finally:
1568 files = patch.updatedir(ui, repo, files, wlock=wlock)
1532 files = patch.updatedir(ui, repo, files, wlock=wlock)
1569 n = repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1533 n = repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1570 if opts.get('exact'):
1534 if opts.get('exact'):
1571 if hex(n) != nodeid:
1535 if hex(n) != nodeid:
1572 repo.rollback(wlock=wlock, lock=lock)
1536 repo.rollback(wlock=wlock, lock=lock)
1573 raise util.Abort(_('patch is damaged or loses information'))
1537 raise util.Abort(_('patch is damaged or loses information'))
1574 finally:
1538 finally:
1575 os.unlink(tmpname)
1539 os.unlink(tmpname)
1576
1540
1577 def incoming(ui, repo, source="default", **opts):
1541 def incoming(ui, repo, source="default", **opts):
1578 """show new changesets found in source
1542 """show new changesets found in source
1579
1543
1580 Show new changesets found in the specified path/URL or the default
1544 Show new changesets found in the specified path/URL or the default
1581 pull location. These are the changesets that would be pulled if a pull
1545 pull location. These are the changesets that would be pulled if a pull
1582 was requested.
1546 was requested.
1583
1547
1584 For remote repository, using --bundle avoids downloading the changesets
1548 For remote repository, using --bundle avoids downloading the changesets
1585 twice if the incoming is followed by a pull.
1549 twice if the incoming is followed by a pull.
1586
1550
1587 See pull for valid source format details.
1551 See pull for valid source format details.
1588 """
1552 """
1589 source, revs = cmdutil.parseurl(ui.expandpath(source), opts['rev'])
1553 source, revs = cmdutil.parseurl(ui.expandpath(source), opts['rev'])
1590 setremoteconfig(ui, opts)
1554 cmdutil.setremoteconfig(ui, opts)
1591
1555
1592 other = hg.repository(ui, source)
1556 other = hg.repository(ui, source)
1593 ui.status(_('comparing with %s\n') % source)
1557 ui.status(_('comparing with %s\n') % source)
1594 if revs:
1558 if revs:
1595 if 'lookup' in other.capabilities:
1559 if 'lookup' in other.capabilities:
1596 revs = [other.lookup(rev) for rev in revs]
1560 revs = [other.lookup(rev) for rev in revs]
1597 else:
1561 else:
1598 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1562 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1599 raise util.Abort(error)
1563 raise util.Abort(error)
1600 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1564 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1601 if not incoming:
1565 if not incoming:
1602 try:
1566 try:
1603 os.unlink(opts["bundle"])
1567 os.unlink(opts["bundle"])
1604 except:
1568 except:
1605 pass
1569 pass
1606 ui.status(_("no changes found\n"))
1570 ui.status(_("no changes found\n"))
1607 return 1
1571 return 1
1608
1572
1609 cleanup = None
1573 cleanup = None
1610 try:
1574 try:
1611 fname = opts["bundle"]
1575 fname = opts["bundle"]
1612 if fname or not other.local():
1576 if fname or not other.local():
1613 # create a bundle (uncompressed if other repo is not local)
1577 # create a bundle (uncompressed if other repo is not local)
1614 if revs is None:
1578 if revs is None:
1615 cg = other.changegroup(incoming, "incoming")
1579 cg = other.changegroup(incoming, "incoming")
1616 else:
1580 else:
1617 if 'changegroupsubset' not in other.capabilities:
1581 if 'changegroupsubset' not in other.capabilities:
1618 raise util.Abort(_("Partial incoming cannot be done because other repository doesn't support changegroupsubset."))
1582 raise util.Abort(_("Partial incoming cannot be done because other repository doesn't support changegroupsubset."))
1619 cg = other.changegroupsubset(incoming, revs, 'incoming')
1583 cg = other.changegroupsubset(incoming, revs, 'incoming')
1620 bundletype = other.local() and "HG10BZ" or "HG10UN"
1584 bundletype = other.local() and "HG10BZ" or "HG10UN"
1621 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1585 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1622 # keep written bundle?
1586 # keep written bundle?
1623 if opts["bundle"]:
1587 if opts["bundle"]:
1624 cleanup = None
1588 cleanup = None
1625 if not other.local():
1589 if not other.local():
1626 # use the created uncompressed bundlerepo
1590 # use the created uncompressed bundlerepo
1627 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1591 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1628
1592
1629 o = other.changelog.nodesbetween(incoming, revs)[0]
1593 o = other.changelog.nodesbetween(incoming, revs)[0]
1630 if opts['newest_first']:
1594 if opts['newest_first']:
1631 o.reverse()
1595 o.reverse()
1632 displayer = cmdutil.show_changeset(ui, other, opts)
1596 displayer = cmdutil.show_changeset(ui, other, opts)
1633 for n in o:
1597 for n in o:
1634 parents = [p for p in other.changelog.parents(n) if p != nullid]
1598 parents = [p for p in other.changelog.parents(n) if p != nullid]
1635 if opts['no_merges'] and len(parents) == 2:
1599 if opts['no_merges'] and len(parents) == 2:
1636 continue
1600 continue
1637 displayer.show(changenode=n)
1601 displayer.show(changenode=n)
1638 finally:
1602 finally:
1639 if hasattr(other, 'close'):
1603 if hasattr(other, 'close'):
1640 other.close()
1604 other.close()
1641 if cleanup:
1605 if cleanup:
1642 os.unlink(cleanup)
1606 os.unlink(cleanup)
1643
1607
1644 def init(ui, dest=".", **opts):
1608 def init(ui, dest=".", **opts):
1645 """create a new repository in the given directory
1609 """create a new repository in the given directory
1646
1610
1647 Initialize a new repository in the given directory. If the given
1611 Initialize a new repository in the given directory. If the given
1648 directory does not exist, it is created.
1612 directory does not exist, it is created.
1649
1613
1650 If no directory is given, the current directory is used.
1614 If no directory is given, the current directory is used.
1651
1615
1652 It is possible to specify an ssh:// URL as the destination.
1616 It is possible to specify an ssh:// URL as the destination.
1653 Look at the help text for the pull command for important details
1617 Look at the help text for the pull command for important details
1654 about ssh:// URLs.
1618 about ssh:// URLs.
1655 """
1619 """
1656 setremoteconfig(ui, opts)
1620 cmdutil.setremoteconfig(ui, opts)
1657 hg.repository(ui, dest, create=1)
1621 hg.repository(ui, dest, create=1)
1658
1622
1659 def locate(ui, repo, *pats, **opts):
1623 def locate(ui, repo, *pats, **opts):
1660 """locate files matching specific patterns
1624 """locate files matching specific patterns
1661
1625
1662 Print all files under Mercurial control whose names match the
1626 Print all files under Mercurial control whose names match the
1663 given patterns.
1627 given patterns.
1664
1628
1665 This command searches the entire repository by default. To search
1629 This command searches the entire repository by default. To search
1666 just the current directory and its subdirectories, use "--include .".
1630 just the current directory and its subdirectories, use "--include .".
1667
1631
1668 If no patterns are given to match, this command prints all file
1632 If no patterns are given to match, this command prints all file
1669 names.
1633 names.
1670
1634
1671 If you want to feed the output of this command into the "xargs"
1635 If you want to feed the output of this command into the "xargs"
1672 command, use the "-0" option to both this command and "xargs".
1636 command, use the "-0" option to both this command and "xargs".
1673 This will avoid the problem of "xargs" treating single filenames
1637 This will avoid the problem of "xargs" treating single filenames
1674 that contain white space as multiple filenames.
1638 that contain white space as multiple filenames.
1675 """
1639 """
1676 end = opts['print0'] and '\0' or '\n'
1640 end = opts['print0'] and '\0' or '\n'
1677 rev = opts['rev']
1641 rev = opts['rev']
1678 if rev:
1642 if rev:
1679 node = repo.lookup(rev)
1643 node = repo.lookup(rev)
1680 else:
1644 else:
1681 node = None
1645 node = None
1682
1646
1683 ret = 1
1647 ret = 1
1684 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1648 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1685 badmatch=util.always,
1649 badmatch=util.always,
1686 default='relglob'):
1650 default='relglob'):
1687 if src == 'b':
1651 if src == 'b':
1688 continue
1652 continue
1689 if not node and repo.dirstate.state(abs) == '?':
1653 if not node and repo.dirstate.state(abs) == '?':
1690 continue
1654 continue
1691 if opts['fullpath']:
1655 if opts['fullpath']:
1692 ui.write(os.path.join(repo.root, abs), end)
1656 ui.write(os.path.join(repo.root, abs), end)
1693 else:
1657 else:
1694 ui.write(((pats and rel) or abs), end)
1658 ui.write(((pats and rel) or abs), end)
1695 ret = 0
1659 ret = 0
1696
1660
1697 return ret
1661 return ret
1698
1662
1699 def log(ui, repo, *pats, **opts):
1663 def log(ui, repo, *pats, **opts):
1700 """show revision history of entire repository or files
1664 """show revision history of entire repository or files
1701
1665
1702 Print the revision history of the specified files or the entire
1666 Print the revision history of the specified files or the entire
1703 project.
1667 project.
1704
1668
1705 File history is shown without following rename or copy history of
1669 File history is shown without following rename or copy history of
1706 files. Use -f/--follow with a file name to follow history across
1670 files. Use -f/--follow with a file name to follow history across
1707 renames and copies. --follow without a file name will only show
1671 renames and copies. --follow without a file name will only show
1708 ancestors or descendants of the starting revision. --follow-first
1672 ancestors or descendants of the starting revision. --follow-first
1709 only follows the first parent of merge revisions.
1673 only follows the first parent of merge revisions.
1710
1674
1711 If no revision range is specified, the default is tip:0 unless
1675 If no revision range is specified, the default is tip:0 unless
1712 --follow is set, in which case the working directory parent is
1676 --follow is set, in which case the working directory parent is
1713 used as the starting revision.
1677 used as the starting revision.
1714
1678
1715 By default this command outputs: changeset id and hash, tags,
1679 By default this command outputs: changeset id and hash, tags,
1716 non-trivial parents, user, date and time, and a summary for each
1680 non-trivial parents, user, date and time, and a summary for each
1717 commit. When the -v/--verbose switch is used, the list of changed
1681 commit. When the -v/--verbose switch is used, the list of changed
1718 files and full commit message is shown.
1682 files and full commit message is shown.
1719
1683
1720 NOTE: log -p may generate unexpected diff output for merge
1684 NOTE: log -p may generate unexpected diff output for merge
1721 changesets, as it will compare the merge changeset against its
1685 changesets, as it will compare the merge changeset against its
1722 first parent only. Also, the files: list will only reflect files
1686 first parent only. Also, the files: list will only reflect files
1723 that are different from BOTH parents.
1687 that are different from BOTH parents.
1724
1688
1725 """
1689 """
1726
1690
1727 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1691 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1728 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1692 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1729
1693
1730 if opts['limit']:
1694 if opts['limit']:
1731 try:
1695 try:
1732 limit = int(opts['limit'])
1696 limit = int(opts['limit'])
1733 except ValueError:
1697 except ValueError:
1734 raise util.Abort(_('limit must be a positive integer'))
1698 raise util.Abort(_('limit must be a positive integer'))
1735 if limit <= 0: raise util.Abort(_('limit must be positive'))
1699 if limit <= 0: raise util.Abort(_('limit must be positive'))
1736 else:
1700 else:
1737 limit = sys.maxint
1701 limit = sys.maxint
1738 count = 0
1702 count = 0
1739
1703
1740 if opts['copies'] and opts['rev']:
1704 if opts['copies'] and opts['rev']:
1741 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1705 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1742 else:
1706 else:
1743 endrev = repo.changelog.count()
1707 endrev = repo.changelog.count()
1744 rcache = {}
1708 rcache = {}
1745 ncache = {}
1709 ncache = {}
1746 dcache = []
1710 dcache = []
1747 def getrenamed(fn, rev, man):
1711 def getrenamed(fn, rev, man):
1748 '''looks up all renames for a file (up to endrev) the first
1712 '''looks up all renames for a file (up to endrev) the first
1749 time the file is given. It indexes on the changerev and only
1713 time the file is given. It indexes on the changerev and only
1750 parses the manifest if linkrev != changerev.
1714 parses the manifest if linkrev != changerev.
1751 Returns rename info for fn at changerev rev.'''
1715 Returns rename info for fn at changerev rev.'''
1752 if fn not in rcache:
1716 if fn not in rcache:
1753 rcache[fn] = {}
1717 rcache[fn] = {}
1754 ncache[fn] = {}
1718 ncache[fn] = {}
1755 fl = repo.file(fn)
1719 fl = repo.file(fn)
1756 for i in xrange(fl.count()):
1720 for i in xrange(fl.count()):
1757 node = fl.node(i)
1721 node = fl.node(i)
1758 lr = fl.linkrev(node)
1722 lr = fl.linkrev(node)
1759 renamed = fl.renamed(node)
1723 renamed = fl.renamed(node)
1760 rcache[fn][lr] = renamed
1724 rcache[fn][lr] = renamed
1761 if renamed:
1725 if renamed:
1762 ncache[fn][node] = renamed
1726 ncache[fn][node] = renamed
1763 if lr >= endrev:
1727 if lr >= endrev:
1764 break
1728 break
1765 if rev in rcache[fn]:
1729 if rev in rcache[fn]:
1766 return rcache[fn][rev]
1730 return rcache[fn][rev]
1767 mr = repo.manifest.rev(man)
1731 mr = repo.manifest.rev(man)
1768 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1732 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1769 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1733 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1770 if not dcache or dcache[0] != man:
1734 if not dcache or dcache[0] != man:
1771 dcache[:] = [man, repo.manifest.readdelta(man)]
1735 dcache[:] = [man, repo.manifest.readdelta(man)]
1772 if fn in dcache[1]:
1736 if fn in dcache[1]:
1773 return ncache[fn].get(dcache[1][fn])
1737 return ncache[fn].get(dcache[1][fn])
1774 return None
1738 return None
1775
1739
1776 df = False
1740 df = False
1777 if opts["date"]:
1741 if opts["date"]:
1778 df = util.matchdate(opts["date"])
1742 df = util.matchdate(opts["date"])
1779
1743
1780 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1744 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1781 for st, rev, fns in changeiter:
1745 for st, rev, fns in changeiter:
1782 if st == 'add':
1746 if st == 'add':
1783 changenode = repo.changelog.node(rev)
1747 changenode = repo.changelog.node(rev)
1784 parents = [p for p in repo.changelog.parentrevs(rev)
1748 parents = [p for p in repo.changelog.parentrevs(rev)
1785 if p != nullrev]
1749 if p != nullrev]
1786 if opts['no_merges'] and len(parents) == 2:
1750 if opts['no_merges'] and len(parents) == 2:
1787 continue
1751 continue
1788 if opts['only_merges'] and len(parents) != 2:
1752 if opts['only_merges'] and len(parents) != 2:
1789 continue
1753 continue
1790
1754
1791 if df:
1755 if df:
1792 changes = get(rev)
1756 changes = get(rev)
1793 if not df(changes[2][0]):
1757 if not df(changes[2][0]):
1794 continue
1758 continue
1795
1759
1796 if opts['keyword']:
1760 if opts['keyword']:
1797 changes = get(rev)
1761 changes = get(rev)
1798 miss = 0
1762 miss = 0
1799 for k in [kw.lower() for kw in opts['keyword']]:
1763 for k in [kw.lower() for kw in opts['keyword']]:
1800 if not (k in changes[1].lower() or
1764 if not (k in changes[1].lower() or
1801 k in changes[4].lower() or
1765 k in changes[4].lower() or
1802 k in " ".join(changes[3]).lower()):
1766 k in " ".join(changes[3]).lower()):
1803 miss = 1
1767 miss = 1
1804 break
1768 break
1805 if miss:
1769 if miss:
1806 continue
1770 continue
1807
1771
1808 copies = []
1772 copies = []
1809 if opts.get('copies') and rev:
1773 if opts.get('copies') and rev:
1810 mf = get(rev)[0]
1774 mf = get(rev)[0]
1811 for fn in get(rev)[3]:
1775 for fn in get(rev)[3]:
1812 rename = getrenamed(fn, rev, mf)
1776 rename = getrenamed(fn, rev, mf)
1813 if rename:
1777 if rename:
1814 copies.append((fn, rename[0]))
1778 copies.append((fn, rename[0]))
1815 displayer.show(rev, changenode, copies=copies)
1779 displayer.show(rev, changenode, copies=copies)
1816 elif st == 'iter':
1780 elif st == 'iter':
1817 if count == limit: break
1781 if count == limit: break
1818 if displayer.flush(rev):
1782 if displayer.flush(rev):
1819 count += 1
1783 count += 1
1820
1784
1821 def manifest(ui, repo, rev=None):
1785 def manifest(ui, repo, rev=None):
1822 """output the current or given revision of the project manifest
1786 """output the current or given revision of the project manifest
1823
1787
1824 Print a list of version controlled files for the given revision.
1788 Print a list of version controlled files for the given revision.
1825 If no revision is given, the parent of the working directory is used,
1789 If no revision is given, the parent of the working directory is used,
1826 or tip if no revision is checked out.
1790 or tip if no revision is checked out.
1827
1791
1828 The manifest is the list of files being version controlled. If no revision
1792 The manifest is the list of files being version controlled. If no revision
1829 is given then the first parent of the working directory is used.
1793 is given then the first parent of the working directory is used.
1830
1794
1831 With -v flag, print file permissions. With --debug flag, print
1795 With -v flag, print file permissions. With --debug flag, print
1832 file revision hashes.
1796 file revision hashes.
1833 """
1797 """
1834
1798
1835 m = repo.changectx(rev).manifest()
1799 m = repo.changectx(rev).manifest()
1836 files = m.keys()
1800 files = m.keys()
1837 files.sort()
1801 files.sort()
1838
1802
1839 for f in files:
1803 for f in files:
1840 if ui.debugflag:
1804 if ui.debugflag:
1841 ui.write("%40s " % hex(m[f]))
1805 ui.write("%40s " % hex(m[f]))
1842 if ui.verbose:
1806 if ui.verbose:
1843 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1807 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1844 ui.write("%s\n" % f)
1808 ui.write("%s\n" % f)
1845
1809
1846 def merge(ui, repo, node=None, force=None, rev=None):
1810 def merge(ui, repo, node=None, force=None, rev=None):
1847 """merge working directory with another revision
1811 """merge working directory with another revision
1848
1812
1849 Merge the contents of the current working directory and the
1813 Merge the contents of the current working directory and the
1850 requested revision. Files that changed between either parent are
1814 requested revision. Files that changed between either parent are
1851 marked as changed for the next commit and a commit must be
1815 marked as changed for the next commit and a commit must be
1852 performed before any further updates are allowed.
1816 performed before any further updates are allowed.
1853
1817
1854 If no revision is specified, the working directory's parent is a
1818 If no revision is specified, the working directory's parent is a
1855 head revision, and the repository contains exactly one other head,
1819 head revision, and the repository contains exactly one other head,
1856 the other head is merged with by default. Otherwise, an explicit
1820 the other head is merged with by default. Otherwise, an explicit
1857 revision to merge with must be provided.
1821 revision to merge with must be provided.
1858 """
1822 """
1859
1823
1860 if rev and node:
1824 if rev and node:
1861 raise util.Abort(_("please specify just one revision"))
1825 raise util.Abort(_("please specify just one revision"))
1862
1826
1863 if not node:
1827 if not node:
1864 node = rev
1828 node = rev
1865
1829
1866 if not node:
1830 if not node:
1867 heads = repo.heads()
1831 heads = repo.heads()
1868 if len(heads) > 2:
1832 if len(heads) > 2:
1869 raise util.Abort(_('repo has %d heads - '
1833 raise util.Abort(_('repo has %d heads - '
1870 'please merge with an explicit rev') %
1834 'please merge with an explicit rev') %
1871 len(heads))
1835 len(heads))
1872 if len(heads) == 1:
1836 if len(heads) == 1:
1873 raise util.Abort(_('there is nothing to merge - '
1837 raise util.Abort(_('there is nothing to merge - '
1874 'use "hg update" instead'))
1838 'use "hg update" instead'))
1875 parent = repo.dirstate.parents()[0]
1839 parent = repo.dirstate.parents()[0]
1876 if parent not in heads:
1840 if parent not in heads:
1877 raise util.Abort(_('working dir not at a head rev - '
1841 raise util.Abort(_('working dir not at a head rev - '
1878 'use "hg update" or merge with an explicit rev'))
1842 'use "hg update" or merge with an explicit rev'))
1879 node = parent == heads[0] and heads[-1] or heads[0]
1843 node = parent == heads[0] and heads[-1] or heads[0]
1880 return hg.merge(repo, node, force=force)
1844 return hg.merge(repo, node, force=force)
1881
1845
1882 def outgoing(ui, repo, dest=None, **opts):
1846 def outgoing(ui, repo, dest=None, **opts):
1883 """show changesets not found in destination
1847 """show changesets not found in destination
1884
1848
1885 Show changesets not found in the specified destination repository or
1849 Show changesets not found in the specified destination repository or
1886 the default push location. These are the changesets that would be pushed
1850 the default push location. These are the changesets that would be pushed
1887 if a push was requested.
1851 if a push was requested.
1888
1852
1889 See pull for valid destination format details.
1853 See pull for valid destination format details.
1890 """
1854 """
1891 dest, revs = cmdutil.parseurl(
1855 dest, revs = cmdutil.parseurl(
1892 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
1856 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
1893 setremoteconfig(ui, opts)
1857 cmdutil.setremoteconfig(ui, opts)
1894 if revs:
1858 if revs:
1895 revs = [repo.lookup(rev) for rev in revs]
1859 revs = [repo.lookup(rev) for rev in revs]
1896
1860
1897 other = hg.repository(ui, dest)
1861 other = hg.repository(ui, dest)
1898 ui.status(_('comparing with %s\n') % dest)
1862 ui.status(_('comparing with %s\n') % dest)
1899 o = repo.findoutgoing(other, force=opts['force'])
1863 o = repo.findoutgoing(other, force=opts['force'])
1900 if not o:
1864 if not o:
1901 ui.status(_("no changes found\n"))
1865 ui.status(_("no changes found\n"))
1902 return 1
1866 return 1
1903 o = repo.changelog.nodesbetween(o, revs)[0]
1867 o = repo.changelog.nodesbetween(o, revs)[0]
1904 if opts['newest_first']:
1868 if opts['newest_first']:
1905 o.reverse()
1869 o.reverse()
1906 displayer = cmdutil.show_changeset(ui, repo, opts)
1870 displayer = cmdutil.show_changeset(ui, repo, opts)
1907 for n in o:
1871 for n in o:
1908 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1872 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1909 if opts['no_merges'] and len(parents) == 2:
1873 if opts['no_merges'] and len(parents) == 2:
1910 continue
1874 continue
1911 displayer.show(changenode=n)
1875 displayer.show(changenode=n)
1912
1876
1913 def parents(ui, repo, file_=None, **opts):
1877 def parents(ui, repo, file_=None, **opts):
1914 """show the parents of the working dir or revision
1878 """show the parents of the working dir or revision
1915
1879
1916 Print the working directory's parent revisions.
1880 Print the working directory's parent revisions.
1917 """
1881 """
1918 rev = opts.get('rev')
1882 rev = opts.get('rev')
1919 if rev:
1883 if rev:
1920 if file_:
1884 if file_:
1921 ctx = repo.filectx(file_, changeid=rev)
1885 ctx = repo.filectx(file_, changeid=rev)
1922 else:
1886 else:
1923 ctx = repo.changectx(rev)
1887 ctx = repo.changectx(rev)
1924 p = [cp.node() for cp in ctx.parents()]
1888 p = [cp.node() for cp in ctx.parents()]
1925 else:
1889 else:
1926 p = repo.dirstate.parents()
1890 p = repo.dirstate.parents()
1927
1891
1928 displayer = cmdutil.show_changeset(ui, repo, opts)
1892 displayer = cmdutil.show_changeset(ui, repo, opts)
1929 for n in p:
1893 for n in p:
1930 if n != nullid:
1894 if n != nullid:
1931 displayer.show(changenode=n)
1895 displayer.show(changenode=n)
1932
1896
1933 def paths(ui, repo, search=None):
1897 def paths(ui, repo, search=None):
1934 """show definition of symbolic path names
1898 """show definition of symbolic path names
1935
1899
1936 Show definition of symbolic path name NAME. If no name is given, show
1900 Show definition of symbolic path name NAME. If no name is given, show
1937 definition of available names.
1901 definition of available names.
1938
1902
1939 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1903 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1940 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1904 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1941 """
1905 """
1942 if search:
1906 if search:
1943 for name, path in ui.configitems("paths"):
1907 for name, path in ui.configitems("paths"):
1944 if name == search:
1908 if name == search:
1945 ui.write("%s\n" % path)
1909 ui.write("%s\n" % path)
1946 return
1910 return
1947 ui.warn(_("not found!\n"))
1911 ui.warn(_("not found!\n"))
1948 return 1
1912 return 1
1949 else:
1913 else:
1950 for name, path in ui.configitems("paths"):
1914 for name, path in ui.configitems("paths"):
1951 ui.write("%s = %s\n" % (name, path))
1915 ui.write("%s = %s\n" % (name, path))
1952
1916
1953 def postincoming(ui, repo, modheads, optupdate):
1917 def postincoming(ui, repo, modheads, optupdate):
1954 if modheads == 0:
1918 if modheads == 0:
1955 return
1919 return
1956 if optupdate:
1920 if optupdate:
1957 if modheads == 1:
1921 if modheads == 1:
1958 return hg.update(repo, repo.changelog.tip()) # update
1922 return hg.update(repo, repo.changelog.tip()) # update
1959 else:
1923 else:
1960 ui.status(_("not updating, since new heads added\n"))
1924 ui.status(_("not updating, since new heads added\n"))
1961 if modheads > 1:
1925 if modheads > 1:
1962 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1926 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1963 else:
1927 else:
1964 ui.status(_("(run 'hg update' to get a working copy)\n"))
1928 ui.status(_("(run 'hg update' to get a working copy)\n"))
1965
1929
1966 def pull(ui, repo, source="default", **opts):
1930 def pull(ui, repo, source="default", **opts):
1967 """pull changes from the specified source
1931 """pull changes from the specified source
1968
1932
1969 Pull changes from a remote repository to a local one.
1933 Pull changes from a remote repository to a local one.
1970
1934
1971 This finds all changes from the repository at the specified path
1935 This finds all changes from the repository at the specified path
1972 or URL and adds them to the local repository. By default, this
1936 or URL and adds them to the local repository. By default, this
1973 does not update the copy of the project in the working directory.
1937 does not update the copy of the project in the working directory.
1974
1938
1975 Valid URLs are of the form:
1939 Valid URLs are of the form:
1976
1940
1977 local/filesystem/path (or file://local/filesystem/path)
1941 local/filesystem/path (or file://local/filesystem/path)
1978 http://[user@]host[:port]/[path]
1942 http://[user@]host[:port]/[path]
1979 https://[user@]host[:port]/[path]
1943 https://[user@]host[:port]/[path]
1980 ssh://[user@]host[:port]/[path]
1944 ssh://[user@]host[:port]/[path]
1981 static-http://host[:port]/[path]
1945 static-http://host[:port]/[path]
1982
1946
1983 Paths in the local filesystem can either point to Mercurial
1947 Paths in the local filesystem can either point to Mercurial
1984 repositories or to bundle files (as created by 'hg bundle' or
1948 repositories or to bundle files (as created by 'hg bundle' or
1985 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1949 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1986 allows access to a Mercurial repository where you simply use a web
1950 allows access to a Mercurial repository where you simply use a web
1987 server to publish the .hg directory as static content.
1951 server to publish the .hg directory as static content.
1988
1952
1989 An optional identifier after # indicates a particular branch, tag,
1953 An optional identifier after # indicates a particular branch, tag,
1990 or changeset to pull.
1954 or changeset to pull.
1991
1955
1992 Some notes about using SSH with Mercurial:
1956 Some notes about using SSH with Mercurial:
1993 - SSH requires an accessible shell account on the destination machine
1957 - SSH requires an accessible shell account on the destination machine
1994 and a copy of hg in the remote path or specified with as remotecmd.
1958 and a copy of hg in the remote path or specified with as remotecmd.
1995 - path is relative to the remote user's home directory by default.
1959 - path is relative to the remote user's home directory by default.
1996 Use an extra slash at the start of a path to specify an absolute path:
1960 Use an extra slash at the start of a path to specify an absolute path:
1997 ssh://example.com//tmp/repository
1961 ssh://example.com//tmp/repository
1998 - Mercurial doesn't use its own compression via SSH; the right thing
1962 - Mercurial doesn't use its own compression via SSH; the right thing
1999 to do is to configure it in your ~/.ssh/config, e.g.:
1963 to do is to configure it in your ~/.ssh/config, e.g.:
2000 Host *.mylocalnetwork.example.com
1964 Host *.mylocalnetwork.example.com
2001 Compression no
1965 Compression no
2002 Host *
1966 Host *
2003 Compression yes
1967 Compression yes
2004 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1968 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2005 with the --ssh command line option.
1969 with the --ssh command line option.
2006 """
1970 """
2007 source, revs = cmdutil.parseurl(ui.expandpath(source), opts['rev'])
1971 source, revs = cmdutil.parseurl(ui.expandpath(source), opts['rev'])
2008 setremoteconfig(ui, opts)
1972 cmdutil.setremoteconfig(ui, opts)
2009
1973
2010 other = hg.repository(ui, source)
1974 other = hg.repository(ui, source)
2011 ui.status(_('pulling from %s\n') % (source))
1975 ui.status(_('pulling from %s\n') % (source))
2012 if revs:
1976 if revs:
2013 if 'lookup' in other.capabilities:
1977 if 'lookup' in other.capabilities:
2014 revs = [other.lookup(rev) for rev in revs]
1978 revs = [other.lookup(rev) for rev in revs]
2015 else:
1979 else:
2016 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1980 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
2017 raise util.Abort(error)
1981 raise util.Abort(error)
2018
1982
2019 modheads = repo.pull(other, heads=revs, force=opts['force'])
1983 modheads = repo.pull(other, heads=revs, force=opts['force'])
2020 return postincoming(ui, repo, modheads, opts['update'])
1984 return postincoming(ui, repo, modheads, opts['update'])
2021
1985
2022 def push(ui, repo, dest=None, **opts):
1986 def push(ui, repo, dest=None, **opts):
2023 """push changes to the specified destination
1987 """push changes to the specified destination
2024
1988
2025 Push changes from the local repository to the given destination.
1989 Push changes from the local repository to the given destination.
2026
1990
2027 This is the symmetrical operation for pull. It helps to move
1991 This is the symmetrical operation for pull. It helps to move
2028 changes from the current repository to a different one. If the
1992 changes from the current repository to a different one. If the
2029 destination is local this is identical to a pull in that directory
1993 destination is local this is identical to a pull in that directory
2030 from the current one.
1994 from the current one.
2031
1995
2032 By default, push will refuse to run if it detects the result would
1996 By default, push will refuse to run if it detects the result would
2033 increase the number of remote heads. This generally indicates the
1997 increase the number of remote heads. This generally indicates the
2034 the client has forgotten to sync and merge before pushing.
1998 the client has forgotten to sync and merge before pushing.
2035
1999
2036 Valid URLs are of the form:
2000 Valid URLs are of the form:
2037
2001
2038 local/filesystem/path (or file://local/filesystem/path)
2002 local/filesystem/path (or file://local/filesystem/path)
2039 ssh://[user@]host[:port]/[path]
2003 ssh://[user@]host[:port]/[path]
2040 http://[user@]host[:port]/[path]
2004 http://[user@]host[:port]/[path]
2041 https://[user@]host[:port]/[path]
2005 https://[user@]host[:port]/[path]
2042
2006
2043 An optional identifier after # indicates a particular branch, tag,
2007 An optional identifier after # indicates a particular branch, tag,
2044 or changeset to push.
2008 or changeset to push.
2045
2009
2046 Look at the help text for the pull command for important details
2010 Look at the help text for the pull command for important details
2047 about ssh:// URLs.
2011 about ssh:// URLs.
2048
2012
2049 Pushing to http:// and https:// URLs is only possible, if this
2013 Pushing to http:// and https:// URLs is only possible, if this
2050 feature is explicitly enabled on the remote Mercurial server.
2014 feature is explicitly enabled on the remote Mercurial server.
2051 """
2015 """
2052 dest, revs = cmdutil.parseurl(
2016 dest, revs = cmdutil.parseurl(
2053 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
2017 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
2054 setremoteconfig(ui, opts)
2018 cmdutil.setremoteconfig(ui, opts)
2055
2019
2056 other = hg.repository(ui, dest)
2020 other = hg.repository(ui, dest)
2057 ui.status('pushing to %s\n' % (dest))
2021 ui.status('pushing to %s\n' % (dest))
2058 if revs:
2022 if revs:
2059 revs = [repo.lookup(rev) for rev in revs]
2023 revs = [repo.lookup(rev) for rev in revs]
2060 r = repo.push(other, opts['force'], revs=revs)
2024 r = repo.push(other, opts['force'], revs=revs)
2061 return r == 0
2025 return r == 0
2062
2026
2063 def rawcommit(ui, repo, *pats, **opts):
2027 def rawcommit(ui, repo, *pats, **opts):
2064 """raw commit interface (DEPRECATED)
2028 """raw commit interface (DEPRECATED)
2065
2029
2066 (DEPRECATED)
2030 (DEPRECATED)
2067 Lowlevel commit, for use in helper scripts.
2031 Lowlevel commit, for use in helper scripts.
2068
2032
2069 This command is not intended to be used by normal users, as it is
2033 This command is not intended to be used by normal users, as it is
2070 primarily useful for importing from other SCMs.
2034 primarily useful for importing from other SCMs.
2071
2035
2072 This command is now deprecated and will be removed in a future
2036 This command is now deprecated and will be removed in a future
2073 release, please use debugsetparents and commit instead.
2037 release, please use debugsetparents and commit instead.
2074 """
2038 """
2075
2039
2076 ui.warn(_("(the rawcommit command is deprecated)\n"))
2040 ui.warn(_("(the rawcommit command is deprecated)\n"))
2077
2041
2078 message = logmessage(opts)
2042 message = cmdutil.logmessage(opts)
2079
2043
2080 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2044 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2081 if opts['files']:
2045 if opts['files']:
2082 files += open(opts['files']).read().splitlines()
2046 files += open(opts['files']).read().splitlines()
2083
2047
2084 parents = [repo.lookup(p) for p in opts['parent']]
2048 parents = [repo.lookup(p) for p in opts['parent']]
2085
2049
2086 try:
2050 try:
2087 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2051 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2088 except ValueError, inst:
2052 except ValueError, inst:
2089 raise util.Abort(str(inst))
2053 raise util.Abort(str(inst))
2090
2054
2091 def recover(ui, repo):
2055 def recover(ui, repo):
2092 """roll back an interrupted transaction
2056 """roll back an interrupted transaction
2093
2057
2094 Recover from an interrupted commit or pull.
2058 Recover from an interrupted commit or pull.
2095
2059
2096 This command tries to fix the repository status after an interrupted
2060 This command tries to fix the repository status after an interrupted
2097 operation. It should only be necessary when Mercurial suggests it.
2061 operation. It should only be necessary when Mercurial suggests it.
2098 """
2062 """
2099 if repo.recover():
2063 if repo.recover():
2100 return hg.verify(repo)
2064 return hg.verify(repo)
2101 return 1
2065 return 1
2102
2066
2103 def remove(ui, repo, *pats, **opts):
2067 def remove(ui, repo, *pats, **opts):
2104 """remove the specified files on the next commit
2068 """remove the specified files on the next commit
2105
2069
2106 Schedule the indicated files for removal from the repository.
2070 Schedule the indicated files for removal from the repository.
2107
2071
2108 This only removes files from the current branch, not from the
2072 This only removes files from the current branch, not from the
2109 entire project history. If the files still exist in the working
2073 entire project history. If the files still exist in the working
2110 directory, they will be deleted from it. If invoked with --after,
2074 directory, they will be deleted from it. If invoked with --after,
2111 files are marked as removed, but not actually unlinked unless --force
2075 files are marked as removed, but not actually unlinked unless --force
2112 is also given. Without exact file names, --after will only mark
2076 is also given. Without exact file names, --after will only mark
2113 files as removed if they are no longer in the working directory.
2077 files as removed if they are no longer in the working directory.
2114
2078
2115 This command schedules the files to be removed at the next commit.
2079 This command schedules the files to be removed at the next commit.
2116 To undo a remove before that, see hg revert.
2080 To undo a remove before that, see hg revert.
2117
2081
2118 Modified files and added files are not removed by default. To
2082 Modified files and added files are not removed by default. To
2119 remove them, use the -f/--force option.
2083 remove them, use the -f/--force option.
2120 """
2084 """
2121 names = []
2085 names = []
2122 if not opts['after'] and not pats:
2086 if not opts['after'] and not pats:
2123 raise util.Abort(_('no files specified'))
2087 raise util.Abort(_('no files specified'))
2124 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2088 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2125 exact = dict.fromkeys(files)
2089 exact = dict.fromkeys(files)
2126 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2090 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2127 modified, added, removed, deleted, unknown = mardu
2091 modified, added, removed, deleted, unknown = mardu
2128 remove, forget = [], []
2092 remove, forget = [], []
2129 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2093 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2130 reason = None
2094 reason = None
2131 if abs in modified and not opts['force']:
2095 if abs in modified and not opts['force']:
2132 reason = _('is modified (use -f to force removal)')
2096 reason = _('is modified (use -f to force removal)')
2133 elif abs in added:
2097 elif abs in added:
2134 if opts['force']:
2098 if opts['force']:
2135 forget.append(abs)
2099 forget.append(abs)
2136 continue
2100 continue
2137 reason = _('has been marked for add (use -f to force removal)')
2101 reason = _('has been marked for add (use -f to force removal)')
2138 elif abs in unknown:
2102 elif abs in unknown:
2139 reason = _('is not managed')
2103 reason = _('is not managed')
2140 elif opts['after'] and not exact and abs not in deleted:
2104 elif opts['after'] and not exact and abs not in deleted:
2141 continue
2105 continue
2142 elif abs in removed:
2106 elif abs in removed:
2143 continue
2107 continue
2144 if reason:
2108 if reason:
2145 if exact:
2109 if exact:
2146 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2110 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2147 else:
2111 else:
2148 if ui.verbose or not exact:
2112 if ui.verbose or not exact:
2149 ui.status(_('removing %s\n') % rel)
2113 ui.status(_('removing %s\n') % rel)
2150 remove.append(abs)
2114 remove.append(abs)
2151 repo.forget(forget)
2115 repo.forget(forget)
2152 repo.remove(remove, unlink=opts['force'] or not opts['after'])
2116 repo.remove(remove, unlink=opts['force'] or not opts['after'])
2153
2117
2154 def rename(ui, repo, *pats, **opts):
2118 def rename(ui, repo, *pats, **opts):
2155 """rename files; equivalent of copy + remove
2119 """rename files; equivalent of copy + remove
2156
2120
2157 Mark dest as copies of sources; mark sources for deletion. If
2121 Mark dest as copies of sources; mark sources for deletion. If
2158 dest is a directory, copies are put in that directory. If dest is
2122 dest is a directory, copies are put in that directory. If dest is
2159 a file, there can only be one source.
2123 a file, there can only be one source.
2160
2124
2161 By default, this command copies the contents of files as they
2125 By default, this command copies the contents of files as they
2162 stand in the working directory. If invoked with --after, the
2126 stand in the working directory. If invoked with --after, the
2163 operation is recorded, but no copying is performed.
2127 operation is recorded, but no copying is performed.
2164
2128
2165 This command takes effect in the next commit. To undo a rename
2129 This command takes effect in the next commit. To undo a rename
2166 before that, see hg revert.
2130 before that, see hg revert.
2167 """
2131 """
2168 wlock = repo.wlock(0)
2132 wlock = repo.wlock(0)
2169 errs, copied = docopy(ui, repo, pats, opts, wlock)
2133 errs, copied = docopy(ui, repo, pats, opts, wlock)
2170 names = []
2134 names = []
2171 for abs, rel, exact in copied:
2135 for abs, rel, exact in copied:
2172 if ui.verbose or not exact:
2136 if ui.verbose or not exact:
2173 ui.status(_('removing %s\n') % rel)
2137 ui.status(_('removing %s\n') % rel)
2174 names.append(abs)
2138 names.append(abs)
2175 if not opts.get('dry_run'):
2139 if not opts.get('dry_run'):
2176 repo.remove(names, True, wlock=wlock)
2140 repo.remove(names, True, wlock=wlock)
2177 return errs
2141 return errs
2178
2142
2179 def revert(ui, repo, *pats, **opts):
2143 def revert(ui, repo, *pats, **opts):
2180 """revert files or dirs to their states as of some revision
2144 """revert files or dirs to their states as of some revision
2181
2145
2182 With no revision specified, revert the named files or directories
2146 With no revision specified, revert the named files or directories
2183 to the contents they had in the parent of the working directory.
2147 to the contents they had in the parent of the working directory.
2184 This restores the contents of the affected files to an unmodified
2148 This restores the contents of the affected files to an unmodified
2185 state and unschedules adds, removes, copies, and renames. If the
2149 state and unschedules adds, removes, copies, and renames. If the
2186 working directory has two parents, you must explicitly specify the
2150 working directory has two parents, you must explicitly specify the
2187 revision to revert to.
2151 revision to revert to.
2188
2152
2189 Modified files are saved with a .orig suffix before reverting.
2153 Modified files are saved with a .orig suffix before reverting.
2190 To disable these backups, use --no-backup.
2154 To disable these backups, use --no-backup.
2191
2155
2192 Using the -r option, revert the given files or directories to their
2156 Using the -r option, revert the given files or directories to their
2193 contents as of a specific revision. This can be helpful to "roll
2157 contents as of a specific revision. This can be helpful to "roll
2194 back" some or all of a change that should not have been committed.
2158 back" some or all of a change that should not have been committed.
2195
2159
2196 Revert modifies the working directory. It does not commit any
2160 Revert modifies the working directory. It does not commit any
2197 changes, or change the parent of the working directory. If you
2161 changes, or change the parent of the working directory. If you
2198 revert to a revision other than the parent of the working
2162 revert to a revision other than the parent of the working
2199 directory, the reverted files will thus appear modified
2163 directory, the reverted files will thus appear modified
2200 afterwards.
2164 afterwards.
2201
2165
2202 If a file has been deleted, it is recreated. If the executable
2166 If a file has been deleted, it is recreated. If the executable
2203 mode of a file was changed, it is reset.
2167 mode of a file was changed, it is reset.
2204
2168
2205 If names are given, all files matching the names are reverted.
2169 If names are given, all files matching the names are reverted.
2206
2170
2207 If no arguments are given, no files are reverted.
2171 If no arguments are given, no files are reverted.
2208 """
2172 """
2209
2173
2210 if opts["date"]:
2174 if opts["date"]:
2211 if opts["rev"]:
2175 if opts["rev"]:
2212 raise util.Abort(_("you can't specify a revision and a date"))
2176 raise util.Abort(_("you can't specify a revision and a date"))
2213 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2177 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2214
2178
2215 if not pats and not opts['all']:
2179 if not pats and not opts['all']:
2216 raise util.Abort(_('no files or directories specified; '
2180 raise util.Abort(_('no files or directories specified; '
2217 'use --all to revert the whole repo'))
2181 'use --all to revert the whole repo'))
2218
2182
2219 parent, p2 = repo.dirstate.parents()
2183 parent, p2 = repo.dirstate.parents()
2220 if not opts['rev'] and p2 != nullid:
2184 if not opts['rev'] and p2 != nullid:
2221 raise util.Abort(_('uncommitted merge - please provide a '
2185 raise util.Abort(_('uncommitted merge - please provide a '
2222 'specific revision'))
2186 'specific revision'))
2223 ctx = repo.changectx(opts['rev'])
2187 ctx = repo.changectx(opts['rev'])
2224 node = ctx.node()
2188 node = ctx.node()
2225 mf = ctx.manifest()
2189 mf = ctx.manifest()
2226 if node == parent:
2190 if node == parent:
2227 pmf = mf
2191 pmf = mf
2228 else:
2192 else:
2229 pmf = None
2193 pmf = None
2230
2194
2231 wlock = repo.wlock()
2195 wlock = repo.wlock()
2232
2196
2233 # need all matching names in dirstate and manifest of target rev,
2197 # need all matching names in dirstate and manifest of target rev,
2234 # so have to walk both. do not print errors if files exist in one
2198 # so have to walk both. do not print errors if files exist in one
2235 # but not other.
2199 # but not other.
2236
2200
2237 names = {}
2201 names = {}
2238 target_only = {}
2202 target_only = {}
2239
2203
2240 # walk dirstate.
2204 # walk dirstate.
2241
2205
2242 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2206 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2243 badmatch=mf.has_key):
2207 badmatch=mf.has_key):
2244 names[abs] = (rel, exact)
2208 names[abs] = (rel, exact)
2245 if src == 'b':
2209 if src == 'b':
2246 target_only[abs] = True
2210 target_only[abs] = True
2247
2211
2248 # walk target manifest.
2212 # walk target manifest.
2249
2213
2250 def badmatch(path):
2214 def badmatch(path):
2251 if path in names:
2215 if path in names:
2252 return True
2216 return True
2253 path_ = path + '/'
2217 path_ = path + '/'
2254 for f in names:
2218 for f in names:
2255 if f.startswith(path_):
2219 if f.startswith(path_):
2256 return True
2220 return True
2257 return False
2221 return False
2258
2222
2259 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2223 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2260 badmatch=badmatch):
2224 badmatch=badmatch):
2261 if abs in names or src == 'b':
2225 if abs in names or src == 'b':
2262 continue
2226 continue
2263 names[abs] = (rel, exact)
2227 names[abs] = (rel, exact)
2264 target_only[abs] = True
2228 target_only[abs] = True
2265
2229
2266 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2230 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2267 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2231 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2268
2232
2269 revert = ([], _('reverting %s\n'))
2233 revert = ([], _('reverting %s\n'))
2270 add = ([], _('adding %s\n'))
2234 add = ([], _('adding %s\n'))
2271 remove = ([], _('removing %s\n'))
2235 remove = ([], _('removing %s\n'))
2272 forget = ([], _('forgetting %s\n'))
2236 forget = ([], _('forgetting %s\n'))
2273 undelete = ([], _('undeleting %s\n'))
2237 undelete = ([], _('undeleting %s\n'))
2274 update = {}
2238 update = {}
2275
2239
2276 disptable = (
2240 disptable = (
2277 # dispatch table:
2241 # dispatch table:
2278 # file state
2242 # file state
2279 # action if in target manifest
2243 # action if in target manifest
2280 # action if not in target manifest
2244 # action if not in target manifest
2281 # make backup if in target manifest
2245 # make backup if in target manifest
2282 # make backup if not in target manifest
2246 # make backup if not in target manifest
2283 (modified, revert, remove, True, True),
2247 (modified, revert, remove, True, True),
2284 (added, revert, forget, True, False),
2248 (added, revert, forget, True, False),
2285 (removed, undelete, None, False, False),
2249 (removed, undelete, None, False, False),
2286 (deleted, revert, remove, False, False),
2250 (deleted, revert, remove, False, False),
2287 (unknown, add, None, True, False),
2251 (unknown, add, None, True, False),
2288 (target_only, add, None, False, False),
2252 (target_only, add, None, False, False),
2289 )
2253 )
2290
2254
2291 entries = names.items()
2255 entries = names.items()
2292 entries.sort()
2256 entries.sort()
2293
2257
2294 for abs, (rel, exact) in entries:
2258 for abs, (rel, exact) in entries:
2295 mfentry = mf.get(abs)
2259 mfentry = mf.get(abs)
2296 target = repo.wjoin(abs)
2260 target = repo.wjoin(abs)
2297 def handle(xlist, dobackup):
2261 def handle(xlist, dobackup):
2298 xlist[0].append(abs)
2262 xlist[0].append(abs)
2299 update[abs] = 1
2263 update[abs] = 1
2300 if (dobackup and not opts['no_backup'] and
2264 if (dobackup and not opts['no_backup'] and
2301 (os.path.islink(target) or os.path.exists(target))):
2265 (os.path.islink(target) or os.path.exists(target))):
2302 bakname = "%s.orig" % rel
2266 bakname = "%s.orig" % rel
2303 ui.note(_('saving current version of %s as %s\n') %
2267 ui.note(_('saving current version of %s as %s\n') %
2304 (rel, bakname))
2268 (rel, bakname))
2305 if not opts.get('dry_run'):
2269 if not opts.get('dry_run'):
2306 util.copyfile(target, bakname)
2270 util.copyfile(target, bakname)
2307 if ui.verbose or not exact:
2271 if ui.verbose or not exact:
2308 ui.status(xlist[1] % rel)
2272 ui.status(xlist[1] % rel)
2309 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2273 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2310 if abs not in table: continue
2274 if abs not in table: continue
2311 # file has changed in dirstate
2275 # file has changed in dirstate
2312 if mfentry:
2276 if mfentry:
2313 handle(hitlist, backuphit)
2277 handle(hitlist, backuphit)
2314 elif misslist is not None:
2278 elif misslist is not None:
2315 handle(misslist, backupmiss)
2279 handle(misslist, backupmiss)
2316 else:
2280 else:
2317 if exact: ui.warn(_('file not managed: %s\n') % rel)
2281 if exact: ui.warn(_('file not managed: %s\n') % rel)
2318 break
2282 break
2319 else:
2283 else:
2320 # file has not changed in dirstate
2284 # file has not changed in dirstate
2321 if node == parent:
2285 if node == parent:
2322 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2286 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2323 continue
2287 continue
2324 if pmf is None:
2288 if pmf is None:
2325 # only need parent manifest in this unlikely case,
2289 # only need parent manifest in this unlikely case,
2326 # so do not read by default
2290 # so do not read by default
2327 pmf = repo.changectx(parent).manifest()
2291 pmf = repo.changectx(parent).manifest()
2328 if abs in pmf:
2292 if abs in pmf:
2329 if mfentry:
2293 if mfentry:
2330 # if version of file is same in parent and target
2294 # if version of file is same in parent and target
2331 # manifests, do nothing
2295 # manifests, do nothing
2332 if pmf[abs] != mfentry:
2296 if pmf[abs] != mfentry:
2333 handle(revert, False)
2297 handle(revert, False)
2334 else:
2298 else:
2335 handle(remove, False)
2299 handle(remove, False)
2336
2300
2337 if not opts.get('dry_run'):
2301 if not opts.get('dry_run'):
2338 repo.dirstate.forget(forget[0])
2302 repo.dirstate.forget(forget[0])
2339 r = hg.revert(repo, node, update.has_key, wlock)
2303 r = hg.revert(repo, node, update.has_key, wlock)
2340 repo.dirstate.update(add[0], 'a')
2304 repo.dirstate.update(add[0], 'a')
2341 repo.dirstate.update(undelete[0], 'n')
2305 repo.dirstate.update(undelete[0], 'n')
2342 repo.dirstate.update(remove[0], 'r')
2306 repo.dirstate.update(remove[0], 'r')
2343 return r
2307 return r
2344
2308
2345 def rollback(ui, repo):
2309 def rollback(ui, repo):
2346 """roll back the last transaction in this repository
2310 """roll back the last transaction in this repository
2347
2311
2348 Roll back the last transaction in this repository, restoring the
2312 Roll back the last transaction in this repository, restoring the
2349 project to its state prior to the transaction.
2313 project to its state prior to the transaction.
2350
2314
2351 Transactions are used to encapsulate the effects of all commands
2315 Transactions are used to encapsulate the effects of all commands
2352 that create new changesets or propagate existing changesets into a
2316 that create new changesets or propagate existing changesets into a
2353 repository. For example, the following commands are transactional,
2317 repository. For example, the following commands are transactional,
2354 and their effects can be rolled back:
2318 and their effects can be rolled back:
2355
2319
2356 commit
2320 commit
2357 import
2321 import
2358 pull
2322 pull
2359 push (with this repository as destination)
2323 push (with this repository as destination)
2360 unbundle
2324 unbundle
2361
2325
2362 This command should be used with care. There is only one level of
2326 This command should be used with care. There is only one level of
2363 rollback, and there is no way to undo a rollback.
2327 rollback, and there is no way to undo a rollback.
2364
2328
2365 This command is not intended for use on public repositories. Once
2329 This command is not intended for use on public repositories. Once
2366 changes are visible for pull by other users, rolling a transaction
2330 changes are visible for pull by other users, rolling a transaction
2367 back locally is ineffective (someone else may already have pulled
2331 back locally is ineffective (someone else may already have pulled
2368 the changes). Furthermore, a race is possible with readers of the
2332 the changes). Furthermore, a race is possible with readers of the
2369 repository; for example an in-progress pull from the repository
2333 repository; for example an in-progress pull from the repository
2370 may fail if a rollback is performed.
2334 may fail if a rollback is performed.
2371 """
2335 """
2372 repo.rollback()
2336 repo.rollback()
2373
2337
2374 def root(ui, repo):
2338 def root(ui, repo):
2375 """print the root (top) of the current working dir
2339 """print the root (top) of the current working dir
2376
2340
2377 Print the root directory of the current repository.
2341 Print the root directory of the current repository.
2378 """
2342 """
2379 ui.write(repo.root + "\n")
2343 ui.write(repo.root + "\n")
2380
2344
2381 def serve(ui, repo, **opts):
2345 def serve(ui, repo, **opts):
2382 """export the repository via HTTP
2346 """export the repository via HTTP
2383
2347
2384 Start a local HTTP repository browser and pull server.
2348 Start a local HTTP repository browser and pull server.
2385
2349
2386 By default, the server logs accesses to stdout and errors to
2350 By default, the server logs accesses to stdout and errors to
2387 stderr. Use the "-A" and "-E" options to log to files.
2351 stderr. Use the "-A" and "-E" options to log to files.
2388 """
2352 """
2389
2353
2390 if opts["stdio"]:
2354 if opts["stdio"]:
2391 if repo is None:
2355 if repo is None:
2392 raise hg.RepoError(_("There is no Mercurial repository here"
2356 raise hg.RepoError(_("There is no Mercurial repository here"
2393 " (.hg not found)"))
2357 " (.hg not found)"))
2394 s = sshserver.sshserver(ui, repo)
2358 s = sshserver.sshserver(ui, repo)
2395 s.serve_forever()
2359 s.serve_forever()
2396
2360
2397 parentui = ui.parentui or ui
2361 parentui = ui.parentui or ui
2398 optlist = ("name templates style address port ipv6"
2362 optlist = ("name templates style address port ipv6"
2399 " accesslog errorlog webdir_conf")
2363 " accesslog errorlog webdir_conf")
2400 for o in optlist.split():
2364 for o in optlist.split():
2401 if opts[o]:
2365 if opts[o]:
2402 parentui.setconfig("web", o, str(opts[o]))
2366 parentui.setconfig("web", o, str(opts[o]))
2403
2367
2404 if repo is None and not ui.config("web", "webdir_conf"):
2368 if repo is None and not ui.config("web", "webdir_conf"):
2405 raise hg.RepoError(_("There is no Mercurial repository here"
2369 raise hg.RepoError(_("There is no Mercurial repository here"
2406 " (.hg not found)"))
2370 " (.hg not found)"))
2407
2371
2408 class service:
2372 class service:
2409 def init(self):
2373 def init(self):
2410 try:
2374 try:
2411 self.httpd = hgweb.server.create_server(parentui, repo)
2375 self.httpd = hgweb.server.create_server(parentui, repo)
2412 except socket.error, inst:
2376 except socket.error, inst:
2413 raise util.Abort(_('cannot start server: ') + inst.args[1])
2377 raise util.Abort(_('cannot start server: ') + inst.args[1])
2414
2378
2415 if not ui.verbose: return
2379 if not ui.verbose: return
2416
2380
2417 if self.httpd.port != 80:
2381 if self.httpd.port != 80:
2418 ui.status(_('listening at http://%s:%d/\n') %
2382 ui.status(_('listening at http://%s:%d/\n') %
2419 (self.httpd.addr, self.httpd.port))
2383 (self.httpd.addr, self.httpd.port))
2420 else:
2384 else:
2421 ui.status(_('listening at http://%s/\n') % self.httpd.addr)
2385 ui.status(_('listening at http://%s/\n') % self.httpd.addr)
2422
2386
2423 def run(self):
2387 def run(self):
2424 self.httpd.serve_forever()
2388 self.httpd.serve_forever()
2425
2389
2426 service = service()
2390 service = service()
2427
2391
2428 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2392 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2429
2393
2430 def status(ui, repo, *pats, **opts):
2394 def status(ui, repo, *pats, **opts):
2431 """show changed files in the working directory
2395 """show changed files in the working directory
2432
2396
2433 Show status of files in the repository. If names are given, only
2397 Show status of files in the repository. If names are given, only
2434 files that match are shown. Files that are clean or ignored, are
2398 files that match are shown. Files that are clean or ignored, are
2435 not listed unless -c (clean), -i (ignored) or -A is given.
2399 not listed unless -c (clean), -i (ignored) or -A is given.
2436
2400
2437 NOTE: status may appear to disagree with diff if permissions have
2401 NOTE: status may appear to disagree with diff if permissions have
2438 changed or a merge has occurred. The standard diff format does not
2402 changed or a merge has occurred. The standard diff format does not
2439 report permission changes and diff only reports changes relative
2403 report permission changes and diff only reports changes relative
2440 to one merge parent.
2404 to one merge parent.
2441
2405
2442 If one revision is given, it is used as the base revision.
2406 If one revision is given, it is used as the base revision.
2443 If two revisions are given, the difference between them is shown.
2407 If two revisions are given, the difference between them is shown.
2444
2408
2445 The codes used to show the status of files are:
2409 The codes used to show the status of files are:
2446 M = modified
2410 M = modified
2447 A = added
2411 A = added
2448 R = removed
2412 R = removed
2449 C = clean
2413 C = clean
2450 ! = deleted, but still tracked
2414 ! = deleted, but still tracked
2451 ? = not tracked
2415 ? = not tracked
2452 I = ignored (not shown by default)
2416 I = ignored (not shown by default)
2453 = the previous added file was copied from here
2417 = the previous added file was copied from here
2454 """
2418 """
2455
2419
2456 all = opts['all']
2420 all = opts['all']
2457 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2421 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2458
2422
2459 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2423 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2460 cwd = (pats and repo.getcwd()) or ''
2424 cwd = (pats and repo.getcwd()) or ''
2461 modified, added, removed, deleted, unknown, ignored, clean = [
2425 modified, added, removed, deleted, unknown, ignored, clean = [
2462 n for n in repo.status(node1=node1, node2=node2, files=files,
2426 n for n in repo.status(node1=node1, node2=node2, files=files,
2463 match=matchfn,
2427 match=matchfn,
2464 list_ignored=all or opts['ignored'],
2428 list_ignored=all or opts['ignored'],
2465 list_clean=all or opts['clean'])]
2429 list_clean=all or opts['clean'])]
2466
2430
2467 changetypes = (('modified', 'M', modified),
2431 changetypes = (('modified', 'M', modified),
2468 ('added', 'A', added),
2432 ('added', 'A', added),
2469 ('removed', 'R', removed),
2433 ('removed', 'R', removed),
2470 ('deleted', '!', deleted),
2434 ('deleted', '!', deleted),
2471 ('unknown', '?', unknown),
2435 ('unknown', '?', unknown),
2472 ('ignored', 'I', ignored))
2436 ('ignored', 'I', ignored))
2473
2437
2474 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2438 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2475
2439
2476 end = opts['print0'] and '\0' or '\n'
2440 end = opts['print0'] and '\0' or '\n'
2477
2441
2478 for opt, char, changes in ([ct for ct in explicit_changetypes
2442 for opt, char, changes in ([ct for ct in explicit_changetypes
2479 if all or opts[ct[0]]]
2443 if all or opts[ct[0]]]
2480 or changetypes):
2444 or changetypes):
2481 if opts['no_status']:
2445 if opts['no_status']:
2482 format = "%%s%s" % end
2446 format = "%%s%s" % end
2483 else:
2447 else:
2484 format = "%s %%s%s" % (char, end)
2448 format = "%s %%s%s" % (char, end)
2485
2449
2486 for f in changes:
2450 for f in changes:
2487 ui.write(format % repo.pathto(f, cwd))
2451 ui.write(format % repo.pathto(f, cwd))
2488 if ((all or opts.get('copies')) and not opts.get('no_status')):
2452 if ((all or opts.get('copies')) and not opts.get('no_status')):
2489 copied = repo.dirstate.copied(f)
2453 copied = repo.dirstate.copied(f)
2490 if copied:
2454 if copied:
2491 ui.write(' %s%s' % (repo.pathto(copied, cwd), end))
2455 ui.write(' %s%s' % (repo.pathto(copied, cwd), end))
2492
2456
2493 def tag(ui, repo, name, rev_=None, **opts):
2457 def tag(ui, repo, name, rev_=None, **opts):
2494 """add a tag for the current or given revision
2458 """add a tag for the current or given revision
2495
2459
2496 Name a particular revision using <name>.
2460 Name a particular revision using <name>.
2497
2461
2498 Tags are used to name particular revisions of the repository and are
2462 Tags are used to name particular revisions of the repository and are
2499 very useful to compare different revision, to go back to significant
2463 very useful to compare different revision, to go back to significant
2500 earlier versions or to mark branch points as releases, etc.
2464 earlier versions or to mark branch points as releases, etc.
2501
2465
2502 If no revision is given, the parent of the working directory is used,
2466 If no revision is given, the parent of the working directory is used,
2503 or tip if no revision is checked out.
2467 or tip if no revision is checked out.
2504
2468
2505 To facilitate version control, distribution, and merging of tags,
2469 To facilitate version control, distribution, and merging of tags,
2506 they are stored as a file named ".hgtags" which is managed
2470 they are stored as a file named ".hgtags" which is managed
2507 similarly to other project files and can be hand-edited if
2471 similarly to other project files and can be hand-edited if
2508 necessary. The file '.hg/localtags' is used for local tags (not
2472 necessary. The file '.hg/localtags' is used for local tags (not
2509 shared among repositories).
2473 shared among repositories).
2510 """
2474 """
2511 if name in ['tip', '.', 'null']:
2475 if name in ['tip', '.', 'null']:
2512 raise util.Abort(_("the name '%s' is reserved") % name)
2476 raise util.Abort(_("the name '%s' is reserved") % name)
2513 if rev_ is not None:
2477 if rev_ is not None:
2514 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2478 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2515 "please use 'hg tag [-r REV] NAME' instead\n"))
2479 "please use 'hg tag [-r REV] NAME' instead\n"))
2516 if opts['rev']:
2480 if opts['rev']:
2517 raise util.Abort(_("use only one form to specify the revision"))
2481 raise util.Abort(_("use only one form to specify the revision"))
2518 if opts['rev'] and opts['remove']:
2482 if opts['rev'] and opts['remove']:
2519 raise util.Abort(_("--rev and --remove are incompatible"))
2483 raise util.Abort(_("--rev and --remove are incompatible"))
2520 if opts['rev']:
2484 if opts['rev']:
2521 rev_ = opts['rev']
2485 rev_ = opts['rev']
2522 message = opts['message']
2486 message = opts['message']
2523 if opts['remove']:
2487 if opts['remove']:
2524 rev_ = nullid
2488 rev_ = nullid
2525 if not message:
2489 if not message:
2526 message = _('Removed tag %s') % name
2490 message = _('Removed tag %s') % name
2527 elif name in repo.tags() and not opts['force']:
2491 elif name in repo.tags() and not opts['force']:
2528 raise util.Abort(_('a tag named %s already exists (use -f to force)')
2492 raise util.Abort(_('a tag named %s already exists (use -f to force)')
2529 % name)
2493 % name)
2530 if not rev_ and repo.dirstate.parents()[1] != nullid:
2494 if not rev_ and repo.dirstate.parents()[1] != nullid:
2531 raise util.Abort(_('uncommitted merge - please provide a '
2495 raise util.Abort(_('uncommitted merge - please provide a '
2532 'specific revision'))
2496 'specific revision'))
2533 r = repo.changectx(rev_).node()
2497 r = repo.changectx(rev_).node()
2534
2498
2535 if not message:
2499 if not message:
2536 message = _('Added tag %s for changeset %s') % (name, short(r))
2500 message = _('Added tag %s for changeset %s') % (name, short(r))
2537
2501
2538 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2502 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2539
2503
2540 def tags(ui, repo):
2504 def tags(ui, repo):
2541 """list repository tags
2505 """list repository tags
2542
2506
2543 List the repository tags.
2507 List the repository tags.
2544
2508
2545 This lists both regular and local tags.
2509 This lists both regular and local tags.
2546 """
2510 """
2547
2511
2548 l = repo.tagslist()
2512 l = repo.tagslist()
2549 l.reverse()
2513 l.reverse()
2550 hexfunc = ui.debugflag and hex or short
2514 hexfunc = ui.debugflag and hex or short
2551 for t, n in l:
2515 for t, n in l:
2552 try:
2516 try:
2553 hn = hexfunc(n)
2517 hn = hexfunc(n)
2554 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2518 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2555 except revlog.LookupError:
2519 except revlog.LookupError:
2556 r = " ?:%s" % hn
2520 r = " ?:%s" % hn
2557 if ui.quiet:
2521 if ui.quiet:
2558 ui.write("%s\n" % t)
2522 ui.write("%s\n" % t)
2559 else:
2523 else:
2560 spaces = " " * (30 - util.locallen(t))
2524 spaces = " " * (30 - util.locallen(t))
2561 ui.write("%s%s %s\n" % (t, spaces, r))
2525 ui.write("%s%s %s\n" % (t, spaces, r))
2562
2526
2563 def tip(ui, repo, **opts):
2527 def tip(ui, repo, **opts):
2564 """show the tip revision
2528 """show the tip revision
2565
2529
2566 Show the tip revision.
2530 Show the tip revision.
2567 """
2531 """
2568 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2532 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2569
2533
2570 def unbundle(ui, repo, fname, **opts):
2534 def unbundle(ui, repo, fname, **opts):
2571 """apply a changegroup file
2535 """apply a changegroup file
2572
2536
2573 Apply a compressed changegroup file generated by the bundle
2537 Apply a compressed changegroup file generated by the bundle
2574 command.
2538 command.
2575 """
2539 """
2576 if os.path.exists(fname):
2540 if os.path.exists(fname):
2577 f = open(fname, "rb")
2541 f = open(fname, "rb")
2578 else:
2542 else:
2579 f = urllib.urlopen(fname)
2543 f = urllib.urlopen(fname)
2580 gen = changegroup.readbundle(f, fname)
2544 gen = changegroup.readbundle(f, fname)
2581 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2545 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2582 return postincoming(ui, repo, modheads, opts['update'])
2546 return postincoming(ui, repo, modheads, opts['update'])
2583
2547
2584 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2548 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2585 """update working directory
2549 """update working directory
2586
2550
2587 Update the working directory to the specified revision, or the
2551 Update the working directory to the specified revision, or the
2588 tip of the current branch if none is specified.
2552 tip of the current branch if none is specified.
2589
2553
2590 If there are no outstanding changes in the working directory and
2554 If there are no outstanding changes in the working directory and
2591 there is a linear relationship between the current version and the
2555 there is a linear relationship between the current version and the
2592 requested version, the result is the requested version.
2556 requested version, the result is the requested version.
2593
2557
2594 To merge the working directory with another revision, use the
2558 To merge the working directory with another revision, use the
2595 merge command.
2559 merge command.
2596
2560
2597 By default, update will refuse to run if doing so would require
2561 By default, update will refuse to run if doing so would require
2598 discarding local changes.
2562 discarding local changes.
2599 """
2563 """
2600 if rev and node:
2564 if rev and node:
2601 raise util.Abort(_("please specify just one revision"))
2565 raise util.Abort(_("please specify just one revision"))
2602
2566
2603 if not rev:
2567 if not rev:
2604 rev = node
2568 rev = node
2605
2569
2606 if date:
2570 if date:
2607 if rev:
2571 if rev:
2608 raise util.Abort(_("you can't specify a revision and a date"))
2572 raise util.Abort(_("you can't specify a revision and a date"))
2609 rev = cmdutil.finddate(ui, repo, date)
2573 rev = cmdutil.finddate(ui, repo, date)
2610
2574
2611 if clean:
2575 if clean:
2612 return hg.clean(repo, rev)
2576 return hg.clean(repo, rev)
2613 else:
2577 else:
2614 return hg.update(repo, rev)
2578 return hg.update(repo, rev)
2615
2579
2616 def verify(ui, repo):
2580 def verify(ui, repo):
2617 """verify the integrity of the repository
2581 """verify the integrity of the repository
2618
2582
2619 Verify the integrity of the current repository.
2583 Verify the integrity of the current repository.
2620
2584
2621 This will perform an extensive check of the repository's
2585 This will perform an extensive check of the repository's
2622 integrity, validating the hashes and checksums of each entry in
2586 integrity, validating the hashes and checksums of each entry in
2623 the changelog, manifest, and tracked files, as well as the
2587 the changelog, manifest, and tracked files, as well as the
2624 integrity of their crosslinks and indices.
2588 integrity of their crosslinks and indices.
2625 """
2589 """
2626 return hg.verify(repo)
2590 return hg.verify(repo)
2627
2591
2628 def version_(ui):
2592 def version_(ui):
2629 """output version and copyright information"""
2593 """output version and copyright information"""
2630 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2594 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2631 % version.get_version())
2595 % version.get_version())
2632 ui.status(_(
2596 ui.status(_(
2633 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
2597 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
2634 "This is free software; see the source for copying conditions. "
2598 "This is free software; see the source for copying conditions. "
2635 "There is NO\nwarranty; "
2599 "There is NO\nwarranty; "
2636 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2600 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2637 ))
2601 ))
2638
2602
2639 # Command options and aliases are listed here, alphabetically
2603 # Command options and aliases are listed here, alphabetically
2640
2604
2641 globalopts = [
2605 globalopts = [
2642 ('R', 'repository', '',
2606 ('R', 'repository', '',
2643 _('repository root directory or symbolic path name')),
2607 _('repository root directory or symbolic path name')),
2644 ('', 'cwd', '', _('change working directory')),
2608 ('', 'cwd', '', _('change working directory')),
2645 ('y', 'noninteractive', None,
2609 ('y', 'noninteractive', None,
2646 _('do not prompt, assume \'yes\' for any required answers')),
2610 _('do not prompt, assume \'yes\' for any required answers')),
2647 ('q', 'quiet', None, _('suppress output')),
2611 ('q', 'quiet', None, _('suppress output')),
2648 ('v', 'verbose', None, _('enable additional output')),
2612 ('v', 'verbose', None, _('enable additional output')),
2649 ('', 'config', [], _('set/override config option')),
2613 ('', 'config', [], _('set/override config option')),
2650 ('', 'debug', None, _('enable debugging output')),
2614 ('', 'debug', None, _('enable debugging output')),
2651 ('', 'debugger', None, _('start debugger')),
2615 ('', 'debugger', None, _('start debugger')),
2652 ('', 'encoding', util._encoding, _('set the charset encoding')),
2616 ('', 'encoding', util._encoding, _('set the charset encoding')),
2653 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2617 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2654 ('', 'lsprof', None, _('print improved command execution profile')),
2618 ('', 'lsprof', None, _('print improved command execution profile')),
2655 ('', 'traceback', None, _('print traceback on exception')),
2619 ('', 'traceback', None, _('print traceback on exception')),
2656 ('', 'time', None, _('time how long the command takes')),
2620 ('', 'time', None, _('time how long the command takes')),
2657 ('', 'profile', None, _('print command execution profile')),
2621 ('', 'profile', None, _('print command execution profile')),
2658 ('', 'version', None, _('output version information and exit')),
2622 ('', 'version', None, _('output version information and exit')),
2659 ('h', 'help', None, _('display help and exit')),
2623 ('h', 'help', None, _('display help and exit')),
2660 ]
2624 ]
2661
2625
2662 dryrunopts = [('n', 'dry-run', None,
2626 dryrunopts = [('n', 'dry-run', None,
2663 _('do not perform actions, just print output'))]
2627 _('do not perform actions, just print output'))]
2664
2628
2665 remoteopts = [
2629 remoteopts = [
2666 ('e', 'ssh', '', _('specify ssh command to use')),
2630 ('e', 'ssh', '', _('specify ssh command to use')),
2667 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2631 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2668 ]
2632 ]
2669
2633
2670 walkopts = [
2634 walkopts = [
2671 ('I', 'include', [], _('include names matching the given patterns')),
2635 ('I', 'include', [], _('include names matching the given patterns')),
2672 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2636 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2673 ]
2637 ]
2674
2638
2675 commitopts = [
2639 commitopts = [
2676 ('m', 'message', '', _('use <text> as commit message')),
2640 ('m', 'message', '', _('use <text> as commit message')),
2677 ('l', 'logfile', '', _('read commit message from <file>')),
2641 ('l', 'logfile', '', _('read commit message from <file>')),
2678 ]
2642 ]
2679
2643
2680 table = {
2644 table = {
2681 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2645 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2682 "addremove":
2646 "addremove":
2683 (addremove,
2647 (addremove,
2684 [('s', 'similarity', '',
2648 [('s', 'similarity', '',
2685 _('guess renamed files by similarity (0<=s<=100)')),
2649 _('guess renamed files by similarity (0<=s<=100)')),
2686 ] + walkopts + dryrunopts,
2650 ] + walkopts + dryrunopts,
2687 _('hg addremove [OPTION]... [FILE]...')),
2651 _('hg addremove [OPTION]... [FILE]...')),
2688 "^annotate":
2652 "^annotate":
2689 (annotate,
2653 (annotate,
2690 [('r', 'rev', '', _('annotate the specified revision')),
2654 [('r', 'rev', '', _('annotate the specified revision')),
2691 ('f', 'follow', None, _('follow file copies and renames')),
2655 ('f', 'follow', None, _('follow file copies and renames')),
2692 ('a', 'text', None, _('treat all files as text')),
2656 ('a', 'text', None, _('treat all files as text')),
2693 ('u', 'user', None, _('list the author')),
2657 ('u', 'user', None, _('list the author')),
2694 ('d', 'date', None, _('list the date')),
2658 ('d', 'date', None, _('list the date')),
2695 ('n', 'number', None, _('list the revision number (default)')),
2659 ('n', 'number', None, _('list the revision number (default)')),
2696 ('c', 'changeset', None, _('list the changeset')),
2660 ('c', 'changeset', None, _('list the changeset')),
2697 ] + walkopts,
2661 ] + walkopts,
2698 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] FILE...')),
2662 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] FILE...')),
2699 "archive":
2663 "archive":
2700 (archive,
2664 (archive,
2701 [('', 'no-decode', None, _('do not pass files through decoders')),
2665 [('', 'no-decode', None, _('do not pass files through decoders')),
2702 ('p', 'prefix', '', _('directory prefix for files in archive')),
2666 ('p', 'prefix', '', _('directory prefix for files in archive')),
2703 ('r', 'rev', '', _('revision to distribute')),
2667 ('r', 'rev', '', _('revision to distribute')),
2704 ('t', 'type', '', _('type of distribution to create')),
2668 ('t', 'type', '', _('type of distribution to create')),
2705 ] + walkopts,
2669 ] + walkopts,
2706 _('hg archive [OPTION]... DEST')),
2670 _('hg archive [OPTION]... DEST')),
2707 "backout":
2671 "backout":
2708 (backout,
2672 (backout,
2709 [('', 'merge', None,
2673 [('', 'merge', None,
2710 _('merge with old dirstate parent after backout')),
2674 _('merge with old dirstate parent after backout')),
2711 ('d', 'date', '', _('record datecode as commit date')),
2675 ('d', 'date', '', _('record datecode as commit date')),
2712 ('', 'parent', '', _('parent to choose when backing out merge')),
2676 ('', 'parent', '', _('parent to choose when backing out merge')),
2713 ('u', 'user', '', _('record user as committer')),
2677 ('u', 'user', '', _('record user as committer')),
2714 ('r', 'rev', '', _('revision to backout')),
2678 ('r', 'rev', '', _('revision to backout')),
2715 ] + walkopts + commitopts,
2679 ] + walkopts + commitopts,
2716 _('hg backout [OPTION]... [-r] REV')),
2680 _('hg backout [OPTION]... [-r] REV')),
2717 "branch": (branch,
2681 "branch": (branch,
2718 [('f', 'force', None,
2682 [('f', 'force', None,
2719 _('set branch name even if it shadows an existing branch'))],
2683 _('set branch name even if it shadows an existing branch'))],
2720 _('hg branch [NAME]')),
2684 _('hg branch [NAME]')),
2721 "branches": (branches, [], _('hg branches')),
2685 "branches": (branches, [], _('hg branches')),
2722 "bundle":
2686 "bundle":
2723 (bundle,
2687 (bundle,
2724 [('f', 'force', None,
2688 [('f', 'force', None,
2725 _('run even when remote repository is unrelated')),
2689 _('run even when remote repository is unrelated')),
2726 ('r', 'rev', [],
2690 ('r', 'rev', [],
2727 _('a changeset you would like to bundle')),
2691 _('a changeset you would like to bundle')),
2728 ('', 'base', [],
2692 ('', 'base', [],
2729 _('a base changeset to specify instead of a destination')),
2693 _('a base changeset to specify instead of a destination')),
2730 ] + remoteopts,
2694 ] + remoteopts,
2731 _('hg bundle [-f] [-r REV]... [--base REV]... FILE [DEST]')),
2695 _('hg bundle [-f] [-r REV]... [--base REV]... FILE [DEST]')),
2732 "cat":
2696 "cat":
2733 (cat,
2697 (cat,
2734 [('o', 'output', '', _('print output to file with formatted name')),
2698 [('o', 'output', '', _('print output to file with formatted name')),
2735 ('r', 'rev', '', _('print the given revision')),
2699 ('r', 'rev', '', _('print the given revision')),
2736 ] + walkopts,
2700 ] + walkopts,
2737 _('hg cat [OPTION]... FILE...')),
2701 _('hg cat [OPTION]... FILE...')),
2738 "^clone":
2702 "^clone":
2739 (clone,
2703 (clone,
2740 [('U', 'noupdate', None, _('do not update the new working directory')),
2704 [('U', 'noupdate', None, _('do not update the new working directory')),
2741 ('r', 'rev', [],
2705 ('r', 'rev', [],
2742 _('a changeset you would like to have after cloning')),
2706 _('a changeset you would like to have after cloning')),
2743 ('', 'pull', None, _('use pull protocol to copy metadata')),
2707 ('', 'pull', None, _('use pull protocol to copy metadata')),
2744 ('', 'uncompressed', None,
2708 ('', 'uncompressed', None,
2745 _('use uncompressed transfer (fast over LAN)')),
2709 _('use uncompressed transfer (fast over LAN)')),
2746 ] + remoteopts,
2710 ] + remoteopts,
2747 _('hg clone [OPTION]... SOURCE [DEST]')),
2711 _('hg clone [OPTION]... SOURCE [DEST]')),
2748 "^commit|ci":
2712 "^commit|ci":
2749 (commit,
2713 (commit,
2750 [('A', 'addremove', None,
2714 [('A', 'addremove', None,
2751 _('mark new/missing files as added/removed before committing')),
2715 _('mark new/missing files as added/removed before committing')),
2752 ('d', 'date', '', _('record datecode as commit date')),
2716 ('d', 'date', '', _('record datecode as commit date')),
2753 ('u', 'user', '', _('record user as commiter')),
2717 ('u', 'user', '', _('record user as commiter')),
2754 ] + walkopts + commitopts,
2718 ] + walkopts + commitopts,
2755 _('hg commit [OPTION]... [FILE]...')),
2719 _('hg commit [OPTION]... [FILE]...')),
2756 "copy|cp":
2720 "copy|cp":
2757 (copy,
2721 (copy,
2758 [('A', 'after', None, _('record a copy that has already occurred')),
2722 [('A', 'after', None, _('record a copy that has already occurred')),
2759 ('f', 'force', None,
2723 ('f', 'force', None,
2760 _('forcibly copy over an existing managed file')),
2724 _('forcibly copy over an existing managed file')),
2761 ] + walkopts + dryrunopts,
2725 ] + walkopts + dryrunopts,
2762 _('hg copy [OPTION]... [SOURCE]... DEST')),
2726 _('hg copy [OPTION]... [SOURCE]... DEST')),
2763 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2727 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2764 "debugcomplete":
2728 "debugcomplete":
2765 (debugcomplete,
2729 (debugcomplete,
2766 [('o', 'options', None, _('show the command options'))],
2730 [('o', 'options', None, _('show the command options'))],
2767 _('debugcomplete [-o] CMD')),
2731 _('debugcomplete [-o] CMD')),
2768 "debuginstall": (debuginstall, [], _('debuginstall')),
2732 "debuginstall": (debuginstall, [], _('debuginstall')),
2769 "debugrebuildstate":
2733 "debugrebuildstate":
2770 (debugrebuildstate,
2734 (debugrebuildstate,
2771 [('r', 'rev', '', _('revision to rebuild to'))],
2735 [('r', 'rev', '', _('revision to rebuild to'))],
2772 _('debugrebuildstate [-r REV] [REV]')),
2736 _('debugrebuildstate [-r REV] [REV]')),
2773 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2737 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2774 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2738 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2775 "debugstate": (debugstate, [], _('debugstate')),
2739 "debugstate": (debugstate, [], _('debugstate')),
2776 "debugdate":
2740 "debugdate":
2777 (debugdate,
2741 (debugdate,
2778 [('e', 'extended', None, _('try extended date formats'))],
2742 [('e', 'extended', None, _('try extended date formats'))],
2779 _('debugdate [-e] DATE [RANGE]')),
2743 _('debugdate [-e] DATE [RANGE]')),
2780 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2744 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2781 "debugindex": (debugindex, [], _('debugindex FILE')),
2745 "debugindex": (debugindex, [], _('debugindex FILE')),
2782 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2746 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2783 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2747 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2784 "debugwalk": (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2748 "debugwalk": (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2785 "^diff":
2749 "^diff":
2786 (diff,
2750 (diff,
2787 [('r', 'rev', [], _('revision')),
2751 [('r', 'rev', [], _('revision')),
2788 ('a', 'text', None, _('treat all files as text')),
2752 ('a', 'text', None, _('treat all files as text')),
2789 ('p', 'show-function', None,
2753 ('p', 'show-function', None,
2790 _('show which function each change is in')),
2754 _('show which function each change is in')),
2791 ('g', 'git', None, _('use git extended diff format')),
2755 ('g', 'git', None, _('use git extended diff format')),
2792 ('', 'nodates', None, _("don't include dates in diff headers")),
2756 ('', 'nodates', None, _("don't include dates in diff headers")),
2793 ('w', 'ignore-all-space', None,
2757 ('w', 'ignore-all-space', None,
2794 _('ignore white space when comparing lines')),
2758 _('ignore white space when comparing lines')),
2795 ('b', 'ignore-space-change', None,
2759 ('b', 'ignore-space-change', None,
2796 _('ignore changes in the amount of white space')),
2760 _('ignore changes in the amount of white space')),
2797 ('B', 'ignore-blank-lines', None,
2761 ('B', 'ignore-blank-lines', None,
2798 _('ignore changes whose lines are all blank')),
2762 _('ignore changes whose lines are all blank')),
2799 ] + walkopts,
2763 ] + walkopts,
2800 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2764 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2801 "^export":
2765 "^export":
2802 (export,
2766 (export,
2803 [('o', 'output', '', _('print output to file with formatted name')),
2767 [('o', 'output', '', _('print output to file with formatted name')),
2804 ('a', 'text', None, _('treat all files as text')),
2768 ('a', 'text', None, _('treat all files as text')),
2805 ('g', 'git', None, _('use git extended diff format')),
2769 ('g', 'git', None, _('use git extended diff format')),
2806 ('', 'nodates', None, _("don't include dates in diff headers")),
2770 ('', 'nodates', None, _("don't include dates in diff headers")),
2807 ('', 'switch-parent', None, _('diff against the second parent'))],
2771 ('', 'switch-parent', None, _('diff against the second parent'))],
2808 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2772 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2809 "grep":
2773 "grep":
2810 (grep,
2774 (grep,
2811 [('0', 'print0', None, _('end fields with NUL')),
2775 [('0', 'print0', None, _('end fields with NUL')),
2812 ('', 'all', None, _('print all revisions that match')),
2776 ('', 'all', None, _('print all revisions that match')),
2813 ('f', 'follow', None,
2777 ('f', 'follow', None,
2814 _('follow changeset history, or file history across copies and renames')),
2778 _('follow changeset history, or file history across copies and renames')),
2815 ('i', 'ignore-case', None, _('ignore case when matching')),
2779 ('i', 'ignore-case', None, _('ignore case when matching')),
2816 ('l', 'files-with-matches', None,
2780 ('l', 'files-with-matches', None,
2817 _('print only filenames and revs that match')),
2781 _('print only filenames and revs that match')),
2818 ('n', 'line-number', None, _('print matching line numbers')),
2782 ('n', 'line-number', None, _('print matching line numbers')),
2819 ('r', 'rev', [], _('search in given revision range')),
2783 ('r', 'rev', [], _('search in given revision range')),
2820 ('u', 'user', None, _('print user who committed change')),
2784 ('u', 'user', None, _('print user who committed change')),
2821 ] + walkopts,
2785 ] + walkopts,
2822 _('hg grep [OPTION]... PATTERN [FILE]...')),
2786 _('hg grep [OPTION]... PATTERN [FILE]...')),
2823 "heads":
2787 "heads":
2824 (heads,
2788 (heads,
2825 [('', 'style', '', _('display using template map file')),
2789 [('', 'style', '', _('display using template map file')),
2826 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2790 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2827 ('', 'template', '', _('display with template'))],
2791 ('', 'template', '', _('display with template'))],
2828 _('hg heads [-r REV]')),
2792 _('hg heads [-r REV]')),
2829 "help": (help_, [], _('hg help [COMMAND]')),
2793 "help": (help_, [], _('hg help [COMMAND]')),
2830 "identify|id": (identify, [], _('hg identify')),
2794 "identify|id": (identify, [], _('hg identify')),
2831 "import|patch":
2795 "import|patch":
2832 (import_,
2796 (import_,
2833 [('p', 'strip', 1,
2797 [('p', 'strip', 1,
2834 _('directory strip option for patch. This has the same\n'
2798 _('directory strip option for patch. This has the same\n'
2835 'meaning as the corresponding patch option')),
2799 'meaning as the corresponding patch option')),
2836 ('b', 'base', '', _('base path')),
2800 ('b', 'base', '', _('base path')),
2837 ('f', 'force', None,
2801 ('f', 'force', None,
2838 _('skip check for outstanding uncommitted changes')),
2802 _('skip check for outstanding uncommitted changes')),
2839 ('', 'exact', None,
2803 ('', 'exact', None,
2840 _('apply patch to the nodes from which it was generated'))] + commitopts,
2804 _('apply patch to the nodes from which it was generated'))] + commitopts,
2841 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2805 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2842 "incoming|in": (incoming,
2806 "incoming|in": (incoming,
2843 [('M', 'no-merges', None, _('do not show merges')),
2807 [('M', 'no-merges', None, _('do not show merges')),
2844 ('f', 'force', None,
2808 ('f', 'force', None,
2845 _('run even when remote repository is unrelated')),
2809 _('run even when remote repository is unrelated')),
2846 ('', 'style', '', _('display using template map file')),
2810 ('', 'style', '', _('display using template map file')),
2847 ('n', 'newest-first', None, _('show newest record first')),
2811 ('n', 'newest-first', None, _('show newest record first')),
2848 ('', 'bundle', '', _('file to store the bundles into')),
2812 ('', 'bundle', '', _('file to store the bundles into')),
2849 ('p', 'patch', None, _('show patch')),
2813 ('p', 'patch', None, _('show patch')),
2850 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2814 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2851 ('', 'template', '', _('display with template')),
2815 ('', 'template', '', _('display with template')),
2852 ] + remoteopts,
2816 ] + remoteopts,
2853 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2817 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2854 ' [--bundle FILENAME] [SOURCE]')),
2818 ' [--bundle FILENAME] [SOURCE]')),
2855 "^init":
2819 "^init":
2856 (init,
2820 (init,
2857 remoteopts,
2821 remoteopts,
2858 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2822 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2859 "locate":
2823 "locate":
2860 (locate,
2824 (locate,
2861 [('r', 'rev', '', _('search the repository as it stood at rev')),
2825 [('r', 'rev', '', _('search the repository as it stood at rev')),
2862 ('0', 'print0', None,
2826 ('0', 'print0', None,
2863 _('end filenames with NUL, for use with xargs')),
2827 _('end filenames with NUL, for use with xargs')),
2864 ('f', 'fullpath', None,
2828 ('f', 'fullpath', None,
2865 _('print complete paths from the filesystem root')),
2829 _('print complete paths from the filesystem root')),
2866 ] + walkopts,
2830 ] + walkopts,
2867 _('hg locate [OPTION]... [PATTERN]...')),
2831 _('hg locate [OPTION]... [PATTERN]...')),
2868 "^log|history":
2832 "^log|history":
2869 (log,
2833 (log,
2870 [('f', 'follow', None,
2834 [('f', 'follow', None,
2871 _('follow changeset history, or file history across copies and renames')),
2835 _('follow changeset history, or file history across copies and renames')),
2872 ('', 'follow-first', None,
2836 ('', 'follow-first', None,
2873 _('only follow the first parent of merge changesets')),
2837 _('only follow the first parent of merge changesets')),
2874 ('d', 'date', '', _('show revs matching date spec')),
2838 ('d', 'date', '', _('show revs matching date spec')),
2875 ('C', 'copies', None, _('show copied files')),
2839 ('C', 'copies', None, _('show copied files')),
2876 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
2840 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
2877 ('l', 'limit', '', _('limit number of changes displayed')),
2841 ('l', 'limit', '', _('limit number of changes displayed')),
2878 ('r', 'rev', [], _('show the specified revision or range')),
2842 ('r', 'rev', [], _('show the specified revision or range')),
2879 ('', 'removed', None, _('include revs where files were removed')),
2843 ('', 'removed', None, _('include revs where files were removed')),
2880 ('M', 'no-merges', None, _('do not show merges')),
2844 ('M', 'no-merges', None, _('do not show merges')),
2881 ('', 'style', '', _('display using template map file')),
2845 ('', 'style', '', _('display using template map file')),
2882 ('m', 'only-merges', None, _('show only merges')),
2846 ('m', 'only-merges', None, _('show only merges')),
2883 ('p', 'patch', None, _('show patch')),
2847 ('p', 'patch', None, _('show patch')),
2884 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2848 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2885 ('', 'template', '', _('display with template')),
2849 ('', 'template', '', _('display with template')),
2886 ] + walkopts,
2850 ] + walkopts,
2887 _('hg log [OPTION]... [FILE]')),
2851 _('hg log [OPTION]... [FILE]')),
2888 "manifest": (manifest, [], _('hg manifest [REV]')),
2852 "manifest": (manifest, [], _('hg manifest [REV]')),
2889 "^merge":
2853 "^merge":
2890 (merge,
2854 (merge,
2891 [('f', 'force', None, _('force a merge with outstanding changes')),
2855 [('f', 'force', None, _('force a merge with outstanding changes')),
2892 ('r', 'rev', '', _('revision to merge')),
2856 ('r', 'rev', '', _('revision to merge')),
2893 ],
2857 ],
2894 _('hg merge [-f] [[-r] REV]')),
2858 _('hg merge [-f] [[-r] REV]')),
2895 "outgoing|out": (outgoing,
2859 "outgoing|out": (outgoing,
2896 [('M', 'no-merges', None, _('do not show merges')),
2860 [('M', 'no-merges', None, _('do not show merges')),
2897 ('f', 'force', None,
2861 ('f', 'force', None,
2898 _('run even when remote repository is unrelated')),
2862 _('run even when remote repository is unrelated')),
2899 ('p', 'patch', None, _('show patch')),
2863 ('p', 'patch', None, _('show patch')),
2900 ('', 'style', '', _('display using template map file')),
2864 ('', 'style', '', _('display using template map file')),
2901 ('r', 'rev', [], _('a specific revision you would like to push')),
2865 ('r', 'rev', [], _('a specific revision you would like to push')),
2902 ('n', 'newest-first', None, _('show newest record first')),
2866 ('n', 'newest-first', None, _('show newest record first')),
2903 ('', 'template', '', _('display with template')),
2867 ('', 'template', '', _('display with template')),
2904 ] + remoteopts,
2868 ] + remoteopts,
2905 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
2869 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
2906 "^parents":
2870 "^parents":
2907 (parents,
2871 (parents,
2908 [('r', 'rev', '', _('show parents from the specified rev')),
2872 [('r', 'rev', '', _('show parents from the specified rev')),
2909 ('', 'style', '', _('display using template map file')),
2873 ('', 'style', '', _('display using template map file')),
2910 ('', 'template', '', _('display with template'))],
2874 ('', 'template', '', _('display with template'))],
2911 _('hg parents [-r REV] [FILE]')),
2875 _('hg parents [-r REV] [FILE]')),
2912 "paths": (paths, [], _('hg paths [NAME]')),
2876 "paths": (paths, [], _('hg paths [NAME]')),
2913 "^pull":
2877 "^pull":
2914 (pull,
2878 (pull,
2915 [('u', 'update', None,
2879 [('u', 'update', None,
2916 _('update to new tip if changesets were pulled')),
2880 _('update to new tip if changesets were pulled')),
2917 ('f', 'force', None,
2881 ('f', 'force', None,
2918 _('run even when remote repository is unrelated')),
2882 _('run even when remote repository is unrelated')),
2919 ('r', 'rev', [],
2883 ('r', 'rev', [],
2920 _('a specific revision up to which you would like to pull')),
2884 _('a specific revision up to which you would like to pull')),
2921 ] + remoteopts,
2885 ] + remoteopts,
2922 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
2886 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
2923 "^push":
2887 "^push":
2924 (push,
2888 (push,
2925 [('f', 'force', None, _('force push')),
2889 [('f', 'force', None, _('force push')),
2926 ('r', 'rev', [], _('a specific revision you would like to push')),
2890 ('r', 'rev', [], _('a specific revision you would like to push')),
2927 ] + remoteopts,
2891 ] + remoteopts,
2928 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
2892 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
2929 "debugrawcommit|rawcommit":
2893 "debugrawcommit|rawcommit":
2930 (rawcommit,
2894 (rawcommit,
2931 [('p', 'parent', [], _('parent')),
2895 [('p', 'parent', [], _('parent')),
2932 ('d', 'date', '', _('date code')),
2896 ('d', 'date', '', _('date code')),
2933 ('u', 'user', '', _('user')),
2897 ('u', 'user', '', _('user')),
2934 ('F', 'files', '', _('file list'))
2898 ('F', 'files', '', _('file list'))
2935 ] + commitopts,
2899 ] + commitopts,
2936 _('hg debugrawcommit [OPTION]... [FILE]...')),
2900 _('hg debugrawcommit [OPTION]... [FILE]...')),
2937 "recover": (recover, [], _('hg recover')),
2901 "recover": (recover, [], _('hg recover')),
2938 "^remove|rm":
2902 "^remove|rm":
2939 (remove,
2903 (remove,
2940 [('A', 'after', None, _('record remove that has already occurred')),
2904 [('A', 'after', None, _('record remove that has already occurred')),
2941 ('f', 'force', None, _('remove file even if modified')),
2905 ('f', 'force', None, _('remove file even if modified')),
2942 ] + walkopts,
2906 ] + walkopts,
2943 _('hg remove [OPTION]... FILE...')),
2907 _('hg remove [OPTION]... FILE...')),
2944 "rename|mv":
2908 "rename|mv":
2945 (rename,
2909 (rename,
2946 [('A', 'after', None, _('record a rename that has already occurred')),
2910 [('A', 'after', None, _('record a rename that has already occurred')),
2947 ('f', 'force', None,
2911 ('f', 'force', None,
2948 _('forcibly copy over an existing managed file')),
2912 _('forcibly copy over an existing managed file')),
2949 ] + walkopts + dryrunopts,
2913 ] + walkopts + dryrunopts,
2950 _('hg rename [OPTION]... SOURCE... DEST')),
2914 _('hg rename [OPTION]... SOURCE... DEST')),
2951 "^revert":
2915 "^revert":
2952 (revert,
2916 (revert,
2953 [('a', 'all', None, _('revert all changes when no arguments given')),
2917 [('a', 'all', None, _('revert all changes when no arguments given')),
2954 ('d', 'date', '', _('tipmost revision matching date')),
2918 ('d', 'date', '', _('tipmost revision matching date')),
2955 ('r', 'rev', '', _('revision to revert to')),
2919 ('r', 'rev', '', _('revision to revert to')),
2956 ('', 'no-backup', None, _('do not save backup copies of files')),
2920 ('', 'no-backup', None, _('do not save backup copies of files')),
2957 ] + walkopts + dryrunopts,
2921 ] + walkopts + dryrunopts,
2958 _('hg revert [OPTION]... [-r REV] [NAME]...')),
2922 _('hg revert [OPTION]... [-r REV] [NAME]...')),
2959 "rollback": (rollback, [], _('hg rollback')),
2923 "rollback": (rollback, [], _('hg rollback')),
2960 "root": (root, [], _('hg root')),
2924 "root": (root, [], _('hg root')),
2961 "showconfig|debugconfig":
2925 "showconfig|debugconfig":
2962 (showconfig,
2926 (showconfig,
2963 [('u', 'untrusted', None, _('show untrusted configuration options'))],
2927 [('u', 'untrusted', None, _('show untrusted configuration options'))],
2964 _('showconfig [-u] [NAME]...')),
2928 _('showconfig [-u] [NAME]...')),
2965 "^serve":
2929 "^serve":
2966 (serve,
2930 (serve,
2967 [('A', 'accesslog', '', _('name of access log file to write to')),
2931 [('A', 'accesslog', '', _('name of access log file to write to')),
2968 ('d', 'daemon', None, _('run server in background')),
2932 ('d', 'daemon', None, _('run server in background')),
2969 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2933 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2970 ('E', 'errorlog', '', _('name of error log file to write to')),
2934 ('E', 'errorlog', '', _('name of error log file to write to')),
2971 ('p', 'port', 0, _('port to use (default: 8000)')),
2935 ('p', 'port', 0, _('port to use (default: 8000)')),
2972 ('a', 'address', '', _('address to use')),
2936 ('a', 'address', '', _('address to use')),
2973 ('n', 'name', '',
2937 ('n', 'name', '',
2974 _('name to show in web pages (default: working dir)')),
2938 _('name to show in web pages (default: working dir)')),
2975 ('', 'webdir-conf', '', _('name of the webdir config file'
2939 ('', 'webdir-conf', '', _('name of the webdir config file'
2976 ' (serve more than one repo)')),
2940 ' (serve more than one repo)')),
2977 ('', 'pid-file', '', _('name of file to write process ID to')),
2941 ('', 'pid-file', '', _('name of file to write process ID to')),
2978 ('', 'stdio', None, _('for remote clients')),
2942 ('', 'stdio', None, _('for remote clients')),
2979 ('t', 'templates', '', _('web templates to use')),
2943 ('t', 'templates', '', _('web templates to use')),
2980 ('', 'style', '', _('template style to use')),
2944 ('', 'style', '', _('template style to use')),
2981 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2945 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2982 _('hg serve [OPTION]...')),
2946 _('hg serve [OPTION]...')),
2983 "^status|st":
2947 "^status|st":
2984 (status,
2948 (status,
2985 [('A', 'all', None, _('show status of all files')),
2949 [('A', 'all', None, _('show status of all files')),
2986 ('m', 'modified', None, _('show only modified files')),
2950 ('m', 'modified', None, _('show only modified files')),
2987 ('a', 'added', None, _('show only added files')),
2951 ('a', 'added', None, _('show only added files')),
2988 ('r', 'removed', None, _('show only removed files')),
2952 ('r', 'removed', None, _('show only removed files')),
2989 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2953 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2990 ('c', 'clean', None, _('show only files without changes')),
2954 ('c', 'clean', None, _('show only files without changes')),
2991 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2955 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2992 ('i', 'ignored', None, _('show only ignored files')),
2956 ('i', 'ignored', None, _('show only ignored files')),
2993 ('n', 'no-status', None, _('hide status prefix')),
2957 ('n', 'no-status', None, _('hide status prefix')),
2994 ('C', 'copies', None, _('show source of copied files')),
2958 ('C', 'copies', None, _('show source of copied files')),
2995 ('0', 'print0', None,
2959 ('0', 'print0', None,
2996 _('end filenames with NUL, for use with xargs')),
2960 _('end filenames with NUL, for use with xargs')),
2997 ('', 'rev', [], _('show difference from revision')),
2961 ('', 'rev', [], _('show difference from revision')),
2998 ] + walkopts,
2962 ] + walkopts,
2999 _('hg status [OPTION]... [FILE]...')),
2963 _('hg status [OPTION]... [FILE]...')),
3000 "tag":
2964 "tag":
3001 (tag,
2965 (tag,
3002 [('f', 'force', None, _('replace existing tag')),
2966 [('f', 'force', None, _('replace existing tag')),
3003 ('l', 'local', None, _('make the tag local')),
2967 ('l', 'local', None, _('make the tag local')),
3004 ('m', 'message', '', _('message for tag commit log entry')),
2968 ('m', 'message', '', _('message for tag commit log entry')),
3005 ('d', 'date', '', _('record datecode as commit date')),
2969 ('d', 'date', '', _('record datecode as commit date')),
3006 ('u', 'user', '', _('record user as commiter')),
2970 ('u', 'user', '', _('record user as commiter')),
3007 ('r', 'rev', '', _('revision to tag')),
2971 ('r', 'rev', '', _('revision to tag')),
3008 ('', 'remove', None, _('remove a tag'))],
2972 ('', 'remove', None, _('remove a tag'))],
3009 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
2973 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3010 "tags": (tags, [], _('hg tags')),
2974 "tags": (tags, [], _('hg tags')),
3011 "tip":
2975 "tip":
3012 (tip,
2976 (tip,
3013 [('', 'style', '', _('display using template map file')),
2977 [('', 'style', '', _('display using template map file')),
3014 ('p', 'patch', None, _('show patch')),
2978 ('p', 'patch', None, _('show patch')),
3015 ('', 'template', '', _('display with template'))],
2979 ('', 'template', '', _('display with template'))],
3016 _('hg tip [-p]')),
2980 _('hg tip [-p]')),
3017 "unbundle":
2981 "unbundle":
3018 (unbundle,
2982 (unbundle,
3019 [('u', 'update', None,
2983 [('u', 'update', None,
3020 _('update to new tip if changesets were unbundled'))],
2984 _('update to new tip if changesets were unbundled'))],
3021 _('hg unbundle [-u] FILE')),
2985 _('hg unbundle [-u] FILE')),
3022 "^update|up|checkout|co":
2986 "^update|up|checkout|co":
3023 (update,
2987 (update,
3024 [('C', 'clean', None, _('overwrite locally modified files')),
2988 [('C', 'clean', None, _('overwrite locally modified files')),
3025 ('d', 'date', '', _('tipmost revision matching date')),
2989 ('d', 'date', '', _('tipmost revision matching date')),
3026 ('r', 'rev', '', _('revision'))],
2990 ('r', 'rev', '', _('revision'))],
3027 _('hg update [-C] [-d DATE] [[-r] REV]')),
2991 _('hg update [-C] [-d DATE] [[-r] REV]')),
3028 "verify": (verify, [], _('hg verify')),
2992 "verify": (verify, [], _('hg verify')),
3029 "version": (version_, [], _('hg version')),
2993 "version": (version_, [], _('hg version')),
3030 }
2994 }
3031
2995
3032 norepo = ("clone init version help debugancestor debugcomplete debugdata"
2996 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3033 " debugindex debugindexdot debugdate debuginstall")
2997 " debugindex debugindexdot debugdate debuginstall")
3034 optionalrepo = ("paths serve showconfig")
2998 optionalrepo = ("paths serve showconfig")
3035
2999
3036 def run():
3000 def run():
3037 try:
3001 try:
3038 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3002 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3039 except util.Abort, inst:
3003 except util.Abort, inst:
3040 sys.stderr.write(_("abort: %s\n") % inst)
3004 sys.stderr.write(_("abort: %s\n") % inst)
3041 return -1
3005 return -1
3042 sys.exit(runcatch(u, sys.argv[1:]))
3006 sys.exit(cmdutil.runcatch(u, sys.argv[1:]))
3043
3007
3044 def runcatch(u, args):
3045 def catchterm(*args):
3046 raise util.SignalInterrupt
3047
3048 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3049 num = getattr(signal, name, None)
3050 if num: signal.signal(num, catchterm)
3051
3052 try:
3053 return dispatch(u, args)
3054 except hg.RepoError, inst:
3055 u.warn(_("abort: %s!\n") % inst)
3056 except lock.LockHeld, inst:
3057 if inst.errno == errno.ETIMEDOUT:
3058 reason = _('timed out waiting for lock held by %s') % inst.locker
3059 else:
3060 reason = _('lock held by %s') % inst.locker
3061 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3062 except lock.LockUnavailable, inst:
3063 u.warn(_("abort: could not lock %s: %s\n") %
3064 (inst.desc or inst.filename, inst.strerror))
3065 except revlog.RevlogError, inst:
3066 u.warn(_("abort: %s!\n") % inst)
3067 except util.SignalInterrupt:
3068 u.warn(_("killed!\n"))
3069 except KeyboardInterrupt:
3070 try:
3071 u.warn(_("interrupted!\n"))
3072 except IOError, inst:
3073 if inst.errno == errno.EPIPE:
3074 if u.debugflag:
3075 u.warn(_("\nbroken pipe\n"))
3076 else:
3077 raise
3078 except socket.error, inst:
3079 u.warn(_("abort: %s\n") % inst[1])
3080 except IOError, inst:
3081 if hasattr(inst, "code"):
3082 u.warn(_("abort: %s\n") % inst)
3083 elif hasattr(inst, "reason"):
3084 try: # usually it is in the form (errno, strerror)
3085 reason = inst.reason.args[1]
3086 except: # it might be anything, for example a string
3087 reason = inst.reason
3088 u.warn(_("abort: error: %s\n") % reason)
3089 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3090 if u.debugflag:
3091 u.warn(_("broken pipe\n"))
3092 elif getattr(inst, "strerror", None):
3093 if getattr(inst, "filename", None):
3094 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3095 else:
3096 u.warn(_("abort: %s\n") % inst.strerror)
3097 else:
3098 raise
3099 except OSError, inst:
3100 if getattr(inst, "filename", None):
3101 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3102 else:
3103 u.warn(_("abort: %s\n") % inst.strerror)
3104 except util.UnexpectedOutput, inst:
3105 u.warn(_("abort: %s") % inst[0])
3106 if not isinstance(inst[1], basestring):
3107 u.warn(" %r\n" % (inst[1],))
3108 elif not inst[1]:
3109 u.warn(_(" empty string\n"))
3110 else:
3111 u.warn("\n%r\n" % util.ellipsis(inst[1]))
3112 except util.Abort, inst:
3113 u.warn(_("abort: %s\n") % inst)
3114 except TypeError, inst:
3115 # was this an argument error?
3116 tb = traceback.extract_tb(sys.exc_info()[2])
3117 if len(tb) > 2: # no
3118 raise
3119 u.debug(inst, "\n")
3120 u.warn(_("%s: invalid arguments\n") % cmd)
3121 help_(u, cmd)
3122 except SystemExit, inst:
3123 # Commands shouldn't sys.exit directly, but give a return code.
3124 # Just in case catch this and and pass exit code to caller.
3125 return inst.code
3126 except:
3127 u.warn(_("** unknown exception encountered, details follow\n"))
3128 u.warn(_("** report bug details to "
3129 "http://www.selenic.com/mercurial/bts\n"))
3130 u.warn(_("** or mercurial@selenic.com\n"))
3131 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3132 % version.get_version())
3133 raise
3134
3135 return -1
3136
3137 def findpossible(ui, cmd):
3138 """
3139 Return cmd -> (aliases, command table entry)
3140 for each matching command.
3141 Return debug commands (or their aliases) only if no normal command matches.
3142 """
3143 choice = {}
3144 debugchoice = {}
3145 for e in table.keys():
3146 aliases = e.lstrip("^").split("|")
3147 found = None
3148 if cmd in aliases:
3149 found = cmd
3150 elif not ui.config("ui", "strict"):
3151 for a in aliases:
3152 if a.startswith(cmd):
3153 found = a
3154 break
3155 if found is not None:
3156 if aliases[0].startswith("debug") or found.startswith("debug"):
3157 debugchoice[found] = (aliases, table[e])
3158 else:
3159 choice[found] = (aliases, table[e])
3160
3161 if not choice and debugchoice:
3162 choice = debugchoice
3163
3164 return choice
3165
3166 def findcmd(ui, cmd):
3167 """Return (aliases, command table entry) for command string."""
3168 choice = findpossible(ui, cmd)
3169
3170 if choice.has_key(cmd):
3171 return choice[cmd]
3172
3173 if len(choice) > 1:
3174 clist = choice.keys()
3175 clist.sort()
3176 raise AmbiguousCommand(cmd, clist)
3177
3178 if choice:
3179 return choice.values()[0]
3180
3181 raise UnknownCommand(cmd)
3182
3183 class ParseError(Exception):
3184 """Exception raised on errors in parsing the command line."""
3185
3186 def parse(ui, args):
3187 options = {}
3188 cmdoptions = {}
3189
3190 try:
3191 args = fancyopts.fancyopts(args, globalopts, options)
3192 except fancyopts.getopt.GetoptError, inst:
3193 raise ParseError(None, inst)
3194
3195 if args:
3196 cmd, args = args[0], args[1:]
3197 aliases, i = findcmd(ui, cmd)
3198 cmd = aliases[0]
3199 defaults = ui.config("defaults", cmd)
3200 if defaults:
3201 args = shlex.split(defaults) + args
3202 c = list(i[1])
3203 else:
3204 cmd = None
3205 c = []
3206
3207 # combine global options into local
3208 for o in globalopts:
3209 c.append((o[0], o[1], options[o[1]], o[3]))
3210
3211 try:
3212 args = fancyopts.fancyopts(args, c, cmdoptions)
3213 except fancyopts.getopt.GetoptError, inst:
3214 raise ParseError(cmd, inst)
3215
3216 # separate global options back out
3217 for o in globalopts:
3218 n = o[1]
3219 options[n] = cmdoptions[n]
3220 del cmdoptions[n]
3221
3222 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3223
3224 def parseconfig(config):
3225 """parse the --config options from the command line"""
3226 parsed = []
3227 for cfg in config:
3228 try:
3229 name, value = cfg.split('=', 1)
3230 section, name = name.split('.', 1)
3231 if not section or not name:
3232 raise IndexError
3233 parsed.append((section, name, value))
3234 except (IndexError, ValueError):
3235 raise util.Abort(_('malformed --config option: %s') % cfg)
3236 return parsed
3237
3238 def dispatch(u, args):
3239 extensions.loadall(u)
3240 u.addreadhook(extensions.loadall)
3241
3242 try:
3243 cmd, func, args, options, cmdoptions = parse(u, args)
3244 except ParseError, inst:
3245 if inst.args[0]:
3246 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3247 help_(u, inst.args[0])
3248 else:
3249 u.warn(_("hg: %s\n") % inst.args[1])
3250 help_(u, 'shortlist')
3251 return -1
3252 except AmbiguousCommand, inst:
3253 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3254 (inst.args[0], " ".join(inst.args[1])))
3255 return -1
3256 except UnknownCommand, inst:
3257 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3258 help_(u, 'shortlist')
3259 return -1
3260
3261 if options["encoding"]:
3262 util._encoding = options["encoding"]
3263 if options["encodingmode"]:
3264 util._encodingmode = options["encodingmode"]
3265 if options["time"]:
3266 def get_times():
3267 t = os.times()
3268 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3269 t = (t[0], t[1], t[2], t[3], time.clock())
3270 return t
3271 s = get_times()
3272 def print_time():
3273 t = get_times()
3274 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3275 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3276 atexit.register(print_time)
3277
3278 if options['cwd']:
3279 os.chdir(options['cwd'])
3280
3281 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3282 not options["noninteractive"], options["traceback"],
3283 parseconfig(options["config"]))
3284
3285 path = u.expandpath(options["repository"]) or ""
3286 repo = path and hg.repository(u, path=path) or None
3287 if repo and not repo.local():
3288 raise util.Abort(_("repository '%s' is not local") % path)
3289
3290 if options['help']:
3291 return help_(u, cmd, options['version'])
3292 elif options['version']:
3293 return version_(u)
3294 elif not cmd:
3295 return help_(u, 'shortlist')
3296
3297 if cmd not in norepo.split():
3298 try:
3299 if not repo:
3300 repo = hg.repository(u, path=path)
3301 u = repo.ui
3302 except hg.RepoError:
3303 if cmd not in optionalrepo.split():
3304 raise
3305 d = lambda: func(u, repo, *args, **cmdoptions)
3306 else:
3307 d = lambda: func(u, *args, **cmdoptions)
3308
3309 return cmdutil.runcommand(u, options, d)
3310
@@ -1,91 +1,91 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
2
3 import ConfigParser
3 import ConfigParser
4 from mercurial import ui, util, commands
4 from mercurial import ui, util, cmdutil
5
5
6 testui = ui.ui()
6 testui = ui.ui()
7 parsed = commands.parseconfig([
7 parsed = cmdutil.parseconfig([
8 'values.string=string value',
8 'values.string=string value',
9 'values.bool1=true',
9 'values.bool1=true',
10 'values.bool2=false',
10 'values.bool2=false',
11 'lists.list1=foo',
11 'lists.list1=foo',
12 'lists.list2=foo bar baz',
12 'lists.list2=foo bar baz',
13 'lists.list3=alice, bob',
13 'lists.list3=alice, bob',
14 'lists.list4=foo bar baz alice, bob',
14 'lists.list4=foo bar baz alice, bob',
15 'interpolation.value1=hallo',
15 'interpolation.value1=hallo',
16 'interpolation.value2=%(value1)s world',
16 'interpolation.value2=%(value1)s world',
17 'interpolation.value3=%(novalue)s',
17 'interpolation.value3=%(novalue)s',
18 'interpolation.value4=%(bad)1',
18 'interpolation.value4=%(bad)1',
19 'interpolation.value5=%bad2',
19 'interpolation.value5=%bad2',
20 ])
20 ])
21 testui.updateopts(config=parsed)
21 testui.updateopts(config=parsed)
22
22
23 print repr(testui.configitems('values'))
23 print repr(testui.configitems('values'))
24 print repr(testui.configitems('lists'))
24 print repr(testui.configitems('lists'))
25 try:
25 try:
26 print repr(testui.configitems('interpolation'))
26 print repr(testui.configitems('interpolation'))
27 except util.Abort, inst:
27 except util.Abort, inst:
28 print inst
28 print inst
29 print "---"
29 print "---"
30 print repr(testui.config('values', 'string'))
30 print repr(testui.config('values', 'string'))
31 print repr(testui.config('values', 'bool1'))
31 print repr(testui.config('values', 'bool1'))
32 print repr(testui.config('values', 'bool2'))
32 print repr(testui.config('values', 'bool2'))
33 print repr(testui.config('values', 'unknown'))
33 print repr(testui.config('values', 'unknown'))
34 print "---"
34 print "---"
35 try:
35 try:
36 print repr(testui.configbool('values', 'string'))
36 print repr(testui.configbool('values', 'string'))
37 except ValueError, why:
37 except ValueError, why:
38 print why
38 print why
39 print repr(testui.configbool('values', 'bool1'))
39 print repr(testui.configbool('values', 'bool1'))
40 print repr(testui.configbool('values', 'bool2'))
40 print repr(testui.configbool('values', 'bool2'))
41 print repr(testui.configbool('values', 'bool2', True))
41 print repr(testui.configbool('values', 'bool2', True))
42 print repr(testui.configbool('values', 'unknown'))
42 print repr(testui.configbool('values', 'unknown'))
43 print repr(testui.configbool('values', 'unknown', True))
43 print repr(testui.configbool('values', 'unknown', True))
44 print "---"
44 print "---"
45 print repr(testui.configlist('lists', 'list1'))
45 print repr(testui.configlist('lists', 'list1'))
46 print repr(testui.configlist('lists', 'list2'))
46 print repr(testui.configlist('lists', 'list2'))
47 print repr(testui.configlist('lists', 'list3'))
47 print repr(testui.configlist('lists', 'list3'))
48 print repr(testui.configlist('lists', 'list4'))
48 print repr(testui.configlist('lists', 'list4'))
49 print repr(testui.configlist('lists', 'list4', ['foo']))
49 print repr(testui.configlist('lists', 'list4', ['foo']))
50 print repr(testui.configlist('lists', 'unknown'))
50 print repr(testui.configlist('lists', 'unknown'))
51 print repr(testui.configlist('lists', 'unknown', ''))
51 print repr(testui.configlist('lists', 'unknown', ''))
52 print repr(testui.configlist('lists', 'unknown', 'foo'))
52 print repr(testui.configlist('lists', 'unknown', 'foo'))
53 print repr(testui.configlist('lists', 'unknown', ['foo']))
53 print repr(testui.configlist('lists', 'unknown', ['foo']))
54 print repr(testui.configlist('lists', 'unknown', 'foo bar'))
54 print repr(testui.configlist('lists', 'unknown', 'foo bar'))
55 print repr(testui.configlist('lists', 'unknown', 'foo, bar'))
55 print repr(testui.configlist('lists', 'unknown', 'foo, bar'))
56 print repr(testui.configlist('lists', 'unknown', ['foo bar']))
56 print repr(testui.configlist('lists', 'unknown', ['foo bar']))
57 print repr(testui.configlist('lists', 'unknown', ['foo', 'bar']))
57 print repr(testui.configlist('lists', 'unknown', ['foo', 'bar']))
58 print "---"
58 print "---"
59 print repr(testui.config('interpolation', 'value1'))
59 print repr(testui.config('interpolation', 'value1'))
60 print repr(testui.config('interpolation', 'value2'))
60 print repr(testui.config('interpolation', 'value2'))
61 try:
61 try:
62 print repr(testui.config('interpolation', 'value3'))
62 print repr(testui.config('interpolation', 'value3'))
63 except util.Abort, inst:
63 except util.Abort, inst:
64 print inst
64 print inst
65 try:
65 try:
66 print repr(testui.config('interpolation', 'value4'))
66 print repr(testui.config('interpolation', 'value4'))
67 except util.Abort, inst:
67 except util.Abort, inst:
68 print inst
68 print inst
69 try:
69 try:
70 print repr(testui.config('interpolation', 'value5'))
70 print repr(testui.config('interpolation', 'value5'))
71 except util.Abort, inst:
71 except util.Abort, inst:
72 print inst
72 print inst
73 print "---"
73 print "---"
74
74
75 cp = util.configparser()
75 cp = util.configparser()
76 cp.add_section('foo')
76 cp.add_section('foo')
77 cp.set('foo', 'bar', 'baz')
77 cp.set('foo', 'bar', 'baz')
78 try:
78 try:
79 # should fail - keys are case-sensitive
79 # should fail - keys are case-sensitive
80 cp.get('foo', 'Bar')
80 cp.get('foo', 'Bar')
81 except ConfigParser.NoOptionError, inst:
81 except ConfigParser.NoOptionError, inst:
82 print inst
82 print inst
83
83
84 def function():
84 def function():
85 pass
85 pass
86
86
87 cp.add_section('hook')
87 cp.add_section('hook')
88 # values that aren't strings should work
88 # values that aren't strings should work
89 cp.set('hook', 'commit', function)
89 cp.set('hook', 'commit', function)
90 f = cp.get('hook', 'commit')
90 f = cp.get('hook', 'commit')
91 print "f %s= function" % (f == function and '=' or '!')
91 print "f %s= function" % (f == function and '=' or '!')
General Comments 0
You need to be logged in to leave comments. Login now