##// END OF EJS Templates
big heap of command clean-up work...
mpm@selenic.com -
r245:fef0f8e0 default
parent child Browse files
Show More
@@ -1,532 +1,411 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # mercurial - a minimal scalable distributed SCM
3 # mercurial - a minimal scalable distributed SCM
4 # v0.5b "katje"
4 # v0.5b "katje"
5 #
5 #
6 # Copyright 2005 Matt Mackall <mpm@selenic.com>
6 # Copyright 2005 Matt Mackall <mpm@selenic.com>
7 #
7 #
8 # This software may be used and distributed according to the terms
8 # This software may be used and distributed according to the terms
9 # of the GNU General Public License, incorporated herein by reference.
9 # of the GNU General Public License, incorporated herein by reference.
10
10
11 # the psyco compiler makes commits a bit faster
11 # the psyco compiler makes commits a bit faster
12 # and makes changegroup merge about 20 times slower!
12 # and makes changegroup merge about 20 times slower!
13 # try:
13 # try:
14 # import psyco
14 # import psyco
15 # psyco.full()
15 # psyco.full()
16 # except:
16 # except:
17 # pass
17 # pass
18
18
19 import sys, os, time
19 import sys, os, time
20 from mercurial import hg, mdiff, fancyopts, ui, commands
20 from mercurial import hg, mdiff, fancyopts, ui, commands
21
21
22 def help():
23 ui.status("""\
24 commands:
25
26 add [files...] add the given files in the next commit
27 addremove add all new files, delete all missing files
28 annotate [files...] show changeset number per file line
29 branch <path> create a branch of <path> in this directory
30 checkout [changeset] checkout the latest or given changeset
31 commit commit all changes to the repository
32 diff [files...] diff working directory (or selected files)
33 dump <file> [rev] dump the latest or given revision of a file
34 dumpmanifest [rev] dump the latest or given revision of the manifest
35 export <rev> dump the changeset header and diffs for a revision
36 history show changeset history
37 init create a new repository in this directory
38 log <file> show revision history of a single file
39 merge <path> merge changes from <path> into local repository
40 recover rollback an interrupted transaction
41 remove [files...] remove the given files in the next commit
42 serve export the repository via HTTP
43 status show new, missing, and changed files in working dir
44 tags show current changeset tags
45 undo undo the last transaction
46 """)
47
48 def filterfiles(list, files):
22 def filterfiles(list, files):
49 l = [ x for x in list if x in files ]
23 l = [ x for x in list if x in files ]
50
24
51 for f in files:
25 for f in files:
52 if f[-1] != os.sep: f += os.sep
26 if f[-1] != os.sep: f += os.sep
53 l += [ x for x in list if x.startswith(f) ]
27 l += [ x for x in list if x.startswith(f) ]
54 return l
28 return l
55
29
56 def diff(files = None, node1 = None, node2 = None):
30 def diff(files = None, node1 = None, node2 = None):
57 def date(c):
31 def date(c):
58 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
32 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
59
33
60 if node2:
34 if node2:
61 change = repo.changelog.read(node2)
35 change = repo.changelog.read(node2)
62 mmap2 = repo.manifest.read(change[0])
36 mmap2 = repo.manifest.read(change[0])
63 (c, a, d) = repo.diffrevs(node1, node2)
37 (c, a, d) = repo.diffrevs(node1, node2)
64 def read(f): return repo.file(f).read(mmap2[f])
38 def read(f): return repo.file(f).read(mmap2[f])
65 date2 = date(change)
39 date2 = date(change)
66 else:
40 else:
67 date2 = time.asctime()
41 date2 = time.asctime()
68 if not node1:
42 if not node1:
69 node1 = repo.dirstate.parents()[0]
43 node1 = repo.dirstate.parents()[0]
70 (c, a, d, u) = repo.diffdir(repo.root, node1)
44 (c, a, d, u) = repo.diffdir(repo.root, node1)
71 def read(f): return file(os.path.join(repo.root, f)).read()
45 def read(f): return file(os.path.join(repo.root, f)).read()
72
46
73 change = repo.changelog.read(node1)
47 change = repo.changelog.read(node1)
74 mmap = repo.manifest.read(change[0])
48 mmap = repo.manifest.read(change[0])
75 date1 = date(change)
49 date1 = date(change)
76
50
77 if files:
51 if files:
78 c, a, d = map(lambda x: filterfiles(x, files), (c, a, d))
52 c, a, d = map(lambda x: filterfiles(x, files), (c, a, d))
79
53
80 for f in c:
54 for f in c:
81 to = repo.file(f).read(mmap[f])
55 to = repo.file(f).read(mmap[f])
82 tn = read(f)
56 tn = read(f)
83 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
57 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
84 for f in a:
58 for f in a:
85 to = ""
59 to = ""
86 tn = read(f)
60 tn = read(f)
87 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
61 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
88 for f in d:
62 for f in d:
89 to = repo.file(f).read(mmap[f])
63 to = repo.file(f).read(mmap[f])
90 tn = ""
64 tn = ""
91 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
65 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
92
66
93
67
94 try:
68 try:
95 sys.exit(commands.dispatch(sys.argv[1:]))
69 sys.exit(commands.dispatch(sys.argv[1:]))
96 except commands.UnknownCommand:
70 except commands.UnknownCommand:
97 # fall through
71 # fall through
98 pass
72 pass
99
73
100 options = {}
74 options = {}
101 opts = [('v', 'verbose', None, 'verbose'),
75 opts = [('v', 'verbose', None, 'verbose'),
102 ('d', 'debug', None, 'debug'),
76 ('d', 'debug', None, 'debug'),
103 ('q', 'quiet', None, 'quiet'),
77 ('q', 'quiet', None, 'quiet'),
104 ('y', 'noninteractive', None, 'run non-interactively'),
78 ('y', 'noninteractive', None, 'run non-interactively'),
105 ]
79 ]
106
80
107 args = fancyopts.fancyopts(sys.argv[1:], opts, options,
81 args = fancyopts.fancyopts(sys.argv[1:], opts, options,
108 'hg [options] <command> [command options] [files]')
82 'hg [options] <command> [command options] [files]')
109
83
110 try:
84 try:
111 cmd = args[0]
85 cmd = args[0]
112 args = args[1:]
86 args = args[1:]
113 except:
87 except:
114 cmd = "help"
88 cmd = "help"
115
89
116 ui = ui.ui(options["verbose"], options["debug"], options["quiet"],
90 ui = ui.ui(options["verbose"], options["debug"], options["quiet"],
117 not options["noninteractive"])
91 not options["noninteractive"])
118
92
119 try:
93 try:
120 repo = hg.repository(ui=ui)
94 repo = hg.repository(ui=ui)
121 except IOError:
95 except IOError:
122 ui.warn("Unable to open repository\n")
96 ui.warn("Unable to open repository\n")
123 sys.exit(0)
97 sys.exit(0)
124
98
125 relpath = None
99 relpath = None
126 if os.getcwd() != repo.root:
100 if os.getcwd() != repo.root:
127 relpath = os.getcwd()[len(repo.root) + 1: ]
101 relpath = os.getcwd()[len(repo.root) + 1: ]
128
102
129 elif cmd == "add":
130 repo.add(args)
131
132 elif cmd == "forget":
133 repo.forget(args)
134
135 elif cmd == "remove" or cmd == "rm" or cmd == "del" or cmd == "delete":
136 repo.remove(args)
137
138 elif cmd == "commit" or cmd == "checkin" or cmd == "ci":
139 if 1:
140 if len(args) > 0:
141 repo.commit(args)
142 else:
143 repo.commit()
144 elif cmd == "rawcommit":
103 elif cmd == "rawcommit":
145 "raw commit interface"
104 "raw commit interface"
146 rc = {}
105 rc = {}
147 opts = [('p', 'parent', [], 'parent'),
106 opts = [('p', 'parent', [], 'parent'),
148 ('d', 'date', "", 'data'),
107 ('d', 'date', "", 'data'),
149 ('u', 'user', "", 'user'),
108 ('u', 'user', "", 'user'),
150 ('F', 'files', "", 'file list'),
109 ('F', 'files', "", 'file list'),
151 ('t', 'text', "", 'commit text'),
110 ('t', 'text', "", 'commit text'),
152 ('l', 'logfile', "", 'commit text file')
111 ('l', 'logfile', "", 'commit text file')
153 ]
112 ]
154 args = fancyopts.fancyopts(args, opts, rc,
113 args = fancyopts.fancyopts(args, opts, rc,
155 "hg rawcommit [options] files")
114 "hg rawcommit [options] files")
156 text = rc['text']
115 text = rc['text']
157 if not text and rc['logfile']:
116 if not text and rc['logfile']:
158 try: text = open(rc['logfile']).read()
117 try: text = open(rc['logfile']).read()
159 except IOError: pass
118 except IOError: pass
160 if not text and not rc['logfile']:
119 if not text and not rc['logfile']:
161 print "missing commit text"
120 print "missing commit text"
162 sys.exit(0)
121 sys.exit(0)
163 if rc['files']:
122 if rc['files']:
164 files = open(rc['files']).read().splitlines()
123 files = open(rc['files']).read().splitlines()
165 else:
124 else:
166 files = args
125 files = args
167
126
168 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
127 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
169
128
170
129
171 elif cmd == "import" or cmd == "patch":
130 elif cmd == "import" or cmd == "patch":
172 try:
131 try:
173 import psyco
132 import psyco
174 psyco.full()
133 psyco.full()
175 except:
134 except:
176 pass
135 pass
177
136
178 ioptions = {}
137 ioptions = {}
179 opts = [('p', 'strip', 1, 'path strip'),
138 opts = [('p', 'strip', 1, 'path strip'),
180 ('b', 'base', "", 'base path'),
139 ('b', 'base', "", 'base path'),
181 ('q', 'quiet', "", 'silence diff')
140 ('q', 'quiet', "", 'silence diff')
182 ]
141 ]
183
142
184 args = fancyopts.fancyopts(args, opts, ioptions,
143 args = fancyopts.fancyopts(args, opts, ioptions,
185 'hg import [options] <patch names>')
144 'hg import [options] <patch names>')
186 d = ioptions["base"]
145 d = ioptions["base"]
187 strip = ioptions["strip"]
146 strip = ioptions["strip"]
188 quiet = ioptions["quiet"] and "> /dev/null" or ""
147 quiet = ioptions["quiet"] and "> /dev/null" or ""
189
148
190 for patch in args:
149 for patch in args:
191 ui.status("applying %s\n" % patch)
150 ui.status("applying %s\n" % patch)
192 pf = os.path.join(d, patch)
151 pf = os.path.join(d, patch)
193
152
194 text = ""
153 text = ""
195 for l in file(pf):
154 for l in file(pf):
196 if l[:4] == "--- ": break
155 if l[:4] == "--- ": break
197 text += l
156 text += l
198
157
199 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
158 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
200 files = filter(None, map(lambda x: x.rstrip(), f.read().splitlines()))
159 files = filter(None, map(lambda x: x.rstrip(), f.read().splitlines()))
201 f.close()
160 f.close()
202
161
203 if files:
162 if files:
204 if os.system("patch -p%d < %s %s" % (strip, pf, quiet)):
163 if os.system("patch -p%d < %s %s" % (strip, pf, quiet)):
205 raise "patch failed!"
164 raise "patch failed!"
206 repo.commit(files, text)
165 repo.commit(files, text)
207
166
208 elif cmd == "diff":
209 revs = []
210
211 if args:
212 doptions = {}
213 opts = [('r', 'revision', [], 'revision')]
214 args = fancyopts.fancyopts(args, opts, doptions,
215 'hg diff [options] [files]')
216 revs = map(lambda x: repo.lookup(x), doptions['revision'])
217
218 if len(revs) > 2:
219 self.ui.warn("too many revisions to diff\n")
220 sys.exit(1)
221
222 if relpath:
223 if not args: args = [ relpath ]
224 else: args = [ os.path.join(relpath, x) for x in args ]
225
226 diff(args, *revs)
227
228 elif cmd == "export":
167 elif cmd == "export":
229 node = repo.lookup(args[0])
168 node = repo.lookup(args[0])
230 prev, other = repo.changelog.parents(node)
169 prev, other = repo.changelog.parents(node)
231 change = repo.changelog.read(node)
170 change = repo.changelog.read(node)
232 print "# HG changeset patch"
171 print "# HG changeset patch"
233 print "# User %s" % change[1]
172 print "# User %s" % change[1]
234 print "# Node ID %s" % hg.hex(node)
173 print "# Node ID %s" % hg.hex(node)
235 print "# Parent %s" % hg.hex(prev)
174 print "# Parent %s" % hg.hex(prev)
236 print
175 print
237 if other != hg.nullid:
176 if other != hg.nullid:
238 print "# Parent %s" % hg.hex(other)
177 print "# Parent %s" % hg.hex(other)
239 print change[4]
178 print change[4]
240
179
241 diff(None, prev, node)
180 diff(None, prev, node)
242
181
243 elif cmd == "debugchangegroup":
182 elif cmd == "debugchangegroup":
244 newer = repo.newer(map(repo.lookup, args))
183 newer = repo.newer(map(repo.lookup, args))
245 for chunk in repo.changegroup(newer):
184 for chunk in repo.changegroup(newer):
246 sys.stdout.write(chunk)
185 sys.stdout.write(chunk)
247
186
248 elif cmd == "debugaddchangegroup":
187 elif cmd == "debugaddchangegroup":
249 data = sys.stdin.read()
188 data = sys.stdin.read()
250 repo.addchangegroup(data)
189 repo.addchangegroup(data)
251
190
252 elif cmd == "addremove":
253 (c, a, d, u) = repo.diffdir(repo.root)
254 repo.add(a)
255 repo.remove(d)
256
257 elif cmd == "history":
191 elif cmd == "history":
258 for i in range(repo.changelog.count()):
192 for i in range(repo.changelog.count()):
259 n = repo.changelog.node(i)
193 n = repo.changelog.node(i)
260 changes = repo.changelog.read(n)
194 changes = repo.changelog.read(n)
261 (p1, p2) = repo.changelog.parents(n)
195 (p1, p2) = repo.changelog.parents(n)
262 (h, h1, h2) = map(hg.hex, (n, p1, p2))
196 (h, h1, h2) = map(hg.hex, (n, p1, p2))
263 (i1, i2) = map(repo.changelog.rev, (p1, p2))
197 (i1, i2) = map(repo.changelog.rev, (p1, p2))
264 print "rev: %4d:%s" % (i, h)
198 print "rev: %4d:%s" % (i, h)
265 print "parents: %4d:%s" % (i1, h1)
199 print "parents: %4d:%s" % (i1, h1)
266 if i2: print " %4d:%s" % (i2, h2)
200 if i2: print " %4d:%s" % (i2, h2)
267 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
201 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
268 hg.hex(changes[0]))
202 hg.hex(changes[0]))
269 print "user:", changes[1]
203 print "user:", changes[1]
270 print "date:", time.asctime(
204 print "date:", time.asctime(
271 time.localtime(float(changes[2].split(' ')[0])))
205 time.localtime(float(changes[2].split(' ')[0])))
272 if ui.verbose: print "files:", " ".join(changes[3])
206 if ui.verbose: print "files:", " ".join(changes[3])
273 print "description:"
207 print "description:"
274 print changes[4]
208 print changes[4]
275
209
276 elif cmd == "tip":
277 n = repo.changelog.tip()
278 t = repo.changelog.rev(n)
279 ui.status("%d:%s\n" % (t, hg.hex(n)))
280
281 elif cmd == "log":
282
283 if len(args) == 1:
284 if relpath:
285 args[0] = os.path.join(relpath, args[0])
286
287 r = repo.file(args[0])
288 for i in range(r.count()):
289 n = r.node(i)
290 (p1, p2) = r.parents(n)
291 (h, h1, h2) = map(hg.hex, (n, p1, p2))
292 (i1, i2) = map(r.rev, (p1, p2))
293 cr = r.linkrev(n)
294 cn = hg.hex(repo.changelog.node(cr))
295 print "rev: %4d:%s" % (i, h)
296 print "changeset: %4d:%s" % (cr, cn)
297 print "parents: %4d:%s" % (i1, h1)
298 if i2: print " %4d:%s" % (i2, h2)
299 changes = repo.changelog.read(repo.changelog.node(cr))
300 print "user: %s" % changes[1]
301 print "date: %s" % time.asctime(
302 time.localtime(float(changes[2].split(' ')[0])))
303 print "description:"
304 print changes[4]
305 print
306 elif len(args) > 1:
307 print "too many args"
308 else:
309 print "missing filename"
310
311 elif cmd == "dump":
210 elif cmd == "dump":
312 if args:
211 if args:
313 r = repo.file(args[0])
212 r = repo.file(args[0])
314 n = r.tip()
213 n = r.tip()
315 if len(args) > 1: n = r.lookup(args[1])
214 if len(args) > 1: n = r.lookup(args[1])
316 sys.stdout.write(r.read(n))
215 sys.stdout.write(r.read(n))
317 else:
216 else:
318 print "missing filename"
217 print "missing filename"
319
218
320 elif cmd == "dumpmanifest":
219 elif cmd == "dumpmanifest":
321 n = repo.manifest.tip()
220 n = repo.manifest.tip()
322 if len(args) > 0:
221 if len(args) > 0:
323 n = repo.manifest.lookup(args[0])
222 n = repo.manifest.lookup(args[0])
324 m = repo.manifest.read(n)
223 m = repo.manifest.read(n)
325 files = m.keys()
224 files = m.keys()
326 files.sort()
225 files.sort()
327
226
328 for f in files:
227 for f in files:
329 print hg.hex(m[f]), f
228 print hg.hex(m[f]), f
330
229
331 elif cmd == "debugindex":
230 elif cmd == "debugindex":
332 if ".hg" not in args[0]:
231 if ".hg" not in args[0]:
333 args[0] = ".hg/data/" + repo.file(args[0]).encodepath(args[0]) + "i"
232 args[0] = ".hg/data/" + repo.file(args[0]).encodepath(args[0]) + "i"
334
233
335 r = hg.revlog(open, args[0], "")
234 r = hg.revlog(open, args[0], "")
336 print " rev offset length base linkrev"+\
235 print " rev offset length base linkrev"+\
337 " p1 p2 nodeid"
236 " p1 p2 nodeid"
338 for i in range(r.count()):
237 for i in range(r.count()):
339 e = r.index[i]
238 e = r.index[i]
340 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
239 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
341 i, e[0], e[1], e[2], e[3],
240 i, e[0], e[1], e[2], e[3],
342 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
241 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
343
242
344 elif cmd == "debugindexdot":
243 elif cmd == "debugindexdot":
345 if ".hg" not in args[0]:
244 if ".hg" not in args[0]:
346 args[0] = ".hg/data/" + repo.file(args[0]).encodepath(args[0]) + "i"
245 args[0] = ".hg/data/" + repo.file(args[0]).encodepath(args[0]) + "i"
347
246
348 r = hg.revlog(open, args[0], "")
247 r = hg.revlog(open, args[0], "")
349 print "digraph G {"
248 print "digraph G {"
350 for i in range(r.count()):
249 for i in range(r.count()):
351 e = r.index[i]
250 e = r.index[i]
352 print "\t%d -> %d" % (r.rev(e[4]), i)
251 print "\t%d -> %d" % (r.rev(e[4]), i)
353 if e[5] != hg.nullid:
252 if e[5] != hg.nullid:
354 print "\t%d -> %d" % (r.rev(e[5]), i)
253 print "\t%d -> %d" % (r.rev(e[5]), i)
355 print "}"
254 print "}"
356
255
357 elif cmd == "merge":
256 elif cmd == "merge":
358 if args:
257 if args:
359 paths = {}
258 paths = {}
360 try:
259 try:
361 pf = os.path.join(os.environ["HOME"], ".hgpaths")
260 pf = os.path.join(os.environ["HOME"], ".hgpaths")
362 for l in file(pf):
261 for l in file(pf):
363 name, path = l.split()
262 name, path = l.split()
364 paths[name] = path
263 paths[name] = path
365 except:
264 except:
366 pass
265 pass
367
266
368 if args[0] in paths: args[0] = paths[args[0]]
267 if args[0] in paths: args[0] = paths[args[0]]
369
268
370 other = hg.repository(ui, args[0])
269 other = hg.repository(ui, args[0])
371 cg = repo.getchangegroup(other)
270 cg = repo.getchangegroup(other)
372 repo.addchangegroup(cg)
271 repo.addchangegroup(cg)
373 else:
272 else:
374 print "missing source repository"
273 print "missing source repository"
375
274
376 elif cmd == "tags":
275 elif cmd == "tags":
377 repo.lookup(0) # prime the cache
276 repo.lookup(0) # prime the cache
378 i = repo.tags.items()
277 i = repo.tags.items()
379 i.sort()
278 i.sort()
380 for k, n in i:
279 for k, n in i:
381 try:
280 try:
382 r = repo.changelog.rev(n)
281 r = repo.changelog.rev(n)
383 except KeyError:
282 except KeyError:
384 r = "?"
283 r = "?"
385 print "%-30s %5d:%s" % (k, repo.changelog.rev(n), hg.hex(n))
284 print "%-30s %5d:%s" % (k, repo.changelog.rev(n), hg.hex(n))
386
285
387 elif cmd == "recover":
388 repo.recover()
389
390 elif cmd == "verify":
286 elif cmd == "verify":
391 filelinkrevs = {}
287 filelinkrevs = {}
392 filenodes = {}
288 filenodes = {}
393 manifestchangeset = {}
289 manifestchangeset = {}
394 changesets = revisions = files = 0
290 changesets = revisions = files = 0
395 errors = 0
291 errors = 0
396
292
397 ui.status("checking changesets\n")
293 ui.status("checking changesets\n")
398 for i in range(repo.changelog.count()):
294 for i in range(repo.changelog.count()):
399 changesets += 1
295 changesets += 1
400 n = repo.changelog.node(i)
296 n = repo.changelog.node(i)
401 for p in repo.changelog.parents(n):
297 for p in repo.changelog.parents(n):
402 if p not in repo.changelog.nodemap:
298 if p not in repo.changelog.nodemap:
403 ui.warn("changeset %s has unknown parent %s\n" %
299 ui.warn("changeset %s has unknown parent %s\n" %
404 (hg.short(n), hg.short(p)))
300 (hg.short(n), hg.short(p)))
405 errors += 1
301 errors += 1
406 try:
302 try:
407 changes = repo.changelog.read(n)
303 changes = repo.changelog.read(n)
408 except Exception, inst:
304 except Exception, inst:
409 ui.warn("unpacking changeset %s: %s\n" % (short(n), inst))
305 ui.warn("unpacking changeset %s: %s\n" % (short(n), inst))
410 errors += 1
306 errors += 1
411
307
412 manifestchangeset[changes[0]] = n
308 manifestchangeset[changes[0]] = n
413 for f in changes[3]:
309 for f in changes[3]:
414 filelinkrevs.setdefault(f, []).append(i)
310 filelinkrevs.setdefault(f, []).append(i)
415
311
416 ui.status("checking manifests\n")
312 ui.status("checking manifests\n")
417 for i in range(repo.manifest.count()):
313 for i in range(repo.manifest.count()):
418 n = repo.manifest.node(i)
314 n = repo.manifest.node(i)
419 for p in repo.manifest.parents(n):
315 for p in repo.manifest.parents(n):
420 if p not in repo.manifest.nodemap:
316 if p not in repo.manifest.nodemap:
421 ui.warn("manifest %s has unknown parent %s\n" %
317 ui.warn("manifest %s has unknown parent %s\n" %
422 (hg.short(n), hg.short(p)))
318 (hg.short(n), hg.short(p)))
423 errors += 1
319 errors += 1
424 ca = repo.changelog.node(repo.manifest.linkrev(n))
320 ca = repo.changelog.node(repo.manifest.linkrev(n))
425 cc = manifestchangeset[n]
321 cc = manifestchangeset[n]
426 if ca != cc:
322 if ca != cc:
427 ui.warn("manifest %s points to %s, not %s\n" %
323 ui.warn("manifest %s points to %s, not %s\n" %
428 (hg.hex(n), hg.hex(ca), hg.hex(cc)))
324 (hg.hex(n), hg.hex(ca), hg.hex(cc)))
429 errors += 1
325 errors += 1
430
326
431 try:
327 try:
432 delta = mdiff.patchtext(repo.manifest.delta(n))
328 delta = mdiff.patchtext(repo.manifest.delta(n))
433 except KeyboardInterrupt:
329 except KeyboardInterrupt:
434 print "aborted"
330 print "aborted"
435 sys.exit(0)
331 sys.exit(0)
436 except Exception, inst:
332 except Exception, inst:
437 ui.warn("unpacking manifest %s: %s\n" % (hg.short(n), inst))
333 ui.warn("unpacking manifest %s: %s\n" % (hg.short(n), inst))
438 errors += 1
334 errors += 1
439
335
440 ff = [ l.split('\0') for l in delta.splitlines() ]
336 ff = [ l.split('\0') for l in delta.splitlines() ]
441 for f, fn in ff:
337 for f, fn in ff:
442 filenodes.setdefault(f, {})[hg.bin(fn)] = 1
338 filenodes.setdefault(f, {})[hg.bin(fn)] = 1
443
339
444 ui.status("crosschecking files in changesets and manifests\n")
340 ui.status("crosschecking files in changesets and manifests\n")
445 for f in filenodes:
341 for f in filenodes:
446 if f not in filelinkrevs:
342 if f not in filelinkrevs:
447 ui.warn("file %s in manifest but not in changesets\n" % f)
343 ui.warn("file %s in manifest but not in changesets\n" % f)
448 errors += 1
344 errors += 1
449
345
450 for f in filelinkrevs:
346 for f in filelinkrevs:
451 if f not in filenodes:
347 if f not in filenodes:
452 ui.warn("file %s in changeset but not in manifest\n" % f)
348 ui.warn("file %s in changeset but not in manifest\n" % f)
453 errors += 1
349 errors += 1
454
350
455 ui.status("checking files\n")
351 ui.status("checking files\n")
456 ff = filenodes.keys()
352 ff = filenodes.keys()
457 ff.sort()
353 ff.sort()
458 for f in ff:
354 for f in ff:
459 if f == "/dev/null": continue
355 if f == "/dev/null": continue
460 files += 1
356 files += 1
461 fl = repo.file(f)
357 fl = repo.file(f)
462 nodes = { hg.nullid: 1 }
358 nodes = { hg.nullid: 1 }
463 for i in range(fl.count()):
359 for i in range(fl.count()):
464 revisions += 1
360 revisions += 1
465 n = fl.node(i)
361 n = fl.node(i)
466
362
467 if n not in filenodes[f]:
363 if n not in filenodes[f]:
468 ui.warn("%s: %d:%s not in manifests\n" % (f, i, hg.short(n)))
364 ui.warn("%s: %d:%s not in manifests\n" % (f, i, hg.short(n)))
469 print len(filenodes[f].keys()), fl.count(), f
365 print len(filenodes[f].keys()), fl.count(), f
470 errors += 1
366 errors += 1
471 else:
367 else:
472 del filenodes[f][n]
368 del filenodes[f][n]
473
369
474 flr = fl.linkrev(n)
370 flr = fl.linkrev(n)
475 if flr not in filelinkrevs[f]:
371 if flr not in filelinkrevs[f]:
476 ui.warn("%s:%s points to unexpected changeset rev %d\n"
372 ui.warn("%s:%s points to unexpected changeset rev %d\n"
477 % (f, hg.short(n), fl.linkrev(n)))
373 % (f, hg.short(n), fl.linkrev(n)))
478 errors += 1
374 errors += 1
479 else:
375 else:
480 filelinkrevs[f].remove(flr)
376 filelinkrevs[f].remove(flr)
481
377
482 # verify contents
378 # verify contents
483 try:
379 try:
484 t = fl.read(n)
380 t = fl.read(n)
485 except Exception, inst:
381 except Exception, inst:
486 ui.warn("unpacking file %s %s: %s\n" % (f, hg.short(n), inst))
382 ui.warn("unpacking file %s %s: %s\n" % (f, hg.short(n), inst))
487 errors += 1
383 errors += 1
488
384
489 # verify parents
385 # verify parents
490 (p1, p2) = fl.parents(n)
386 (p1, p2) = fl.parents(n)
491 if p1 not in nodes:
387 if p1 not in nodes:
492 ui.warn("file %s:%s unknown parent 1 %s" %
388 ui.warn("file %s:%s unknown parent 1 %s" %
493 (f, hg.short(n), hg.short(p1)))
389 (f, hg.short(n), hg.short(p1)))
494 errors += 1
390 errors += 1
495 if p2 not in nodes:
391 if p2 not in nodes:
496 ui.warn("file %s:%s unknown parent 2 %s" %
392 ui.warn("file %s:%s unknown parent 2 %s" %
497 (f, hg.short(n), hg.short(p1)))
393 (f, hg.short(n), hg.short(p1)))
498 errors += 1
394 errors += 1
499 nodes[n] = 1
395 nodes[n] = 1
500
396
501 # cross-check
397 # cross-check
502 for node in filenodes[f]:
398 for node in filenodes[f]:
503 ui.warn("node %s in manifests not in %s\n" % (hg.hex(n), f))
399 ui.warn("node %s in manifests not in %s\n" % (hg.hex(n), f))
504 errors += 1
400 errors += 1
505
401
506 ui.status("%d files, %d changesets, %d total revisions\n" %
402 ui.status("%d files, %d changesets, %d total revisions\n" %
507 (files, changesets, revisions))
403 (files, changesets, revisions))
508
404
509 if errors:
405 if errors:
510 ui.warn("%d integrity errors encountered!\n" % errors)
406 ui.warn("%d integrity errors encountered!\n" % errors)
511 sys.exit(1)
407 sys.exit(1)
512
408
513 elif cmd == "serve":
514 from mercurial import hgweb
515
516 soptions = {}
517 opts = [('p', 'port', 8000, 'listen port'),
518 ('a', 'address', '', 'interface address'),
519 ('n', 'name', os.getcwd(), 'repository name'),
520 ('t', 'templates', "", 'template map')
521 ]
522
523 args = fancyopts.fancyopts(args, opts, soptions,
524 'hg serve [options]')
525
526 hgweb.server(repo.root, soptions["name"], soptions["templates"],
527 soptions["address"], soptions["port"])
528
529 else:
409 else:
530 if cmd: ui.warn("unknown command\n\n")
410 if cmd: ui.warn("unknown command\n\n")
531 help()
532 sys.exit(1)
411 sys.exit(1)
@@ -1,261 +1,386 b''
1 import os, re, traceback, sys, signal, time
1 import os, re, traceback, sys, signal, time, mdiff
2 from mercurial import fancyopts, ui, hg
2 from mercurial import fancyopts, ui, hg
3
3
4 class UnknownCommand(Exception): pass
4 class UnknownCommand(Exception): pass
5
5
6 def filterfiles(list, files):
6 def filterfiles(filters, files):
7 l = [ x for x in list if x in files ]
7 l = [ x for x in files if x in filters ]
8
8
9 for f in files:
9 for t in filters:
10 if f[-1] != os.sep: f += os.sep
10 if t and t[-1] != os.sep: t += os.sep
11 l += [ x for x in list if x.startswith(f) ]
11 l += [ x for x in files if x.startswith(t) ]
12 return l
12 return l
13
13
14 def relfilter(repo, args):
14 def relfilter(repo, files):
15 if os.getcwd() != repo.root:
15 if os.getcwd() != repo.root:
16 p = os.getcwd()[len(repo.root) + 1: ]
16 p = os.getcwd()[len(repo.root) + 1: ]
17 return filterfiles(p, args)
17 return filterfiles(p, files)
18 return args
18 return files
19
19
20 def relpath(repo, args):
20 def relpath(repo, args):
21 if os.getcwd() != repo.root:
21 if os.getcwd() != repo.root:
22 p = os.getcwd()[len(repo.root) + 1: ]
22 p = os.getcwd()[len(repo.root) + 1: ]
23 return [ os.path.join(p, x) for x in args ]
23 return [ os.path.normpath(os.path.join(p, x)) for x in args ]
24 return args
24 return args
25
25
26 def dodiff(repo, files = None, node1 = None, node2 = None):
27 def date(c):
28 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
29
30 if node2:
31 change = repo.changelog.read(node2)
32 mmap2 = repo.manifest.read(change[0])
33 (c, a, d) = repo.diffrevs(node1, node2)
34 def read(f): return repo.file(f).read(mmap2[f])
35 date2 = date(change)
36 else:
37 date2 = time.asctime()
38 (c, a, d, u) = repo.diffdir(repo.root, node1)
39 if not node1:
40 node1 = repo.dirstate.parents()[0]
41 def read(f): return file(os.path.join(repo.root, f)).read()
42
43 change = repo.changelog.read(node1)
44 mmap = repo.manifest.read(change[0])
45 date1 = date(change)
46
47 if files:
48 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
49
50 for f in c:
51 to = repo.file(f).read(mmap[f])
52 tn = read(f)
53 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
54 for f in a:
55 to = ""
56 tn = read(f)
57 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
58 for f in d:
59 to = repo.file(f).read(mmap[f])
60 tn = ""
61 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
62
26 def help(ui, cmd=None):
63 def help(ui, cmd=None):
27 '''show help'''
64 '''show help'''
28 if cmd:
65 if cmd:
29 try:
66 try:
30 i = find(cmd)
67 i = find(cmd)
31 ui.write("%s\n\n" % i[2])
68 ui.write("%s\n\n" % i[2])
32 ui.write(i[0].__doc__, "\n")
69 ui.write(i[0].__doc__, "\n")
33 except UnknownCommand:
70 except UnknownCommand:
34 ui.warn("unknown command %s", cmd)
71 ui.warn("unknown command %s", cmd)
35 sys.exit(0)
72 sys.exit(0)
36
73
37 ui.status("""\
74 ui.status("""\
38 hg commands:
75 hg commands:
39
76
40 add [files...] add the given files in the next commit
77 add [files...] add the given files in the next commit
41 addremove add all new files, delete all missing files
78 addremove add all new files, delete all missing files
42 annotate [files...] show changeset number per file line
79 annotate [files...] show changeset number per file line
43 branch <path> create a branch of <path> in this directory
80 branch <path> create a branch of <path> in this directory
44 checkout [changeset] checkout the latest or given changeset
81 checkout [changeset] checkout the latest or given changeset
45 commit commit all changes to the repository
82 commit commit all changes to the repository
46 diff [files...] diff working directory (or selected files)
83 diff [files...] diff working directory (or selected files)
47 dump <file> [rev] dump the latest or given revision of a file
84 dump <file> [rev] dump the latest or given revision of a file
48 dumpmanifest [rev] dump the latest or given revision of the manifest
85 dumpmanifest [rev] dump the latest or given revision of the manifest
49 export <rev> dump the changeset header and diffs for a revision
86 export <rev> dump the changeset header and diffs for a revision
50 history show changeset history
87 history show changeset history
51 init create a new repository in this directory
88 init create a new repository in this directory
52 log <file> show revision history of a single file
89 log <file> show revision history of a single file
53 merge <path> merge changes from <path> into local repository
90 merge <path> merge changes from <path> into local repository
54 recover rollback an interrupted transaction
91 recover rollback an interrupted transaction
55 remove [files...] remove the given files in the next commit
92 remove [files...] remove the given files in the next commit
56 serve export the repository via HTTP
93 serve export the repository via HTTP
57 status show new, missing, and changed files in working dir
94 status show new, missing, and changed files in working dir
58 tags show current changeset tags
95 tags show current changeset tags
59 undo undo the last transaction
96 undo undo the last transaction
60 """)
97 """)
61
98
62 def init(ui):
99 def add(ui, repo, file, *files):
63 """create a repository"""
100 '''add the specified files on the next commit'''
64 hg.repository(ui, ".", create=1)
101 repo.add(relpath(repo, (file,) + files))
65
66 def branch(ui, path):
67 '''branch from a local repository'''
68 # this should eventually support remote repos
69 os.system("cp -al %s/.hg .hg" % path)
70
102
71 def checkout(ui, repo, changeset=None):
103 def addremove(ui, repo):
72 '''checkout a given changeset or the current tip'''
73 (c, a, d, u) = repo.diffdir(repo.root)
104 (c, a, d, u) = repo.diffdir(repo.root)
74 if c or a or d:
105 repo.add(a)
75 ui.warn("aborting (outstanding changes in working directory)\n")
106 repo.remove(d)
76 sys.exit(1)
77
107
78 node = repo.changelog.tip()
108 def annotate(u, repo, file, *files, **ops):
79 if changeset:
80 node = repo.lookup(changeset)
81 repo.checkout(node)
82
83 def annotate(u, repo, *args, **ops):
84 def getnode(rev):
109 def getnode(rev):
85 return hg.short(repo.changelog.node(rev))
110 return hg.short(repo.changelog.node(rev))
86
111
87 def getname(rev):
112 def getname(rev):
88 try:
113 try:
89 return bcache[rev]
114 return bcache[rev]
90 except KeyError:
115 except KeyError:
91 cl = repo.changelog.read(repo.changelog.node(rev))
116 cl = repo.changelog.read(repo.changelog.node(rev))
92 name = cl[1]
117 name = cl[1]
93 f = name.find('@')
118 f = name.find('@')
94 if f >= 0:
119 if f >= 0:
95 name = name[:f]
120 name = name[:f]
96 bcache[rev] = name
121 bcache[rev] = name
97 return name
122 return name
98
123
99 bcache = {}
124 bcache = {}
100 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
125 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
101 if not ops['user'] and not ops['changeset']:
126 if not ops['user'] and not ops['changeset']:
102 ops['number'] = 1
127 ops['number'] = 1
103
128
104 args = relpath(repo, args)
105 node = repo.dirstate.parents()[0]
129 node = repo.dirstate.parents()[0]
106 if ops['revision']:
130 if ops['revision']:
107 node = repo.changelog.lookup(ops['revision'])
131 node = repo.changelog.lookup(ops['revision'])
108 change = repo.changelog.read(node)
132 change = repo.changelog.read(node)
109 mmap = repo.manifest.read(change[0])
133 mmap = repo.manifest.read(change[0])
110 maxuserlen = 0
134 maxuserlen = 0
111 maxchangelen = 0
135 maxchangelen = 0
112 for f in args:
136 for f in relpath(repo, (file,) + files):
113 lines = repo.file(f).annotate(mmap[f])
137 lines = repo.file(f).annotate(mmap[f])
114 pieces = []
138 pieces = []
115
139
116 for o, f in opmap:
140 for o, f in opmap:
117 if ops[o]:
141 if ops[o]:
118 l = [ f(n) for n,t in lines ]
142 l = [ f(n) for n,t in lines ]
119 m = max(map(len, l))
143 m = max(map(len, l))
120 pieces.append([ "%*s" % (m, x) for x in l])
144 pieces.append([ "%*s" % (m, x) for x in l])
121
145
122 for p,l in zip(zip(*pieces), lines):
146 for p,l in zip(zip(*pieces), lines):
123 u.write(" ".join(p) + ": " + l[1])
147 u.write(" ".join(p) + ": " + l[1])
124
148
149 def branch(ui, path):
150 '''branch from a local repository'''
151 # this should eventually support remote repos
152 os.system("cp -al %s/.hg .hg" % path)
153
154 def checkout(ui, repo, changeset=None):
155 '''checkout a given changeset or the current tip'''
156 (c, a, d, u) = repo.diffdir(repo.root)
157 if c or a or d:
158 ui.warn("aborting (outstanding changes in working directory)\n")
159 sys.exit(1)
160
161 node = repo.changelog.tip()
162 if changeset:
163 node = repo.lookup(changeset)
164 repo.checkout(node)
165
166 def commit(ui, repo, *files):
167 """commit the specified files or all outstanding changes"""
168 repo.commit(relpath(repo, files))
169
170 def diff(ui, repo, *files, **opts):
171 revs = []
172 if opts['rev']:
173 revs = map(lambda x: repo.lookup(x), opts['rev'])
174
175 if len(revs) > 2:
176 self.ui.warn("too many revisions to diff\n")
177 sys.exit(1)
178
179 if files:
180 files = relpath(repo, files)
181 else:
182 files = relpath(repo, [""])
183
184 dodiff(repo, files, *revs)
185
186 def forget(ui, repo, file, *files):
187 """don't add the specified files on the next commit"""
188 repo.forget(relpath(repo, (file,) + files))
189
125 def heads(ui, repo):
190 def heads(ui, repo):
126 '''show current repository heads'''
191 '''show current repository heads'''
127 for n in repo.changelog.heads():
192 for n in repo.changelog.heads():
128 i = repo.changelog.rev(n)
193 i = repo.changelog.rev(n)
129 changes = repo.changelog.read(n)
194 changes = repo.changelog.read(n)
130 (p1, p2) = repo.changelog.parents(n)
195 (p1, p2) = repo.changelog.parents(n)
131 (h, h1, h2) = map(hg.hex, (n, p1, p2))
196 (h, h1, h2) = map(hg.hex, (n, p1, p2))
132 (i1, i2) = map(repo.changelog.rev, (p1, p2))
197 (i1, i2) = map(repo.changelog.rev, (p1, p2))
133 print "rev: %4d:%s" % (i, h)
198 print "rev: %4d:%s" % (i, h)
134 print "parents: %4d:%s" % (i1, h1)
199 print "parents: %4d:%s" % (i1, h1)
135 if i2: print " %4d:%s" % (i2, h2)
200 if i2: print " %4d:%s" % (i2, h2)
136 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
201 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
137 hg.hex(changes[0]))
202 hg.hex(changes[0]))
138 print "user:", changes[1]
203 print "user:", changes[1]
139 print "date:", time.asctime(
204 print "date:", time.asctime(
140 time.localtime(float(changes[2].split(' ')[0])))
205 time.localtime(float(changes[2].split(' ')[0])))
141 if ui.verbose: print "files:", " ".join(changes[3])
206 if ui.verbose: print "files:", " ".join(changes[3])
142 print "description:"
207 print "description:"
143 print changes[4]
208 print changes[4]
144
209
210 def init(ui):
211 """create a repository"""
212 hg.repository(ui, ".", create=1)
213
214 def log(ui, repo, f):
215 f = relpath(repo, [f])[0]
216
217 r = repo.file(f)
218 for i in range(r.count()):
219 n = r.node(i)
220 (p1, p2) = r.parents(n)
221 (h, h1, h2) = map(hg.hex, (n, p1, p2))
222 (i1, i2) = map(r.rev, (p1, p2))
223 cr = r.linkrev(n)
224 cn = hg.hex(repo.changelog.node(cr))
225 print "rev: %4d:%s" % (i, h)
226 print "changeset: %4d:%s" % (cr, cn)
227 print "parents: %4d:%s" % (i1, h1)
228 if i2: print " %4d:%s" % (i2, h2)
229 changes = repo.changelog.read(repo.changelog.node(cr))
230 print "user: %s" % changes[1]
231 print "date: %s" % time.asctime(
232 time.localtime(float(changes[2].split(' ')[0])))
233 print "description:"
234 print changes[4].rstrip()
235 print
236
145 def parents(ui, repo, node = None):
237 def parents(ui, repo, node = None):
146 '''show the parents of the current working dir'''
238 '''show the parents of the current working dir'''
147 if node:
239 if node:
148 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
240 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
149 else:
241 else:
150 p = repo.dirstate.parents()
242 p = repo.dirstate.parents()
151
243
152 for n in p:
244 for n in p:
153 if n != hg.nullid:
245 if n != hg.nullid:
154 ui.write("%d:%s\n" % (repo.changelog.rev(n), hg.hex(n)))
246 ui.write("%d:%s\n" % (repo.changelog.rev(n), hg.hex(n)))
155
247
248 def recover(ui, repo):
249 repo.recover()
250
251 def remove(ui, repo, file, *files):
252 """remove the specified files on the next commit"""
253 repo.remove(relpath(repo, (file,) + files))
254
156 def resolve(ui, repo, node = None):
255 def resolve(ui, repo, node=None):
157 '''merge a given node or the current tip into the working dir'''
256 '''merge a given node or the current tip into the working dir'''
158 if not node:
257 if not node:
159 node = repo.changelog.tip()
258 node = repo.changelog.tip()
160 else:
259 else:
161 node = repo.lookup(node)
260 node = repo.lookup(node)
162 repo.resolve(node)
261 repo.resolve(node)
163
262
263 def serve(ui, repo, **opts):
264 from mercurial import hgweb
265 hgweb.server(repo.root, opts["name"], opts["templates"],
266 opts["address"], opts["port"])
267
164 def status(ui, repo):
268 def status(ui, repo):
165 '''show changed files in the working directory
269 '''show changed files in the working directory
166
270
167 C = changed
271 C = changed
168 A = added
272 A = added
169 R = removed
273 R = removed
170 ? = not tracked'''
274 ? = not tracked'''
275
171 (c, a, d, u) = repo.diffdir(repo.root)
276 (c, a, d, u) = repo.diffdir(repo.root)
172 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
277 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
173
278
174 for f in c: print "C", f
279 for f in c: print "C", f
175 for f in a: print "A", f
280 for f in a: print "A", f
176 for f in d: print "R", f
281 for f in d: print "R", f
177 for f in u: print "?", f
282 for f in u: print "?", f
178
283
284 def tip(ui, repo):
285 n = repo.changelog.tip()
286 t = repo.changelog.rev(n)
287 ui.status("%d:%s\n" % (t, hg.hex(n)))
288
179 def undo(ui, repo):
289 def undo(ui, repo):
180 repo.undo()
290 repo.undo()
181
291
182 table = {
292 table = {
183 "init": (init, [], 'hg init'),
293 "add": (add, [], "hg add [files]"),
184 "branch|clone": (branch, [], 'hg branch [path]'),
294 "addremove": (addremove, [], "hg addremove"),
185 "heads": (heads, [], 'hg heads'),
186 "help": (help, [], 'hg help [command]'),
187 "checkout|co": (checkout, [], 'hg checkout [changeset]'),
188 "ann|annotate": (annotate,
295 "ann|annotate": (annotate,
189 [('r', 'revision', '', 'revision'),
296 [('r', 'revision', '', 'revision'),
190 ('u', 'user', None, 'show user'),
297 ('u', 'user', None, 'show user'),
191 ('n', 'number', None, 'show revision number'),
298 ('n', 'number', None, 'show revision number'),
192 ('c', 'changeset', None, 'show changeset')],
299 ('c', 'changeset', None, 'show changeset')],
193 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
300 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
301 "branch|clone": (branch, [], 'hg branch [path]'),
302 "checkout|co": (checkout, [], 'hg checkout [changeset]'),
303 "commit|ci": (commit, [], 'hg commit [files]'),
304 "diff": (diff, [('r', 'rev', [], 'revision')],
305 'hg diff [-r A] [-r B] [files]'),
306 "forget": (forget, [], "hg forget [files]"),
307 "heads": (heads, [], 'hg heads'),
308 "help": (help, [], 'hg help [command]'),
309 "init": (init, [], 'hg init'),
310 "log": (log, [], 'hg log <file>'),
194 "parents": (parents, [], 'hg parents [node]'),
311 "parents": (parents, [], 'hg parents [node]'),
312 "recover": (recover, [], "hg recover"),
313 "remove": (remove, [], "hg remove [files]"),
195 "resolve": (resolve, [], 'hg resolve [node]'),
314 "resolve": (resolve, [], 'hg resolve [node]'),
315 "serve": (serve, [('p', 'port', 8000, 'listen port'),
316 ('a', 'address', '', 'interface address'),
317 ('n', 'name', os.getcwd(), 'repository name'),
318 ('t', 'templates', "", 'template map')],
319 "hg serve [options]"),
196 "status": (status, [], 'hg status'),
320 "status": (status, [], 'hg status'),
321 "tip": (tip, [], 'hg tip'),
197 "undo": (undo, [], 'hg undo'),
322 "undo": (undo, [], 'hg undo'),
198 }
323 }
199
324
200 norepo = "init branch help"
325 norepo = "init branch help"
201
326
202 def find(cmd):
327 def find(cmd):
203 i = None
328 i = None
204 for e in table.keys():
329 for e in table.keys():
205 if re.match(e + "$", cmd):
330 if re.match(e + "$", cmd):
206 return table[e]
331 return table[e]
207
332
208 raise UnknownCommand(cmd)
333 raise UnknownCommand(cmd)
209
334
210 class SignalInterrupt(Exception): pass
335 class SignalInterrupt(Exception): pass
211
336
212 def catchterm(*args):
337 def catchterm(*args):
213 raise SignalInterrupt
338 raise SignalInterrupt
214
339
215 def dispatch(args):
340 def dispatch(args):
216 options = {}
341 options = {}
217 opts = [('v', 'verbose', None, 'verbose'),
342 opts = [('v', 'verbose', None, 'verbose'),
218 ('d', 'debug', None, 'debug'),
343 ('d', 'debug', None, 'debug'),
219 ('q', 'quiet', None, 'quiet'),
344 ('q', 'quiet', None, 'quiet'),
220 ('y', 'noninteractive', None, 'run non-interactively'),
345 ('y', 'noninteractive', None, 'run non-interactively'),
221 ]
346 ]
222
347
223 args = fancyopts.fancyopts(args, opts, options,
348 args = fancyopts.fancyopts(args, opts, options,
224 'hg [options] <command> [options] [files]')
349 'hg [options] <command> [options] [files]')
225
350
226 if not args:
351 if not args:
227 cmd = "help"
352 cmd = "help"
228 else:
353 else:
229 cmd, args = args[0], args[1:]
354 cmd, args = args[0], args[1:]
230
355
231 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
356 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
232 not options["noninteractive"])
357 not options["noninteractive"])
233
358
234 # deal with unfound commands later
359 # deal with unfound commands later
235 i = find(cmd)
360 i = find(cmd)
236
361
237 signal.signal(signal.SIGTERM, catchterm)
362 signal.signal(signal.SIGTERM, catchterm)
238
363
239 cmdoptions = {}
364 cmdoptions = {}
240 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
365 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
241
366
242 if cmd not in norepo.split():
367 if cmd not in norepo.split():
243 repo = hg.repository(ui = u)
368 repo = hg.repository(ui = u)
244 d = lambda: i[0](u, repo, *args, **cmdoptions)
369 d = lambda: i[0](u, repo, *args, **cmdoptions)
245 else:
370 else:
246 d = lambda: i[0](u, *args, **cmdoptions)
371 d = lambda: i[0](u, *args, **cmdoptions)
247
372
248 try:
373 try:
249 d()
374 d()
250 except SignalInterrupt:
375 except SignalInterrupt:
251 u.warn("killed!\n")
376 u.warn("killed!\n")
252 except KeyboardInterrupt:
377 except KeyboardInterrupt:
253 u.warn("interrupted!\n")
378 u.warn("interrupted!\n")
254 except TypeError, inst:
379 except TypeError, inst:
255 # was this an argument error?
380 # was this an argument error?
256 tb = traceback.extract_tb(sys.exc_info()[2])
381 tb = traceback.extract_tb(sys.exc_info()[2])
257 if len(tb) > 2: # no
382 if len(tb) > 2: # no
258 raise
383 raise
259 u.warn("%s: invalid arguments\n" % i[0].__name__)
384 u.warn("%s: invalid arguments\n" % i[0].__name__)
260 u.warn("syntax: %s\n" % i[2])
385 u.warn("syntax: %s\n" % i[2])
261 sys.exit(-1)
386 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now