##// END OF EJS Templates
hg cat: relative file support...
mpm@selenic.com -
r281:57442050 default
parent child Browse files
Show More
@@ -1,613 +1,613 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(file)
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):
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 repo.commit(relpath(repo, files))
171
171
172 def debugaddchangegroup(ui, repo):
172 def debugaddchangegroup(ui, repo):
173 data = sys.stdin.read()
173 data = sys.stdin.read()
174 repo.addchangegroup(data)
174 repo.addchangegroup(data)
175
175
176 def debugchangegroup(ui, repo, roots):
176 def debugchangegroup(ui, repo, roots):
177 newer = repo.newer(map(repo.lookup, roots))
177 newer = repo.newer(map(repo.lookup, roots))
178 for chunk in repo.changegroup(newer):
178 for chunk in repo.changegroup(newer):
179 sys.stdout.write(chunk)
179 sys.stdout.write(chunk)
180
180
181 def debugindex(ui, file):
181 def debugindex(ui, file):
182 r = hg.revlog(open, file, "")
182 r = hg.revlog(open, file, "")
183 print " rev offset length base linkrev"+\
183 print " rev offset length base linkrev"+\
184 " p1 p2 nodeid"
184 " p1 p2 nodeid"
185 for i in range(r.count()):
185 for i in range(r.count()):
186 e = r.index[i]
186 e = r.index[i]
187 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
187 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
188 i, e[0], e[1], e[2], e[3],
188 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]))
189 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
190
190
191 def debugindexdot(ui, file):
191 def debugindexdot(ui, file):
192 r = hg.revlog(open, file, "")
192 r = hg.revlog(open, file, "")
193 print "digraph G {"
193 print "digraph G {"
194 for i in range(r.count()):
194 for i in range(r.count()):
195 e = r.index[i]
195 e = r.index[i]
196 print "\t%d -> %d" % (r.rev(e[4]), i)
196 print "\t%d -> %d" % (r.rev(e[4]), i)
197 if e[5] != hg.nullid:
197 if e[5] != hg.nullid:
198 print "\t%d -> %d" % (r.rev(e[5]), i)
198 print "\t%d -> %d" % (r.rev(e[5]), i)
199 print "}"
199 print "}"
200
200
201 def diff(ui, repo, *files, **opts):
201 def diff(ui, repo, *files, **opts):
202 """diff working directory (or selected files)"""
202 """diff working directory (or selected files)"""
203 revs = []
203 revs = []
204 if opts['rev']:
204 if opts['rev']:
205 revs = map(lambda x: repo.lookup(x), opts['rev'])
205 revs = map(lambda x: repo.lookup(x), opts['rev'])
206
206
207 if len(revs) > 2:
207 if len(revs) > 2:
208 self.ui.warn("too many revisions to diff\n")
208 self.ui.warn("too many revisions to diff\n")
209 sys.exit(1)
209 sys.exit(1)
210
210
211 if files:
211 if files:
212 files = relpath(repo, files)
212 files = relpath(repo, files)
213 else:
213 else:
214 files = relpath(repo, [""])
214 files = relpath(repo, [""])
215
215
216 dodiff(repo, files, *revs)
216 dodiff(repo, files, *revs)
217
217
218 def export(ui, repo, changeset):
218 def export(ui, repo, changeset):
219 """dump the changeset header and diffs for a revision"""
219 """dump the changeset header and diffs for a revision"""
220 node = repo.lookup(changeset)
220 node = repo.lookup(changeset)
221 prev, other = repo.changelog.parents(node)
221 prev, other = repo.changelog.parents(node)
222 change = repo.changelog.read(node)
222 change = repo.changelog.read(node)
223 print "# HG changeset patch"
223 print "# HG changeset patch"
224 print "# User %s" % change[1]
224 print "# User %s" % change[1]
225 print "# Node ID %s" % hg.hex(node)
225 print "# Node ID %s" % hg.hex(node)
226 print "# Parent %s" % hg.hex(prev)
226 print "# Parent %s" % hg.hex(prev)
227 print
227 print
228 if other != hg.nullid:
228 if other != hg.nullid:
229 print "# Parent %s" % hg.hex(other)
229 print "# Parent %s" % hg.hex(other)
230 print change[4].rstrip()
230 print change[4].rstrip()
231 print
231 print
232
232
233 dodiff(repo, None, prev, node)
233 dodiff(repo, None, prev, node)
234
234
235 def forget(ui, repo, file, *files):
235 def forget(ui, repo, file, *files):
236 """don't add the specified files on the next commit"""
236 """don't add the specified files on the next commit"""
237 repo.forget(relpath(repo, (file,) + files))
237 repo.forget(relpath(repo, (file,) + files))
238
238
239 def heads(ui, repo):
239 def heads(ui, repo):
240 '''show current repository heads'''
240 '''show current repository heads'''
241 for n in repo.changelog.heads():
241 for n in repo.changelog.heads():
242 i = repo.changelog.rev(n)
242 i = repo.changelog.rev(n)
243 changes = repo.changelog.read(n)
243 changes = repo.changelog.read(n)
244 (p1, p2) = repo.changelog.parents(n)
244 (p1, p2) = repo.changelog.parents(n)
245 (h, h1, h2) = map(hg.hex, (n, p1, p2))
245 (h, h1, h2) = map(hg.hex, (n, p1, p2))
246 (i1, i2) = map(repo.changelog.rev, (p1, p2))
246 (i1, i2) = map(repo.changelog.rev, (p1, p2))
247 print "rev: %4d:%s" % (i, h)
247 print "rev: %4d:%s" % (i, h)
248 print "parents: %4d:%s" % (i1, h1)
248 print "parents: %4d:%s" % (i1, h1)
249 if i2: print " %4d:%s" % (i2, h2)
249 if i2: print " %4d:%s" % (i2, h2)
250 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
250 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
251 hg.hex(changes[0]))
251 hg.hex(changes[0]))
252 print "user:", changes[1]
252 print "user:", changes[1]
253 print "date:", time.asctime(
253 print "date:", time.asctime(
254 time.localtime(float(changes[2].split(' ')[0])))
254 time.localtime(float(changes[2].split(' ')[0])))
255 if ui.verbose: print "files:", " ".join(changes[3])
255 if ui.verbose: print "files:", " ".join(changes[3])
256 print "description:"
256 print "description:"
257 print changes[4]
257 print changes[4]
258
258
259 def history(ui, repo):
259 def history(ui, repo):
260 """show the changelog history"""
260 """show the changelog history"""
261 for i in range(repo.changelog.count() - 1, -1, -1):
261 for i in range(repo.changelog.count() - 1, -1, -1):
262 n = repo.changelog.node(i)
262 n = repo.changelog.node(i)
263 changes = repo.changelog.read(n)
263 changes = repo.changelog.read(n)
264 (p1, p2) = repo.changelog.parents(n)
264 (p1, p2) = repo.changelog.parents(n)
265 (h, h1, h2) = map(hg.hex, (n, p1, p2))
265 (h, h1, h2) = map(hg.hex, (n, p1, p2))
266 (i1, i2) = map(repo.changelog.rev, (p1, p2))
266 (i1, i2) = map(repo.changelog.rev, (p1, p2))
267 print "rev: %4d:%s" % (i, h)
267 print "rev: %4d:%s" % (i, h)
268 print "parents: %4d:%s" % (i1, h1)
268 print "parents: %4d:%s" % (i1, h1)
269 if i2: print " %4d:%s" % (i2, h2)
269 if i2: print " %4d:%s" % (i2, h2)
270 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
270 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
271 hg.hex(changes[0]))
271 hg.hex(changes[0]))
272 print "user:", changes[1]
272 print "user:", changes[1]
273 print "date:", time.asctime(
273 print "date:", time.asctime(
274 time.localtime(float(changes[2].split(' ')[0])))
274 time.localtime(float(changes[2].split(' ')[0])))
275 if ui.verbose: print "files:", " ".join(changes[3])
275 if ui.verbose: print "files:", " ".join(changes[3])
276 print "description:"
276 print "description:"
277 print changes[4]
277 print changes[4]
278
278
279 def init(ui):
279 def init(ui):
280 """create a repository"""
280 """create a repository"""
281 hg.repository(ui, ".", create=1)
281 hg.repository(ui, ".", create=1)
282
282
283 def log(ui, repo, f):
283 def log(ui, repo, f):
284 """show the revision history of a single file"""
284 """show the revision history of a single file"""
285 f = relpath(repo, [f])[0]
285 f = relpath(repo, [f])[0]
286
286
287 r = repo.file(f)
287 r = repo.file(f)
288 for i in range(r.count() - 1, -1, -1):
288 for i in range(r.count() - 1, -1, -1):
289 n = r.node(i)
289 n = r.node(i)
290 (p1, p2) = r.parents(n)
290 (p1, p2) = r.parents(n)
291 (h, h1, h2) = map(hg.hex, (n, p1, p2))
291 (h, h1, h2) = map(hg.hex, (n, p1, p2))
292 (i1, i2) = map(r.rev, (p1, p2))
292 (i1, i2) = map(r.rev, (p1, p2))
293 cr = r.linkrev(n)
293 cr = r.linkrev(n)
294 cn = hg.hex(repo.changelog.node(cr))
294 cn = hg.hex(repo.changelog.node(cr))
295 print "rev: %4d:%s" % (i, h)
295 print "rev: %4d:%s" % (i, h)
296 print "changeset: %4d:%s" % (cr, cn)
296 print "changeset: %4d:%s" % (cr, cn)
297 print "parents: %4d:%s" % (i1, h1)
297 print "parents: %4d:%s" % (i1, h1)
298 if i2: print " %4d:%s" % (i2, h2)
298 if i2: print " %4d:%s" % (i2, h2)
299 changes = repo.changelog.read(repo.changelog.node(cr))
299 changes = repo.changelog.read(repo.changelog.node(cr))
300 print "user: %s" % changes[1]
300 print "user: %s" % changes[1]
301 print "date: %s" % time.asctime(
301 print "date: %s" % time.asctime(
302 time.localtime(float(changes[2].split(' ')[0])))
302 time.localtime(float(changes[2].split(' ')[0])))
303 print "description:"
303 print "description:"
304 print changes[4].rstrip()
304 print changes[4].rstrip()
305 print
305 print
306
306
307 def manifest(ui, repo, rev = []):
307 def manifest(ui, repo, rev = []):
308 """output the latest or given revision of the project manifest"""
308 """output the latest or given revision of the project manifest"""
309 n = repo.manifest.tip()
309 n = repo.manifest.tip()
310 if rev:
310 if rev:
311 n = repo.manifest.lookup(rev)
311 n = repo.manifest.lookup(rev)
312 m = repo.manifest.read(n)
312 m = repo.manifest.read(n)
313 mf = repo.manifest.readflags(n)
313 mf = repo.manifest.readflags(n)
314 files = m.keys()
314 files = m.keys()
315 files.sort()
315 files.sort()
316
316
317 for f in files:
317 for f in files:
318 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
318 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
319
319
320 def parents(ui, repo, node = None):
320 def parents(ui, repo, node = None):
321 '''show the parents of the current working dir'''
321 '''show the parents of the current working dir'''
322 if node:
322 if node:
323 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
323 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
324 else:
324 else:
325 p = repo.dirstate.parents()
325 p = repo.dirstate.parents()
326
326
327 for n in p:
327 for n in p:
328 if n != hg.nullid:
328 if n != hg.nullid:
329 ui.write("%d:%s\n" % (repo.changelog.rev(n), hg.hex(n)))
329 ui.write("%d:%s\n" % (repo.changelog.rev(n), hg.hex(n)))
330
330
331 def patch(ui, repo, patches, **opts):
331 def patch(ui, repo, patches, **opts):
332 """import an ordered set of patches"""
332 """import an ordered set of patches"""
333 try:
333 try:
334 import psyco
334 import psyco
335 psyco.full()
335 psyco.full()
336 except:
336 except:
337 pass
337 pass
338
338
339 d = opts["base"]
339 d = opts["base"]
340 strip = opts["strip"]
340 strip = opts["strip"]
341 quiet = opts["quiet"] and "> /dev/null" or ""
341 quiet = opts["quiet"] and "> /dev/null" or ""
342
342
343 for patch in patches:
343 for patch in patches:
344 ui.status("applying %s\n" % patch)
344 ui.status("applying %s\n" % patch)
345 pf = os.path.join(d, patch)
345 pf = os.path.join(d, patch)
346
346
347 text = ""
347 text = ""
348 for l in file(pf):
348 for l in file(pf):
349 if l[:4] == "--- ": break
349 if l[:4] == "--- ": break
350 text += l
350 text += l
351
351
352 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
352 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
353 files = filter(None, map(lambda x: x.rstrip(), f.read().splitlines()))
353 files = filter(None, map(lambda x: x.rstrip(), f.read().splitlines()))
354 f.close()
354 f.close()
355
355
356 if files:
356 if files:
357 if os.system("patch -p%d < %s %s" % (strip, pf, quiet)):
357 if os.system("patch -p%d < %s %s" % (strip, pf, quiet)):
358 raise "patch failed!"
358 raise "patch failed!"
359 repo.commit(files, text)
359 repo.commit(files, text)
360
360
361 def pull(ui, repo, source):
361 def pull(ui, repo, source):
362 """pull changes from the specified source"""
362 """pull changes from the specified source"""
363 paths = {}
363 paths = {}
364 try:
364 try:
365 pf = os.path.expanduser("~/.hgpaths")
365 pf = os.path.expanduser("~/.hgpaths")
366 for l in file(pf):
366 for l in file(pf):
367 name, path = l.split()
367 name, path = l.split()
368 paths[name] = path
368 paths[name] = path
369 except IOError:
369 except IOError:
370 pass
370 pass
371
371
372 if source in paths: source = paths[source]
372 if source in paths: source = paths[source]
373
373
374 other = hg.repository(ui, source)
374 other = hg.repository(ui, source)
375 cg = repo.getchangegroup(other)
375 cg = repo.getchangegroup(other)
376 repo.addchangegroup(cg)
376 repo.addchangegroup(cg)
377
377
378 def rawcommit(ui, repo, files, **rc):
378 def rawcommit(ui, repo, files, **rc):
379 "raw commit interface"
379 "raw commit interface"
380
380
381 text = rc['text']
381 text = rc['text']
382 if not text and rc['logfile']:
382 if not text and rc['logfile']:
383 try: text = open(rc['logfile']).read()
383 try: text = open(rc['logfile']).read()
384 except IOError: pass
384 except IOError: pass
385 if not text and not rc['logfile']:
385 if not text and not rc['logfile']:
386 print "missing commit text"
386 print "missing commit text"
387 return 1
387 return 1
388
388
389 files = relpath(repo, files)
389 files = relpath(repo, files)
390 if rc['files']:
390 if rc['files']:
391 files += open(rc['files']).read().splitlines()
391 files += open(rc['files']).read().splitlines()
392
392
393 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
393 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
394
394
395 def recover(ui, repo):
395 def recover(ui, repo):
396 """roll back an interrupted transaction"""
396 """roll back an interrupted transaction"""
397 repo.recover()
397 repo.recover()
398
398
399 def remove(ui, repo, file, *files):
399 def remove(ui, repo, file, *files):
400 """remove the specified files on the next commit"""
400 """remove the specified files on the next commit"""
401 repo.remove(relpath(repo, (file,) + files))
401 repo.remove(relpath(repo, (file,) + files))
402
402
403 def serve(ui, repo, **opts):
403 def serve(ui, repo, **opts):
404 """export the repository via HTTP"""
404 """export the repository via HTTP"""
405 hgweb.server(repo.root, opts["name"], opts["templates"],
405 hgweb.server(repo.root, opts["name"], opts["templates"],
406 opts["address"], opts["port"])
406 opts["address"], opts["port"])
407
407
408 def status(ui, repo):
408 def status(ui, repo):
409 '''show changed files in the working directory
409 '''show changed files in the working directory
410
410
411 C = changed
411 C = changed
412 A = added
412 A = added
413 R = removed
413 R = removed
414 ? = not tracked'''
414 ? = not tracked'''
415
415
416 (c, a, d, u) = repo.diffdir(repo.root)
416 (c, a, d, u) = repo.diffdir(repo.root)
417 (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))
418
418
419 for f in c: print "C", f
419 for f in c: print "C", f
420 for f in a: print "A", f
420 for f in a: print "A", f
421 for f in d: print "R", f
421 for f in d: print "R", f
422 for f in u: print "?", f
422 for f in u: print "?", f
423
423
424 def tags(ui, repo):
424 def tags(ui, repo):
425 """list repository tags"""
425 """list repository tags"""
426 repo.lookup(0) # prime the cache
426 repo.lookup(0) # prime the cache
427 i = repo.tags.items()
427 i = repo.tags.items()
428 n = []
428 n = []
429 for e in i:
429 for e in i:
430 try:
430 try:
431 l = repo.changelog.rev(e[1])
431 l = repo.changelog.rev(e[1])
432 except KeyError:
432 except KeyError:
433 l = -2
433 l = -2
434 n.append((l, e))
434 n.append((l, e))
435
435
436 n.sort()
436 n.sort()
437 n.reverse()
437 n.reverse()
438 i = [ e[1] for e in n ]
438 i = [ e[1] for e in n ]
439 for k, n in i:
439 for k, n in i:
440 try:
440 try:
441 r = repo.changelog.rev(n)
441 r = repo.changelog.rev(n)
442 except KeyError:
442 except KeyError:
443 r = "?"
443 r = "?"
444 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))
445
445
446 def tip(ui, repo):
446 def tip(ui, repo):
447 """show the tip revision"""
447 """show the tip revision"""
448 n = repo.changelog.tip()
448 n = repo.changelog.tip()
449 t = repo.changelog.rev(n)
449 t = repo.changelog.rev(n)
450 ui.status("%d:%s\n" % (t, hg.hex(n)))
450 ui.status("%d:%s\n" % (t, hg.hex(n)))
451
451
452 def undo(ui, repo):
452 def undo(ui, repo):
453 """undo the last transaction"""
453 """undo the last transaction"""
454 repo.undo()
454 repo.undo()
455
455
456 def update(ui, repo, node=None, merge=False, clean=False):
456 def update(ui, repo, node=None, merge=False, clean=False):
457 '''update or merge working directory
457 '''update or merge working directory
458
458
459 If there are no outstanding changes in the working directory and
459 If there are no outstanding changes in the working directory and
460 there is a linear relationship between the current version and the
460 there is a linear relationship between the current version and the
461 requested version, the result is the requested version.
461 requested version, the result is the requested version.
462
462
463 Otherwise the result is a merge between the contents of the
463 Otherwise the result is a merge between the contents of the
464 current working directory and the requested version. Files that
464 current working directory and the requested version. Files that
465 changed between either parent are marked as changed for the next
465 changed between either parent are marked as changed for the next
466 commit and a commit must be performed before any further updates
466 commit and a commit must be performed before any further updates
467 are allowed.
467 are allowed.
468 '''
468 '''
469 node = node and repo.lookup(node) or repo.changelog.tip()
469 node = node and repo.lookup(node) or repo.changelog.tip()
470 return repo.update(node, allow=merge, force=clean)
470 return repo.update(node, allow=merge, force=clean)
471
471
472 def verify(ui, repo):
472 def verify(ui, repo):
473 """verify the integrity of the repository"""
473 """verify the integrity of the repository"""
474 return repo.verify()
474 return repo.verify()
475
475
476 # Command options and aliases are listed here, alphabetically
476 # Command options and aliases are listed here, alphabetically
477
477
478 table = {
478 table = {
479 "add": (add, [], "hg add [files]"),
479 "add": (add, [], "hg add [files]"),
480 "addremove": (addremove, [], "hg addremove"),
480 "addremove": (addremove, [], "hg addremove"),
481 "ann|annotate": (annotate,
481 "ann|annotate": (annotate,
482 [('r', 'revision', '', 'revision'),
482 [('r', 'revision', '', 'revision'),
483 ('u', 'user', None, 'show user'),
483 ('u', 'user', None, 'show user'),
484 ('n', 'number', None, 'show revision number'),
484 ('n', 'number', None, 'show revision number'),
485 ('c', 'changeset', None, 'show changeset')],
485 ('c', 'changeset', None, 'show changeset')],
486 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
486 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
487 "branch|clone": (branch, [], 'hg branch [path]'),
487 "branch|clone": (branch, [], 'hg branch [path]'),
488 "cat|dump": (cat, [], 'hg cat <file> [rev]'),
488 "cat|dump": (cat, [], 'hg cat <file> [rev]'),
489 "commit|ci": (commit, [], 'hg commit [files]'),
489 "commit|ci": (commit, [], 'hg commit [files]'),
490 "debugaddchangegroup": (debugaddchangegroup, [], 'debugaddchangegroup'),
490 "debugaddchangegroup": (debugaddchangegroup, [], 'debugaddchangegroup'),
491 "debugchangegroup": (debugchangegroup, [], 'debugchangegroup [roots]'),
491 "debugchangegroup": (debugchangegroup, [], 'debugchangegroup [roots]'),
492 "debugindex": (debugindex, [], 'debugindex <file>'),
492 "debugindex": (debugindex, [], 'debugindex <file>'),
493 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
493 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
494 "diff": (diff, [('r', 'rev', [], 'revision')],
494 "diff": (diff, [('r', 'rev', [], 'revision')],
495 'hg diff [-r A] [-r B] [files]'),
495 'hg diff [-r A] [-r B] [files]'),
496 "export": (export, [], "hg export <changeset>"),
496 "export": (export, [], "hg export <changeset>"),
497 "forget": (forget, [], "hg forget [files]"),
497 "forget": (forget, [], "hg forget [files]"),
498 "heads": (heads, [], 'hg heads'),
498 "heads": (heads, [], 'hg heads'),
499 "history": (history, [], 'hg history'),
499 "history": (history, [], 'hg history'),
500 "help": (help, [], 'hg help [command]'),
500 "help": (help, [], 'hg help [command]'),
501 "init": (init, [], 'hg init'),
501 "init": (init, [], 'hg init'),
502 "log": (log, [], 'hg log <file>'),
502 "log": (log, [], 'hg log <file>'),
503 "manifest|dumpmanifest": (manifest, [], 'hg manifest [rev]'),
503 "manifest|dumpmanifest": (manifest, [], 'hg manifest [rev]'),
504 "parents": (parents, [], 'hg parents [node]'),
504 "parents": (parents, [], 'hg parents [node]'),
505 "patch|import": (patch,
505 "patch|import": (patch,
506 [('p', 'strip', 1, 'path strip'),
506 [('p', 'strip', 1, 'path strip'),
507 ('b', 'base', "", 'base path'),
507 ('b', 'base', "", 'base path'),
508 ('q', 'quiet', "", 'silence diff')],
508 ('q', 'quiet', "", 'silence diff')],
509 "hg import [options] patches"),
509 "hg import [options] patches"),
510 "pull|merge": (pull, [], 'hg pull [source]'),
510 "pull|merge": (pull, [], 'hg pull [source]'),
511 "rawcommit": (rawcommit,
511 "rawcommit": (rawcommit,
512 [('p', 'parent', [], 'parent'),
512 [('p', 'parent', [], 'parent'),
513 ('d', 'date', "", 'data'),
513 ('d', 'date', "", 'data'),
514 ('u', 'user', "", 'user'),
514 ('u', 'user', "", 'user'),
515 ('F', 'files', "", 'file list'),
515 ('F', 'files', "", 'file list'),
516 ('t', 'text', "", 'commit text'),
516 ('t', 'text', "", 'commit text'),
517 ('l', 'logfile', "", 'commit text file')],
517 ('l', 'logfile', "", 'commit text file')],
518 'hg rawcommit [options] [files]'),
518 'hg rawcommit [options] [files]'),
519 "recover": (recover, [], "hg recover"),
519 "recover": (recover, [], "hg recover"),
520 "remove": (remove, [], "hg remove [files]"),
520 "remove": (remove, [], "hg remove [files]"),
521 "serve": (serve, [('p', 'port', 8000, 'listen port'),
521 "serve": (serve, [('p', 'port', 8000, 'listen port'),
522 ('a', 'address', '', 'interface address'),
522 ('a', 'address', '', 'interface address'),
523 ('n', 'name', os.getcwd(), 'repository name'),
523 ('n', 'name', os.getcwd(), 'repository name'),
524 ('t', 'templates', "", 'template map')],
524 ('t', 'templates', "", 'template map')],
525 "hg serve [options]"),
525 "hg serve [options]"),
526 "status": (status, [], 'hg status'),
526 "status": (status, [], 'hg status'),
527 "tags": (tags, [], 'hg tags'),
527 "tags": (tags, [], 'hg tags'),
528 "tip": (tip, [], 'hg tip'),
528 "tip": (tip, [], 'hg tip'),
529 "undo": (undo, [], 'hg undo'),
529 "undo": (undo, [], 'hg undo'),
530 "update|up|checkout|co|resolve": (update,
530 "update|up|checkout|co|resolve": (update,
531 [('m', 'merge', None,
531 [('m', 'merge', None,
532 'allow merging of conflicts'),
532 'allow merging of conflicts'),
533 ('C', 'clean', None,
533 ('C', 'clean', None,
534 'overwrite locally modified files')],
534 'overwrite locally modified files')],
535 'hg update [options] [node]'),
535 'hg update [options] [node]'),
536 "verify": (verify, [], 'hg verify'),
536 "verify": (verify, [], 'hg verify'),
537 }
537 }
538
538
539 norepo = "init branch help debugindex debugindexdot"
539 norepo = "init branch help debugindex debugindexdot"
540
540
541 def find(cmd):
541 def find(cmd):
542 i = None
542 i = None
543 for e in table.keys():
543 for e in table.keys():
544 if re.match(e + "$", cmd):
544 if re.match(e + "$", cmd):
545 return table[e]
545 return table[e]
546
546
547 raise UnknownCommand(cmd)
547 raise UnknownCommand(cmd)
548
548
549 class SignalInterrupt(Exception): pass
549 class SignalInterrupt(Exception): pass
550
550
551 def catchterm(*args):
551 def catchterm(*args):
552 raise SignalInterrupt
552 raise SignalInterrupt
553
553
554 def run():
554 def run():
555 sys.exit(dispatch(sys.argv[1:]))
555 sys.exit(dispatch(sys.argv[1:]))
556
556
557 def dispatch(args):
557 def dispatch(args):
558 options = {}
558 options = {}
559 opts = [('v', 'verbose', None, 'verbose'),
559 opts = [('v', 'verbose', None, 'verbose'),
560 ('d', 'debug', None, 'debug'),
560 ('d', 'debug', None, 'debug'),
561 ('q', 'quiet', None, 'quiet'),
561 ('q', 'quiet', None, 'quiet'),
562 ('y', 'noninteractive', None, 'run non-interactively'),
562 ('y', 'noninteractive', None, 'run non-interactively'),
563 ]
563 ]
564
564
565 args = fancyopts.fancyopts(args, opts, options,
565 args = fancyopts.fancyopts(args, opts, options,
566 'hg [options] <command> [options] [files]')
566 'hg [options] <command> [options] [files]')
567
567
568 if not args:
568 if not args:
569 cmd = "help"
569 cmd = "help"
570 else:
570 else:
571 cmd, args = args[0], args[1:]
571 cmd, args = args[0], args[1:]
572
572
573 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
573 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
574 not options["noninteractive"])
574 not options["noninteractive"])
575
575
576 try:
576 try:
577 i = find(cmd)
577 i = find(cmd)
578 except UnknownCommand:
578 except UnknownCommand:
579 u.warn("hg: unknown command '%s'\n" % cmd)
579 u.warn("hg: unknown command '%s'\n" % cmd)
580 help(u)
580 help(u)
581 sys.exit(1)
581 sys.exit(1)
582
582
583 signal.signal(signal.SIGTERM, catchterm)
583 signal.signal(signal.SIGTERM, catchterm)
584
584
585 cmdoptions = {}
585 cmdoptions = {}
586 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
586 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
587
587
588 if cmd not in norepo.split():
588 if cmd not in norepo.split():
589 repo = hg.repository(ui = u)
589 repo = hg.repository(ui = u)
590 d = lambda: i[0](u, repo, *args, **cmdoptions)
590 d = lambda: i[0](u, repo, *args, **cmdoptions)
591 else:
591 else:
592 d = lambda: i[0](u, *args, **cmdoptions)
592 d = lambda: i[0](u, *args, **cmdoptions)
593
593
594 try:
594 try:
595 return d()
595 return d()
596 except SignalInterrupt:
596 except SignalInterrupt:
597 u.warn("killed!\n")
597 u.warn("killed!\n")
598 except KeyboardInterrupt:
598 except KeyboardInterrupt:
599 u.warn("interrupted!\n")
599 u.warn("interrupted!\n")
600 except IOError, inst:
600 except IOError, inst:
601 if inst.errno == 32:
601 if inst.errno == 32:
602 u.warn("broken pipe\n")
602 u.warn("broken pipe\n")
603 else:
603 else:
604 raise
604 raise
605 except TypeError, inst:
605 except TypeError, inst:
606 # was this an argument error?
606 # was this an argument error?
607 tb = traceback.extract_tb(sys.exc_info()[2])
607 tb = traceback.extract_tb(sys.exc_info()[2])
608 if len(tb) > 2: # no
608 if len(tb) > 2: # no
609 raise
609 raise
610 raise
610 raise
611 u.warn("%s: invalid arguments\n" % i[0].__name__)
611 u.warn("%s: invalid arguments\n" % i[0].__name__)
612 u.warn("syntax: %s\n" % i[2])
612 u.warn("syntax: %s\n" % i[2])
613 sys.exit(-1)
613 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now