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