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