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