##// END OF EJS Templates
hg clone stored path fix...
Mikael Berthe -
r675:49de76ab default
parent child Browse files
Show More
@@ -1,1281 +1,1284 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 *
8 from demandload import *
9 demandload(globals(), "os re sys signal")
9 demandload(globals(), "os re sys signal")
10 demandload(globals(), "fancyopts ui hg util")
10 demandload(globals(), "fancyopts ui hg util")
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")
12 demandload(globals(), "errno socket version struct")
13
13
14 class UnknownCommand(Exception): pass
14 class UnknownCommand(Exception): pass
15
15
16 def filterfiles(filters, files):
16 def filterfiles(filters, files):
17 l = [ x for x in files if x in filters ]
17 l = [ x for x in files if x in filters ]
18
18
19 for t in filters:
19 for t in filters:
20 if t and t[-1] != "/": t += "/"
20 if t and t[-1] != "/": t += "/"
21 l += [ x for x in files if x.startswith(t) ]
21 l += [ x for x in files if x.startswith(t) ]
22 return l
22 return l
23
23
24 def relfilter(repo, files):
24 def relfilter(repo, files):
25 cwd = repo.getcwd()
25 cwd = repo.getcwd()
26 if cwd:
26 if cwd:
27 return filterfiles([util.pconvert(cwd)], files)
27 return filterfiles([util.pconvert(cwd)], files)
28 return files
28 return files
29
29
30 def relpath(repo, args):
30 def relpath(repo, args):
31 cwd = repo.getcwd()
31 cwd = repo.getcwd()
32 if cwd:
32 if cwd:
33 return [ util.pconvert(os.path.normpath(os.path.join(cwd, x))) for x in args ]
33 return [ util.pconvert(os.path.normpath(os.path.join(cwd, x))) for x in args ]
34 return args
34 return args
35
35
36 revrangesep = ':'
36 revrangesep = ':'
37
37
38 def revrange(ui, repo, revs = [], revlog = None):
38 def revrange(ui, repo, revs = [], revlog = None):
39 if revlog is None:
39 if revlog is None:
40 revlog = repo.changelog
40 revlog = repo.changelog
41 revcount = revlog.count()
41 revcount = revlog.count()
42 def fix(val, defval):
42 def fix(val, defval):
43 if not val: return defval
43 if not val: return defval
44 try:
44 try:
45 num = int(val)
45 num = int(val)
46 if str(num) != val: raise ValueError
46 if str(num) != val: raise ValueError
47 if num < 0: num += revcount
47 if num < 0: num += revcount
48 if not (0 <= num < revcount):
48 if not (0 <= num < revcount):
49 raise ValueError
49 raise ValueError
50 except ValueError:
50 except ValueError:
51 try:
51 try:
52 num = repo.changelog.rev(repo.lookup(val))
52 num = repo.changelog.rev(repo.lookup(val))
53 except KeyError:
53 except KeyError:
54 try:
54 try:
55 num = revlog.rev(revlog.lookup(val))
55 num = revlog.rev(revlog.lookup(val))
56 except KeyError:
56 except KeyError:
57 ui.warn('abort: invalid revision identifier %s\n' % val)
57 ui.warn('abort: invalid revision identifier %s\n' % val)
58 sys.exit(1)
58 sys.exit(1)
59 return num
59 return num
60 for spec in revs:
60 for spec in revs:
61 if spec.find(revrangesep) >= 0:
61 if spec.find(revrangesep) >= 0:
62 start, end = spec.split(revrangesep, 1)
62 start, end = spec.split(revrangesep, 1)
63 start = fix(start, 0)
63 start = fix(start, 0)
64 end = fix(end, revcount - 1)
64 end = fix(end, revcount - 1)
65 if end > start:
65 if end > start:
66 end += 1
66 end += 1
67 step = 1
67 step = 1
68 else:
68 else:
69 end -= 1
69 end -= 1
70 step = -1
70 step = -1
71 for rev in xrange(start, end, step):
71 for rev in xrange(start, end, step):
72 yield str(rev)
72 yield str(rev)
73 else:
73 else:
74 yield spec
74 yield spec
75
75
76 def make_filename(repo, r, pat, node=None,
76 def make_filename(repo, r, pat, node=None,
77 total=None, seqno=None, revwidth=None):
77 total=None, seqno=None, revwidth=None):
78 node_expander = {
78 node_expander = {
79 'H': lambda: hg.hex(node),
79 'H': lambda: hg.hex(node),
80 'R': lambda: str(r.rev(node)),
80 'R': lambda: str(r.rev(node)),
81 'h': lambda: hg.short(node),
81 'h': lambda: hg.short(node),
82 }
82 }
83 expander = {
83 expander = {
84 '%': lambda: '%',
84 '%': lambda: '%',
85 'b': lambda: os.path.basename(repo.root),
85 'b': lambda: os.path.basename(repo.root),
86 }
86 }
87
87
88 if node: expander.update(node_expander)
88 if node: expander.update(node_expander)
89 if node and revwidth is not None:
89 if node and revwidth is not None:
90 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
90 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
91 if total is not None: expander['N'] = lambda: str(total)
91 if total is not None: expander['N'] = lambda: str(total)
92 if seqno is not None: expander['n'] = lambda: str(seqno)
92 if seqno is not None: expander['n'] = lambda: str(seqno)
93 if total is not None and seqno is not None:
93 if total is not None and seqno is not None:
94 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
94 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
95
95
96 newname = []
96 newname = []
97 patlen = len(pat)
97 patlen = len(pat)
98 i = 0
98 i = 0
99 while i < patlen:
99 while i < patlen:
100 c = pat[i]
100 c = pat[i]
101 if c == '%':
101 if c == '%':
102 i += 1
102 i += 1
103 c = pat[i]
103 c = pat[i]
104 c = expander[c]()
104 c = expander[c]()
105 newname.append(c)
105 newname.append(c)
106 i += 1
106 i += 1
107 return ''.join(newname)
107 return ''.join(newname)
108
108
109 def dodiff(fp, ui, repo, files = None, node1 = None, node2 = None):
109 def dodiff(fp, ui, repo, files = None, node1 = None, node2 = None):
110 def date(c):
110 def date(c):
111 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
111 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
112
112
113 (c, a, d, u) = repo.changes(node1, node2, files)
113 (c, a, d, u) = repo.changes(node1, node2, files)
114 if files:
114 if files:
115 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
115 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
116
116
117 if not c and not a and not d:
117 if not c and not a and not d:
118 return
118 return
119
119
120 if node2:
120 if node2:
121 change = repo.changelog.read(node2)
121 change = repo.changelog.read(node2)
122 mmap2 = repo.manifest.read(change[0])
122 mmap2 = repo.manifest.read(change[0])
123 def read(f): return repo.file(f).read(mmap2[f])
123 def read(f): return repo.file(f).read(mmap2[f])
124 date2 = date(change)
124 date2 = date(change)
125 else:
125 else:
126 date2 = time.asctime()
126 date2 = time.asctime()
127 if not node1:
127 if not node1:
128 node1 = repo.dirstate.parents()[0]
128 node1 = repo.dirstate.parents()[0]
129 def read(f): return repo.wfile(f).read()
129 def read(f): return repo.wfile(f).read()
130
130
131 if ui.quiet:
131 if ui.quiet:
132 r = None
132 r = None
133 else:
133 else:
134 hexfunc = ui.verbose and hg.hex or hg.short
134 hexfunc = ui.verbose and hg.hex or hg.short
135 r = [hexfunc(node) for node in [node1, node2] if node]
135 r = [hexfunc(node) for node in [node1, node2] if node]
136
136
137 change = repo.changelog.read(node1)
137 change = repo.changelog.read(node1)
138 mmap = repo.manifest.read(change[0])
138 mmap = repo.manifest.read(change[0])
139 date1 = date(change)
139 date1 = date(change)
140
140
141 for f in c:
141 for f in c:
142 to = None
142 to = None
143 if f in mmap:
143 if f in mmap:
144 to = repo.file(f).read(mmap[f])
144 to = repo.file(f).read(mmap[f])
145 tn = read(f)
145 tn = read(f)
146 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
146 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
147 for f in a:
147 for f in a:
148 to = None
148 to = None
149 tn = read(f)
149 tn = read(f)
150 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
150 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
151 for f in d:
151 for f in d:
152 to = repo.file(f).read(mmap[f])
152 to = repo.file(f).read(mmap[f])
153 tn = None
153 tn = None
154 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
154 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
155
155
156 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
156 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
157 """show a single changeset or file revision"""
157 """show a single changeset or file revision"""
158 changelog = repo.changelog
158 changelog = repo.changelog
159 if filelog:
159 if filelog:
160 log = filelog
160 log = filelog
161 filerev = rev
161 filerev = rev
162 node = filenode = filelog.node(filerev)
162 node = filenode = filelog.node(filerev)
163 changerev = filelog.linkrev(filenode)
163 changerev = filelog.linkrev(filenode)
164 changenode = changenode or changelog.node(changerev)
164 changenode = changenode or changelog.node(changerev)
165 else:
165 else:
166 log = changelog
166 log = changelog
167 changerev = rev
167 changerev = rev
168 if changenode is None:
168 if changenode is None:
169 changenode = changelog.node(changerev)
169 changenode = changelog.node(changerev)
170 elif not changerev:
170 elif not changerev:
171 rev = changerev = changelog.rev(changenode)
171 rev = changerev = changelog.rev(changenode)
172 node = changenode
172 node = changenode
173
173
174 if ui.quiet:
174 if ui.quiet:
175 ui.write("%d:%s\n" % (rev, hg.hex(node)))
175 ui.write("%d:%s\n" % (rev, hg.hex(node)))
176 return
176 return
177
177
178 changes = changelog.read(changenode)
178 changes = changelog.read(changenode)
179
179
180 parents = [(log.rev(parent), hg.hex(parent))
180 parents = [(log.rev(parent), hg.hex(parent))
181 for parent in log.parents(node)
181 for parent in log.parents(node)
182 if ui.debugflag or parent != hg.nullid]
182 if ui.debugflag or parent != hg.nullid]
183 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
183 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
184 parents = []
184 parents = []
185
185
186 if filelog:
186 if filelog:
187 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
187 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
188 for parent in parents:
188 for parent in parents:
189 ui.write("parent: %d:%s\n" % parent)
189 ui.write("parent: %d:%s\n" % parent)
190 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
190 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
191 else:
191 else:
192 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
192 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
193 for tag in repo.nodetags(changenode):
193 for tag in repo.nodetags(changenode):
194 ui.status("tag: %s\n" % tag)
194 ui.status("tag: %s\n" % tag)
195 for parent in parents:
195 for parent in parents:
196 ui.write("parent: %d:%s\n" % parent)
196 ui.write("parent: %d:%s\n" % parent)
197 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
197 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
198 hg.hex(changes[0])))
198 hg.hex(changes[0])))
199 ui.status("user: %s\n" % changes[1])
199 ui.status("user: %s\n" % changes[1])
200 ui.status("date: %s\n" % time.asctime(
200 ui.status("date: %s\n" % time.asctime(
201 time.localtime(float(changes[2].split(' ')[0]))))
201 time.localtime(float(changes[2].split(' ')[0]))))
202 if ui.debugflag:
202 if ui.debugflag:
203 files = repo.changes(changelog.parents(changenode)[0], changenode)
203 files = repo.changes(changelog.parents(changenode)[0], changenode)
204 for key, value in zip(["files:", "files+:", "files-:"], files):
204 for key, value in zip(["files:", "files+:", "files-:"], files):
205 if value:
205 if value:
206 ui.note("%-12s %s\n" % (key, " ".join(value)))
206 ui.note("%-12s %s\n" % (key, " ".join(value)))
207 else:
207 else:
208 ui.note("files: %s\n" % " ".join(changes[3]))
208 ui.note("files: %s\n" % " ".join(changes[3]))
209 description = changes[4].strip()
209 description = changes[4].strip()
210 if description:
210 if description:
211 if ui.verbose:
211 if ui.verbose:
212 ui.status("description:\n")
212 ui.status("description:\n")
213 ui.status(description)
213 ui.status(description)
214 ui.status("\n\n")
214 ui.status("\n\n")
215 else:
215 else:
216 ui.status("summary: %s\n" % description.splitlines()[0])
216 ui.status("summary: %s\n" % description.splitlines()[0])
217 ui.status("\n")
217 ui.status("\n")
218
218
219 def show_version(ui):
219 def show_version(ui):
220 """output version and copyright information"""
220 """output version and copyright information"""
221 ui.write("Mercurial version %s\n" % version.get_version())
221 ui.write("Mercurial version %s\n" % version.get_version())
222 ui.status(
222 ui.status(
223 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
223 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
224 "This is free software; see the source for copying conditions. "
224 "This is free software; see the source for copying conditions. "
225 "There is NO\nwarranty; "
225 "There is NO\nwarranty; "
226 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
226 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
227 )
227 )
228
228
229 def help(ui, cmd=None):
229 def help(ui, cmd=None):
230 '''show help for a given command or all commands'''
230 '''show help for a given command or all commands'''
231 if cmd:
231 if cmd:
232 try:
232 try:
233 i = find(cmd)
233 i = find(cmd)
234 ui.write("%s\n\n" % i[2])
234 ui.write("%s\n\n" % i[2])
235
235
236 if i[1]:
236 if i[1]:
237 for s, l, d, c in i[1]:
237 for s, l, d, c in i[1]:
238 opt=' '
238 opt=' '
239 if s: opt = opt + '-' + s + ' '
239 if s: opt = opt + '-' + s + ' '
240 if l: opt = opt + '--' + l + ' '
240 if l: opt = opt + '--' + l + ' '
241 if d: opt = opt + '(' + str(d) + ')'
241 if d: opt = opt + '(' + str(d) + ')'
242 ui.write(opt, "\n")
242 ui.write(opt, "\n")
243 if c: ui.write(' %s\n' % c)
243 if c: ui.write(' %s\n' % c)
244 ui.write("\n")
244 ui.write("\n")
245
245
246 ui.write(i[0].__doc__, "\n")
246 ui.write(i[0].__doc__, "\n")
247 except UnknownCommand:
247 except UnknownCommand:
248 ui.warn("hg: unknown command %s\n" % cmd)
248 ui.warn("hg: unknown command %s\n" % cmd)
249 sys.exit(0)
249 sys.exit(0)
250 else:
250 else:
251 if ui.verbose:
251 if ui.verbose:
252 show_version(ui)
252 show_version(ui)
253 ui.write('\n')
253 ui.write('\n')
254 if ui.verbose:
254 if ui.verbose:
255 ui.write('hg commands:\n\n')
255 ui.write('hg commands:\n\n')
256 else:
256 else:
257 ui.write('basic hg commands (use "hg help -v" for more):\n\n')
257 ui.write('basic hg commands (use "hg help -v" for more):\n\n')
258
258
259 h = {}
259 h = {}
260 for c, e in table.items():
260 for c, e in table.items():
261 f = c.split("|")[0]
261 f = c.split("|")[0]
262 if not ui.verbose and not f.startswith("^"):
262 if not ui.verbose and not f.startswith("^"):
263 continue
263 continue
264 if not ui.debugflag and f.startswith("debug"):
264 if not ui.debugflag and f.startswith("debug"):
265 continue
265 continue
266 f = f.lstrip("^")
266 f = f.lstrip("^")
267 d = ""
267 d = ""
268 if e[0].__doc__:
268 if e[0].__doc__:
269 d = e[0].__doc__.splitlines(0)[0].rstrip()
269 d = e[0].__doc__.splitlines(0)[0].rstrip()
270 h[f] = d
270 h[f] = d
271
271
272 fns = h.keys()
272 fns = h.keys()
273 fns.sort()
273 fns.sort()
274 m = max(map(len, fns))
274 m = max(map(len, fns))
275 for f in fns:
275 for f in fns:
276 ui.write(' %-*s %s\n' % (m, f, h[f]))
276 ui.write(' %-*s %s\n' % (m, f, h[f]))
277
277
278 # Commands start here, listed alphabetically
278 # Commands start here, listed alphabetically
279
279
280 def add(ui, repo, file, *files):
280 def add(ui, repo, file, *files):
281 '''add the specified files on the next commit'''
281 '''add the specified files on the next commit'''
282 repo.add(relpath(repo, (file,) + files))
282 repo.add(relpath(repo, (file,) + files))
283
283
284 def addremove(ui, repo, *files):
284 def addremove(ui, repo, *files):
285 """add all new files, delete all missing files"""
285 """add all new files, delete all missing files"""
286 if files:
286 if files:
287 files = relpath(repo, files)
287 files = relpath(repo, files)
288 d = []
288 d = []
289 u = []
289 u = []
290 for f in files:
290 for f in files:
291 p = repo.wjoin(f)
291 p = repo.wjoin(f)
292 s = repo.dirstate.state(f)
292 s = repo.dirstate.state(f)
293 isfile = os.path.isfile(p)
293 isfile = os.path.isfile(p)
294 if s != 'r' and not isfile:
294 if s != 'r' and not isfile:
295 d.append(f)
295 d.append(f)
296 elif s not in 'nmai' and isfile:
296 elif s not in 'nmai' and isfile:
297 u.append(f)
297 u.append(f)
298 else:
298 else:
299 (c, a, d, u) = repo.changes(None, None)
299 (c, a, d, u) = repo.changes(None, None)
300 repo.add(u)
300 repo.add(u)
301 repo.remove(d)
301 repo.remove(d)
302
302
303 def annotate(u, repo, file, *files, **ops):
303 def annotate(u, repo, file, *files, **ops):
304 """show changeset information per file line"""
304 """show changeset information per file line"""
305 def getnode(rev):
305 def getnode(rev):
306 return hg.short(repo.changelog.node(rev))
306 return hg.short(repo.changelog.node(rev))
307
307
308 def getname(rev):
308 def getname(rev):
309 try:
309 try:
310 return bcache[rev]
310 return bcache[rev]
311 except KeyError:
311 except KeyError:
312 cl = repo.changelog.read(repo.changelog.node(rev))
312 cl = repo.changelog.read(repo.changelog.node(rev))
313 name = cl[1]
313 name = cl[1]
314 f = name.find('@')
314 f = name.find('@')
315 if f >= 0:
315 if f >= 0:
316 name = name[:f]
316 name = name[:f]
317 f = name.find('<')
317 f = name.find('<')
318 if f >= 0:
318 if f >= 0:
319 name = name[f+1:]
319 name = name[f+1:]
320 bcache[rev] = name
320 bcache[rev] = name
321 return name
321 return name
322
322
323 bcache = {}
323 bcache = {}
324 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
324 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
325 if not ops['user'] and not ops['changeset']:
325 if not ops['user'] and not ops['changeset']:
326 ops['number'] = 1
326 ops['number'] = 1
327
327
328 node = repo.dirstate.parents()[0]
328 node = repo.dirstate.parents()[0]
329 if ops['revision']:
329 if ops['revision']:
330 node = repo.changelog.lookup(ops['revision'])
330 node = repo.changelog.lookup(ops['revision'])
331 change = repo.changelog.read(node)
331 change = repo.changelog.read(node)
332 mmap = repo.manifest.read(change[0])
332 mmap = repo.manifest.read(change[0])
333 for f in relpath(repo, (file,) + files):
333 for f in relpath(repo, (file,) + files):
334 lines = repo.file(f).annotate(mmap[f])
334 lines = repo.file(f).annotate(mmap[f])
335 pieces = []
335 pieces = []
336
336
337 for o, f in opmap:
337 for o, f in opmap:
338 if ops[o]:
338 if ops[o]:
339 l = [ f(n) for n,t in lines ]
339 l = [ f(n) for n,t in lines ]
340 m = max(map(len, l))
340 m = max(map(len, l))
341 pieces.append([ "%*s" % (m, x) for x in l])
341 pieces.append([ "%*s" % (m, x) for x in l])
342
342
343 for p,l in zip(zip(*pieces), lines):
343 for p,l in zip(zip(*pieces), lines):
344 u.write(" ".join(p) + ": " + l[1])
344 u.write(" ".join(p) + ": " + l[1])
345
345
346 def cat(ui, repo, file, rev = [], **opts):
346 def cat(ui, repo, file, rev = [], **opts):
347 """output the latest or given revision of a file"""
347 """output the latest or given revision of a file"""
348 r = repo.file(relpath(repo, [file])[0])
348 r = repo.file(relpath(repo, [file])[0])
349 n = r.tip()
349 n = r.tip()
350 if rev: n = r.lookup(rev)
350 if rev: n = r.lookup(rev)
351 if opts['output'] and opts['output'] != '-':
351 if opts['output'] and opts['output'] != '-':
352 try:
352 try:
353 outname = make_filename(repo, r, opts['output'], node=n)
353 outname = make_filename(repo, r, opts['output'], node=n)
354 fp = open(outname, 'wb')
354 fp = open(outname, 'wb')
355 except KeyError, inst:
355 except KeyError, inst:
356 ui.warn("error: invlaid format spec '%%%s' in output file name\n" %
356 ui.warn("error: invlaid format spec '%%%s' in output file name\n" %
357 inst.args[0])
357 inst.args[0])
358 sys.exit(1);
358 sys.exit(1);
359 else:
359 else:
360 fp = sys.stdout
360 fp = sys.stdout
361 fp.write(r.read(n))
361 fp.write(r.read(n))
362
362
363 def clone(ui, source, dest = None, **opts):
363 def clone(ui, source, dest = None, **opts):
364 """make a copy of an existing repository"""
364 """make a copy of an existing repository"""
365 if dest is None:
365 if dest is None:
366 dest = os.path.basename(os.path.normpath(source))
366 dest = os.path.basename(os.path.normpath(source))
367
367
368 if os.path.exists(dest):
368 if os.path.exists(dest):
369 ui.warn("abort: destination '%s' already exists\n" % dest)
369 ui.warn("abort: destination '%s' already exists\n" % dest)
370 return 1
370 return 1
371
371
372 class dircleanup:
372 class dircleanup:
373 def __init__(self, dir):
373 def __init__(self, dir):
374 import shutil
374 import shutil
375 self.rmtree = shutil.rmtree
375 self.rmtree = shutil.rmtree
376 self.dir = dir
376 self.dir = dir
377 os.mkdir(dir)
377 os.mkdir(dir)
378 def close(self):
378 def close(self):
379 self.dir = None
379 self.dir = None
380 def __del__(self):
380 def __del__(self):
381 if self.dir:
381 if self.dir:
382 self.rmtree(self.dir, True)
382 self.rmtree(self.dir, True)
383
383
384 d = dircleanup(dest)
384 d = dircleanup(dest)
385 link = 0
385 link = 0
386 abspath = source
386 abspath = source
387 source = ui.expandpath(source)
387 source = ui.expandpath(source)
388 other = hg.repository(ui, source)
388 other = hg.repository(ui, source)
389
389
390 if other.dev() != -1:
391 abspath = os.path.abspath(source)
392
390 if other.dev() != -1 and os.stat(dest).st_dev == other.dev():
393 if other.dev() != -1 and os.stat(dest).st_dev == other.dev():
391 ui.note("cloning by hardlink\n")
394 ui.note("cloning by hardlink\n")
392 util.system("cp -al '%s'/.hg '%s'/.hg" % (source, dest))
395 util.system("cp -al '%s'/.hg '%s'/.hg" % (source, dest))
393 try:
396 try:
394 os.remove(os.path.join(dest, ".hg", "dirstate"))
397 os.remove(os.path.join(dest, ".hg", "dirstate"))
395 except: pass
398 except: pass
396
399
397 repo = hg.repository(ui, dest)
400 repo = hg.repository(ui, dest)
398
401
399 else:
402 else:
400 repo = hg.repository(ui, dest, create=1)
403 repo = hg.repository(ui, dest, create=1)
401 repo.pull(other)
404 repo.pull(other)
402
405
403 f = repo.opener("hgrc", "w")
406 f = repo.opener("hgrc", "w")
404 f.write("[paths]\n")
407 f.write("[paths]\n")
405 f.write("default = %s\n" % abspath)
408 f.write("default = %s\n" % abspath)
406
409
407 if not opts['noupdate']:
410 if not opts['noupdate']:
408 update(ui, repo)
411 update(ui, repo)
409
412
410 d.close()
413 d.close()
411
414
412 def commit(ui, repo, *files, **opts):
415 def commit(ui, repo, *files, **opts):
413 """commit the specified files or all outstanding changes"""
416 """commit the specified files or all outstanding changes"""
414 text = opts['text']
417 text = opts['text']
415 if not text and opts['logfile']:
418 if not text and opts['logfile']:
416 try: text = open(opts['logfile']).read()
419 try: text = open(opts['logfile']).read()
417 except IOError: pass
420 except IOError: pass
418
421
419 if opts['addremove']:
422 if opts['addremove']:
420 addremove(ui, repo, *files)
423 addremove(ui, repo, *files)
421 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
424 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
422
425
423 def copy(ui, repo, source, dest):
426 def copy(ui, repo, source, dest):
424 """mark a file as copied or renamed for the next commit"""
427 """mark a file as copied or renamed for the next commit"""
425 return repo.copy(*relpath(repo, (source, dest)))
428 return repo.copy(*relpath(repo, (source, dest)))
426
429
427 def debugcheckstate(ui, repo):
430 def debugcheckstate(ui, repo):
428 """validate the correctness of the current dirstate"""
431 """validate the correctness of the current dirstate"""
429 parent1, parent2 = repo.dirstate.parents()
432 parent1, parent2 = repo.dirstate.parents()
430 repo.dirstate.read()
433 repo.dirstate.read()
431 dc = repo.dirstate.map
434 dc = repo.dirstate.map
432 keys = dc.keys()
435 keys = dc.keys()
433 keys.sort()
436 keys.sort()
434 m1n = repo.changelog.read(parent1)[0]
437 m1n = repo.changelog.read(parent1)[0]
435 m2n = repo.changelog.read(parent2)[0]
438 m2n = repo.changelog.read(parent2)[0]
436 m1 = repo.manifest.read(m1n)
439 m1 = repo.manifest.read(m1n)
437 m2 = repo.manifest.read(m2n)
440 m2 = repo.manifest.read(m2n)
438 errors = 0
441 errors = 0
439 for f in dc:
442 for f in dc:
440 state = repo.dirstate.state(f)
443 state = repo.dirstate.state(f)
441 if state in "nr" and f not in m1:
444 if state in "nr" and f not in m1:
442 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
445 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
443 errors += 1
446 errors += 1
444 if state in "a" and f in m1:
447 if state in "a" and f in m1:
445 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
448 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
446 errors += 1
449 errors += 1
447 if state in "m" and f not in m1 and f not in m2:
450 if state in "m" and f not in m1 and f not in m2:
448 ui.warn("%s in state %s, but not in either manifest\n" %
451 ui.warn("%s in state %s, but not in either manifest\n" %
449 (f, state))
452 (f, state))
450 errors += 1
453 errors += 1
451 for f in m1:
454 for f in m1:
452 state = repo.dirstate.state(f)
455 state = repo.dirstate.state(f)
453 if state not in "nrm":
456 if state not in "nrm":
454 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
457 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
455 errors += 1
458 errors += 1
456 if errors:
459 if errors:
457 ui.warn(".hg/dirstate inconsistent with current parent's manifest\n")
460 ui.warn(".hg/dirstate inconsistent with current parent's manifest\n")
458 sys.exit(1)
461 sys.exit(1)
459
462
460 def debugstate(ui, repo):
463 def debugstate(ui, repo):
461 """show the contents of the current dirstate"""
464 """show the contents of the current dirstate"""
462 repo.dirstate.read()
465 repo.dirstate.read()
463 dc = repo.dirstate.map
466 dc = repo.dirstate.map
464 keys = dc.keys()
467 keys = dc.keys()
465 keys.sort()
468 keys.sort()
466 for file in keys:
469 for file in keys:
467 ui.write("%c %s\n" % (dc[file][0], file))
470 ui.write("%c %s\n" % (dc[file][0], file))
468
471
469 def debugindex(ui, file):
472 def debugindex(ui, file):
470 """dump the contents of an index file"""
473 """dump the contents of an index file"""
471 r = hg.revlog(hg.opener(""), file, "")
474 r = hg.revlog(hg.opener(""), file, "")
472 ui.write(" rev offset length base linkrev" +
475 ui.write(" rev offset length base linkrev" +
473 " p1 p2 nodeid\n")
476 " p1 p2 nodeid\n")
474 for i in range(r.count()):
477 for i in range(r.count()):
475 e = r.index[i]
478 e = r.index[i]
476 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
479 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
477 i, e[0], e[1], e[2], e[3],
480 i, e[0], e[1], e[2], e[3],
478 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
481 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
479
482
480 def debugindexdot(ui, file):
483 def debugindexdot(ui, file):
481 """dump an index DAG as a .dot file"""
484 """dump an index DAG as a .dot file"""
482 r = hg.revlog(hg.opener(""), file, "")
485 r = hg.revlog(hg.opener(""), file, "")
483 ui.write("digraph G {\n")
486 ui.write("digraph G {\n")
484 for i in range(r.count()):
487 for i in range(r.count()):
485 e = r.index[i]
488 e = r.index[i]
486 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
489 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
487 if e[5] != hg.nullid:
490 if e[5] != hg.nullid:
488 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
491 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
489 ui.write("}\n")
492 ui.write("}\n")
490
493
491 def diff(ui, repo, *files, **opts):
494 def diff(ui, repo, *files, **opts):
492 """diff working directory (or selected files)"""
495 """diff working directory (or selected files)"""
493 revs = []
496 revs = []
494 if opts['rev']:
497 if opts['rev']:
495 revs = map(lambda x: repo.lookup(x), opts['rev'])
498 revs = map(lambda x: repo.lookup(x), opts['rev'])
496
499
497 if len(revs) > 2:
500 if len(revs) > 2:
498 ui.warn("too many revisions to diff\n")
501 ui.warn("too many revisions to diff\n")
499 sys.exit(1)
502 sys.exit(1)
500
503
501 if files:
504 if files:
502 files = relpath(repo, files)
505 files = relpath(repo, files)
503 else:
506 else:
504 files = relpath(repo, [""])
507 files = relpath(repo, [""])
505
508
506 dodiff(sys.stdout, ui, repo, files, *revs)
509 dodiff(sys.stdout, ui, repo, files, *revs)
507
510
508 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
511 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
509 node = repo.lookup(changeset)
512 node = repo.lookup(changeset)
510 prev, other = repo.changelog.parents(node)
513 prev, other = repo.changelog.parents(node)
511 change = repo.changelog.read(node)
514 change = repo.changelog.read(node)
512
515
513 if opts['output'] and opts['output'] != '-':
516 if opts['output'] and opts['output'] != '-':
514 try:
517 try:
515 outname = make_filename(repo, repo.changelog, opts['output'],
518 outname = make_filename(repo, repo.changelog, opts['output'],
516 node=node, total=total, seqno=seqno,
519 node=node, total=total, seqno=seqno,
517 revwidth=revwidth)
520 revwidth=revwidth)
518 fp = open(outname, 'wb')
521 fp = open(outname, 'wb')
519 except KeyError, inst:
522 except KeyError, inst:
520 ui.warn("error: invalid format spec '%%%s' in output file name\n" %
523 ui.warn("error: invalid format spec '%%%s' in output file name\n" %
521 inst.args[0])
524 inst.args[0])
522 sys.exit(1)
525 sys.exit(1)
523 else:
526 else:
524 fp = sys.stdout
527 fp = sys.stdout
525
528
526 fp.write("# HG changeset patch\n")
529 fp.write("# HG changeset patch\n")
527 fp.write("# User %s\n" % change[1])
530 fp.write("# User %s\n" % change[1])
528 fp.write("# Node ID %s\n" % hg.hex(node))
531 fp.write("# Node ID %s\n" % hg.hex(node))
529 fp.write("# Parent %s\n" % hg.hex(prev))
532 fp.write("# Parent %s\n" % hg.hex(prev))
530 if other != hg.nullid:
533 if other != hg.nullid:
531 fp.write("# Parent %s\n" % hg.hex(other))
534 fp.write("# Parent %s\n" % hg.hex(other))
532 fp.write(change[4].rstrip())
535 fp.write(change[4].rstrip())
533 fp.write("\n\n")
536 fp.write("\n\n")
534
537
535 dodiff(fp, ui, repo, None, prev, node)
538 dodiff(fp, ui, repo, None, prev, node)
536
539
537 def export(ui, repo, *changesets, **opts):
540 def export(ui, repo, *changesets, **opts):
538 """dump the header and diffs for one or more changesets"""
541 """dump the header and diffs for one or more changesets"""
539 if not changesets:
542 if not changesets:
540 ui.warn("error: export requires at least one changeset\n")
543 ui.warn("error: export requires at least one changeset\n")
541 sys.exit(1)
544 sys.exit(1)
542 seqno = 0
545 seqno = 0
543 revs = list(revrange(ui, repo, changesets))
546 revs = list(revrange(ui, repo, changesets))
544 total = len(revs)
547 total = len(revs)
545 revwidth = max(len(revs[0]), len(revs[-1]))
548 revwidth = max(len(revs[0]), len(revs[-1]))
546 for cset in revs:
549 for cset in revs:
547 seqno += 1
550 seqno += 1
548 doexport(ui, repo, cset, seqno, total, revwidth, opts)
551 doexport(ui, repo, cset, seqno, total, revwidth, opts)
549
552
550 def forget(ui, repo, file, *files):
553 def forget(ui, repo, file, *files):
551 """don't add the specified files on the next commit"""
554 """don't add the specified files on the next commit"""
552 repo.forget(relpath(repo, (file,) + files))
555 repo.forget(relpath(repo, (file,) + files))
553
556
554 def heads(ui, repo):
557 def heads(ui, repo):
555 """show current repository heads"""
558 """show current repository heads"""
556 for n in repo.changelog.heads():
559 for n in repo.changelog.heads():
557 show_changeset(ui, repo, changenode=n)
560 show_changeset(ui, repo, changenode=n)
558
561
559 def identify(ui, repo):
562 def identify(ui, repo):
560 """print information about the working copy"""
563 """print information about the working copy"""
561 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
564 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
562 if not parents:
565 if not parents:
563 ui.write("unknown\n")
566 ui.write("unknown\n")
564 return
567 return
565
568
566 hexfunc = ui.verbose and hg.hex or hg.short
569 hexfunc = ui.verbose and hg.hex or hg.short
567 (c, a, d, u) = repo.changes(None, None)
570 (c, a, d, u) = repo.changes(None, None)
568 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
571 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
569 (c or a or d) and "+" or "")]
572 (c or a or d) and "+" or "")]
570
573
571 if not ui.quiet:
574 if not ui.quiet:
572 # multiple tags for a single parent separated by '/'
575 # multiple tags for a single parent separated by '/'
573 parenttags = ['/'.join(tags)
576 parenttags = ['/'.join(tags)
574 for tags in map(repo.nodetags, parents) if tags]
577 for tags in map(repo.nodetags, parents) if tags]
575 # tags for multiple parents separated by ' + '
578 # tags for multiple parents separated by ' + '
576 output.append(' + '.join(parenttags))
579 output.append(' + '.join(parenttags))
577
580
578 ui.write("%s\n" % ' '.join(output))
581 ui.write("%s\n" % ' '.join(output))
579
582
580 def import_(ui, repo, patch1, *patches, **opts):
583 def import_(ui, repo, patch1, *patches, **opts):
581 """import an ordered set of patches"""
584 """import an ordered set of patches"""
582 try:
585 try:
583 import psyco
586 import psyco
584 psyco.full()
587 psyco.full()
585 except:
588 except:
586 pass
589 pass
587
590
588 patches = (patch1,) + patches
591 patches = (patch1,) + patches
589
592
590 d = opts["base"]
593 d = opts["base"]
591 strip = opts["strip"]
594 strip = opts["strip"]
592
595
593 for patch in patches:
596 for patch in patches:
594 ui.status("applying %s\n" % patch)
597 ui.status("applying %s\n" % patch)
595 pf = os.path.join(d, patch)
598 pf = os.path.join(d, patch)
596
599
597 text = ""
600 text = ""
598 for l in file(pf):
601 for l in file(pf):
599 if l.startswith("--- ") or l.startswith("diff -r"): break
602 if l.startswith("--- ") or l.startswith("diff -r"): break
600 text += l
603 text += l
601
604
602 # parse values that exist when importing the result of an hg export
605 # parse values that exist when importing the result of an hg export
603 hgpatch = user = snippet = None
606 hgpatch = user = snippet = None
604 ui.debug('text:\n')
607 ui.debug('text:\n')
605 for t in text.splitlines():
608 for t in text.splitlines():
606 ui.debug(t,'\n')
609 ui.debug(t,'\n')
607 if t == '# HG changeset patch' or hgpatch == True:
610 if t == '# HG changeset patch' or hgpatch == True:
608 hgpatch = True
611 hgpatch = True
609 if t.startswith("# User "):
612 if t.startswith("# User "):
610 user = t[7:]
613 user = t[7:]
611 ui.debug('User: %s\n' % user)
614 ui.debug('User: %s\n' % user)
612 if not t.startswith("# ") and t.strip() and not snippet: snippet = t
615 if not t.startswith("# ") and t.strip() and not snippet: snippet = t
613 if snippet: text = snippet + '\n' + text
616 if snippet: text = snippet + '\n' + text
614 ui.debug('text:\n%s\n' % text)
617 ui.debug('text:\n%s\n' % text)
615
618
616 # make sure text isn't empty
619 # make sure text isn't empty
617 if not text: text = "imported patch %s\n" % patch
620 if not text: text = "imported patch %s\n" % patch
618
621
619 f = os.popen("patch -p%d < %s" % (strip, pf))
622 f = os.popen("patch -p%d < %s" % (strip, pf))
620 files = []
623 files = []
621 for l in f.read().splitlines():
624 for l in f.read().splitlines():
622 l.rstrip('\r\n');
625 l.rstrip('\r\n');
623 ui.status("%s\n" % l)
626 ui.status("%s\n" % l)
624 if l.startswith('patching file '):
627 if l.startswith('patching file '):
625 pf = l[14:]
628 pf = l[14:]
626 if pf not in files:
629 if pf not in files:
627 files.append(pf)
630 files.append(pf)
628 patcherr = f.close()
631 patcherr = f.close()
629 if patcherr:
632 if patcherr:
630 sys.stderr.write("patch failed")
633 sys.stderr.write("patch failed")
631 sys.exit(1)
634 sys.exit(1)
632
635
633 if len(files) > 0:
636 if len(files) > 0:
634 addremove(ui, repo, *files)
637 addremove(ui, repo, *files)
635 repo.commit(files, text, user)
638 repo.commit(files, text, user)
636
639
637 def init(ui, source=None):
640 def init(ui, source=None):
638 """create a new repository in the current directory"""
641 """create a new repository in the current directory"""
639
642
640 if source:
643 if source:
641 ui.warn("no longer supported: use \"hg clone\" instead\n")
644 ui.warn("no longer supported: use \"hg clone\" instead\n")
642 sys.exit(1)
645 sys.exit(1)
643 repo = hg.repository(ui, ".", create=1)
646 repo = hg.repository(ui, ".", create=1)
644
647
645 def locate(ui, repo, *pats, **opts):
648 def locate(ui, repo, *pats, **opts):
646 """locate files matching specific patterns"""
649 """locate files matching specific patterns"""
647 if [p for p in pats if os.sep in p]:
650 if [p for p in pats if os.sep in p]:
648 ui.warn("error: patterns may not contain '%s'\n" % os.sep)
651 ui.warn("error: patterns may not contain '%s'\n" % os.sep)
649 ui.warn("use '-i <dir>' instead\n")
652 ui.warn("use '-i <dir>' instead\n")
650 sys.exit(1)
653 sys.exit(1)
651 def compile(pats, head = '^', tail = os.sep, on_empty = True):
654 def compile(pats, head = '^', tail = os.sep, on_empty = True):
652 if not pats:
655 if not pats:
653 class c:
656 class c:
654 def match(self, x): return on_empty
657 def match(self, x): return on_empty
655 return c()
658 return c()
656 regexp = r'%s(?:%s)%s' % (
659 regexp = r'%s(?:%s)%s' % (
657 head,
660 head,
658 '|'.join([fnmatch.translate(os.path.normpath(os.path.normcase(p)))[:-1]
661 '|'.join([fnmatch.translate(os.path.normpath(os.path.normcase(p)))[:-1]
659 for p in pats]),
662 for p in pats]),
660 tail)
663 tail)
661 return re.compile(regexp)
664 return re.compile(regexp)
662 exclude = compile(opts['exclude'], on_empty = False)
665 exclude = compile(opts['exclude'], on_empty = False)
663 include = compile(opts['include'])
666 include = compile(opts['include'])
664 pat = compile([os.path.normcase(p) for p in pats], head = '', tail = '$')
667 pat = compile([os.path.normcase(p) for p in pats], head = '', tail = '$')
665 end = '\n'
668 end = '\n'
666 if opts['print0']: end = '\0'
669 if opts['print0']: end = '\0'
667 if opts['rev']: node = repo.manifest.lookup(opts['rev'])
670 if opts['rev']: node = repo.manifest.lookup(opts['rev'])
668 else: node = repo.manifest.tip()
671 else: node = repo.manifest.tip()
669 manifest = repo.manifest.read(node)
672 manifest = repo.manifest.read(node)
670 cwd = repo.getcwd()
673 cwd = repo.getcwd()
671 cwd_plus = cwd and (cwd + os.sep)
674 cwd_plus = cwd and (cwd + os.sep)
672 found = []
675 found = []
673 for f in manifest:
676 for f in manifest:
674 f = os.path.normcase(f)
677 f = os.path.normcase(f)
675 if exclude.match(f) or not(include.match(f) and
678 if exclude.match(f) or not(include.match(f) and
676 f.startswith(cwd_plus) and
679 f.startswith(cwd_plus) and
677 pat.match(os.path.basename(f))): continue
680 pat.match(os.path.basename(f))): continue
678 if opts['fullpath']: f = os.path.join(repo.root, f)
681 if opts['fullpath']: f = os.path.join(repo.root, f)
679 elif cwd: f = f[len(cwd_plus):]
682 elif cwd: f = f[len(cwd_plus):]
680 found.append(f)
683 found.append(f)
681 found.sort()
684 found.sort()
682 for f in found: ui.write(f, end)
685 for f in found: ui.write(f, end)
683
686
684 def log(ui, repo, f=None, **opts):
687 def log(ui, repo, f=None, **opts):
685 """show the revision history of the repository or a single file"""
688 """show the revision history of the repository or a single file"""
686 if f:
689 if f:
687 files = relpath(repo, [f])
690 files = relpath(repo, [f])
688 filelog = repo.file(files[0])
691 filelog = repo.file(files[0])
689 log = filelog
692 log = filelog
690 lookup = filelog.lookup
693 lookup = filelog.lookup
691 else:
694 else:
692 files = None
695 files = None
693 filelog = None
696 filelog = None
694 log = repo.changelog
697 log = repo.changelog
695 lookup = repo.lookup
698 lookup = repo.lookup
696 revlist = []
699 revlist = []
697 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
700 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
698 while revs:
701 while revs:
699 if len(revs) == 1:
702 if len(revs) == 1:
700 revlist.append(revs.pop(0))
703 revlist.append(revs.pop(0))
701 else:
704 else:
702 a = revs.pop(0)
705 a = revs.pop(0)
703 b = revs.pop(0)
706 b = revs.pop(0)
704 off = a > b and -1 or 1
707 off = a > b and -1 or 1
705 revlist.extend(range(a, b + off, off))
708 revlist.extend(range(a, b + off, off))
706
709
707 for i in revlist or range(log.count() - 1, -1, -1):
710 for i in revlist or range(log.count() - 1, -1, -1):
708 show_changeset(ui, repo, filelog=filelog, rev=i)
711 show_changeset(ui, repo, filelog=filelog, rev=i)
709 if opts['patch']:
712 if opts['patch']:
710 if filelog:
713 if filelog:
711 filenode = filelog.node(i)
714 filenode = filelog.node(i)
712 i = filelog.linkrev(filenode)
715 i = filelog.linkrev(filenode)
713 changenode = repo.changelog.node(i)
716 changenode = repo.changelog.node(i)
714 prev, other = repo.changelog.parents(changenode)
717 prev, other = repo.changelog.parents(changenode)
715 dodiff(sys.stdout, ui, repo, files, prev, changenode)
718 dodiff(sys.stdout, ui, repo, files, prev, changenode)
716 ui.write("\n")
719 ui.write("\n")
717 ui.write("\n")
720 ui.write("\n")
718
721
719 def manifest(ui, repo, rev = []):
722 def manifest(ui, repo, rev = []):
720 """output the latest or given revision of the project manifest"""
723 """output the latest or given revision of the project manifest"""
721 n = repo.manifest.tip()
724 n = repo.manifest.tip()
722 if rev:
725 if rev:
723 n = repo.manifest.lookup(rev)
726 n = repo.manifest.lookup(rev)
724 m = repo.manifest.read(n)
727 m = repo.manifest.read(n)
725 mf = repo.manifest.readflags(n)
728 mf = repo.manifest.readflags(n)
726 files = m.keys()
729 files = m.keys()
727 files.sort()
730 files.sort()
728
731
729 for f in files:
732 for f in files:
730 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
733 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
731
734
732 def parents(ui, repo, node = None):
735 def parents(ui, repo, node = None):
733 '''show the parents of the current working dir'''
736 '''show the parents of the current working dir'''
734 if node:
737 if node:
735 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
738 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
736 else:
739 else:
737 p = repo.dirstate.parents()
740 p = repo.dirstate.parents()
738
741
739 for n in p:
742 for n in p:
740 if n != hg.nullid:
743 if n != hg.nullid:
741 show_changeset(ui, repo, changenode=n)
744 show_changeset(ui, repo, changenode=n)
742
745
743 def pull(ui, repo, source="default", **opts):
746 def pull(ui, repo, source="default", **opts):
744 """pull changes from the specified source"""
747 """pull changes from the specified source"""
745 source = ui.expandpath(source)
748 source = ui.expandpath(source)
746 ui.status('pulling from %s\n' % (source))
749 ui.status('pulling from %s\n' % (source))
747
750
748 other = hg.repository(ui, source)
751 other = hg.repository(ui, source)
749 r = repo.pull(other)
752 r = repo.pull(other)
750 if not r:
753 if not r:
751 if opts['update']:
754 if opts['update']:
752 return update(ui, repo)
755 return update(ui, repo)
753 else:
756 else:
754 ui.status("(run 'hg update' to get a working copy)\n")
757 ui.status("(run 'hg update' to get a working copy)\n")
755
758
756 return r
759 return r
757
760
758 def push(ui, repo, dest="default-push"):
761 def push(ui, repo, dest="default-push"):
759 """push changes to the specified destination"""
762 """push changes to the specified destination"""
760 dest = ui.expandpath(dest)
763 dest = ui.expandpath(dest)
761 ui.status('pushing to %s\n' % (dest))
764 ui.status('pushing to %s\n' % (dest))
762
765
763 other = hg.repository(ui, dest)
766 other = hg.repository(ui, dest)
764 r = repo.push(other)
767 r = repo.push(other)
765 return r
768 return r
766
769
767 def rawcommit(ui, repo, *flist, **rc):
770 def rawcommit(ui, repo, *flist, **rc):
768 "raw commit interface"
771 "raw commit interface"
769
772
770 text = rc['text']
773 text = rc['text']
771 if not text and rc['logfile']:
774 if not text and rc['logfile']:
772 try: text = open(rc['logfile']).read()
775 try: text = open(rc['logfile']).read()
773 except IOError: pass
776 except IOError: pass
774 if not text and not rc['logfile']:
777 if not text and not rc['logfile']:
775 ui.warn("abort: missing commit text\n")
778 ui.warn("abort: missing commit text\n")
776 return 1
779 return 1
777
780
778 files = relpath(repo, list(flist))
781 files = relpath(repo, list(flist))
779 if rc['files']:
782 if rc['files']:
780 files += open(rc['files']).read().splitlines()
783 files += open(rc['files']).read().splitlines()
781
784
782 rc['parent'] = map(repo.lookup, rc['parent'])
785 rc['parent'] = map(repo.lookup, rc['parent'])
783
786
784 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
787 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
785
788
786 def recover(ui, repo):
789 def recover(ui, repo):
787 """roll back an interrupted transaction"""
790 """roll back an interrupted transaction"""
788 repo.recover()
791 repo.recover()
789
792
790 def remove(ui, repo, file, *files):
793 def remove(ui, repo, file, *files):
791 """remove the specified files on the next commit"""
794 """remove the specified files on the next commit"""
792 repo.remove(relpath(repo, (file,) + files))
795 repo.remove(relpath(repo, (file,) + files))
793
796
794 def revert(ui, repo, *names, **opts):
797 def revert(ui, repo, *names, **opts):
795 """revert modified files or dirs back to their unmodified states"""
798 """revert modified files or dirs back to their unmodified states"""
796 node = opts['rev'] and repo.lookup(opts['rev']) or \
799 node = opts['rev'] and repo.lookup(opts['rev']) or \
797 repo.dirstate.parents()[0]
800 repo.dirstate.parents()[0]
798 root = os.path.realpath(repo.root)
801 root = os.path.realpath(repo.root)
799
802
800 def trimpath(p):
803 def trimpath(p):
801 p = os.path.realpath(p)
804 p = os.path.realpath(p)
802 if p.startswith(root):
805 if p.startswith(root):
803 rest = p[len(root):]
806 rest = p[len(root):]
804 if not rest:
807 if not rest:
805 return rest
808 return rest
806 if p.startswith(os.sep):
809 if p.startswith(os.sep):
807 return rest[1:]
810 return rest[1:]
808 return p
811 return p
809
812
810 relnames = map(trimpath, names or [os.getcwd()])
813 relnames = map(trimpath, names or [os.getcwd()])
811 chosen = {}
814 chosen = {}
812
815
813 def choose(name):
816 def choose(name):
814 def body(name):
817 def body(name):
815 for r in relnames:
818 for r in relnames:
816 if not name.startswith(r): continue
819 if not name.startswith(r): continue
817 rest = name[len(r):]
820 rest = name[len(r):]
818 if not rest: return r, True
821 if not rest: return r, True
819 depth = rest.count(os.sep)
822 depth = rest.count(os.sep)
820 if not r:
823 if not r:
821 if depth == 0 or not opts['nonrecursive']: return r, True
824 if depth == 0 or not opts['nonrecursive']: return r, True
822 elif rest[0] == os.sep:
825 elif rest[0] == os.sep:
823 if depth == 1 or not opts['nonrecursive']: return r, True
826 if depth == 1 or not opts['nonrecursive']: return r, True
824 return None, False
827 return None, False
825 relname, ret = body(name)
828 relname, ret = body(name)
826 if ret:
829 if ret:
827 chosen[relname] = 1
830 chosen[relname] = 1
828 return ret
831 return ret
829
832
830 r = repo.update(node, False, True, choose, False)
833 r = repo.update(node, False, True, choose, False)
831 for n in relnames:
834 for n in relnames:
832 if n not in chosen:
835 if n not in chosen:
833 ui.warn('error: no matches for %s\n' % n)
836 ui.warn('error: no matches for %s\n' % n)
834 r = 1
837 r = 1
835 sys.stdout.flush()
838 sys.stdout.flush()
836 return r
839 return r
837
840
838 def root(ui, repo):
841 def root(ui, repo):
839 """print the root (top) of the current working dir"""
842 """print the root (top) of the current working dir"""
840 ui.write(repo.root + "\n")
843 ui.write(repo.root + "\n")
841
844
842 def serve(ui, repo, **opts):
845 def serve(ui, repo, **opts):
843 """export the repository via HTTP"""
846 """export the repository via HTTP"""
844
847
845 if opts["stdio"]:
848 if opts["stdio"]:
846 fin, fout = sys.stdin, sys.stdout
849 fin, fout = sys.stdin, sys.stdout
847 sys.stdout = sys.stderr
850 sys.stdout = sys.stderr
848
851
849 def getarg():
852 def getarg():
850 argline = fin.readline()[:-1]
853 argline = fin.readline()[:-1]
851 arg, l = argline.split()
854 arg, l = argline.split()
852 val = fin.read(int(l))
855 val = fin.read(int(l))
853 return arg, val
856 return arg, val
854 def respond(v):
857 def respond(v):
855 fout.write("%d\n" % len(v))
858 fout.write("%d\n" % len(v))
856 fout.write(v)
859 fout.write(v)
857 fout.flush()
860 fout.flush()
858
861
859 lock = None
862 lock = None
860
863
861 while 1:
864 while 1:
862 cmd = fin.readline()[:-1]
865 cmd = fin.readline()[:-1]
863 if cmd == '':
866 if cmd == '':
864 return
867 return
865 if cmd == "heads":
868 if cmd == "heads":
866 h = repo.heads()
869 h = repo.heads()
867 respond(" ".join(map(hg.hex, h)) + "\n")
870 respond(" ".join(map(hg.hex, h)) + "\n")
868 if cmd == "lock":
871 if cmd == "lock":
869 lock = repo.lock()
872 lock = repo.lock()
870 respond("")
873 respond("")
871 if cmd == "unlock":
874 if cmd == "unlock":
872 if lock: lock.release()
875 if lock: lock.release()
873 lock = None
876 lock = None
874 respond("")
877 respond("")
875 elif cmd == "branches":
878 elif cmd == "branches":
876 arg, nodes = getarg()
879 arg, nodes = getarg()
877 nodes = map(hg.bin, nodes.split(" "))
880 nodes = map(hg.bin, nodes.split(" "))
878 r = []
881 r = []
879 for b in repo.branches(nodes):
882 for b in repo.branches(nodes):
880 r.append(" ".join(map(hg.hex, b)) + "\n")
883 r.append(" ".join(map(hg.hex, b)) + "\n")
881 respond("".join(r))
884 respond("".join(r))
882 elif cmd == "between":
885 elif cmd == "between":
883 arg, pairs = getarg()
886 arg, pairs = getarg()
884 pairs = [ map(hg.bin, p.split("-")) for p in pairs.split(" ") ]
887 pairs = [ map(hg.bin, p.split("-")) for p in pairs.split(" ") ]
885 r = []
888 r = []
886 for b in repo.between(pairs):
889 for b in repo.between(pairs):
887 r.append(" ".join(map(hg.hex, b)) + "\n")
890 r.append(" ".join(map(hg.hex, b)) + "\n")
888 respond("".join(r))
891 respond("".join(r))
889 elif cmd == "changegroup":
892 elif cmd == "changegroup":
890 nodes = []
893 nodes = []
891 arg, roots = getarg()
894 arg, roots = getarg()
892 nodes = map(hg.bin, roots.split(" "))
895 nodes = map(hg.bin, roots.split(" "))
893
896
894 cg = repo.changegroup(nodes)
897 cg = repo.changegroup(nodes)
895 while 1:
898 while 1:
896 d = cg.read(4096)
899 d = cg.read(4096)
897 if not d: break
900 if not d: break
898 fout.write(d)
901 fout.write(d)
899
902
900 fout.flush()
903 fout.flush()
901
904
902 elif cmd == "addchangegroup":
905 elif cmd == "addchangegroup":
903 if not lock:
906 if not lock:
904 respond("not locked")
907 respond("not locked")
905 continue
908 continue
906 respond("")
909 respond("")
907
910
908 r = repo.addchangegroup(fin)
911 r = repo.addchangegroup(fin)
909 respond("")
912 respond("")
910
913
911 def openlog(opt, default):
914 def openlog(opt, default):
912 if opts[opt] and opts[opt] != '-': return open(opts[opt], 'w')
915 if opts[opt] and opts[opt] != '-': return open(opts[opt], 'w')
913 else: return default
916 else: return default
914
917
915 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
918 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
916 opts["address"], opts["port"],
919 opts["address"], opts["port"],
917 openlog('accesslog', sys.stdout),
920 openlog('accesslog', sys.stdout),
918 openlog('errorlog', sys.stderr))
921 openlog('errorlog', sys.stderr))
919 if ui.verbose:
922 if ui.verbose:
920 addr, port = httpd.socket.getsockname()
923 addr, port = httpd.socket.getsockname()
921 if addr == '0.0.0.0':
924 if addr == '0.0.0.0':
922 addr = socket.gethostname()
925 addr = socket.gethostname()
923 else:
926 else:
924 try:
927 try:
925 addr = socket.gethostbyaddr(addr)[0]
928 addr = socket.gethostbyaddr(addr)[0]
926 except: pass
929 except: pass
927 if port != 80:
930 if port != 80:
928 ui.status('listening at http://%s:%d/\n' % (addr, port))
931 ui.status('listening at http://%s:%d/\n' % (addr, port))
929 else:
932 else:
930 ui.status('listening at http://%s/\n' % addr)
933 ui.status('listening at http://%s/\n' % addr)
931 httpd.serve_forever()
934 httpd.serve_forever()
932
935
933 def status(ui, repo):
936 def status(ui, repo):
934 '''show changed files in the working directory
937 '''show changed files in the working directory
935
938
936 C = changed
939 C = changed
937 A = added
940 A = added
938 R = removed
941 R = removed
939 ? = not tracked'''
942 ? = not tracked'''
940
943
941 (c, a, d, u) = repo.changes(None, None)
944 (c, a, d, u) = repo.changes(None, None)
942 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
945 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
943
946
944 for f in c: ui.write("C ", f, "\n")
947 for f in c: ui.write("C ", f, "\n")
945 for f in a: ui.write("A ", f, "\n")
948 for f in a: ui.write("A ", f, "\n")
946 for f in d: ui.write("R ", f, "\n")
949 for f in d: ui.write("R ", f, "\n")
947 for f in u: ui.write("? ", f, "\n")
950 for f in u: ui.write("? ", f, "\n")
948
951
949 def tag(ui, repo, name, rev = None, **opts):
952 def tag(ui, repo, name, rev = None, **opts):
950 """add a tag for the current tip or a given revision"""
953 """add a tag for the current tip or a given revision"""
951
954
952 if name == "tip":
955 if name == "tip":
953 ui.warn("abort: 'tip' is a reserved name!\n")
956 ui.warn("abort: 'tip' is a reserved name!\n")
954 return -1
957 return -1
955 if rev:
958 if rev:
956 r = hg.hex(repo.lookup(rev))
959 r = hg.hex(repo.lookup(rev))
957 else:
960 else:
958 r = hg.hex(repo.changelog.tip())
961 r = hg.hex(repo.changelog.tip())
959
962
960 if name.find(revrangesep) >= 0:
963 if name.find(revrangesep) >= 0:
961 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
964 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
962 return -1
965 return -1
963
966
964 if opts['local']:
967 if opts['local']:
965 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
968 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
966 return
969 return
967
970
968 (c, a, d, u) = repo.changes(None, None)
971 (c, a, d, u) = repo.changes(None, None)
969 for x in (c, a, d, u):
972 for x in (c, a, d, u):
970 if ".hgtags" in x:
973 if ".hgtags" in x:
971 ui.warn("abort: working copy of .hgtags is changed!\n")
974 ui.warn("abort: working copy of .hgtags is changed!\n")
972 ui.status("(please commit .hgtags manually)\n")
975 ui.status("(please commit .hgtags manually)\n")
973 return -1
976 return -1
974
977
975 add = 0
978 add = 0
976 if not os.path.exists(repo.wjoin(".hgtags")): add = 1
979 if not os.path.exists(repo.wjoin(".hgtags")): add = 1
977 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
980 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
978 if add: repo.add([".hgtags"])
981 if add: repo.add([".hgtags"])
979
982
980 if not opts['text']:
983 if not opts['text']:
981 opts['text'] = "Added tag %s for changeset %s" % (name, r)
984 opts['text'] = "Added tag %s for changeset %s" % (name, r)
982
985
983 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
986 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
984
987
985 def tags(ui, repo):
988 def tags(ui, repo):
986 """list repository tags"""
989 """list repository tags"""
987
990
988 l = repo.tagslist()
991 l = repo.tagslist()
989 l.reverse()
992 l.reverse()
990 for t, n in l:
993 for t, n in l:
991 try:
994 try:
992 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
995 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
993 except KeyError:
996 except KeyError:
994 r = " ?:?"
997 r = " ?:?"
995 ui.write("%-30s %s\n" % (t, r))
998 ui.write("%-30s %s\n" % (t, r))
996
999
997 def tip(ui, repo):
1000 def tip(ui, repo):
998 """show the tip revision"""
1001 """show the tip revision"""
999 n = repo.changelog.tip()
1002 n = repo.changelog.tip()
1000 show_changeset(ui, repo, changenode=n)
1003 show_changeset(ui, repo, changenode=n)
1001
1004
1002 def undo(ui, repo):
1005 def undo(ui, repo):
1003 """undo the last commit or pull
1006 """undo the last commit or pull
1004
1007
1005 Roll back the last pull or commit transaction on the
1008 Roll back the last pull or commit transaction on the
1006 repository, restoring the project to its earlier state.
1009 repository, restoring the project to its earlier state.
1007
1010
1008 This command should be used with care. There is only one level of
1011 This command should be used with care. There is only one level of
1009 undo and there is no redo.
1012 undo and there is no redo.
1010
1013
1011 This command is not intended for use on public repositories. Once
1014 This command is not intended for use on public repositories. Once
1012 a change is visible for pull by other users, undoing it locally is
1015 a change is visible for pull by other users, undoing it locally is
1013 ineffective.
1016 ineffective.
1014 """
1017 """
1015 repo.undo()
1018 repo.undo()
1016
1019
1017 def update(ui, repo, node=None, merge=False, clean=False):
1020 def update(ui, repo, node=None, merge=False, clean=False):
1018 '''update or merge working directory
1021 '''update or merge working directory
1019
1022
1020 If there are no outstanding changes in the working directory and
1023 If there are no outstanding changes in the working directory and
1021 there is a linear relationship between the current version and the
1024 there is a linear relationship between the current version and the
1022 requested version, the result is the requested version.
1025 requested version, the result is the requested version.
1023
1026
1024 Otherwise the result is a merge between the contents of the
1027 Otherwise the result is a merge between the contents of the
1025 current working directory and the requested version. Files that
1028 current working directory and the requested version. Files that
1026 changed between either parent are marked as changed for the next
1029 changed between either parent are marked as changed for the next
1027 commit and a commit must be performed before any further updates
1030 commit and a commit must be performed before any further updates
1028 are allowed.
1031 are allowed.
1029 '''
1032 '''
1030 node = node and repo.lookup(node) or repo.changelog.tip()
1033 node = node and repo.lookup(node) or repo.changelog.tip()
1031 return repo.update(node, allow=merge, force=clean)
1034 return repo.update(node, allow=merge, force=clean)
1032
1035
1033 def verify(ui, repo):
1036 def verify(ui, repo):
1034 """verify the integrity of the repository"""
1037 """verify the integrity of the repository"""
1035 return repo.verify()
1038 return repo.verify()
1036
1039
1037 # Command options and aliases are listed here, alphabetically
1040 # Command options and aliases are listed here, alphabetically
1038
1041
1039 table = {
1042 table = {
1040 "^add": (add, [], "hg add [files]"),
1043 "^add": (add, [], "hg add [files]"),
1041 "addremove": (addremove, [], "hg addremove [files]"),
1044 "addremove": (addremove, [], "hg addremove [files]"),
1042 "^annotate": (annotate,
1045 "^annotate": (annotate,
1043 [('r', 'revision', '', 'revision'),
1046 [('r', 'revision', '', 'revision'),
1044 ('u', 'user', None, 'show user'),
1047 ('u', 'user', None, 'show user'),
1045 ('n', 'number', None, 'show revision number'),
1048 ('n', 'number', None, 'show revision number'),
1046 ('c', 'changeset', None, 'show changeset')],
1049 ('c', 'changeset', None, 'show changeset')],
1047 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
1050 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
1048 "cat": (cat, [('o', 'output', "", 'output to file')], 'hg cat [-o outfile] <file> [rev]'),
1051 "cat": (cat, [('o', 'output', "", 'output to file')], 'hg cat [-o outfile] <file> [rev]'),
1049 "^clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
1052 "^clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
1050 'hg clone [options] <source> [dest]'),
1053 'hg clone [options] <source> [dest]'),
1051 "^commit|ci": (commit,
1054 "^commit|ci": (commit,
1052 [('t', 'text', "", 'commit text'),
1055 [('t', 'text', "", 'commit text'),
1053 ('A', 'addremove', None, 'run add/remove during commit'),
1056 ('A', 'addremove', None, 'run add/remove during commit'),
1054 ('l', 'logfile', "", 'commit text file'),
1057 ('l', 'logfile', "", 'commit text file'),
1055 ('d', 'date', "", 'date code'),
1058 ('d', 'date', "", 'date code'),
1056 ('u', 'user', "", 'user')],
1059 ('u', 'user', "", 'user')],
1057 'hg commit [files]'),
1060 'hg commit [files]'),
1058 "copy": (copy, [], 'hg copy <source> <dest>'),
1061 "copy": (copy, [], 'hg copy <source> <dest>'),
1059 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1062 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1060 "debugstate": (debugstate, [], 'debugstate'),
1063 "debugstate": (debugstate, [], 'debugstate'),
1061 "debugindex": (debugindex, [], 'debugindex <file>'),
1064 "debugindex": (debugindex, [], 'debugindex <file>'),
1062 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
1065 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
1063 "^diff": (diff, [('r', 'rev', [], 'revision')],
1066 "^diff": (diff, [('r', 'rev', [], 'revision')],
1064 'hg diff [-r A] [-r B] [files]'),
1067 'hg diff [-r A] [-r B] [files]'),
1065 "^export": (export, [('o', 'output', "", 'output to file')],
1068 "^export": (export, [('o', 'output', "", 'output to file')],
1066 "hg export [-o file] <changeset> ..."),
1069 "hg export [-o file] <changeset> ..."),
1067 "forget": (forget, [], "hg forget [files]"),
1070 "forget": (forget, [], "hg forget [files]"),
1068 "heads": (heads, [], 'hg heads'),
1071 "heads": (heads, [], 'hg heads'),
1069 "help": (help, [], 'hg help [command]'),
1072 "help": (help, [], 'hg help [command]'),
1070 "identify|id": (identify, [], 'hg identify'),
1073 "identify|id": (identify, [], 'hg identify'),
1071 "import|patch": (import_,
1074 "import|patch": (import_,
1072 [('p', 'strip', 1, 'path strip'),
1075 [('p', 'strip', 1, 'path strip'),
1073 ('b', 'base', "", 'base path')],
1076 ('b', 'base', "", 'base path')],
1074 "hg import [options] <patches>"),
1077 "hg import [options] <patches>"),
1075 "^init": (init, [], 'hg init'),
1078 "^init": (init, [], 'hg init'),
1076 "locate": (locate,
1079 "locate": (locate,
1077 [('0', 'print0', None, 'end records with NUL'),
1080 [('0', 'print0', None, 'end records with NUL'),
1078 ('f', 'fullpath', None, 'print complete paths'),
1081 ('f', 'fullpath', None, 'print complete paths'),
1079 ('i', 'include', [], 'include path in search'),
1082 ('i', 'include', [], 'include path in search'),
1080 ('r', 'rev', '', 'revision'),
1083 ('r', 'rev', '', 'revision'),
1081 ('x', 'exclude', [], 'exclude path from search')],
1084 ('x', 'exclude', [], 'exclude path from search')],
1082 'hg locate [options] [files]'),
1085 'hg locate [options] [files]'),
1083 "^log|history": (log,
1086 "^log|history": (log,
1084 [('r', 'rev', [], 'revision'),
1087 [('r', 'rev', [], 'revision'),
1085 ('p', 'patch', None, 'show patch')],
1088 ('p', 'patch', None, 'show patch')],
1086 'hg log [-r A] [-r B] [-p] [file]'),
1089 'hg log [-r A] [-r B] [-p] [file]'),
1087 "manifest": (manifest, [], 'hg manifest [rev]'),
1090 "manifest": (manifest, [], 'hg manifest [rev]'),
1088 "parents": (parents, [], 'hg parents [node]'),
1091 "parents": (parents, [], 'hg parents [node]'),
1089 "^pull": (pull,
1092 "^pull": (pull,
1090 [('u', 'update', None, 'update working directory')],
1093 [('u', 'update', None, 'update working directory')],
1091 'hg pull [options] [source]'),
1094 'hg pull [options] [source]'),
1092 "^push": (push, [], 'hg push <destination>'),
1095 "^push": (push, [], 'hg push <destination>'),
1093 "rawcommit": (rawcommit,
1096 "rawcommit": (rawcommit,
1094 [('p', 'parent', [], 'parent'),
1097 [('p', 'parent', [], 'parent'),
1095 ('d', 'date', "", 'date code'),
1098 ('d', 'date', "", 'date code'),
1096 ('u', 'user', "", 'user'),
1099 ('u', 'user', "", 'user'),
1097 ('F', 'files', "", 'file list'),
1100 ('F', 'files', "", 'file list'),
1098 ('t', 'text', "", 'commit text'),
1101 ('t', 'text', "", 'commit text'),
1099 ('l', 'logfile', "", 'commit text file')],
1102 ('l', 'logfile', "", 'commit text file')],
1100 'hg rawcommit [options] [files]'),
1103 'hg rawcommit [options] [files]'),
1101 "recover": (recover, [], "hg recover"),
1104 "recover": (recover, [], "hg recover"),
1102 "^remove|rm": (remove, [], "hg remove [files]"),
1105 "^remove|rm": (remove, [], "hg remove [files]"),
1103 "^revert": (revert,
1106 "^revert": (revert,
1104 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1107 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1105 ("r", "rev", "", "revision")],
1108 ("r", "rev", "", "revision")],
1106 "hg revert [files|dirs]"),
1109 "hg revert [files|dirs]"),
1107 "root": (root, [], "hg root"),
1110 "root": (root, [], "hg root"),
1108 "^serve": (serve, [('A', 'accesslog', '', 'access log file'),
1111 "^serve": (serve, [('A', 'accesslog', '', 'access log file'),
1109 ('E', 'errorlog', '', 'error log file'),
1112 ('E', 'errorlog', '', 'error log file'),
1110 ('p', 'port', 8000, 'listen port'),
1113 ('p', 'port', 8000, 'listen port'),
1111 ('a', 'address', '', 'interface address'),
1114 ('a', 'address', '', 'interface address'),
1112 ('n', 'name', os.getcwd(), 'repository name'),
1115 ('n', 'name', os.getcwd(), 'repository name'),
1113 ('', 'stdio', None, 'for remote clients'),
1116 ('', 'stdio', None, 'for remote clients'),
1114 ('t', 'templates', "", 'template map')],
1117 ('t', 'templates', "", 'template map')],
1115 "hg serve [options]"),
1118 "hg serve [options]"),
1116 "^status": (status, [], 'hg status'),
1119 "^status": (status, [], 'hg status'),
1117 "tag": (tag, [('l', 'local', None, 'make the tag local'),
1120 "tag": (tag, [('l', 'local', None, 'make the tag local'),
1118 ('t', 'text', "", 'commit text'),
1121 ('t', 'text', "", 'commit text'),
1119 ('d', 'date', "", 'date code'),
1122 ('d', 'date', "", 'date code'),
1120 ('u', 'user', "", 'user')],
1123 ('u', 'user', "", 'user')],
1121 'hg tag [options] <name> [rev]'),
1124 'hg tag [options] <name> [rev]'),
1122 "tags": (tags, [], 'hg tags'),
1125 "tags": (tags, [], 'hg tags'),
1123 "tip": (tip, [], 'hg tip'),
1126 "tip": (tip, [], 'hg tip'),
1124 "undo": (undo, [], 'hg undo'),
1127 "undo": (undo, [], 'hg undo'),
1125 "^update|up|checkout|co":
1128 "^update|up|checkout|co":
1126 (update,
1129 (update,
1127 [('m', 'merge', None, 'allow merging of conflicts'),
1130 [('m', 'merge', None, 'allow merging of conflicts'),
1128 ('C', 'clean', None, 'overwrite locally modified files')],
1131 ('C', 'clean', None, 'overwrite locally modified files')],
1129 'hg update [options] [node]'),
1132 'hg update [options] [node]'),
1130 "verify": (verify, [], 'hg verify'),
1133 "verify": (verify, [], 'hg verify'),
1131 "version": (show_version, [], 'hg version'),
1134 "version": (show_version, [], 'hg version'),
1132 }
1135 }
1133
1136
1134 globalopts = [('v', 'verbose', None, 'verbose'),
1137 globalopts = [('v', 'verbose', None, 'verbose'),
1135 ('', 'debug', None, 'debug'),
1138 ('', 'debug', None, 'debug'),
1136 ('q', 'quiet', None, 'quiet'),
1139 ('q', 'quiet', None, 'quiet'),
1137 ('', 'profile', None, 'profile'),
1140 ('', 'profile', None, 'profile'),
1138 ('R', 'repository', "", 'repository root directory'),
1141 ('R', 'repository', "", 'repository root directory'),
1139 ('', 'traceback', None, 'print traceback on exception'),
1142 ('', 'traceback', None, 'print traceback on exception'),
1140 ('y', 'noninteractive', None, 'run non-interactively'),
1143 ('y', 'noninteractive', None, 'run non-interactively'),
1141 ('', 'version', None, 'output version information and exit'),
1144 ('', 'version', None, 'output version information and exit'),
1142 ]
1145 ]
1143
1146
1144 norepo = "clone init version help debugindex debugindexdot"
1147 norepo = "clone init version help debugindex debugindexdot"
1145
1148
1146 def find(cmd):
1149 def find(cmd):
1147 for e in table.keys():
1150 for e in table.keys():
1148 if re.match("(%s)$" % e, cmd):
1151 if re.match("(%s)$" % e, cmd):
1149 return table[e]
1152 return table[e]
1150
1153
1151 raise UnknownCommand(cmd)
1154 raise UnknownCommand(cmd)
1152
1155
1153 class SignalInterrupt(Exception): pass
1156 class SignalInterrupt(Exception): pass
1154
1157
1155 def catchterm(*args):
1158 def catchterm(*args):
1156 raise SignalInterrupt
1159 raise SignalInterrupt
1157
1160
1158 def run():
1161 def run():
1159 sys.exit(dispatch(sys.argv[1:]))
1162 sys.exit(dispatch(sys.argv[1:]))
1160
1163
1161 class ParseError(Exception): pass
1164 class ParseError(Exception): pass
1162
1165
1163 def parse(args):
1166 def parse(args):
1164 options = {}
1167 options = {}
1165 cmdoptions = {}
1168 cmdoptions = {}
1166
1169
1167 try:
1170 try:
1168 args = fancyopts.fancyopts(args, globalopts, options)
1171 args = fancyopts.fancyopts(args, globalopts, options)
1169 except fancyopts.getopt.GetoptError, inst:
1172 except fancyopts.getopt.GetoptError, inst:
1170 raise ParseError(None, inst)
1173 raise ParseError(None, inst)
1171
1174
1172 if options["version"]:
1175 if options["version"]:
1173 return ("version", show_version, [], options, cmdoptions)
1176 return ("version", show_version, [], options, cmdoptions)
1174 elif not args:
1177 elif not args:
1175 return ("help", help, [], options, cmdoptions)
1178 return ("help", help, [], options, cmdoptions)
1176 else:
1179 else:
1177 cmd, args = args[0], args[1:]
1180 cmd, args = args[0], args[1:]
1178
1181
1179 i = find(cmd)
1182 i = find(cmd)
1180
1183
1181 # combine global options into local
1184 # combine global options into local
1182 c = list(i[1])
1185 c = list(i[1])
1183 l = len(c)
1186 l = len(c)
1184 for o in globalopts:
1187 for o in globalopts:
1185 c.append((o[0], o[1], options[o[1]], o[3]))
1188 c.append((o[0], o[1], options[o[1]], o[3]))
1186
1189
1187 try:
1190 try:
1188 args = fancyopts.fancyopts(args, c, cmdoptions)
1191 args = fancyopts.fancyopts(args, c, cmdoptions)
1189 except fancyopts.getopt.GetoptError, inst:
1192 except fancyopts.getopt.GetoptError, inst:
1190 raise ParseError(cmd, inst)
1193 raise ParseError(cmd, inst)
1191
1194
1192 # separate global options back out
1195 # separate global options back out
1193 for o in globalopts:
1196 for o in globalopts:
1194 n = o[1]
1197 n = o[1]
1195 options[n] = cmdoptions[n]
1198 options[n] = cmdoptions[n]
1196 del cmdoptions[n]
1199 del cmdoptions[n]
1197
1200
1198 return (cmd, i[0], args, options, cmdoptions)
1201 return (cmd, i[0], args, options, cmdoptions)
1199
1202
1200 def dispatch(args):
1203 def dispatch(args):
1201 signal.signal(signal.SIGTERM, catchterm)
1204 signal.signal(signal.SIGTERM, catchterm)
1202 if os.name != 'nt':
1205 if os.name != 'nt':
1203 signal.signal(signal.SIGHUP, catchterm)
1206 signal.signal(signal.SIGHUP, catchterm)
1204
1207
1205 try:
1208 try:
1206 cmd, func, args, options, cmdoptions = parse(args)
1209 cmd, func, args, options, cmdoptions = parse(args)
1207 except ParseError, inst:
1210 except ParseError, inst:
1208 u = ui.ui()
1211 u = ui.ui()
1209 if inst.args[0]:
1212 if inst.args[0]:
1210 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1213 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1211 help(u, inst.args[0])
1214 help(u, inst.args[0])
1212 else:
1215 else:
1213 u.warn("hg: %s\n" % inst.args[1])
1216 u.warn("hg: %s\n" % inst.args[1])
1214 help(u)
1217 help(u)
1215 sys.exit(-1)
1218 sys.exit(-1)
1216 except UnknownCommand, inst:
1219 except UnknownCommand, inst:
1217 u = ui.ui()
1220 u = ui.ui()
1218 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1221 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1219 help(u)
1222 help(u)
1220 sys.exit(1)
1223 sys.exit(1)
1221
1224
1222 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1225 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1223 not options["noninteractive"])
1226 not options["noninteractive"])
1224
1227
1225 try:
1228 try:
1226 try:
1229 try:
1227 if cmd not in norepo.split():
1230 if cmd not in norepo.split():
1228 path = options["repository"] or ""
1231 path = options["repository"] or ""
1229 repo = hg.repository(ui=u, path=path)
1232 repo = hg.repository(ui=u, path=path)
1230 d = lambda: func(u, repo, *args, **cmdoptions)
1233 d = lambda: func(u, repo, *args, **cmdoptions)
1231 else:
1234 else:
1232 d = lambda: func(u, *args, **cmdoptions)
1235 d = lambda: func(u, *args, **cmdoptions)
1233
1236
1234 if options['profile']:
1237 if options['profile']:
1235 import hotshot, hotshot.stats
1238 import hotshot, hotshot.stats
1236 prof = hotshot.Profile("hg.prof")
1239 prof = hotshot.Profile("hg.prof")
1237 r = prof.runcall(d)
1240 r = prof.runcall(d)
1238 prof.close()
1241 prof.close()
1239 stats = hotshot.stats.load("hg.prof")
1242 stats = hotshot.stats.load("hg.prof")
1240 stats.strip_dirs()
1243 stats.strip_dirs()
1241 stats.sort_stats('time', 'calls')
1244 stats.sort_stats('time', 'calls')
1242 stats.print_stats(40)
1245 stats.print_stats(40)
1243 return r
1246 return r
1244 else:
1247 else:
1245 return d()
1248 return d()
1246 except:
1249 except:
1247 if options['traceback']:
1250 if options['traceback']:
1248 traceback.print_exc()
1251 traceback.print_exc()
1249 raise
1252 raise
1250 except util.CommandError, inst:
1253 except util.CommandError, inst:
1251 u.warn("abort: %s\n" % inst.args)
1254 u.warn("abort: %s\n" % inst.args)
1252 except hg.RepoError, inst:
1255 except hg.RepoError, inst:
1253 u.warn("abort: ", inst, "!\n")
1256 u.warn("abort: ", inst, "!\n")
1254 except SignalInterrupt:
1257 except SignalInterrupt:
1255 u.warn("killed!\n")
1258 u.warn("killed!\n")
1256 except KeyboardInterrupt:
1259 except KeyboardInterrupt:
1257 u.warn("interrupted!\n")
1260 u.warn("interrupted!\n")
1258 except IOError, inst:
1261 except IOError, inst:
1259 if hasattr(inst, "code"):
1262 if hasattr(inst, "code"):
1260 u.warn("abort: %s\n" % inst)
1263 u.warn("abort: %s\n" % inst)
1261 elif hasattr(inst, "reason"):
1264 elif hasattr(inst, "reason"):
1262 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1265 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1263 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1266 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1264 u.warn("broken pipe\n")
1267 u.warn("broken pipe\n")
1265 else:
1268 else:
1266 raise
1269 raise
1267 except OSError, inst:
1270 except OSError, inst:
1268 if hasattr(inst, "filename"):
1271 if hasattr(inst, "filename"):
1269 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1272 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1270 else:
1273 else:
1271 u.warn("abort: %s\n" % inst.strerror)
1274 u.warn("abort: %s\n" % inst.strerror)
1272 except TypeError, inst:
1275 except TypeError, inst:
1273 # was this an argument error?
1276 # was this an argument error?
1274 tb = traceback.extract_tb(sys.exc_info()[2])
1277 tb = traceback.extract_tb(sys.exc_info()[2])
1275 if len(tb) > 2: # no
1278 if len(tb) > 2: # no
1276 raise
1279 raise
1277 u.debug(inst, "\n")
1280 u.debug(inst, "\n")
1278 u.warn("%s: invalid arguments\n" % cmd)
1281 u.warn("%s: invalid arguments\n" % cmd)
1279 help(u, cmd)
1282 help(u, cmd)
1280
1283
1281 sys.exit(-1)
1284 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now