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