##// END OF EJS Templates
Cleanups to commands.py
Thomas Arendsen Hein -
r1065:6e94c036 default
parent child Browse files
Show More
@@ -1,1838 +1,1855 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 from demandload import demandload
9 demandload(globals(), "os re sys signal shutil")
9 demandload(globals(), "os re sys signal shutil")
10 demandload(globals(), "fancyopts ui hg util lock")
10 demandload(globals(), "fancyopts ui hg util lock")
11 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
11 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
12 demandload(globals(), "errno socket version struct atexit sets")
12 demandload(globals(), "errno socket version struct atexit sets")
13
13
14 class UnknownCommand(Exception):
14 class UnknownCommand(Exception):
15 """Exception raised if command is not in the command table."""
15 """Exception raised if command is not in the command table."""
16
16
17 def filterfiles(filters, files):
17 def filterfiles(filters, files):
18 l = [x for x in files if x in filters]
18 l = [x for x in files if x in filters]
19
19
20 for t in filters:
20 for t in filters:
21 if t and t[-1] != "/":
21 if t and t[-1] != "/":
22 t += "/"
22 t += "/"
23 l += [x for x in files if x.startswith(t)]
23 l += [x for x in files if x.startswith(t)]
24 return l
24 return l
25
25
26 def relpath(repo, args):
26 def relpath(repo, args):
27 cwd = repo.getcwd()
27 cwd = repo.getcwd()
28 if cwd:
28 if cwd:
29 return [util.normpath(os.path.join(cwd, x)) for x in args]
29 return [util.normpath(os.path.join(cwd, x)) for x in args]
30 return args
30 return args
31
31
32 def matchpats(repo, cwd, pats=[], opts={}, head=''):
32 def matchpats(repo, cwd, pats=[], opts={}, head=''):
33 return util.matcher(repo, cwd, pats or ['.'], opts.get('include'),
33 return util.matcher(repo, cwd, pats or ['.'], opts.get('include'),
34 opts.get('exclude'), head)
34 opts.get('exclude'), head)
35
35
36 def makewalk(repo, pats, opts, head=''):
36 def makewalk(repo, pats, opts, head=''):
37 cwd = repo.getcwd()
37 cwd = repo.getcwd()
38 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
38 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
39 exact = dict(zip(files, files))
39 exact = dict(zip(files, files))
40 def walk():
40 def walk():
41 for src, fn in repo.walk(files=files, match=matchfn):
41 for src, fn in repo.walk(files=files, match=matchfn):
42 yield src, fn, util.pathto(cwd, fn), fn in exact
42 yield src, fn, util.pathto(cwd, fn), fn in exact
43 return files, matchfn, walk()
43 return files, matchfn, walk()
44
44
45 def walk(repo, pats, opts, head=''):
45 def walk(repo, pats, opts, head=''):
46 files, matchfn, results = makewalk(repo, pats, opts, head)
46 files, matchfn, results = makewalk(repo, pats, opts, head)
47 for r in results: yield r
47 for r in results:
48 yield r
48
49
49 def walkchangerevs(ui, repo, cwd, pats, opts):
50 def walkchangerevs(ui, repo, cwd, pats, opts):
50 # This code most commonly needs to iterate backwards over the
51 # This code most commonly needs to iterate backwards over the
51 # history it is interested in. Doing so has awful
52 # history it is interested in. Doing so has awful
52 # (quadratic-looking) performance, so we use iterators in a
53 # (quadratic-looking) performance, so we use iterators in a
53 # "windowed" way. Walk forwards through a window of revisions,
54 # "windowed" way. Walk forwards through a window of revisions,
54 # yielding them in the desired order, and walk the windows
55 # yielding them in the desired order, and walk the windows
55 # themselves backwards.
56 # themselves backwards.
56 cwd = repo.getcwd()
57 cwd = repo.getcwd()
57 if not pats and cwd:
58 if not pats and cwd:
58 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
59 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
59 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
60 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
60 files, matchfn, anypats = matchpats(repo, (pats and cwd) or '',
61 files, matchfn, anypats = matchpats(repo, (pats and cwd) or '',
61 pats, opts)
62 pats, opts)
62 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
63 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
63 wanted = {}
64 wanted = {}
64 slowpath = anypats
65 slowpath = anypats
65 window = 300
66 window = 300
66 fncache = {}
67 fncache = {}
67 if not slowpath and not files:
68 if not slowpath and not files:
68 # No files, no patterns. Display all revs.
69 # No files, no patterns. Display all revs.
69 wanted = dict(zip(revs, revs))
70 wanted = dict(zip(revs, revs))
70 if not slowpath:
71 if not slowpath:
71 # Only files, no patterns. Check the history of each file.
72 # Only files, no patterns. Check the history of each file.
72 def filerevgen(filelog):
73 def filerevgen(filelog):
73 for i in xrange(filelog.count() - 1, -1, -window):
74 for i in xrange(filelog.count() - 1, -1, -window):
74 revs = []
75 revs = []
75 for j in xrange(max(0, i - window), i + 1):
76 for j in xrange(max(0, i - window), i + 1):
76 revs.append(filelog.linkrev(filelog.node(j)))
77 revs.append(filelog.linkrev(filelog.node(j)))
77 revs.reverse()
78 revs.reverse()
78 for rev in revs:
79 for rev in revs:
79 yield rev
80 yield rev
80
81
81 minrev, maxrev = min(revs), max(revs)
82 minrev, maxrev = min(revs), max(revs)
82 for file in files:
83 for file in files:
83 filelog = repo.file(file)
84 filelog = repo.file(file)
84 # A zero count may be a directory or deleted file, so
85 # A zero count may be a directory or deleted file, so
85 # try to find matching entries on the slow path.
86 # try to find matching entries on the slow path.
86 if filelog.count() == 0:
87 if filelog.count() == 0:
87 slowpath = True
88 slowpath = True
88 break
89 break
89 for rev in filerevgen(filelog):
90 for rev in filerevgen(filelog):
90 if rev <= maxrev:
91 if rev <= maxrev:
91 if rev < minrev: break
92 if rev < minrev:
93 break
92 fncache.setdefault(rev, [])
94 fncache.setdefault(rev, [])
93 fncache[rev].append(file)
95 fncache[rev].append(file)
94 wanted[rev] = 1
96 wanted[rev] = 1
95 if slowpath:
97 if slowpath:
96 # The slow path checks files modified in every changeset.
98 # The slow path checks files modified in every changeset.
97 def changerevgen():
99 def changerevgen():
98 for i in xrange(repo.changelog.count() - 1, -1, -window):
100 for i in xrange(repo.changelog.count() - 1, -1, -window):
99 for j in xrange(max(0, i - window), i + 1):
101 for j in xrange(max(0, i - window), i + 1):
100 yield j, repo.changelog.read(repo.lookup(str(j)))[3]
102 yield j, repo.changelog.read(repo.lookup(str(j)))[3]
101
103
102 for rev, changefiles in changerevgen():
104 for rev, changefiles in changerevgen():
103 matches = filter(matchfn, changefiles)
105 matches = filter(matchfn, changefiles)
104 if matches:
106 if matches:
105 fncache[rev] = matches
107 fncache[rev] = matches
106 wanted[rev] = 1
108 wanted[rev] = 1
107
109
108 for i in xrange(0, len(revs), window):
110 for i in xrange(0, len(revs), window):
109 yield 'window', revs[0] < revs[-1], revs[-1]
111 yield 'window', revs[0] < revs[-1], revs[-1]
110 nrevs = [rev for rev in revs[i : min(i + window, len(revs))]
112 nrevs = [rev for rev in revs[i:min(i+window, len(revs))]
111 if rev in wanted]
113 if rev in wanted]
112 srevs = list(nrevs)
114 srevs = list(nrevs)
113 srevs.sort()
115 srevs.sort()
114 for rev in srevs:
116 for rev in srevs:
115 fns = fncache.get(rev)
117 fns = fncache.get(rev)
116 if not fns:
118 if not fns:
117 fns = repo.changelog.read(repo.lookup(str(rev)))[3]
119 fns = repo.changelog.read(repo.lookup(str(rev)))[3]
118 fns = filter(matchfn, fns)
120 fns = filter(matchfn, fns)
119 yield 'add', rev, fns
121 yield 'add', rev, fns
120 for rev in nrevs:
122 for rev in nrevs:
121 yield 'iter', rev, None
123 yield 'iter', rev, None
122
124
123 revrangesep = ':'
125 revrangesep = ':'
124
126
125 def revrange(ui, repo, revs, revlog=None):
127 def revrange(ui, repo, revs, revlog=None):
126 if revlog is None:
128 if revlog is None:
127 revlog = repo.changelog
129 revlog = repo.changelog
128 revcount = revlog.count()
130 revcount = revlog.count()
129 def fix(val, defval):
131 def fix(val, defval):
130 if not val:
132 if not val:
131 return defval
133 return defval
132 try:
134 try:
133 num = int(val)
135 num = int(val)
134 if str(num) != val:
136 if str(num) != val:
135 raise ValueError
137 raise ValueError
136 if num < 0:
138 if num < 0:
137 num += revcount
139 num += revcount
138 if not (0 <= num < revcount):
140 if not (0 <= num < revcount):
139 raise ValueError
141 raise ValueError
140 except ValueError:
142 except ValueError:
141 try:
143 try:
142 num = repo.changelog.rev(repo.lookup(val))
144 num = repo.changelog.rev(repo.lookup(val))
143 except KeyError:
145 except KeyError:
144 try:
146 try:
145 num = revlog.rev(revlog.lookup(val))
147 num = revlog.rev(revlog.lookup(val))
146 except KeyError:
148 except KeyError:
147 raise util.Abort('invalid revision identifier %s', val)
149 raise util.Abort('invalid revision identifier %s', val)
148 return num
150 return num
149 for spec in revs:
151 for spec in revs:
150 if spec.find(revrangesep) >= 0:
152 if spec.find(revrangesep) >= 0:
151 start, end = spec.split(revrangesep, 1)
153 start, end = spec.split(revrangesep, 1)
152 start = fix(start, 0)
154 start = fix(start, 0)
153 end = fix(end, revcount - 1)
155 end = fix(end, revcount - 1)
154 if end > start:
156 if end > start:
155 end += 1
157 end += 1
156 step = 1
158 step = 1
157 else:
159 else:
158 end -= 1
160 end -= 1
159 step = -1
161 step = -1
160 for rev in xrange(start, end, step):
162 for rev in xrange(start, end, step):
161 yield str(rev)
163 yield str(rev)
162 else:
164 else:
163 yield str(fix(spec, None))
165 yield str(fix(spec, None))
164
166
165 def make_filename(repo, r, pat, node=None,
167 def make_filename(repo, r, pat, node=None,
166 total=None, seqno=None, revwidth=None):
168 total=None, seqno=None, revwidth=None):
167 node_expander = {
169 node_expander = {
168 'H': lambda: hg.hex(node),
170 'H': lambda: hg.hex(node),
169 'R': lambda: str(r.rev(node)),
171 'R': lambda: str(r.rev(node)),
170 'h': lambda: hg.short(node),
172 'h': lambda: hg.short(node),
171 }
173 }
172 expander = {
174 expander = {
173 '%': lambda: '%',
175 '%': lambda: '%',
174 'b': lambda: os.path.basename(repo.root),
176 'b': lambda: os.path.basename(repo.root),
175 }
177 }
176
178
177 try:
179 try:
178 if node:
180 if node:
179 expander.update(node_expander)
181 expander.update(node_expander)
180 if node and revwidth is not None:
182 if node and revwidth is not None:
181 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
183 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
182 if total is not None:
184 if total is not None:
183 expander['N'] = lambda: str(total)
185 expander['N'] = lambda: str(total)
184 if seqno is not None:
186 if seqno is not None:
185 expander['n'] = lambda: str(seqno)
187 expander['n'] = lambda: str(seqno)
186 if total is not None and seqno is not None:
188 if total is not None and seqno is not None:
187 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
189 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
188
190
189 newname = []
191 newname = []
190 patlen = len(pat)
192 patlen = len(pat)
191 i = 0
193 i = 0
192 while i < patlen:
194 while i < patlen:
193 c = pat[i]
195 c = pat[i]
194 if c == '%':
196 if c == '%':
195 i += 1
197 i += 1
196 c = pat[i]
198 c = pat[i]
197 c = expander[c]()
199 c = expander[c]()
198 newname.append(c)
200 newname.append(c)
199 i += 1
201 i += 1
200 return ''.join(newname)
202 return ''.join(newname)
201 except KeyError, inst:
203 except KeyError, inst:
202 raise util.Abort("invalid format spec '%%%s' in output file name",
204 raise util.Abort("invalid format spec '%%%s' in output file name",
203 inst.args[0])
205 inst.args[0])
204
206
205 def make_file(repo, r, pat, node=None,
207 def make_file(repo, r, pat, node=None,
206 total=None, seqno=None, revwidth=None, mode='wb'):
208 total=None, seqno=None, revwidth=None, mode='wb'):
207 if not pat or pat == '-':
209 if not pat or pat == '-':
208 if 'w' in mode: return sys.stdout
210 return 'w' in mode and sys.stdout or sys.stdin
209 else: return sys.stdin
210 if hasattr(pat, 'write') and 'w' in mode:
211 if hasattr(pat, 'write') and 'w' in mode:
211 return pat
212 return pat
212 if hasattr(pat, 'read') and 'r' in mode:
213 if hasattr(pat, 'read') and 'r' in mode:
213 return pat
214 return pat
214 return open(make_filename(repo, r, pat, node, total, seqno, revwidth),
215 return open(make_filename(repo, r, pat, node, total, seqno, revwidth),
215 mode)
216 mode)
216
217
217 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
218 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
218 changes=None, text=False):
219 changes=None, text=False):
219 def date(c):
220 def date(c):
220 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
221 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
221
222
222 if not changes:
223 if not changes:
223 (c, a, d, u) = repo.changes(node1, node2, files, match=match)
224 (c, a, d, u) = repo.changes(node1, node2, files, match=match)
224 else:
225 else:
225 (c, a, d, u) = changes
226 (c, a, d, u) = changes
226 if files:
227 if files:
227 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
228 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
228
229
229 if not c and not a and not d:
230 if not c and not a and not d:
230 return
231 return
231
232
232 if node2:
233 if node2:
233 change = repo.changelog.read(node2)
234 change = repo.changelog.read(node2)
234 mmap2 = repo.manifest.read(change[0])
235 mmap2 = repo.manifest.read(change[0])
235 date2 = date(change)
236 date2 = date(change)
236 def read(f):
237 def read(f):
237 return repo.file(f).read(mmap2[f])
238 return repo.file(f).read(mmap2[f])
238 else:
239 else:
239 date2 = time.asctime()
240 date2 = time.asctime()
240 if not node1:
241 if not node1:
241 node1 = repo.dirstate.parents()[0]
242 node1 = repo.dirstate.parents()[0]
242 def read(f):
243 def read(f):
243 return repo.wfile(f).read()
244 return repo.wfile(f).read()
244
245
245 if ui.quiet:
246 if ui.quiet:
246 r = None
247 r = None
247 else:
248 else:
248 hexfunc = ui.verbose and hg.hex or hg.short
249 hexfunc = ui.verbose and hg.hex or hg.short
249 r = [hexfunc(node) for node in [node1, node2] if node]
250 r = [hexfunc(node) for node in [node1, node2] if node]
250
251
251 change = repo.changelog.read(node1)
252 change = repo.changelog.read(node1)
252 mmap = repo.manifest.read(change[0])
253 mmap = repo.manifest.read(change[0])
253 date1 = date(change)
254 date1 = date(change)
254
255
255 for f in c:
256 for f in c:
256 to = None
257 to = None
257 if f in mmap:
258 if f in mmap:
258 to = repo.file(f).read(mmap[f])
259 to = repo.file(f).read(mmap[f])
259 tn = read(f)
260 tn = read(f)
260 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
261 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
261 for f in a:
262 for f in a:
262 to = None
263 to = None
263 tn = read(f)
264 tn = read(f)
264 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
265 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
265 for f in d:
266 for f in d:
266 to = repo.file(f).read(mmap[f])
267 to = repo.file(f).read(mmap[f])
267 tn = None
268 tn = None
268 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
269 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
269
270
270 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
271 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
271 """show a single changeset or file revision"""
272 """show a single changeset or file revision"""
272 log = repo.changelog
273 log = repo.changelog
273 if changenode is None:
274 if changenode is None:
274 changenode = log.node(rev)
275 changenode = log.node(rev)
275 elif not rev:
276 elif not rev:
276 rev = log.rev(changenode)
277 rev = log.rev(changenode)
277
278
278 if ui.quiet:
279 if ui.quiet:
279 ui.write("%d:%s\n" % (rev, hg.short(changenode)))
280 ui.write("%d:%s\n" % (rev, hg.short(changenode)))
280 return
281 return
281
282
282 changes = log.read(changenode)
283 changes = log.read(changenode)
283
284
284 t, tz = changes[2].split(' ')
285 t, tz = changes[2].split(' ')
285 # a conversion tool was sticking non-integer offsets into repos
286 # a conversion tool was sticking non-integer offsets into repos
286 try:
287 try:
287 tz = int(tz)
288 tz = int(tz)
288 except ValueError:
289 except ValueError:
289 tz = 0
290 tz = 0
290 date = time.asctime(time.localtime(float(t))) + " %+05d" % (int(tz)/-36)
291 date = time.asctime(time.localtime(float(t))) + " %+05d" % (int(tz)/-36)
291
292
292 parents = [(log.rev(p), ui.verbose and hg.hex(p) or hg.short(p))
293 parents = [(log.rev(p), ui.verbose and hg.hex(p) or hg.short(p))
293 for p in log.parents(changenode)
294 for p in log.parents(changenode)
294 if ui.debugflag or p != hg.nullid]
295 if ui.debugflag or p != hg.nullid]
295 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
296 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
296 parents = []
297 parents = []
297
298
298 if ui.verbose:
299 if ui.verbose:
299 ui.write("changeset: %d:%s\n" % (rev, hg.hex(changenode)))
300 ui.write("changeset: %d:%s\n" % (rev, hg.hex(changenode)))
300 else:
301 else:
301 ui.write("changeset: %d:%s\n" % (rev, hg.short(changenode)))
302 ui.write("changeset: %d:%s\n" % (rev, hg.short(changenode)))
302
303
303 for tag in repo.nodetags(changenode):
304 for tag in repo.nodetags(changenode):
304 ui.status("tag: %s\n" % tag)
305 ui.status("tag: %s\n" % tag)
305 for parent in parents:
306 for parent in parents:
306 ui.write("parent: %d:%s\n" % parent)
307 ui.write("parent: %d:%s\n" % parent)
307
308
308 if brinfo and changenode in brinfo:
309 if brinfo and changenode in brinfo:
309 br = brinfo[changenode]
310 br = brinfo[changenode]
310 ui.write("branch: %s\n" % " ".join(br))
311 ui.write("branch: %s\n" % " ".join(br))
311
312
312 ui.debug("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
313 ui.debug("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
313 hg.hex(changes[0])))
314 hg.hex(changes[0])))
314 ui.status("user: %s\n" % changes[1])
315 ui.status("user: %s\n" % changes[1])
315 ui.status("date: %s\n" % date)
316 ui.status("date: %s\n" % date)
316
317
317 if ui.debugflag:
318 if ui.debugflag:
318 files = repo.changes(log.parents(changenode)[0], changenode)
319 files = repo.changes(log.parents(changenode)[0], changenode)
319 for key, value in zip(["files:", "files+:", "files-:"], files):
320 for key, value in zip(["files:", "files+:", "files-:"], files):
320 if value:
321 if value:
321 ui.note("%-12s %s\n" % (key, " ".join(value)))
322 ui.note("%-12s %s\n" % (key, " ".join(value)))
322 else:
323 else:
323 ui.note("files: %s\n" % " ".join(changes[3]))
324 ui.note("files: %s\n" % " ".join(changes[3]))
324
325
325 description = changes[4].strip()
326 description = changes[4].strip()
326 if description:
327 if description:
327 if ui.verbose:
328 if ui.verbose:
328 ui.status("description:\n")
329 ui.status("description:\n")
329 ui.status(description)
330 ui.status(description)
330 ui.status("\n\n")
331 ui.status("\n\n")
331 else:
332 else:
332 ui.status("summary: %s\n" % description.splitlines()[0])
333 ui.status("summary: %s\n" % description.splitlines()[0])
333 ui.status("\n")
334 ui.status("\n")
334
335
335 def show_version(ui):
336 def show_version(ui):
336 """output version and copyright information"""
337 """output version and copyright information"""
337 ui.write("Mercurial Distributed SCM (version %s)\n"
338 ui.write("Mercurial Distributed SCM (version %s)\n"
338 % version.get_version())
339 % version.get_version())
339 ui.status(
340 ui.status(
340 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
341 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
341 "This is free software; see the source for copying conditions. "
342 "This is free software; see the source for copying conditions. "
342 "There is NO\nwarranty; "
343 "There is NO\nwarranty; "
343 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
344 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
344 )
345 )
345
346
346 def help_(ui, cmd=None, with_version=False):
347 def help_(ui, cmd=None, with_version=False):
347 """show help for a given command or all commands"""
348 """show help for a given command or all commands"""
348 option_lists = []
349 option_lists = []
349 if cmd and cmd != 'shortlist':
350 if cmd and cmd != 'shortlist':
350 if with_version:
351 if with_version:
351 show_version(ui)
352 show_version(ui)
352 ui.write('\n')
353 ui.write('\n')
353 key, i = find(cmd)
354 key, i = find(cmd)
354 # synopsis
355 # synopsis
355 ui.write("%s\n\n" % i[2])
356 ui.write("%s\n\n" % i[2])
356
357
357 # description
358 # description
358 doc = i[0].__doc__
359 doc = i[0].__doc__
359 if ui.quiet:
360 if ui.quiet:
360 doc = doc.splitlines(0)[0]
361 doc = doc.splitlines(0)[0]
361 ui.write("%s\n" % doc.rstrip())
362 ui.write("%s\n" % doc.rstrip())
362
363
363 if not ui.quiet:
364 if not ui.quiet:
364 # aliases
365 # aliases
365 aliases = ', '.join(key.split('|')[1:])
366 aliases = ', '.join(key.split('|')[1:])
366 if aliases:
367 if aliases:
367 ui.write("\naliases: %s\n" % aliases)
368 ui.write("\naliases: %s\n" % aliases)
368
369
369 # options
370 # options
370 if i[1]:
371 if i[1]:
371 option_lists.append(("options", i[1]))
372 option_lists.append(("options", i[1]))
372
373
373 else:
374 else:
374 # program name
375 # program name
375 if ui.verbose or with_version:
376 if ui.verbose or with_version:
376 show_version(ui)
377 show_version(ui)
377 else:
378 else:
378 ui.status("Mercurial Distributed SCM\n")
379 ui.status("Mercurial Distributed SCM\n")
379 ui.status('\n')
380 ui.status('\n')
380
381
381 # list of commands
382 # list of commands
382 if cmd == "shortlist":
383 if cmd == "shortlist":
383 ui.status('basic commands (use "hg help" '
384 ui.status('basic commands (use "hg help" '
384 'for the full list or option "-v" for details):\n\n')
385 'for the full list or option "-v" for details):\n\n')
385 elif ui.verbose:
386 elif ui.verbose:
386 ui.status('list of commands:\n\n')
387 ui.status('list of commands:\n\n')
387 else:
388 else:
388 ui.status('list of commands (use "hg help -v" '
389 ui.status('list of commands (use "hg help -v" '
389 'to show aliases and global options):\n\n')
390 'to show aliases and global options):\n\n')
390
391
391 h = {}
392 h = {}
392 cmds = {}
393 cmds = {}
393 for c, e in table.items():
394 for c, e in table.items():
394 f = c.split("|")[0]
395 f = c.split("|")[0]
395 if cmd == "shortlist" and not f.startswith("^"):
396 if cmd == "shortlist" and not f.startswith("^"):
396 continue
397 continue
397 f = f.lstrip("^")
398 f = f.lstrip("^")
398 if not ui.debugflag and f.startswith("debug"):
399 if not ui.debugflag and f.startswith("debug"):
399 continue
400 continue
400 d = ""
401 d = ""
401 if e[0].__doc__:
402 if e[0].__doc__:
402 d = e[0].__doc__.splitlines(0)[0].rstrip()
403 d = e[0].__doc__.splitlines(0)[0].rstrip()
403 h[f] = d
404 h[f] = d
404 cmds[f]=c.lstrip("^")
405 cmds[f]=c.lstrip("^")
405
406
406 fns = h.keys()
407 fns = h.keys()
407 fns.sort()
408 fns.sort()
408 m = max(map(len, fns))
409 m = max(map(len, fns))
409 for f in fns:
410 for f in fns:
410 if ui.verbose:
411 if ui.verbose:
411 commands = cmds[f].replace("|",", ")
412 commands = cmds[f].replace("|",", ")
412 ui.write(" %s:\n %s\n"%(commands,h[f]))
413 ui.write(" %s:\n %s\n"%(commands,h[f]))
413 else:
414 else:
414 ui.write(' %-*s %s\n' % (m, f, h[f]))
415 ui.write(' %-*s %s\n' % (m, f, h[f]))
415
416
416 # global options
417 # global options
417 if ui.verbose:
418 if ui.verbose:
418 option_lists.append(("global options", globalopts))
419 option_lists.append(("global options", globalopts))
419
420
420 # list all option lists
421 # list all option lists
421 opt_output = []
422 opt_output = []
422 for title, options in option_lists:
423 for title, options in option_lists:
423 opt_output.append(("\n%s:\n" % title, None))
424 opt_output.append(("\n%s:\n" % title, None))
424 for shortopt, longopt, default, desc in options:
425 for shortopt, longopt, default, desc in options:
425 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
426 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
426 longopt and " --%s" % longopt),
427 longopt and " --%s" % longopt),
427 "%s%s" % (desc,
428 "%s%s" % (desc,
428 default and " (default: %s)" % default
429 default and " (default: %s)" % default
429 or "")))
430 or "")))
430
431
431 if opt_output:
432 if opt_output:
432 opts_len = max([len(line[0]) for line in opt_output if line[1]])
433 opts_len = max([len(line[0]) for line in opt_output if line[1]])
433 for first, second in opt_output:
434 for first, second in opt_output:
434 if second:
435 if second:
435 ui.write(" %-*s %s\n" % (opts_len, first, second))
436 ui.write(" %-*s %s\n" % (opts_len, first, second))
436 else:
437 else:
437 ui.write("%s\n" % first)
438 ui.write("%s\n" % first)
438
439
439 # Commands start here, listed alphabetically
440 # Commands start here, listed alphabetically
440
441
441 def add(ui, repo, *pats, **opts):
442 def add(ui, repo, *pats, **opts):
442 '''add the specified files on the next commit'''
443 '''add the specified files on the next commit'''
443 names = []
444 names = []
444 for src, abs, rel, exact in walk(repo, pats, opts):
445 for src, abs, rel, exact in walk(repo, pats, opts):
445 if exact:
446 if exact:
446 names.append(abs)
447 names.append(abs)
447 elif repo.dirstate.state(abs) == '?':
448 elif repo.dirstate.state(abs) == '?':
448 ui.status('adding %s\n' % rel)
449 ui.status('adding %s\n' % rel)
449 names.append(abs)
450 names.append(abs)
450 repo.add(names)
451 repo.add(names)
451
452
452 def addremove(ui, repo, *pats, **opts):
453 def addremove(ui, repo, *pats, **opts):
453 """add all new files, delete all missing files"""
454 """add all new files, delete all missing files"""
454 add, remove = [], []
455 add, remove = [], []
455 for src, abs, rel, exact in walk(repo, pats, opts):
456 for src, abs, rel, exact in walk(repo, pats, opts):
456 if src == 'f' and repo.dirstate.state(abs) == '?':
457 if src == 'f' and repo.dirstate.state(abs) == '?':
457 add.append(abs)
458 add.append(abs)
458 if not exact: ui.status('adding ', rel, '\n')
459 if not exact:
460 ui.status('adding ', rel, '\n')
459 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
461 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
460 remove.append(abs)
462 remove.append(abs)
461 if not exact: ui.status('removing ', rel, '\n')
463 if not exact:
464 ui.status('removing ', rel, '\n')
462 repo.add(add)
465 repo.add(add)
463 repo.remove(remove)
466 repo.remove(remove)
464
467
465 def annotate(ui, repo, *pats, **opts):
468 def annotate(ui, repo, *pats, **opts):
466 """show changeset information per file line"""
469 """show changeset information per file line"""
467 def getnode(rev):
470 def getnode(rev):
468 return hg.short(repo.changelog.node(rev))
471 return hg.short(repo.changelog.node(rev))
469
472
470 def getname(rev):
473 def getname(rev):
471 try:
474 try:
472 return bcache[rev]
475 return bcache[rev]
473 except KeyError:
476 except KeyError:
474 cl = repo.changelog.read(repo.changelog.node(rev))
477 cl = repo.changelog.read(repo.changelog.node(rev))
475 name = cl[1]
478 name = cl[1]
476 f = name.find('@')
479 f = name.find('@')
477 if f >= 0:
480 if f >= 0:
478 name = name[:f]
481 name = name[:f]
479 f = name.find('<')
482 f = name.find('<')
480 if f >= 0:
483 if f >= 0:
481 name = name[f+1:]
484 name = name[f+1:]
482 bcache[rev] = name
485 bcache[rev] = name
483 return name
486 return name
484
487
485 if not pats:
488 if not pats:
486 raise util.Abort('at least one file name or pattern required')
489 raise util.Abort('at least one file name or pattern required')
487
490
488 bcache = {}
491 bcache = {}
489 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
492 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
490 if not opts['user'] and not opts['changeset']:
493 if not opts['user'] and not opts['changeset']:
491 opts['number'] = 1
494 opts['number'] = 1
492
495
493 if opts['rev']:
496 if opts['rev']:
494 node = repo.changelog.lookup(opts['rev'])
497 node = repo.changelog.lookup(opts['rev'])
495 else:
498 else:
496 node = repo.dirstate.parents()[0]
499 node = repo.dirstate.parents()[0]
497 change = repo.changelog.read(node)
500 change = repo.changelog.read(node)
498 mmap = repo.manifest.read(change[0])
501 mmap = repo.manifest.read(change[0])
499
502
500 for src, abs, rel, exact in walk(repo, pats, opts):
503 for src, abs, rel, exact in walk(repo, pats, opts):
501 if abs not in mmap:
504 if abs not in mmap:
502 ui.warn("warning: %s is not in the repository!\n" % rel)
505 ui.warn("warning: %s is not in the repository!\n" % rel)
503 continue
506 continue
504
507
505 f = repo.file(abs)
508 f = repo.file(abs)
506 if not opts['text'] and util.binary(f.read(mmap[abs])):
509 if not opts['text'] and util.binary(f.read(mmap[abs])):
507 ui.write("%s: binary file\n" % rel)
510 ui.write("%s: binary file\n" % rel)
508 continue
511 continue
509
512
510 lines = f.annotate(mmap[abs])
513 lines = f.annotate(mmap[abs])
511 pieces = []
514 pieces = []
512
515
513 for o, f in opmap:
516 for o, f in opmap:
514 if opts[o]:
517 if opts[o]:
515 l = [f(n) for n, dummy in lines]
518 l = [f(n) for n, dummy in lines]
516 if l:
519 if l:
517 m = max(map(len, l))
520 m = max(map(len, l))
518 pieces.append(["%*s" % (m, x) for x in l])
521 pieces.append(["%*s" % (m, x) for x in l])
519
522
520 if pieces:
523 if pieces:
521 for p, l in zip(zip(*pieces), lines):
524 for p, l in zip(zip(*pieces), lines):
522 ui.write("%s: %s" % (" ".join(p), l[1]))
525 ui.write("%s: %s" % (" ".join(p), l[1]))
523
526
524 def cat(ui, repo, file1, rev=None, **opts):
527 def cat(ui, repo, file1, rev=None, **opts):
525 """output the latest or given revision of a file"""
528 """output the latest or given revision of a file"""
526 r = repo.file(relpath(repo, [file1])[0])
529 r = repo.file(relpath(repo, [file1])[0])
527 if rev:
530 if rev:
528 try:
531 try:
529 # assume all revision numbers are for changesets
532 # assume all revision numbers are for changesets
530 n = repo.lookup(rev)
533 n = repo.lookup(rev)
531 change = repo.changelog.read(n)
534 change = repo.changelog.read(n)
532 m = repo.manifest.read(change[0])
535 m = repo.manifest.read(change[0])
533 n = m[relpath(repo, [file1])[0]]
536 n = m[relpath(repo, [file1])[0]]
534 except hg.RepoError, KeyError:
537 except hg.RepoError, KeyError:
535 n = r.lookup(rev)
538 n = r.lookup(rev)
536 else:
539 else:
537 n = r.tip()
540 n = r.tip()
538 fp = make_file(repo, r, opts['output'], node=n)
541 fp = make_file(repo, r, opts['output'], node=n)
539 fp.write(r.read(n))
542 fp.write(r.read(n))
540
543
541 def clone(ui, source, dest=None, **opts):
544 def clone(ui, source, dest=None, **opts):
542 """make a copy of an existing repository"""
545 """make a copy of an existing repository"""
543 if dest is None:
546 if dest is None:
544 dest = os.path.basename(os.path.normpath(source))
547 dest = os.path.basename(os.path.normpath(source))
545
548
546 if os.path.exists(dest):
549 if os.path.exists(dest):
547 ui.warn("abort: destination '%s' already exists\n" % dest)
550 ui.warn("abort: destination '%s' already exists\n" % dest)
548 return 1
551 return 1
549
552
550 dest = os.path.realpath(dest)
553 dest = os.path.realpath(dest)
551
554
552 class Dircleanup:
555 class Dircleanup:
553 def __init__(self, dir_):
556 def __init__(self, dir_):
554 self.rmtree = shutil.rmtree
557 self.rmtree = shutil.rmtree
555 self.dir_ = dir_
558 self.dir_ = dir_
556 os.mkdir(dir_)
559 os.mkdir(dir_)
557 def close(self):
560 def close(self):
558 self.dir_ = None
561 self.dir_ = None
559 def __del__(self):
562 def __del__(self):
560 if self.dir_:
563 if self.dir_:
561 self.rmtree(self.dir_, True)
564 self.rmtree(self.dir_, True)
562
565
563 if opts['ssh']:
566 if opts['ssh']:
564 ui.setconfig("ui", "ssh", opts['ssh'])
567 ui.setconfig("ui", "ssh", opts['ssh'])
565 if opts['remotecmd']:
568 if opts['remotecmd']:
566 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
569 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
567
570
568 d = Dircleanup(dest)
571 d = Dircleanup(dest)
569 source = ui.expandpath(source)
572 source = ui.expandpath(source)
570 abspath = source
573 abspath = source
571 other = hg.repository(ui, source)
574 other = hg.repository(ui, source)
572
575
573 if other.dev() != -1:
576 if other.dev() != -1:
574 abspath = os.path.abspath(source)
577 abspath = os.path.abspath(source)
575 copyfile = (os.stat(dest).st_dev == other.dev()
578 copyfile = (os.stat(dest).st_dev == other.dev()
576 and getattr(os, 'link', None) or shutil.copy2)
579 and getattr(os, 'link', None) or shutil.copy2)
577 if copyfile is not shutil.copy2:
580 if copyfile is not shutil.copy2:
578 ui.note("cloning by hardlink\n")
581 ui.note("cloning by hardlink\n")
579 # we use a lock here because because we're not nicely ordered
582 # we use a lock here because because we're not nicely ordered
580 l = lock.lock(os.path.join(source, ".hg", "lock"))
583 l = lock.lock(os.path.join(source, ".hg", "lock"))
581
584
582 util.copytree(os.path.join(source, ".hg"), os.path.join(dest, ".hg"),
585 util.copytree(os.path.join(source, ".hg"), os.path.join(dest, ".hg"),
583 copyfile)
586 copyfile)
584 try:
587 try:
585 os.unlink(os.path.join(dest, ".hg", "dirstate"))
588 os.unlink(os.path.join(dest, ".hg", "dirstate"))
586 except OSError:
589 except OSError:
587 pass
590 pass
588
591
589 repo = hg.repository(ui, dest)
592 repo = hg.repository(ui, dest)
590
593
591 else:
594 else:
592 repo = hg.repository(ui, dest, create=1)
595 repo = hg.repository(ui, dest, create=1)
593 repo.pull(other)
596 repo.pull(other)
594
597
595 f = repo.opener("hgrc", "w")
598 f = repo.opener("hgrc", "w")
596 f.write("[paths]\n")
599 f.write("[paths]\n")
597 f.write("default = %s\n" % abspath)
600 f.write("default = %s\n" % abspath)
598
601
599 if not opts['noupdate']:
602 if not opts['noupdate']:
600 update(ui, repo)
603 update(ui, repo)
601
604
602 d.close()
605 d.close()
603
606
604 def commit(ui, repo, *pats, **opts):
607 def commit(ui, repo, *pats, **opts):
605 """commit the specified files or all outstanding changes"""
608 """commit the specified files or all outstanding changes"""
606 if opts['text']:
609 if opts['text']:
607 ui.warn("Warning: -t and --text is deprecated,"
610 ui.warn("Warning: -t and --text is deprecated,"
608 " please use -m or --message instead.\n")
611 " please use -m or --message instead.\n")
609 message = opts['message'] or opts['text']
612 message = opts['message'] or opts['text']
610 logfile = opts['logfile']
613 logfile = opts['logfile']
611 if not message and logfile:
614 if not message and logfile:
612 try:
615 try:
613 if logfile == '-':
616 if logfile == '-':
614 message = sys.stdin.read()
617 message = sys.stdin.read()
615 else:
618 else:
616 message = open(logfile).read()
619 message = open(logfile).read()
617 except IOError, why:
620 except IOError, why:
618 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
621 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
619
622
620 if opts['addremove']:
623 if opts['addremove']:
621 addremove(ui, repo, *pats, **opts)
624 addremove(ui, repo, *pats, **opts)
622 cwd = repo.getcwd()
625 cwd = repo.getcwd()
623 if not pats and cwd:
626 if not pats and cwd:
624 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
627 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
625 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
628 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
626 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
629 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
627 pats, opts)
630 pats, opts)
628 if pats:
631 if pats:
629 c, a, d, u = repo.changes(files=fns, match=match)
632 c, a, d, u = repo.changes(files=fns, match=match)
630 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
633 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
631 else:
634 else:
632 files = []
635 files = []
633 repo.commit(files, message, opts['user'], opts['date'], match)
636 repo.commit(files, message, opts['user'], opts['date'], match)
634
637
635 def copy(ui, repo, source, dest):
638 def copy(ui, repo, source, dest):
636 """mark a file as copied or renamed for the next commit"""
639 """mark a file as copied or renamed for the next commit"""
637 return repo.copy(*relpath(repo, (source, dest)))
640 return repo.copy(*relpath(repo, (source, dest)))
638
641
639 def debugcheckstate(ui, repo):
642 def debugcheckstate(ui, repo):
640 """validate the correctness of the current dirstate"""
643 """validate the correctness of the current dirstate"""
641 parent1, parent2 = repo.dirstate.parents()
644 parent1, parent2 = repo.dirstate.parents()
642 repo.dirstate.read()
645 repo.dirstate.read()
643 dc = repo.dirstate.map
646 dc = repo.dirstate.map
644 keys = dc.keys()
647 keys = dc.keys()
645 keys.sort()
648 keys.sort()
646 m1n = repo.changelog.read(parent1)[0]
649 m1n = repo.changelog.read(parent1)[0]
647 m2n = repo.changelog.read(parent2)[0]
650 m2n = repo.changelog.read(parent2)[0]
648 m1 = repo.manifest.read(m1n)
651 m1 = repo.manifest.read(m1n)
649 m2 = repo.manifest.read(m2n)
652 m2 = repo.manifest.read(m2n)
650 errors = 0
653 errors = 0
651 for f in dc:
654 for f in dc:
652 state = repo.dirstate.state(f)
655 state = repo.dirstate.state(f)
653 if state in "nr" and f not in m1:
656 if state in "nr" and f not in m1:
654 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
657 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
655 errors += 1
658 errors += 1
656 if state in "a" and f in m1:
659 if state in "a" and f in m1:
657 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
660 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
658 errors += 1
661 errors += 1
659 if state in "m" and f not in m1 and f not in m2:
662 if state in "m" and f not in m1 and f not in m2:
660 ui.warn("%s in state %s, but not in either manifest\n" %
663 ui.warn("%s in state %s, but not in either manifest\n" %
661 (f, state))
664 (f, state))
662 errors += 1
665 errors += 1
663 for f in m1:
666 for f in m1:
664 state = repo.dirstate.state(f)
667 state = repo.dirstate.state(f)
665 if state not in "nrm":
668 if state not in "nrm":
666 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
669 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
667 errors += 1
670 errors += 1
668 if errors:
671 if errors:
669 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
672 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
670
673
671 def debugconfig(ui):
674 def debugconfig(ui):
672 """show combined config settings from all hgrc files"""
675 """show combined config settings from all hgrc files"""
673 try:
676 try:
674 repo = hg.repository(ui)
677 repo = hg.repository(ui)
675 except: pass
678 except hg.RepoError:
679 pass
676 for section, name, value in ui.walkconfig():
680 for section, name, value in ui.walkconfig():
677 ui.write('%s.%s=%s\n' % (section, name, value))
681 ui.write('%s.%s=%s\n' % (section, name, value))
678
682
679 def debugstate(ui, repo):
683 def debugstate(ui, repo):
680 """show the contents of the current dirstate"""
684 """show the contents of the current dirstate"""
681 repo.dirstate.read()
685 repo.dirstate.read()
682 dc = repo.dirstate.map
686 dc = repo.dirstate.map
683 keys = dc.keys()
687 keys = dc.keys()
684 keys.sort()
688 keys.sort()
685 for file_ in keys:
689 for file_ in keys:
686 ui.write("%c %3o %10d %s %s\n"
690 ui.write("%c %3o %10d %s %s\n"
687 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
691 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
688 time.strftime("%x %X",
692 time.strftime("%x %X",
689 time.localtime(dc[file_][3])), file_))
693 time.localtime(dc[file_][3])), file_))
690
694
691 def debugdata(ui, file_, rev):
695 def debugdata(ui, file_, rev):
692 """dump the contents of an data file revision"""
696 """dump the contents of an data file revision"""
693 r = hg.revlog(hg.opener(""), file_[:-2] + ".i", file_)
697 r = hg.revlog(hg.opener(""), file_[:-2] + ".i", file_)
694 ui.write(r.revision(r.lookup(rev)))
698 ui.write(r.revision(r.lookup(rev)))
695
699
696 def debugindex(ui, file_):
700 def debugindex(ui, file_):
697 """dump the contents of an index file"""
701 """dump the contents of an index file"""
698 r = hg.revlog(hg.opener(""), file_, "")
702 r = hg.revlog(hg.opener(""), file_, "")
699 ui.write(" rev offset length base linkrev" +
703 ui.write(" rev offset length base linkrev" +
700 " nodeid p1 p2\n")
704 " nodeid p1 p2\n")
701 for i in range(r.count()):
705 for i in range(r.count()):
702 e = r.index[i]
706 e = r.index[i]
703 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
707 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
704 i, e[0], e[1], e[2], e[3],
708 i, e[0], e[1], e[2], e[3],
705 hg.short(e[6]), hg.short(e[4]), hg.short(e[5])))
709 hg.short(e[6]), hg.short(e[4]), hg.short(e[5])))
706
710
707 def debugindexdot(ui, file_):
711 def debugindexdot(ui, file_):
708 """dump an index DAG as a .dot file"""
712 """dump an index DAG as a .dot file"""
709 r = hg.revlog(hg.opener(""), file_, "")
713 r = hg.revlog(hg.opener(""), file_, "")
710 ui.write("digraph G {\n")
714 ui.write("digraph G {\n")
711 for i in range(r.count()):
715 for i in range(r.count()):
712 e = r.index[i]
716 e = r.index[i]
713 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
717 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
714 if e[5] != hg.nullid:
718 if e[5] != hg.nullid:
715 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
719 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
716 ui.write("}\n")
720 ui.write("}\n")
717
721
718 def debugwalk(ui, repo, *pats, **opts):
722 def debugwalk(ui, repo, *pats, **opts):
719 """show how files match on given patterns"""
723 """show how files match on given patterns"""
720 items = list(walk(repo, pats, opts))
724 items = list(walk(repo, pats, opts))
721 if not items: return
725 if not items:
726 return
722 fmt = '%%s %%-%ds %%-%ds %%s\n' % (
727 fmt = '%%s %%-%ds %%-%ds %%s\n' % (
723 max([len(abs) for (src, abs, rel, exact) in items]),
728 max([len(abs) for (src, abs, rel, exact) in items]),
724 max([len(rel) for (src, abs, rel, exact) in items]))
729 max([len(rel) for (src, abs, rel, exact) in items]))
725 exactly = {True: 'exact', False: ''}
726 for src, abs, rel, exact in items:
730 for src, abs, rel, exact in items:
727 ui.write(fmt % (src, abs, rel, exactly[exact]))
731 ui.write(fmt % (src, abs, rel, exact and 'exact' or ''))
728
732
729 def diff(ui, repo, *pats, **opts):
733 def diff(ui, repo, *pats, **opts):
730 """diff working directory (or selected files)"""
734 """diff working directory (or selected files)"""
731 node1, node2 = None, None
735 node1, node2 = None, None
732 revs = [repo.lookup(x) for x in opts['rev']]
736 revs = [repo.lookup(x) for x in opts['rev']]
733
737
734 if len(revs) > 0:
738 if len(revs) > 0:
735 node1 = revs[0]
739 node1 = revs[0]
736 if len(revs) > 1:
740 if len(revs) > 1:
737 node2 = revs[1]
741 node2 = revs[1]
738 if len(revs) > 2:
742 if len(revs) > 2:
739 raise util.Abort("too many revisions to diff")
743 raise util.Abort("too many revisions to diff")
740
744
741 files = []
745 files = []
742 match = util.always
746 match = util.always
743 if pats:
747 if pats:
744 roots, match, results = makewalk(repo, pats, opts)
748 roots, match, results = makewalk(repo, pats, opts)
745 for src, abs, rel, exact in results:
749 for src, abs, rel, exact in results:
746 files.append(abs)
750 files.append(abs)
747
751
748 dodiff(sys.stdout, ui, repo, node1, node2, files, match=match,
752 dodiff(sys.stdout, ui, repo, node1, node2, files, match=match,
749 text=opts['text'])
753 text=opts['text'])
750
754
751 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
755 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
752 node = repo.lookup(changeset)
756 node = repo.lookup(changeset)
753 prev, other = repo.changelog.parents(node)
757 prev, other = repo.changelog.parents(node)
754 change = repo.changelog.read(node)
758 change = repo.changelog.read(node)
755
759
756 fp = make_file(repo, repo.changelog, opts['output'],
760 fp = make_file(repo, repo.changelog, opts['output'],
757 node=node, total=total, seqno=seqno,
761 node=node, total=total, seqno=seqno,
758 revwidth=revwidth)
762 revwidth=revwidth)
759 if fp != sys.stdout:
763 if fp != sys.stdout:
760 ui.note("%s\n" % fp.name)
764 ui.note("%s\n" % fp.name)
761
765
762 fp.write("# HG changeset patch\n")
766 fp.write("# HG changeset patch\n")
763 fp.write("# User %s\n" % change[1])
767 fp.write("# User %s\n" % change[1])
764 fp.write("# Node ID %s\n" % hg.hex(node))
768 fp.write("# Node ID %s\n" % hg.hex(node))
765 fp.write("# Parent %s\n" % hg.hex(prev))
769 fp.write("# Parent %s\n" % hg.hex(prev))
766 if other != hg.nullid:
770 if other != hg.nullid:
767 fp.write("# Parent %s\n" % hg.hex(other))
771 fp.write("# Parent %s\n" % hg.hex(other))
768 fp.write(change[4].rstrip())
772 fp.write(change[4].rstrip())
769 fp.write("\n\n")
773 fp.write("\n\n")
770
774
771 dodiff(fp, ui, repo, prev, node, text=opts['text'])
775 dodiff(fp, ui, repo, prev, node, text=opts['text'])
772 if fp != sys.stdout: fp.close()
776 if fp != sys.stdout:
777 fp.close()
773
778
774 def export(ui, repo, *changesets, **opts):
779 def export(ui, repo, *changesets, **opts):
775 """dump the header and diffs for one or more changesets"""
780 """dump the header and diffs for one or more changesets"""
776 if not changesets:
781 if not changesets:
777 raise util.Abort("export requires at least one changeset")
782 raise util.Abort("export requires at least one changeset")
778 seqno = 0
783 seqno = 0
779 revs = list(revrange(ui, repo, changesets))
784 revs = list(revrange(ui, repo, changesets))
780 total = len(revs)
785 total = len(revs)
781 revwidth = max(len(revs[0]), len(revs[-1]))
786 revwidth = max(len(revs[0]), len(revs[-1]))
782 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
787 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
783 for cset in revs:
788 for cset in revs:
784 seqno += 1
789 seqno += 1
785 doexport(ui, repo, cset, seqno, total, revwidth, opts)
790 doexport(ui, repo, cset, seqno, total, revwidth, opts)
786
791
787 def forget(ui, repo, *pats, **opts):
792 def forget(ui, repo, *pats, **opts):
788 """don't add the specified files on the next commit"""
793 """don't add the specified files on the next commit"""
789 forget = []
794 forget = []
790 for src, abs, rel, exact in walk(repo, pats, opts):
795 for src, abs, rel, exact in walk(repo, pats, opts):
791 if repo.dirstate.state(abs) == 'a':
796 if repo.dirstate.state(abs) == 'a':
792 forget.append(abs)
797 forget.append(abs)
793 if not exact: ui.status('forgetting ', rel, '\n')
798 if not exact:
799 ui.status('forgetting ', rel, '\n')
794 repo.forget(forget)
800 repo.forget(forget)
795
801
796 def grep(ui, repo, pattern=None, *pats, **opts):
802 def grep(ui, repo, pattern=None, *pats, **opts):
797 """search for a pattern in specified files and revisions"""
803 """search for a pattern in specified files and revisions"""
798 if pattern is None: pattern = opts['regexp']
804 if pattern is None:
799 if not pattern: raise util.Abort('no pattern to search for')
805 pattern = opts['regexp']
806 if not pattern:
807 raise util.Abort('no pattern to search for')
800 reflags = 0
808 reflags = 0
801 if opts['ignore_case']: reflags |= re.I
809 if opts['ignore_case']:
810 reflags |= re.I
802 regexp = re.compile(pattern, reflags)
811 regexp = re.compile(pattern, reflags)
803 sep, end = ':', '\n'
812 sep, end = ':', '\n'
804 if opts['null'] or opts['print0']: sep = end = '\0'
813 if opts['null'] or opts['print0']:
814 sep = end = '\0'
805
815
806 fcache = {}
816 fcache = {}
807 def getfile(fn):
817 def getfile(fn):
808 if fn not in fcache:
818 if fn not in fcache:
809 fcache[fn] = repo.file(fn)
819 fcache[fn] = repo.file(fn)
810 return fcache[fn]
820 return fcache[fn]
811
821
812 def matchlines(body):
822 def matchlines(body):
813 begin = 0
823 begin = 0
814 linenum = 0
824 linenum = 0
815 while True:
825 while True:
816 match = regexp.search(body, begin)
826 match = regexp.search(body, begin)
817 if not match: break
827 if not match:
828 break
818 mstart, mend = match.span()
829 mstart, mend = match.span()
819 linenum += body.count('\n', begin, mstart) + 1
830 linenum += body.count('\n', begin, mstart) + 1
820 lstart = body.rfind('\n', begin, mstart) + 1 or begin
831 lstart = body.rfind('\n', begin, mstart) + 1 or begin
821 lend = body.find('\n', mend)
832 lend = body.find('\n', mend)
822 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
833 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
823 begin = lend + 1
834 begin = lend + 1
824
835
825 class linestate:
836 class linestate:
826 def __init__(self, line, linenum, colstart, colend):
837 def __init__(self, line, linenum, colstart, colend):
827 self.line = line
838 self.line = line
828 self.linenum = linenum
839 self.linenum = linenum
829 self.colstart = colstart
840 self.colstart = colstart
830 self.colend = colend
841 self.colend = colend
831 def __eq__(self, other): return self.line == other.line
842 def __eq__(self, other):
832 def __hash__(self): return hash(self.line)
843 return self.line == other.line
844 def __hash__(self):
845 return hash(self.line)
833
846
834 matches = {}
847 matches = {}
835 def grepbody(fn, rev, body):
848 def grepbody(fn, rev, body):
836 matches[rev].setdefault(fn, {})
849 matches[rev].setdefault(fn, {})
837 m = matches[rev][fn]
850 m = matches[rev][fn]
838 for lnum, cstart, cend, line in matchlines(body):
851 for lnum, cstart, cend, line in matchlines(body):
839 s = linestate(line, lnum, cstart, cend)
852 s = linestate(line, lnum, cstart, cend)
840 m[s] = s
853 m[s] = s
841
854
842 prev = {}
855 prev = {}
843 def display(fn, rev, states, prevstates):
856 def display(fn, rev, states, prevstates):
844 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
857 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
845 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
858 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
846 for l in diff:
859 for l in diff:
847 if incrementing:
860 if incrementing:
848 change = ((l in prevstates) and '-') or '+'
861 change = ((l in prevstates) and '-') or '+'
849 r = rev
862 r = rev
850 else:
863 else:
851 change = ((l in states) and '-') or '+'
864 change = ((l in states) and '-') or '+'
852 r = prev[fn]
865 r = prev[fn]
853 ui.write('%s:%s:%s:%s%s\n' % (fn, r, l.linenum, change, l.line))
866 ui.write('%s:%s:%s:%s%s\n' % (fn, r, l.linenum, change, l.line))
854
867
855 fstate = {}
868 fstate = {}
856 for st, rev, fns in walkchangerevs(ui, repo, repo.getcwd(), pats, opts):
869 for st, rev, fns in walkchangerevs(ui, repo, repo.getcwd(), pats, opts):
857 if st == 'window':
870 if st == 'window':
858 incrementing = rev
871 incrementing = rev
859 matches.clear()
872 matches.clear()
860 elif st == 'add':
873 elif st == 'add':
861 change = repo.changelog.read(repo.lookup(str(rev)))
874 change = repo.changelog.read(repo.lookup(str(rev)))
862 mf = repo.manifest.read(change[0])
875 mf = repo.manifest.read(change[0])
863 matches[rev] = {}
876 matches[rev] = {}
864 for fn in fns:
877 for fn in fns:
865 fstate.setdefault(fn, {})
878 fstate.setdefault(fn, {})
866 try:
879 try:
867 grepbody(fn, rev, getfile(fn).read(mf[fn]))
880 grepbody(fn, rev, getfile(fn).read(mf[fn]))
868 except KeyError:
881 except KeyError:
869 pass
882 pass
870 elif st == 'iter':
883 elif st == 'iter':
871 states = matches[rev].items()
884 states = matches[rev].items()
872 states.sort()
885 states.sort()
873 for fn, m in states:
886 for fn, m in states:
874 if incrementing or fstate[fn]:
887 if incrementing or fstate[fn]:
875 display(fn, rev, m, fstate[fn])
888 display(fn, rev, m, fstate[fn])
876 fstate[fn] = m
889 fstate[fn] = m
877 prev[fn] = rev
890 prev[fn] = rev
878
891
879 if not incrementing:
892 if not incrementing:
880 fstate = fstate.items()
893 fstate = fstate.items()
881 fstate.sort()
894 fstate.sort()
882 for fn, state in fstate:
895 for fn, state in fstate:
883 display(fn, rev, {}, state)
896 display(fn, rev, {}, state)
884
897
885 def heads(ui, repo, **opts):
898 def heads(ui, repo, **opts):
886 """show current repository heads"""
899 """show current repository heads"""
887 heads = repo.changelog.heads()
900 heads = repo.changelog.heads()
888 br = None
901 br = None
889 if opts['branches']:
902 if opts['branches']:
890 br = repo.branchlookup(heads)
903 br = repo.branchlookup(heads)
891 for n in repo.changelog.heads():
904 for n in repo.changelog.heads():
892 show_changeset(ui, repo, changenode=n, brinfo=br)
905 show_changeset(ui, repo, changenode=n, brinfo=br)
893
906
894 def identify(ui, repo):
907 def identify(ui, repo):
895 """print information about the working copy"""
908 """print information about the working copy"""
896 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
909 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
897 if not parents:
910 if not parents:
898 ui.write("unknown\n")
911 ui.write("unknown\n")
899 return
912 return
900
913
901 hexfunc = ui.verbose and hg.hex or hg.short
914 hexfunc = ui.verbose and hg.hex or hg.short
902 (c, a, d, u) = repo.changes()
915 (c, a, d, u) = repo.changes()
903 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
916 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
904 (c or a or d) and "+" or "")]
917 (c or a or d) and "+" or "")]
905
918
906 if not ui.quiet:
919 if not ui.quiet:
907 # multiple tags for a single parent separated by '/'
920 # multiple tags for a single parent separated by '/'
908 parenttags = ['/'.join(tags)
921 parenttags = ['/'.join(tags)
909 for tags in map(repo.nodetags, parents) if tags]
922 for tags in map(repo.nodetags, parents) if tags]
910 # tags for multiple parents separated by ' + '
923 # tags for multiple parents separated by ' + '
911 if parenttags:
924 if parenttags:
912 output.append(' + '.join(parenttags))
925 output.append(' + '.join(parenttags))
913
926
914 ui.write("%s\n" % ' '.join(output))
927 ui.write("%s\n" % ' '.join(output))
915
928
916 def import_(ui, repo, patch1, *patches, **opts):
929 def import_(ui, repo, patch1, *patches, **opts):
917 """import an ordered set of patches"""
930 """import an ordered set of patches"""
918 patches = (patch1,) + patches
931 patches = (patch1,) + patches
919
932
920 if not opts['force']:
933 if not opts['force']:
921 (c, a, d, u) = repo.changes()
934 (c, a, d, u) = repo.changes()
922 if c or a or d:
935 if c or a or d:
923 ui.warn("abort: outstanding uncommitted changes!\n")
936 ui.warn("abort: outstanding uncommitted changes!\n")
924 return 1
937 return 1
925
938
926 d = opts["base"]
939 d = opts["base"]
927 strip = opts["strip"]
940 strip = opts["strip"]
928
941
929 for patch in patches:
942 for patch in patches:
930 ui.status("applying %s\n" % patch)
943 ui.status("applying %s\n" % patch)
931 pf = os.path.join(d, patch)
944 pf = os.path.join(d, patch)
932
945
933 message = []
946 message = []
934 user = None
947 user = None
935 hgpatch = False
948 hgpatch = False
936 for line in file(pf):
949 for line in file(pf):
937 line = line.rstrip()
950 line = line.rstrip()
938 if line.startswith("--- ") or line.startswith("diff -r"):
951 if line.startswith("--- ") or line.startswith("diff -r"):
939 break
952 break
940 elif hgpatch:
953 elif hgpatch:
941 # parse values when importing the result of an hg export
954 # parse values when importing the result of an hg export
942 if line.startswith("# User "):
955 if line.startswith("# User "):
943 user = line[7:]
956 user = line[7:]
944 ui.debug('User: %s\n' % user)
957 ui.debug('User: %s\n' % user)
945 elif not line.startswith("# ") and line:
958 elif not line.startswith("# ") and line:
946 message.append(line)
959 message.append(line)
947 hgpatch = False
960 hgpatch = False
948 elif line == '# HG changeset patch':
961 elif line == '# HG changeset patch':
949 hgpatch = True
962 hgpatch = True
950 message = [] # We may have collected garbage
963 message = [] # We may have collected garbage
951 else:
964 else:
952 message.append(line)
965 message.append(line)
953
966
954 # make sure message isn't empty
967 # make sure message isn't empty
955 if not message:
968 if not message:
956 message = "imported patch %s\n" % patch
969 message = "imported patch %s\n" % patch
957 else:
970 else:
958 message = "%s\n" % '\n'.join(message)
971 message = "%s\n" % '\n'.join(message)
959 ui.debug('message:\n%s\n' % message)
972 ui.debug('message:\n%s\n' % message)
960
973
961 f = os.popen("patch -p%d < '%s'" % (strip, pf))
974 f = os.popen("patch -p%d < '%s'" % (strip, pf))
962 files = []
975 files = []
963 for l in f.read().splitlines():
976 for l in f.read().splitlines():
964 l.rstrip('\r\n');
977 l.rstrip('\r\n');
965 ui.status("%s\n" % l)
978 ui.status("%s\n" % l)
966 if l.startswith('patching file '):
979 if l.startswith('patching file '):
967 pf = l[14:]
980 pf = l[14:]
968 if pf not in files:
981 if pf not in files:
969 files.append(pf)
982 files.append(pf)
970 patcherr = f.close()
983 patcherr = f.close()
971 if patcherr:
984 if patcherr:
972 raise util.Abort("patch failed")
985 raise util.Abort("patch failed")
973
986
974 if len(files) > 0:
987 if len(files) > 0:
975 addremove(ui, repo, *files)
988 addremove(ui, repo, *files)
976 repo.commit(files, message, user)
989 repo.commit(files, message, user)
977
990
978 def incoming(ui, repo, source="default"):
991 def incoming(ui, repo, source="default"):
979 """show new changesets found in source"""
992 """show new changesets found in source"""
980 source = ui.expandpath(source)
993 source = ui.expandpath(source)
981 other = hg.repository(ui, source)
994 other = hg.repository(ui, source)
982 if not other.local():
995 if not other.local():
983 ui.warn("abort: incoming doesn't work for remote"
996 ui.warn("abort: incoming doesn't work for remote"
984 + " repositories yet, sorry!\n")
997 + " repositories yet, sorry!\n")
985 return 1
998 return 1
986 o = repo.findincoming(other)
999 o = repo.findincoming(other)
987 if not o:
1000 if not o:
988 return
1001 return
989 o = other.newer(o)
1002 o = other.newer(o)
990 o.reverse()
1003 o.reverse()
991 for n in o:
1004 for n in o:
992 show_changeset(ui, other, changenode=n)
1005 show_changeset(ui, other, changenode=n)
993
1006
994 def init(ui, dest="."):
1007 def init(ui, dest="."):
995 """create a new repository in the given directory"""
1008 """create a new repository in the given directory"""
996 if not os.path.exists(dest):
1009 if not os.path.exists(dest):
997 os.mkdir(dest)
1010 os.mkdir(dest)
998 hg.repository(ui, dest, create=1)
1011 hg.repository(ui, dest, create=1)
999
1012
1000 def locate(ui, repo, *pats, **opts):
1013 def locate(ui, repo, *pats, **opts):
1001 """locate files matching specific patterns"""
1014 """locate files matching specific patterns"""
1002 end = '\n'
1015 end = opts['print0'] and '\0' or '\n'
1003 if opts['print0']: end = '\0'
1004
1016
1005 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1017 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1006 if repo.dirstate.state(abs) == '?': continue
1018 if repo.dirstate.state(abs) == '?':
1019 continue
1007 if opts['fullpath']:
1020 if opts['fullpath']:
1008 ui.write(os.path.join(repo.root, abs), end)
1021 ui.write(os.path.join(repo.root, abs), end)
1009 else:
1022 else:
1010 ui.write(rel, end)
1023 ui.write(rel, end)
1011
1024
1012 def log(ui, repo, *pats, **opts):
1025 def log(ui, repo, *pats, **opts):
1013 """show revision history of entire repository or files"""
1026 """show revision history of entire repository or files"""
1014 class dui:
1027 class dui:
1015 # Implement and delegate some ui protocol. Save hunks of
1028 # Implement and delegate some ui protocol. Save hunks of
1016 # output for later display in the desired order.
1029 # output for later display in the desired order.
1017 def __init__(self, ui):
1030 def __init__(self, ui):
1018 self.ui = ui
1031 self.ui = ui
1019 self.hunk = {}
1032 self.hunk = {}
1020 def bump(self, rev):
1033 def bump(self, rev):
1021 self.rev = rev
1034 self.rev = rev
1022 self.hunk[rev] = []
1035 self.hunk[rev] = []
1023 def note(self, *args):
1036 def note(self, *args):
1024 if self.verbose: self.write(*args)
1037 if self.verbose:
1038 self.write(*args)
1025 def status(self, *args):
1039 def status(self, *args):
1026 if not self.quiet: self.write(*args)
1040 if not self.quiet:
1041 self.write(*args)
1027 def write(self, *args):
1042 def write(self, *args):
1028 self.hunk[self.rev].append(args)
1043 self.hunk[self.rev].append(args)
1029 def __getattr__(self, key):
1044 def __getattr__(self, key):
1030 return getattr(self.ui, key)
1045 return getattr(self.ui, key)
1031 cwd = repo.getcwd()
1046 cwd = repo.getcwd()
1032 if not pats and cwd:
1047 if not pats and cwd:
1033 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1048 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1034 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1049 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1035 for st, rev, fns in walkchangerevs(ui, repo, (pats and cwd) or '', pats,
1050 for st, rev, fns in walkchangerevs(ui, repo, (pats and cwd) or '', pats,
1036 opts):
1051 opts):
1037 if st == 'window':
1052 if st == 'window':
1038 du = dui(ui)
1053 du = dui(ui)
1039 elif st == 'add':
1054 elif st == 'add':
1040 du.bump(rev)
1055 du.bump(rev)
1041 show_changeset(du, repo, rev)
1056 show_changeset(du, repo, rev)
1042 if opts['patch']:
1057 if opts['patch']:
1043 changenode = repo.changelog.node(rev)
1058 changenode = repo.changelog.node(rev)
1044 prev, other = repo.changelog.parents(changenode)
1059 prev, other = repo.changelog.parents(changenode)
1045 dodiff(du, du, repo, prev, changenode, fns)
1060 dodiff(du, du, repo, prev, changenode, fns)
1046 du.write("\n\n")
1061 du.write("\n\n")
1047 elif st == 'iter':
1062 elif st == 'iter':
1048 for args in du.hunk[rev]:
1063 for args in du.hunk[rev]:
1049 ui.write(*args)
1064 ui.write(*args)
1050
1065
1051 def manifest(ui, repo, rev=None):
1066 def manifest(ui, repo, rev=None):
1052 """output the latest or given revision of the project manifest"""
1067 """output the latest or given revision of the project manifest"""
1053 if rev:
1068 if rev:
1054 try:
1069 try:
1055 # assume all revision numbers are for changesets
1070 # assume all revision numbers are for changesets
1056 n = repo.lookup(rev)
1071 n = repo.lookup(rev)
1057 change = repo.changelog.read(n)
1072 change = repo.changelog.read(n)
1058 n = change[0]
1073 n = change[0]
1059 except hg.RepoError:
1074 except hg.RepoError:
1060 n = repo.manifest.lookup(rev)
1075 n = repo.manifest.lookup(rev)
1061 else:
1076 else:
1062 n = repo.manifest.tip()
1077 n = repo.manifest.tip()
1063 m = repo.manifest.read(n)
1078 m = repo.manifest.read(n)
1064 mf = repo.manifest.readflags(n)
1079 mf = repo.manifest.readflags(n)
1065 files = m.keys()
1080 files = m.keys()
1066 files.sort()
1081 files.sort()
1067
1082
1068 for f in files:
1083 for f in files:
1069 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
1084 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
1070
1085
1071 def outgoing(ui, repo, dest="default-push"):
1086 def outgoing(ui, repo, dest="default-push"):
1072 """show changesets not found in destination"""
1087 """show changesets not found in destination"""
1073 dest = ui.expandpath(dest)
1088 dest = ui.expandpath(dest)
1074 other = hg.repository(ui, dest)
1089 other = hg.repository(ui, dest)
1075 o = repo.findoutgoing(other)
1090 o = repo.findoutgoing(other)
1076 o = repo.newer(o)
1091 o = repo.newer(o)
1077 o.reverse()
1092 o.reverse()
1078 for n in o:
1093 for n in o:
1079 show_changeset(ui, repo, changenode=n)
1094 show_changeset(ui, repo, changenode=n)
1080
1095
1081 def parents(ui, repo, rev=None):
1096 def parents(ui, repo, rev=None):
1082 """show the parents of the working dir or revision"""
1097 """show the parents of the working dir or revision"""
1083 if rev:
1098 if rev:
1084 p = repo.changelog.parents(repo.lookup(rev))
1099 p = repo.changelog.parents(repo.lookup(rev))
1085 else:
1100 else:
1086 p = repo.dirstate.parents()
1101 p = repo.dirstate.parents()
1087
1102
1088 for n in p:
1103 for n in p:
1089 if n != hg.nullid:
1104 if n != hg.nullid:
1090 show_changeset(ui, repo, changenode=n)
1105 show_changeset(ui, repo, changenode=n)
1091
1106
1092 def paths(ui, search=None):
1107 def paths(ui, search=None):
1093 """show definition of symbolic path names"""
1108 """show definition of symbolic path names"""
1094 try:
1109 try:
1095 repo = hg.repository(ui=ui)
1110 repo = hg.repository(ui=ui)
1096 except:
1111 except hg.RepoError:
1097 pass
1112 pass
1098
1113
1099 if search:
1114 if search:
1100 for name, path in ui.configitems("paths"):
1115 for name, path in ui.configitems("paths"):
1101 if name == search:
1116 if name == search:
1102 ui.write("%s\n" % path)
1117 ui.write("%s\n" % path)
1103 return
1118 return
1104 ui.warn("not found!\n")
1119 ui.warn("not found!\n")
1105 return 1
1120 return 1
1106 else:
1121 else:
1107 for name, path in ui.configitems("paths"):
1122 for name, path in ui.configitems("paths"):
1108 ui.write("%s = %s\n" % (name, path))
1123 ui.write("%s = %s\n" % (name, path))
1109
1124
1110 def pull(ui, repo, source="default", **opts):
1125 def pull(ui, repo, source="default", **opts):
1111 """pull changes from the specified source"""
1126 """pull changes from the specified source"""
1112 source = ui.expandpath(source)
1127 source = ui.expandpath(source)
1113 ui.status('pulling from %s\n' % (source))
1128 ui.status('pulling from %s\n' % (source))
1114
1129
1115 if opts['ssh']:
1130 if opts['ssh']:
1116 ui.setconfig("ui", "ssh", opts['ssh'])
1131 ui.setconfig("ui", "ssh", opts['ssh'])
1117 if opts['remotecmd']:
1132 if opts['remotecmd']:
1118 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1133 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1119
1134
1120 other = hg.repository(ui, source)
1135 other = hg.repository(ui, source)
1121 r = repo.pull(other)
1136 r = repo.pull(other)
1122 if not r:
1137 if not r:
1123 if opts['update']:
1138 if opts['update']:
1124 return update(ui, repo)
1139 return update(ui, repo)
1125 else:
1140 else:
1126 ui.status("(run 'hg update' to get a working copy)\n")
1141 ui.status("(run 'hg update' to get a working copy)\n")
1127
1142
1128 return r
1143 return r
1129
1144
1130 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1145 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1131 """push changes to the specified destination"""
1146 """push changes to the specified destination"""
1132 dest = ui.expandpath(dest)
1147 dest = ui.expandpath(dest)
1133 ui.status('pushing to %s\n' % (dest))
1148 ui.status('pushing to %s\n' % (dest))
1134
1149
1135 if ssh:
1150 if ssh:
1136 ui.setconfig("ui", "ssh", ssh)
1151 ui.setconfig("ui", "ssh", ssh)
1137 if remotecmd:
1152 if remotecmd:
1138 ui.setconfig("ui", "remotecmd", remotecmd)
1153 ui.setconfig("ui", "remotecmd", remotecmd)
1139
1154
1140 other = hg.repository(ui, dest)
1155 other = hg.repository(ui, dest)
1141 r = repo.push(other, force)
1156 r = repo.push(other, force)
1142 return r
1157 return r
1143
1158
1144 def rawcommit(ui, repo, *flist, **rc):
1159 def rawcommit(ui, repo, *flist, **rc):
1145 "raw commit interface"
1160 "raw commit interface"
1146 if rc['text']:
1161 if rc['text']:
1147 ui.warn("Warning: -t and --text is deprecated,"
1162 ui.warn("Warning: -t and --text is deprecated,"
1148 " please use -m or --message instead.\n")
1163 " please use -m or --message instead.\n")
1149 message = rc['message'] or rc['text']
1164 message = rc['message'] or rc['text']
1150 if not message and rc['logfile']:
1165 if not message and rc['logfile']:
1151 try:
1166 try:
1152 message = open(rc['logfile']).read()
1167 message = open(rc['logfile']).read()
1153 except IOError:
1168 except IOError:
1154 pass
1169 pass
1155 if not message and not rc['logfile']:
1170 if not message and not rc['logfile']:
1156 ui.warn("abort: missing commit message\n")
1171 ui.warn("abort: missing commit message\n")
1157 return 1
1172 return 1
1158
1173
1159 files = relpath(repo, list(flist))
1174 files = relpath(repo, list(flist))
1160 if rc['files']:
1175 if rc['files']:
1161 files += open(rc['files']).read().splitlines()
1176 files += open(rc['files']).read().splitlines()
1162
1177
1163 rc['parent'] = map(repo.lookup, rc['parent'])
1178 rc['parent'] = map(repo.lookup, rc['parent'])
1164
1179
1165 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1180 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1166
1181
1167 def recover(ui, repo):
1182 def recover(ui, repo):
1168 """roll back an interrupted transaction"""
1183 """roll back an interrupted transaction"""
1169 repo.recover()
1184 repo.recover()
1170
1185
1171 def remove(ui, repo, file1, *files):
1186 def remove(ui, repo, file1, *files):
1172 """remove the specified files on the next commit"""
1187 """remove the specified files on the next commit"""
1173 repo.remove(relpath(repo, (file1,) + files))
1188 repo.remove(relpath(repo, (file1,) + files))
1174
1189
1175 def revert(ui, repo, *names, **opts):
1190 def revert(ui, repo, *names, **opts):
1176 """revert modified files or dirs back to their unmodified states"""
1191 """revert modified files or dirs back to their unmodified states"""
1177 node = opts['rev'] and repo.lookup(opts['rev']) or \
1192 node = opts['rev'] and repo.lookup(opts['rev']) or \
1178 repo.dirstate.parents()[0]
1193 repo.dirstate.parents()[0]
1179 root = os.path.realpath(repo.root)
1194 root = os.path.realpath(repo.root)
1180
1195
1181 def trimpath(p):
1196 def trimpath(p):
1182 p = os.path.realpath(p)
1197 p = os.path.realpath(p)
1183 if p.startswith(root):
1198 if p.startswith(root):
1184 rest = p[len(root):]
1199 rest = p[len(root):]
1185 if not rest:
1200 if not rest:
1186 return rest
1201 return rest
1187 if p.startswith(os.sep):
1202 if p.startswith(os.sep):
1188 return rest[1:]
1203 return rest[1:]
1189 return p
1204 return p
1190
1205
1191 relnames = map(trimpath, names or [os.getcwd()])
1206 relnames = map(trimpath, names or [os.getcwd()])
1192 chosen = {}
1207 chosen = {}
1193
1208
1194 def choose(name):
1209 def choose(name):
1195 def body(name):
1210 def body(name):
1196 for r in relnames:
1211 for r in relnames:
1197 if not name.startswith(r):
1212 if not name.startswith(r):
1198 continue
1213 continue
1199 rest = name[len(r):]
1214 rest = name[len(r):]
1200 if not rest:
1215 if not rest:
1201 return r, True
1216 return r, True
1202 depth = rest.count(os.sep)
1217 depth = rest.count(os.sep)
1203 if not r:
1218 if not r:
1204 if depth == 0 or not opts['nonrecursive']:
1219 if depth == 0 or not opts['nonrecursive']:
1205 return r, True
1220 return r, True
1206 elif rest[0] == os.sep:
1221 elif rest[0] == os.sep:
1207 if depth == 1 or not opts['nonrecursive']:
1222 if depth == 1 or not opts['nonrecursive']:
1208 return r, True
1223 return r, True
1209 return None, False
1224 return None, False
1210 relname, ret = body(name)
1225 relname, ret = body(name)
1211 if ret:
1226 if ret:
1212 chosen[relname] = 1
1227 chosen[relname] = 1
1213 return ret
1228 return ret
1214
1229
1215 r = repo.update(node, False, True, choose, False)
1230 r = repo.update(node, False, True, choose, False)
1216 for n in relnames:
1231 for n in relnames:
1217 if n not in chosen:
1232 if n not in chosen:
1218 ui.warn('error: no matches for %s\n' % n)
1233 ui.warn('error: no matches for %s\n' % n)
1219 r = 1
1234 r = 1
1220 sys.stdout.flush()
1235 sys.stdout.flush()
1221 return r
1236 return r
1222
1237
1223 def root(ui, repo):
1238 def root(ui, repo):
1224 """print the root (top) of the current working dir"""
1239 """print the root (top) of the current working dir"""
1225 ui.write(repo.root + "\n")
1240 ui.write(repo.root + "\n")
1226
1241
1227 def serve(ui, repo, **opts):
1242 def serve(ui, repo, **opts):
1228 """export the repository via HTTP"""
1243 """export the repository via HTTP"""
1229
1244
1230 if opts["stdio"]:
1245 if opts["stdio"]:
1231 fin, fout = sys.stdin, sys.stdout
1246 fin, fout = sys.stdin, sys.stdout
1232 sys.stdout = sys.stderr
1247 sys.stdout = sys.stderr
1233
1248
1234 def getarg():
1249 def getarg():
1235 argline = fin.readline()[:-1]
1250 argline = fin.readline()[:-1]
1236 arg, l = argline.split()
1251 arg, l = argline.split()
1237 val = fin.read(int(l))
1252 val = fin.read(int(l))
1238 return arg, val
1253 return arg, val
1239 def respond(v):
1254 def respond(v):
1240 fout.write("%d\n" % len(v))
1255 fout.write("%d\n" % len(v))
1241 fout.write(v)
1256 fout.write(v)
1242 fout.flush()
1257 fout.flush()
1243
1258
1244 lock = None
1259 lock = None
1245
1260
1246 while 1:
1261 while 1:
1247 cmd = fin.readline()[:-1]
1262 cmd = fin.readline()[:-1]
1248 if cmd == '':
1263 if cmd == '':
1249 return
1264 return
1250 if cmd == "heads":
1265 if cmd == "heads":
1251 h = repo.heads()
1266 h = repo.heads()
1252 respond(" ".join(map(hg.hex, h)) + "\n")
1267 respond(" ".join(map(hg.hex, h)) + "\n")
1253 if cmd == "lock":
1268 if cmd == "lock":
1254 lock = repo.lock()
1269 lock = repo.lock()
1255 respond("")
1270 respond("")
1256 if cmd == "unlock":
1271 if cmd == "unlock":
1257 if lock:
1272 if lock:
1258 lock.release()
1273 lock.release()
1259 lock = None
1274 lock = None
1260 respond("")
1275 respond("")
1261 elif cmd == "branches":
1276 elif cmd == "branches":
1262 arg, nodes = getarg()
1277 arg, nodes = getarg()
1263 nodes = map(hg.bin, nodes.split(" "))
1278 nodes = map(hg.bin, nodes.split(" "))
1264 r = []
1279 r = []
1265 for b in repo.branches(nodes):
1280 for b in repo.branches(nodes):
1266 r.append(" ".join(map(hg.hex, b)) + "\n")
1281 r.append(" ".join(map(hg.hex, b)) + "\n")
1267 respond("".join(r))
1282 respond("".join(r))
1268 elif cmd == "between":
1283 elif cmd == "between":
1269 arg, pairs = getarg()
1284 arg, pairs = getarg()
1270 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
1285 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
1271 r = []
1286 r = []
1272 for b in repo.between(pairs):
1287 for b in repo.between(pairs):
1273 r.append(" ".join(map(hg.hex, b)) + "\n")
1288 r.append(" ".join(map(hg.hex, b)) + "\n")
1274 respond("".join(r))
1289 respond("".join(r))
1275 elif cmd == "changegroup":
1290 elif cmd == "changegroup":
1276 nodes = []
1291 nodes = []
1277 arg, roots = getarg()
1292 arg, roots = getarg()
1278 nodes = map(hg.bin, roots.split(" "))
1293 nodes = map(hg.bin, roots.split(" "))
1279
1294
1280 cg = repo.changegroup(nodes)
1295 cg = repo.changegroup(nodes)
1281 while 1:
1296 while 1:
1282 d = cg.read(4096)
1297 d = cg.read(4096)
1283 if not d:
1298 if not d:
1284 break
1299 break
1285 fout.write(d)
1300 fout.write(d)
1286
1301
1287 fout.flush()
1302 fout.flush()
1288
1303
1289 elif cmd == "addchangegroup":
1304 elif cmd == "addchangegroup":
1290 if not lock:
1305 if not lock:
1291 respond("not locked")
1306 respond("not locked")
1292 continue
1307 continue
1293 respond("")
1308 respond("")
1294
1309
1295 r = repo.addchangegroup(fin)
1310 r = repo.addchangegroup(fin)
1296 respond("")
1311 respond("")
1297
1312
1298 optlist = "name templates style address port ipv6 accesslog errorlog"
1313 optlist = "name templates style address port ipv6 accesslog errorlog"
1299 for o in optlist.split():
1314 for o in optlist.split():
1300 if opts[o]:
1315 if opts[o]:
1301 ui.setconfig("web", o, opts[o])
1316 ui.setconfig("web", o, opts[o])
1302
1317
1303 httpd = hgweb.create_server(repo)
1318 httpd = hgweb.create_server(repo)
1304
1319
1305 if ui.verbose:
1320 if ui.verbose:
1306 addr, port = httpd.socket.getsockname()
1321 addr, port = httpd.socket.getsockname()
1307 if addr == '0.0.0.0':
1322 if addr == '0.0.0.0':
1308 addr = socket.gethostname()
1323 addr = socket.gethostname()
1309 else:
1324 else:
1310 try:
1325 try:
1311 addr = socket.gethostbyaddr(addr)[0]
1326 addr = socket.gethostbyaddr(addr)[0]
1312 except socket.error:
1327 except socket.error:
1313 pass
1328 pass
1314 if port != 80:
1329 if port != 80:
1315 ui.status('listening at http://%s:%d/\n' % (addr, port))
1330 ui.status('listening at http://%s:%d/\n' % (addr, port))
1316 else:
1331 else:
1317 ui.status('listening at http://%s/\n' % addr)
1332 ui.status('listening at http://%s/\n' % addr)
1318 httpd.serve_forever()
1333 httpd.serve_forever()
1319
1334
1320 def status(ui, repo, *pats, **opts):
1335 def status(ui, repo, *pats, **opts):
1321 '''show changed files in the working directory
1336 '''show changed files in the working directory
1322
1337
1323 M = modified
1338 M = modified
1324 A = added
1339 A = added
1325 R = removed
1340 R = removed
1326 ? = not tracked
1341 ? = not tracked
1327 '''
1342 '''
1328
1343
1329 cwd = repo.getcwd()
1344 cwd = repo.getcwd()
1330 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1345 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1331 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1346 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1332 for n in repo.changes(files=files, match=matchfn)]
1347 for n in repo.changes(files=files, match=matchfn)]
1333
1348
1334 changetypes = [('modified', 'M', c),
1349 changetypes = [('modified', 'M', c),
1335 ('added', 'A', a),
1350 ('added', 'A', a),
1336 ('removed', 'R', d),
1351 ('removed', 'R', d),
1337 ('unknown', '?', u)]
1352 ('unknown', '?', u)]
1338
1353
1339 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1354 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1340 or changetypes):
1355 or changetypes):
1341 for f in changes:
1356 for f in changes:
1342 ui.write("%s %s\n" % (char, f))
1357 ui.write("%s %s\n" % (char, f))
1343
1358
1344 def tag(ui, repo, name, rev=None, **opts):
1359 def tag(ui, repo, name, rev=None, **opts):
1345 """add a tag for the current tip or a given revision"""
1360 """add a tag for the current tip or a given revision"""
1346 if opts['text']:
1361 if opts['text']:
1347 ui.warn("Warning: -t and --text is deprecated,"
1362 ui.warn("Warning: -t and --text is deprecated,"
1348 " please use -m or --message instead.\n")
1363 " please use -m or --message instead.\n")
1349 if name == "tip":
1364 if name == "tip":
1350 ui.warn("abort: 'tip' is a reserved name!\n")
1365 ui.warn("abort: 'tip' is a reserved name!\n")
1351 return -1
1366 return -1
1352 if rev:
1367 if rev:
1353 r = hg.hex(repo.lookup(rev))
1368 r = hg.hex(repo.lookup(rev))
1354 else:
1369 else:
1355 r = hg.hex(repo.changelog.tip())
1370 r = hg.hex(repo.changelog.tip())
1356
1371
1357 if name.find(revrangesep) >= 0:
1372 if name.find(revrangesep) >= 0:
1358 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1373 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1359 return -1
1374 return -1
1360
1375
1361 if opts['local']:
1376 if opts['local']:
1362 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1377 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1363 return
1378 return
1364
1379
1365 (c, a, d, u) = repo.changes()
1380 (c, a, d, u) = repo.changes()
1366 for x in (c, a, d, u):
1381 for x in (c, a, d, u):
1367 if ".hgtags" in x:
1382 if ".hgtags" in x:
1368 ui.warn("abort: working copy of .hgtags is changed!\n")
1383 ui.warn("abort: working copy of .hgtags is changed!\n")
1369 ui.status("(please commit .hgtags manually)\n")
1384 ui.status("(please commit .hgtags manually)\n")
1370 return -1
1385 return -1
1371
1386
1372 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1387 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1373 if repo.dirstate.state(".hgtags") == '?':
1388 if repo.dirstate.state(".hgtags") == '?':
1374 repo.add([".hgtags"])
1389 repo.add([".hgtags"])
1375
1390
1376 message = (opts['message'] or opts['text'] or
1391 message = (opts['message'] or opts['text'] or
1377 "Added tag %s for changeset %s" % (name, r))
1392 "Added tag %s for changeset %s" % (name, r))
1378 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1393 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1379
1394
1380 def tags(ui, repo):
1395 def tags(ui, repo):
1381 """list repository tags"""
1396 """list repository tags"""
1382
1397
1383 l = repo.tagslist()
1398 l = repo.tagslist()
1384 l.reverse()
1399 l.reverse()
1385 for t, n in l:
1400 for t, n in l:
1386 try:
1401 try:
1387 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1402 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1388 except KeyError:
1403 except KeyError:
1389 r = " ?:?"
1404 r = " ?:?"
1390 ui.write("%-30s %s\n" % (t, r))
1405 ui.write("%-30s %s\n" % (t, r))
1391
1406
1392 def tip(ui, repo):
1407 def tip(ui, repo):
1393 """show the tip revision"""
1408 """show the tip revision"""
1394 n = repo.changelog.tip()
1409 n = repo.changelog.tip()
1395 show_changeset(ui, repo, changenode=n)
1410 show_changeset(ui, repo, changenode=n)
1396
1411
1397 def undo(ui, repo):
1412 def undo(ui, repo):
1398 """undo the last commit or pull
1413 """undo the last commit or pull
1399
1414
1400 Roll back the last pull or commit transaction on the
1415 Roll back the last pull or commit transaction on the
1401 repository, restoring the project to its earlier state.
1416 repository, restoring the project to its earlier state.
1402
1417
1403 This command should be used with care. There is only one level of
1418 This command should be used with care. There is only one level of
1404 undo and there is no redo.
1419 undo and there is no redo.
1405
1420
1406 This command is not intended for use on public repositories. Once
1421 This command is not intended for use on public repositories. Once
1407 a change is visible for pull by other users, undoing it locally is
1422 a change is visible for pull by other users, undoing it locally is
1408 ineffective.
1423 ineffective.
1409 """
1424 """
1410 repo.undo()
1425 repo.undo()
1411
1426
1412 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1427 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1413 '''update or merge working directory
1428 '''update or merge working directory
1414
1429
1415 If there are no outstanding changes in the working directory and
1430 If there are no outstanding changes in the working directory and
1416 there is a linear relationship between the current version and the
1431 there is a linear relationship between the current version and the
1417 requested version, the result is the requested version.
1432 requested version, the result is the requested version.
1418
1433
1419 Otherwise the result is a merge between the contents of the
1434 Otherwise the result is a merge between the contents of the
1420 current working directory and the requested version. Files that
1435 current working directory and the requested version. Files that
1421 changed between either parent are marked as changed for the next
1436 changed between either parent are marked as changed for the next
1422 commit and a commit must be performed before any further updates
1437 commit and a commit must be performed before any further updates
1423 are allowed.
1438 are allowed.
1424 '''
1439 '''
1425 if branch:
1440 if branch:
1426 br = repo.branchlookup(branch=branch)
1441 br = repo.branchlookup(branch=branch)
1427 found = []
1442 found = []
1428 for x in br:
1443 for x in br:
1429 if branch in br[x]:
1444 if branch in br[x]:
1430 found.append(x)
1445 found.append(x)
1431 if len(found) > 1:
1446 if len(found) > 1:
1432 ui.warn("Found multiple heads for %s\n" % branch)
1447 ui.warn("Found multiple heads for %s\n" % branch)
1433 for x in found:
1448 for x in found:
1434 show_changeset(ui, repo, changenode=x, brinfo=br)
1449 show_changeset(ui, repo, changenode=x, brinfo=br)
1435 return 1
1450 return 1
1436 if len(found) == 1:
1451 if len(found) == 1:
1437 node = found[0]
1452 node = found[0]
1438 ui.warn("Using head %s for branch %s\n" % (hg.short(node), branch))
1453 ui.warn("Using head %s for branch %s\n" % (hg.short(node), branch))
1439 else:
1454 else:
1440 ui.warn("branch %s not found\n" % (branch))
1455 ui.warn("branch %s not found\n" % (branch))
1441 return 1
1456 return 1
1442 else:
1457 else:
1443 node = node and repo.lookup(node) or repo.changelog.tip()
1458 node = node and repo.lookup(node) or repo.changelog.tip()
1444 return repo.update(node, allow=merge, force=clean)
1459 return repo.update(node, allow=merge, force=clean)
1445
1460
1446 def verify(ui, repo):
1461 def verify(ui, repo):
1447 """verify the integrity of the repository"""
1462 """verify the integrity of the repository"""
1448 return repo.verify()
1463 return repo.verify()
1449
1464
1450 # Command options and aliases are listed here, alphabetically
1465 # Command options and aliases are listed here, alphabetically
1451
1466
1452 table = {
1467 table = {
1453 "^add":
1468 "^add":
1454 (add,
1469 (add,
1455 [('I', 'include', [], 'include path in search'),
1470 [('I', 'include', [], 'include path in search'),
1456 ('X', 'exclude', [], 'exclude path from search')],
1471 ('X', 'exclude', [], 'exclude path from search')],
1457 "hg add [OPTION]... [FILE]..."),
1472 "hg add [OPTION]... [FILE]..."),
1458 "addremove":
1473 "addremove":
1459 (addremove,
1474 (addremove,
1460 [('I', 'include', [], 'include path in search'),
1475 [('I', 'include', [], 'include path in search'),
1461 ('X', 'exclude', [], 'exclude path from search')],
1476 ('X', 'exclude', [], 'exclude path from search')],
1462 "hg addremove [OPTION]... [FILE]..."),
1477 "hg addremove [OPTION]... [FILE]..."),
1463 "^annotate":
1478 "^annotate":
1464 (annotate,
1479 (annotate,
1465 [('r', 'rev', '', 'revision'),
1480 [('r', 'rev', '', 'revision'),
1466 ('a', 'text', None, 'treat all files as text'),
1481 ('a', 'text', None, 'treat all files as text'),
1467 ('u', 'user', None, 'show user'),
1482 ('u', 'user', None, 'show user'),
1468 ('n', 'number', None, 'show revision number'),
1483 ('n', 'number', None, 'show revision number'),
1469 ('c', 'changeset', None, 'show changeset'),
1484 ('c', 'changeset', None, 'show changeset'),
1470 ('I', 'include', [], 'include path in search'),
1485 ('I', 'include', [], 'include path in search'),
1471 ('X', 'exclude', [], 'exclude path from search')],
1486 ('X', 'exclude', [], 'exclude path from search')],
1472 'hg annotate [OPTION]... FILE...'),
1487 'hg annotate [OPTION]... FILE...'),
1473 "cat":
1488 "cat":
1474 (cat,
1489 (cat,
1475 [('o', 'output', "", 'output to file')],
1490 [('o', 'output', "", 'output to file')],
1476 'hg cat [-o OUTFILE] FILE [REV]'),
1491 'hg cat [-o OUTFILE] FILE [REV]'),
1477 "^clone":
1492 "^clone":
1478 (clone,
1493 (clone,
1479 [('U', 'noupdate', None, 'skip update after cloning'),
1494 [('U', 'noupdate', None, 'skip update after cloning'),
1480 ('e', 'ssh', "", 'ssh command'),
1495 ('e', 'ssh', "", 'ssh command'),
1481 ('', 'remotecmd', "", 'remote hg command')],
1496 ('', 'remotecmd', "", 'remote hg command')],
1482 'hg clone [OPTION]... SOURCE [DEST]'),
1497 'hg clone [OPTION]... SOURCE [DEST]'),
1483 "^commit|ci":
1498 "^commit|ci":
1484 (commit,
1499 (commit,
1485 [('A', 'addremove', None, 'run add/remove during commit'),
1500 [('A', 'addremove', None, 'run add/remove during commit'),
1486 ('I', 'include', [], 'include path in search'),
1501 ('I', 'include', [], 'include path in search'),
1487 ('X', 'exclude', [], 'exclude path from search'),
1502 ('X', 'exclude', [], 'exclude path from search'),
1488 ('m', 'message', "", 'commit message'),
1503 ('m', 'message', "", 'commit message'),
1489 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1504 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1490 ('l', 'logfile', "", 'commit message file'),
1505 ('l', 'logfile', "", 'commit message file'),
1491 ('d', 'date', "", 'date code'),
1506 ('d', 'date', "", 'date code'),
1492 ('u', 'user', "", 'user')],
1507 ('u', 'user', "", 'user')],
1493 'hg commit [OPTION]... [FILE]...'),
1508 'hg commit [OPTION]... [FILE]...'),
1494 "copy": (copy, [], 'hg copy SOURCE DEST'),
1509 "copy": (copy, [], 'hg copy SOURCE DEST'),
1495 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1510 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1496 "debugconfig": (debugconfig, [], 'debugconfig'),
1511 "debugconfig": (debugconfig, [], 'debugconfig'),
1497 "debugstate": (debugstate, [], 'debugstate'),
1512 "debugstate": (debugstate, [], 'debugstate'),
1498 "debugdata": (debugdata, [], 'debugdata FILE REV'),
1513 "debugdata": (debugdata, [], 'debugdata FILE REV'),
1499 "debugindex": (debugindex, [], 'debugindex FILE'),
1514 "debugindex": (debugindex, [], 'debugindex FILE'),
1500 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1515 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1501 "debugwalk":
1516 "debugwalk":
1502 (debugwalk,
1517 (debugwalk,
1503 [('I', 'include', [], 'include path in search'),
1518 [('I', 'include', [], 'include path in search'),
1504 ('X', 'exclude', [], 'exclude path from search')],
1519 ('X', 'exclude', [], 'exclude path from search')],
1505 'debugwalk [OPTION]... [FILE]...'),
1520 'debugwalk [OPTION]... [FILE]...'),
1506 "^diff":
1521 "^diff":
1507 (diff,
1522 (diff,
1508 [('r', 'rev', [], 'revision'),
1523 [('r', 'rev', [], 'revision'),
1509 ('a', 'text', None, 'treat all files as text'),
1524 ('a', 'text', None, 'treat all files as text'),
1510 ('I', 'include', [], 'include path in search'),
1525 ('I', 'include', [], 'include path in search'),
1511 ('X', 'exclude', [], 'exclude path from search')],
1526 ('X', 'exclude', [], 'exclude path from search')],
1512 'hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...'),
1527 'hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...'),
1513 "^export":
1528 "^export":
1514 (export,
1529 (export,
1515 [('o', 'output', "", 'output to file'),
1530 [('o', 'output', "", 'output to file'),
1516 ('a', 'text', None, 'treat all files as text')],
1531 ('a', 'text', None, 'treat all files as text')],
1517 "hg export [-a] [-o OUTFILE] REV..."),
1532 "hg export [-a] [-o OUTFILE] REV..."),
1518 "forget":
1533 "forget":
1519 (forget,
1534 (forget,
1520 [('I', 'include', [], 'include path in search'),
1535 [('I', 'include', [], 'include path in search'),
1521 ('X', 'exclude', [], 'exclude path from search')],
1536 ('X', 'exclude', [], 'exclude path from search')],
1522 "hg forget [OPTION]... FILE..."),
1537 "hg forget [OPTION]... FILE..."),
1523 "grep": (grep,
1538 "grep":
1524 [('0', 'print0', None, 'terminate file names with NUL'),
1539 (grep,
1525 ('I', 'include', [], 'include path in search'),
1540 [('0', 'print0', None, 'terminate file names with NUL'),
1526 ('X', 'exclude', [], 'include path in search'),
1541 ('I', 'include', [], 'include path in search'),
1527 ('Z', 'null', None, 'terminate file names with NUL'),
1542 ('X', 'exclude', [], 'include path in search'),
1528 ('a', 'all-revs', '', 'search all revs'),
1543 ('Z', 'null', None, 'terminate file names with NUL'),
1529 ('e', 'regexp', '', 'pattern to search for'),
1544 ('a', 'all-revs', '', 'search all revs'),
1530 ('f', 'full-path', None, 'print complete paths'),
1545 ('e', 'regexp', '', 'pattern to search for'),
1531 ('i', 'ignore-case', None, 'ignore case when matching'),
1546 ('f', 'full-path', None, 'print complete paths'),
1532 ('l', 'files-with-matches', None, 'print names of files with matches'),
1547 ('i', 'ignore-case', None, 'ignore case when matching'),
1533 ('n', 'line-number', '', 'print line numbers'),
1548 ('l', 'files-with-matches', None, 'print names of files with matches'),
1534 ('r', 'rev', [], 'search in revision rev'),
1549 ('n', 'line-number', '', 'print line numbers'),
1535 ('s', 'no-messages', None, 'do not print error messages'),
1550 ('r', 'rev', [], 'search in revision rev'),
1536 ('v', 'invert-match', None, 'select non-matching lines')],
1551 ('s', 'no-messages', None, 'do not print error messages'),
1537 "hg grep [options] [pat] [files]"),
1552 ('v', 'invert-match', None, 'select non-matching lines')],
1553 "hg grep [options] [pat] [files]"),
1538 "heads":
1554 "heads":
1539 (heads,
1555 (heads,
1540 [('b', 'branches', None, 'find branch info')],
1556 [('b', 'branches', None, 'find branch info')],
1541 'hg heads [-b]'),
1557 'hg heads [-b]'),
1542 "help": (help_, [], 'hg help [COMMAND]'),
1558 "help": (help_, [], 'hg help [COMMAND]'),
1543 "identify|id": (identify, [], 'hg identify'),
1559 "identify|id": (identify, [], 'hg identify'),
1544 "import|patch":
1560 "import|patch":
1545 (import_,
1561 (import_,
1546 [('p', 'strip', 1, 'path strip'),
1562 [('p', 'strip', 1, 'path strip'),
1547 ('f', 'force', None, 'skip check for outstanding changes'),
1563 ('f', 'force', None, 'skip check for outstanding changes'),
1548 ('b', 'base', "", 'base path')],
1564 ('b', 'base', "", 'base path')],
1549 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
1565 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
1550 "incoming|in": (incoming, [], 'hg incoming [SOURCE]'),
1566 "incoming|in": (incoming, [], 'hg incoming [SOURCE]'),
1551 "^init": (init, [], 'hg init [DEST]'),
1567 "^init": (init, [], 'hg init [DEST]'),
1552 "locate":
1568 "locate":
1553 (locate,
1569 (locate,
1554 [('r', 'rev', '', 'revision'),
1570 [('r', 'rev', '', 'revision'),
1555 ('0', 'print0', None, 'end records with NUL'),
1571 ('0', 'print0', None, 'end records with NUL'),
1556 ('f', 'fullpath', None, 'print complete paths'),
1572 ('f', 'fullpath', None, 'print complete paths'),
1557 ('I', 'include', [], 'include path in search'),
1573 ('I', 'include', [], 'include path in search'),
1558 ('X', 'exclude', [], 'exclude path from search')],
1574 ('X', 'exclude', [], 'exclude path from search')],
1559 'hg locate [OPTION]... [PATTERN]...'),
1575 'hg locate [OPTION]... [PATTERN]...'),
1560 "^log|history":
1576 "^log|history":
1561 (log,
1577 (log,
1562 [('I', 'include', [], 'include path in search'),
1578 [('I', 'include', [], 'include path in search'),
1563 ('X', 'exclude', [], 'exclude path from search'),
1579 ('X', 'exclude', [], 'exclude path from search'),
1564 ('r', 'rev', [], 'revision'),
1580 ('r', 'rev', [], 'revision'),
1565 ('p', 'patch', None, 'show patch')],
1581 ('p', 'patch', None, 'show patch')],
1566 'hg log [-I] [-X] [-r REV]... [-p] [FILE]'),
1582 'hg log [-I] [-X] [-r REV]... [-p] [FILE]'),
1567 "manifest": (manifest, [], 'hg manifest [REV]'),
1583 "manifest": (manifest, [], 'hg manifest [REV]'),
1568 "outgoing|out": (outgoing, [], 'hg outgoing [DEST]'),
1584 "outgoing|out": (outgoing, [], 'hg outgoing [DEST]'),
1569 "parents": (parents, [], 'hg parents [REV]'),
1585 "parents": (parents, [], 'hg parents [REV]'),
1570 "paths": (paths, [], 'hg paths [NAME]'),
1586 "paths": (paths, [], 'hg paths [NAME]'),
1571 "^pull":
1587 "^pull":
1572 (pull,
1588 (pull,
1573 [('u', 'update', None, 'update working directory'),
1589 [('u', 'update', None, 'update working directory'),
1574 ('e', 'ssh', "", 'ssh command'),
1590 ('e', 'ssh', "", 'ssh command'),
1575 ('', 'remotecmd', "", 'remote hg command')],
1591 ('', 'remotecmd', "", 'remote hg command')],
1576 'hg pull [-u] [-e FILE] [--remotecmd FILE] [SOURCE]'),
1592 'hg pull [-u] [-e FILE] [--remotecmd FILE] [SOURCE]'),
1577 "^push":
1593 "^push":
1578 (push,
1594 (push,
1579 [('f', 'force', None, 'force push'),
1595 [('f', 'force', None, 'force push'),
1580 ('e', 'ssh', "", 'ssh command'),
1596 ('e', 'ssh', "", 'ssh command'),
1581 ('', 'remotecmd', "", 'remote hg command')],
1597 ('', 'remotecmd', "", 'remote hg command')],
1582 'hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]'),
1598 'hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]'),
1583 "rawcommit":
1599 "rawcommit":
1584 (rawcommit,
1600 (rawcommit,
1585 [('p', 'parent', [], 'parent'),
1601 [('p', 'parent', [], 'parent'),
1586 ('d', 'date', "", 'date code'),
1602 ('d', 'date', "", 'date code'),
1587 ('u', 'user', "", 'user'),
1603 ('u', 'user', "", 'user'),
1588 ('F', 'files', "", 'file list'),
1604 ('F', 'files', "", 'file list'),
1589 ('m', 'message', "", 'commit message'),
1605 ('m', 'message', "", 'commit message'),
1590 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1606 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1591 ('l', 'logfile', "", 'commit message file')],
1607 ('l', 'logfile', "", 'commit message file')],
1592 'hg rawcommit [OPTION]... [FILE]...'),
1608 'hg rawcommit [OPTION]... [FILE]...'),
1593 "recover": (recover, [], "hg recover"),
1609 "recover": (recover, [], "hg recover"),
1594 "^remove|rm": (remove, [], "hg remove FILE..."),
1610 "^remove|rm": (remove, [], "hg remove FILE..."),
1595 "^revert":
1611 "^revert":
1596 (revert,
1612 (revert,
1597 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1613 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1598 ("r", "rev", "", "revision")],
1614 ("r", "rev", "", "revision")],
1599 "hg revert [-n] [-r REV] [NAME]..."),
1615 "hg revert [-n] [-r REV] [NAME]..."),
1600 "root": (root, [], "hg root"),
1616 "root": (root, [], "hg root"),
1601 "^serve":
1617 "^serve":
1602 (serve,
1618 (serve,
1603 [('A', 'accesslog', '', 'access log file'),
1619 [('A', 'accesslog', '', 'access log file'),
1604 ('E', 'errorlog', '', 'error log file'),
1620 ('E', 'errorlog', '', 'error log file'),
1605 ('p', 'port', 0, 'listen port'),
1621 ('p', 'port', 0, 'listen port'),
1606 ('a', 'address', '', 'interface address'),
1622 ('a', 'address', '', 'interface address'),
1607 ('n', 'name', "", 'repository name'),
1623 ('n', 'name', "", 'repository name'),
1608 ('', 'stdio', None, 'for remote clients'),
1624 ('', 'stdio', None, 'for remote clients'),
1609 ('t', 'templates', "", 'template directory'),
1625 ('t', 'templates', "", 'template directory'),
1610 ('', 'style', "", 'template style'),
1626 ('', 'style', "", 'template style'),
1611 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1627 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1612 "hg serve [OPTION]..."),
1628 "hg serve [OPTION]..."),
1613 "^status":
1629 "^status":
1614 (status,
1630 (status,
1615 [('m', 'modified', None, 'show only modified files'),
1631 [('m', 'modified', None, 'show only modified files'),
1616 ('a', 'added', None, 'show only added files'),
1632 ('a', 'added', None, 'show only added files'),
1617 ('r', 'removed', None, 'show only removed files'),
1633 ('r', 'removed', None, 'show only removed files'),
1618 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1634 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1619 ('I', 'include', [], 'include path in search'),
1635 ('I', 'include', [], 'include path in search'),
1620 ('X', 'exclude', [], 'exclude path from search')],
1636 ('X', 'exclude', [], 'exclude path from search')],
1621 "hg status [OPTION]... [FILE]..."),
1637 "hg status [OPTION]... [FILE]..."),
1622 "tag":
1638 "tag":
1623 (tag,
1639 (tag,
1624 [('l', 'local', None, 'make the tag local'),
1640 [('l', 'local', None, 'make the tag local'),
1625 ('m', 'message', "", 'commit message'),
1641 ('m', 'message', "", 'commit message'),
1626 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1642 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1627 ('d', 'date', "", 'date code'),
1643 ('d', 'date', "", 'date code'),
1628 ('u', 'user', "", 'user')],
1644 ('u', 'user', "", 'user')],
1629 'hg tag [OPTION]... NAME [REV]'),
1645 'hg tag [OPTION]... NAME [REV]'),
1630 "tags": (tags, [], 'hg tags'),
1646 "tags": (tags, [], 'hg tags'),
1631 "tip": (tip, [], 'hg tip'),
1647 "tip": (tip, [], 'hg tip'),
1632 "undo": (undo, [], 'hg undo'),
1648 "undo": (undo, [], 'hg undo'),
1633 "^update|up|checkout|co":
1649 "^update|up|checkout|co":
1634 (update,
1650 (update,
1635 [('b', 'branch', "", 'checkout the head of a specific branch'),
1651 [('b', 'branch', "", 'checkout the head of a specific branch'),
1636 ('m', 'merge', None, 'allow merging of conflicts'),
1652 ('m', 'merge', None, 'allow merging of conflicts'),
1637 ('C', 'clean', None, 'overwrite locally modified files')],
1653 ('C', 'clean', None, 'overwrite locally modified files')],
1638 'hg update [-b TAG] [-m] [-C] [REV]'),
1654 'hg update [-b TAG] [-m] [-C] [REV]'),
1639 "verify": (verify, [], 'hg verify'),
1655 "verify": (verify, [], 'hg verify'),
1640 "version": (show_version, [], 'hg version'),
1656 "version": (show_version, [], 'hg version'),
1641 }
1657 }
1642
1658
1643 globalopts = [
1659 globalopts = [
1644 ('R', 'repository', "", 'repository root directory'),
1660 ('R', 'repository', "", 'repository root directory'),
1645 ('', 'cwd', '', 'change working directory'),
1661 ('', 'cwd', '', 'change working directory'),
1646 ('y', 'noninteractive', None, 'run non-interactively'),
1662 ('y', 'noninteractive', None, 'run non-interactively'),
1647 ('q', 'quiet', None, 'quiet mode'),
1663 ('q', 'quiet', None, 'quiet mode'),
1648 ('v', 'verbose', None, 'verbose mode'),
1664 ('v', 'verbose', None, 'verbose mode'),
1649 ('', 'debug', None, 'debug mode'),
1665 ('', 'debug', None, 'debug mode'),
1650 ('', 'traceback', None, 'print traceback on exception'),
1666 ('', 'traceback', None, 'print traceback on exception'),
1651 ('', 'time', None, 'time how long the command takes'),
1667 ('', 'time', None, 'time how long the command takes'),
1652 ('', 'profile', None, 'profile'),
1668 ('', 'profile', None, 'profile'),
1653 ('', 'version', None, 'output version information and exit'),
1669 ('', 'version', None, 'output version information and exit'),
1654 ('h', 'help', None, 'display help and exit'),
1670 ('h', 'help', None, 'display help and exit'),
1655 ]
1671 ]
1656
1672
1657 norepo = "clone init version help debugconfig debugdata" + \
1673 norepo = ("clone init version help debugconfig debugdata"
1658 " debugindex debugindexdot paths"
1674 " debugindex debugindexdot paths")
1659
1675
1660 def find(cmd):
1676 def find(cmd):
1661 for e in table.keys():
1677 for e in table.keys():
1662 if re.match("(%s)$" % e, cmd):
1678 if re.match("(%s)$" % e, cmd):
1663 return e, table[e]
1679 return e, table[e]
1664
1680
1665 raise UnknownCommand(cmd)
1681 raise UnknownCommand(cmd)
1666
1682
1667 class SignalInterrupt(Exception):
1683 class SignalInterrupt(Exception):
1668 """Exception raised on SIGTERM and SIGHUP."""
1684 """Exception raised on SIGTERM and SIGHUP."""
1669
1685
1670 def catchterm(*args):
1686 def catchterm(*args):
1671 raise SignalInterrupt
1687 raise SignalInterrupt
1672
1688
1673 def run():
1689 def run():
1674 sys.exit(dispatch(sys.argv[1:]))
1690 sys.exit(dispatch(sys.argv[1:]))
1675
1691
1676 class ParseError(Exception):
1692 class ParseError(Exception):
1677 """Exception raised on errors in parsing the command line."""
1693 """Exception raised on errors in parsing the command line."""
1678
1694
1679 def parse(args):
1695 def parse(args):
1680 options = {}
1696 options = {}
1681 cmdoptions = {}
1697 cmdoptions = {}
1682
1698
1683 try:
1699 try:
1684 args = fancyopts.fancyopts(args, globalopts, options)
1700 args = fancyopts.fancyopts(args, globalopts, options)
1685 except fancyopts.getopt.GetoptError, inst:
1701 except fancyopts.getopt.GetoptError, inst:
1686 raise ParseError(None, inst)
1702 raise ParseError(None, inst)
1687
1703
1688 if args:
1704 if args:
1689 cmd, args = args[0], args[1:]
1705 cmd, args = args[0], args[1:]
1690 i = find(cmd)[1]
1706 i = find(cmd)[1]
1691 c = list(i[1])
1707 c = list(i[1])
1692 else:
1708 else:
1693 cmd = None
1709 cmd = None
1694 c = []
1710 c = []
1695
1711
1696 # combine global options into local
1712 # combine global options into local
1697 for o in globalopts:
1713 for o in globalopts:
1698 c.append((o[0], o[1], options[o[1]], o[3]))
1714 c.append((o[0], o[1], options[o[1]], o[3]))
1699
1715
1700 try:
1716 try:
1701 args = fancyopts.fancyopts(args, c, cmdoptions)
1717 args = fancyopts.fancyopts(args, c, cmdoptions)
1702 except fancyopts.getopt.GetoptError, inst:
1718 except fancyopts.getopt.GetoptError, inst:
1703 raise ParseError(cmd, inst)
1719 raise ParseError(cmd, inst)
1704
1720
1705 # separate global options back out
1721 # separate global options back out
1706 for o in globalopts:
1722 for o in globalopts:
1707 n = o[1]
1723 n = o[1]
1708 options[n] = cmdoptions[n]
1724 options[n] = cmdoptions[n]
1709 del cmdoptions[n]
1725 del cmdoptions[n]
1710
1726
1711 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
1727 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
1712
1728
1713 def dispatch(args):
1729 def dispatch(args):
1714 signal.signal(signal.SIGTERM, catchterm)
1730 signal.signal(signal.SIGTERM, catchterm)
1715 try:
1731 try:
1716 signal.signal(signal.SIGHUP, catchterm)
1732 signal.signal(signal.SIGHUP, catchterm)
1717 except AttributeError:
1733 except AttributeError:
1718 pass
1734 pass
1719
1735
1720 try:
1736 try:
1721 cmd, func, args, options, cmdoptions = parse(args)
1737 cmd, func, args, options, cmdoptions = parse(args)
1722 except ParseError, inst:
1738 except ParseError, inst:
1723 u = ui.ui()
1739 u = ui.ui()
1724 if inst.args[0]:
1740 if inst.args[0]:
1725 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1741 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1726 help_(u, inst.args[0])
1742 help_(u, inst.args[0])
1727 else:
1743 else:
1728 u.warn("hg: %s\n" % inst.args[1])
1744 u.warn("hg: %s\n" % inst.args[1])
1729 help_(u, 'shortlist')
1745 help_(u, 'shortlist')
1730 sys.exit(-1)
1746 sys.exit(-1)
1731 except UnknownCommand, inst:
1747 except UnknownCommand, inst:
1732 u = ui.ui()
1748 u = ui.ui()
1733 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1749 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1734 help_(u, 'shortlist')
1750 help_(u, 'shortlist')
1735 sys.exit(1)
1751 sys.exit(1)
1736
1752
1737 if options["time"]:
1753 if options["time"]:
1738 def get_times():
1754 def get_times():
1739 t = os.times()
1755 t = os.times()
1740 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1756 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1741 t = (t[0], t[1], t[2], t[3], time.clock())
1757 t = (t[0], t[1], t[2], t[3], time.clock())
1742 return t
1758 return t
1743 s = get_times()
1759 s = get_times()
1744 def print_time():
1760 def print_time():
1745 t = get_times()
1761 t = get_times()
1746 u = ui.ui()
1762 u = ui.ui()
1747 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1763 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1748 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1764 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1749 atexit.register(print_time)
1765 atexit.register(print_time)
1750
1766
1751 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1767 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1752 not options["noninteractive"])
1768 not options["noninteractive"])
1753
1769
1754 try:
1770 try:
1755 try:
1771 try:
1756 if options['help']:
1772 if options['help']:
1757 help_(u, cmd, options['version'])
1773 help_(u, cmd, options['version'])
1758 sys.exit(0)
1774 sys.exit(0)
1759 elif options['version']:
1775 elif options['version']:
1760 show_version(u)
1776 show_version(u)
1761 sys.exit(0)
1777 sys.exit(0)
1762 elif not cmd:
1778 elif not cmd:
1763 help_(u, 'shortlist')
1779 help_(u, 'shortlist')
1764 sys.exit(0)
1780 sys.exit(0)
1765
1781
1766 if options['cwd']:
1782 if options['cwd']:
1767 try:
1783 try:
1768 os.chdir(options['cwd'])
1784 os.chdir(options['cwd'])
1769 except OSError, inst:
1785 except OSError, inst:
1770 u.warn('abort: %s: %s\n' % (options['cwd'], inst.strerror))
1786 u.warn('abort: %s: %s\n' % (options['cwd'], inst.strerror))
1771 sys.exit(1)
1787 sys.exit(1)
1772
1788
1773 if cmd not in norepo.split():
1789 if cmd not in norepo.split():
1774 path = options["repository"] or ""
1790 path = options["repository"] or ""
1775 repo = hg.repository(ui=u, path=path)
1791 repo = hg.repository(ui=u, path=path)
1776 d = lambda: func(u, repo, *args, **cmdoptions)
1792 d = lambda: func(u, repo, *args, **cmdoptions)
1777 else:
1793 else:
1778 d = lambda: func(u, *args, **cmdoptions)
1794 d = lambda: func(u, *args, **cmdoptions)
1779
1795
1780 if options['profile']:
1796 if options['profile']:
1781 import hotshot, hotshot.stats
1797 import hotshot, hotshot.stats
1782 prof = hotshot.Profile("hg.prof")
1798 prof = hotshot.Profile("hg.prof")
1783 r = prof.runcall(d)
1799 r = prof.runcall(d)
1784 prof.close()
1800 prof.close()
1785 stats = hotshot.stats.load("hg.prof")
1801 stats = hotshot.stats.load("hg.prof")
1786 stats.strip_dirs()
1802 stats.strip_dirs()
1787 stats.sort_stats('time', 'calls')
1803 stats.sort_stats('time', 'calls')
1788 stats.print_stats(40)
1804 stats.print_stats(40)
1789 return r
1805 return r
1790 else:
1806 else:
1791 return d()
1807 return d()
1792 except:
1808 except:
1793 if options['traceback']:
1809 if options['traceback']:
1794 traceback.print_exc()
1810 traceback.print_exc()
1795 raise
1811 raise
1796 except hg.RepoError, inst:
1812 except hg.RepoError, inst:
1797 u.warn("abort: ", inst, "!\n")
1813 u.warn("abort: ", inst, "!\n")
1798 except SignalInterrupt:
1814 except SignalInterrupt:
1799 u.warn("killed!\n")
1815 u.warn("killed!\n")
1800 except KeyboardInterrupt:
1816 except KeyboardInterrupt:
1801 try:
1817 try:
1802 u.warn("interrupted!\n")
1818 u.warn("interrupted!\n")
1803 except IOError, inst:
1819 except IOError, inst:
1804 if inst.errno == errno.EPIPE:
1820 if inst.errno == errno.EPIPE:
1805 if u.debugflag:
1821 if u.debugflag:
1806 u.warn("\nbroken pipe\n")
1822 u.warn("\nbroken pipe\n")
1807 else:
1823 else:
1808 raise
1824 raise
1809 except IOError, inst:
1825 except IOError, inst:
1810 if hasattr(inst, "code"):
1826 if hasattr(inst, "code"):
1811 u.warn("abort: %s\n" % inst)
1827 u.warn("abort: %s\n" % inst)
1812 elif hasattr(inst, "reason"):
1828 elif hasattr(inst, "reason"):
1813 u.warn("abort: error: %s\n" % inst.reason[1])
1829 u.warn("abort: error: %s\n" % inst.reason[1])
1814 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1830 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1815 if u.debugflag: u.warn("broken pipe\n")
1831 if u.debugflag:
1832 u.warn("broken pipe\n")
1816 else:
1833 else:
1817 raise
1834 raise
1818 except OSError, inst:
1835 except OSError, inst:
1819 if hasattr(inst, "filename"):
1836 if hasattr(inst, "filename"):
1820 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1837 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1821 else:
1838 else:
1822 u.warn("abort: %s\n" % inst.strerror)
1839 u.warn("abort: %s\n" % inst.strerror)
1823 except util.Abort, inst:
1840 except util.Abort, inst:
1824 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1841 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1825 sys.exit(1)
1842 sys.exit(1)
1826 except TypeError, inst:
1843 except TypeError, inst:
1827 # was this an argument error?
1844 # was this an argument error?
1828 tb = traceback.extract_tb(sys.exc_info()[2])
1845 tb = traceback.extract_tb(sys.exc_info()[2])
1829 if len(tb) > 2: # no
1846 if len(tb) > 2: # no
1830 raise
1847 raise
1831 u.debug(inst, "\n")
1848 u.debug(inst, "\n")
1832 u.warn("%s: invalid arguments\n" % cmd)
1849 u.warn("%s: invalid arguments\n" % cmd)
1833 help_(u, cmd)
1850 help_(u, cmd)
1834 except UnknownCommand, inst:
1851 except UnknownCommand, inst:
1835 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1852 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1836 help_(u, 'shortlist')
1853 help_(u, 'shortlist')
1837
1854
1838 sys.exit(-1)
1855 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now