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