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