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