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