##// END OF EJS Templates
parseurl: also return the revision after the "#"; add a test
Alexis S. L. Carvalho -
r5222:cbe6e263 default
parent child Browse files
Show More
@@ -0,0 +1,50
1 #!/bin/sh
2 # test basic functionality of url#rev syntax
3
4 hg init repo
5 cd repo
6 echo a > a
7 hg ci -qAm 'add a' -d '0 0'
8 hg branch foo
9 echo >> a
10 hg ci -m 'change a' -d '0 0'
11 cd ..
12
13 echo '% clone repo#foo'
14 hg clone 'repo#foo' clone
15 hg --cwd clone heads
16 sed -e 's/default.*#/default = #/' clone/.hg/hgrc
17 echo
18
19 echo '% changing original repo'
20 cd repo
21 echo >> a
22 hg ci -m 'new head of branch foo' -d '0 0'
23 hg up -qC default
24 echo bar > bar
25 hg ci -qAm 'add bar' -d '0 0'
26 hg log
27 echo
28
29 echo '% outgoing'
30 hg -q outgoing '../clone#foo'
31 echo
32
33 echo '% push'
34 hg -q push '../clone#foo'
35 hg --cwd ../clone heads
36 cd ..
37 echo
38
39 echo '% rolling back'
40 cd clone
41 hg rollback
42
43 echo '% incoming'
44 hg -q incoming
45
46 echo '% pull'
47 hg -q pull
48 hg heads
49 echo
50
@@ -0,0 +1,69
1 marked working directory as branch foo
2 % clone repo#foo
3 requesting all changes
4 adding changesets
5 adding manifests
6 adding file changes
7 added 2 changesets with 2 changes to 1 files
8 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
9 changeset: 1:cd2a86ecc814
10 branch: foo
11 tag: tip
12 user: test
13 date: Thu Jan 01 00:00:00 1970 +0000
14 summary: change a
15
16 [paths]
17 default = #foo
18
19 % changing original repo
20 changeset: 3:4cd725637392
21 tag: tip
22 parent: 0:1f0dee641bb7
23 user: test
24 date: Thu Jan 01 00:00:00 1970 +0000
25 summary: add bar
26
27 changeset: 2:faba9097cad4
28 branch: foo
29 user: test
30 date: Thu Jan 01 00:00:00 1970 +0000
31 summary: new head of branch foo
32
33 changeset: 1:cd2a86ecc814
34 branch: foo
35 user: test
36 date: Thu Jan 01 00:00:00 1970 +0000
37 summary: change a
38
39 changeset: 0:1f0dee641bb7
40 user: test
41 date: Thu Jan 01 00:00:00 1970 +0000
42 summary: add a
43
44
45 % outgoing
46 2:faba9097cad4
47
48 % push
49 changeset: 2:faba9097cad4
50 branch: foo
51 tag: tip
52 user: test
53 date: Thu Jan 01 00:00:00 1970 +0000
54 summary: new head of branch foo
55
56
57 % rolling back
58 rolling back last transaction
59 % incoming
60 2:faba9097cad4
61 % pull
62 changeset: 2:faba9097cad4
63 branch: foo
64 tag: tip
65 user: test
66 date: Thu Jan 01 00:00:00 1970 +0000
67 summary: new head of branch foo
68
69
@@ -1,1275 +1,1275
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 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 from node import *
8 from node import *
9 from i18n import _
9 from i18n import _
10 import os, sys, atexit, signal, pdb, traceback, socket, errno, shlex
10 import os, sys, atexit, signal, pdb, traceback, socket, errno, shlex
11 import mdiff, bdiff, util, templater, patch, commands, hg, lock, time
11 import mdiff, bdiff, util, templater, patch, commands, hg, lock, time
12 import fancyopts, revlog, version, extensions, hook
12 import fancyopts, revlog, version, extensions, hook
13
13
14 revrangesep = ':'
14 revrangesep = ':'
15
15
16 class UnknownCommand(Exception):
16 class UnknownCommand(Exception):
17 """Exception raised if command is not in the command table."""
17 """Exception raised if command is not in the command table."""
18 class AmbiguousCommand(Exception):
18 class AmbiguousCommand(Exception):
19 """Exception raised if command shortcut matches more than one command."""
19 """Exception raised if command shortcut matches more than one command."""
20 class ParseError(Exception):
20 class ParseError(Exception):
21 """Exception raised on errors in parsing the command line."""
21 """Exception raised on errors in parsing the command line."""
22
22
23 def runcatch(ui, args):
23 def runcatch(ui, args):
24 def catchterm(*args):
24 def catchterm(*args):
25 raise util.SignalInterrupt
25 raise util.SignalInterrupt
26
26
27 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
27 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
28 num = getattr(signal, name, None)
28 num = getattr(signal, name, None)
29 if num: signal.signal(num, catchterm)
29 if num: signal.signal(num, catchterm)
30
30
31 try:
31 try:
32 try:
32 try:
33 # enter the debugger before command execution
33 # enter the debugger before command execution
34 if '--debugger' in args:
34 if '--debugger' in args:
35 pdb.set_trace()
35 pdb.set_trace()
36 try:
36 try:
37 return dispatch(ui, args)
37 return dispatch(ui, args)
38 finally:
38 finally:
39 ui.flush()
39 ui.flush()
40 except:
40 except:
41 # enter the debugger when we hit an exception
41 # enter the debugger when we hit an exception
42 if '--debugger' in args:
42 if '--debugger' in args:
43 pdb.post_mortem(sys.exc_info()[2])
43 pdb.post_mortem(sys.exc_info()[2])
44 ui.print_exc()
44 ui.print_exc()
45 raise
45 raise
46
46
47 except ParseError, inst:
47 except ParseError, inst:
48 if inst.args[0]:
48 if inst.args[0]:
49 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
49 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
50 commands.help_(ui, inst.args[0])
50 commands.help_(ui, inst.args[0])
51 else:
51 else:
52 ui.warn(_("hg: %s\n") % inst.args[1])
52 ui.warn(_("hg: %s\n") % inst.args[1])
53 commands.help_(ui, 'shortlist')
53 commands.help_(ui, 'shortlist')
54 except AmbiguousCommand, inst:
54 except AmbiguousCommand, inst:
55 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
55 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
56 (inst.args[0], " ".join(inst.args[1])))
56 (inst.args[0], " ".join(inst.args[1])))
57 except UnknownCommand, inst:
57 except UnknownCommand, inst:
58 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
58 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
59 commands.help_(ui, 'shortlist')
59 commands.help_(ui, 'shortlist')
60 except hg.RepoError, inst:
60 except hg.RepoError, inst:
61 ui.warn(_("abort: %s!\n") % inst)
61 ui.warn(_("abort: %s!\n") % inst)
62 except lock.LockHeld, inst:
62 except lock.LockHeld, inst:
63 if inst.errno == errno.ETIMEDOUT:
63 if inst.errno == errno.ETIMEDOUT:
64 reason = _('timed out waiting for lock held by %s') % inst.locker
64 reason = _('timed out waiting for lock held by %s') % inst.locker
65 else:
65 else:
66 reason = _('lock held by %s') % inst.locker
66 reason = _('lock held by %s') % inst.locker
67 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
67 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
68 except lock.LockUnavailable, inst:
68 except lock.LockUnavailable, inst:
69 ui.warn(_("abort: could not lock %s: %s\n") %
69 ui.warn(_("abort: could not lock %s: %s\n") %
70 (inst.desc or inst.filename, inst.strerror))
70 (inst.desc or inst.filename, inst.strerror))
71 except revlog.RevlogError, inst:
71 except revlog.RevlogError, inst:
72 ui.warn(_("abort: %s!\n") % inst)
72 ui.warn(_("abort: %s!\n") % inst)
73 except util.SignalInterrupt:
73 except util.SignalInterrupt:
74 ui.warn(_("killed!\n"))
74 ui.warn(_("killed!\n"))
75 except KeyboardInterrupt:
75 except KeyboardInterrupt:
76 try:
76 try:
77 ui.warn(_("interrupted!\n"))
77 ui.warn(_("interrupted!\n"))
78 except IOError, inst:
78 except IOError, inst:
79 if inst.errno == errno.EPIPE:
79 if inst.errno == errno.EPIPE:
80 if ui.debugflag:
80 if ui.debugflag:
81 ui.warn(_("\nbroken pipe\n"))
81 ui.warn(_("\nbroken pipe\n"))
82 else:
82 else:
83 raise
83 raise
84 except socket.error, inst:
84 except socket.error, inst:
85 ui.warn(_("abort: %s\n") % inst[1])
85 ui.warn(_("abort: %s\n") % inst[1])
86 except IOError, inst:
86 except IOError, inst:
87 if hasattr(inst, "code"):
87 if hasattr(inst, "code"):
88 ui.warn(_("abort: %s\n") % inst)
88 ui.warn(_("abort: %s\n") % inst)
89 elif hasattr(inst, "reason"):
89 elif hasattr(inst, "reason"):
90 try: # usually it is in the form (errno, strerror)
90 try: # usually it is in the form (errno, strerror)
91 reason = inst.reason.args[1]
91 reason = inst.reason.args[1]
92 except: # it might be anything, for example a string
92 except: # it might be anything, for example a string
93 reason = inst.reason
93 reason = inst.reason
94 ui.warn(_("abort: error: %s\n") % reason)
94 ui.warn(_("abort: error: %s\n") % reason)
95 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
95 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
96 if ui.debugflag:
96 if ui.debugflag:
97 ui.warn(_("broken pipe\n"))
97 ui.warn(_("broken pipe\n"))
98 elif getattr(inst, "strerror", None):
98 elif getattr(inst, "strerror", None):
99 if getattr(inst, "filename", None):
99 if getattr(inst, "filename", None):
100 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
100 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
101 else:
101 else:
102 ui.warn(_("abort: %s\n") % inst.strerror)
102 ui.warn(_("abort: %s\n") % inst.strerror)
103 else:
103 else:
104 raise
104 raise
105 except OSError, inst:
105 except OSError, inst:
106 if getattr(inst, "filename", None):
106 if getattr(inst, "filename", None):
107 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
107 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
108 else:
108 else:
109 ui.warn(_("abort: %s\n") % inst.strerror)
109 ui.warn(_("abort: %s\n") % inst.strerror)
110 except util.UnexpectedOutput, inst:
110 except util.UnexpectedOutput, inst:
111 ui.warn(_("abort: %s") % inst[0])
111 ui.warn(_("abort: %s") % inst[0])
112 if not isinstance(inst[1], basestring):
112 if not isinstance(inst[1], basestring):
113 ui.warn(" %r\n" % (inst[1],))
113 ui.warn(" %r\n" % (inst[1],))
114 elif not inst[1]:
114 elif not inst[1]:
115 ui.warn(_(" empty string\n"))
115 ui.warn(_(" empty string\n"))
116 else:
116 else:
117 ui.warn("\n%r\n" % util.ellipsis(inst[1]))
117 ui.warn("\n%r\n" % util.ellipsis(inst[1]))
118 except ImportError, inst:
118 except ImportError, inst:
119 m = str(inst).split()[-1]
119 m = str(inst).split()[-1]
120 ui.warn(_("abort: could not import module %s!\n" % m))
120 ui.warn(_("abort: could not import module %s!\n" % m))
121 if m in "mpatch bdiff".split():
121 if m in "mpatch bdiff".split():
122 ui.warn(_("(did you forget to compile extensions?)\n"))
122 ui.warn(_("(did you forget to compile extensions?)\n"))
123 elif m in "zlib".split():
123 elif m in "zlib".split():
124 ui.warn(_("(is your Python install correct?)\n"))
124 ui.warn(_("(is your Python install correct?)\n"))
125
125
126 except util.Abort, inst:
126 except util.Abort, inst:
127 ui.warn(_("abort: %s\n") % inst)
127 ui.warn(_("abort: %s\n") % inst)
128 except SystemExit, inst:
128 except SystemExit, inst:
129 # Commands shouldn't sys.exit directly, but give a return code.
129 # Commands shouldn't sys.exit directly, but give a return code.
130 # Just in case catch this and and pass exit code to caller.
130 # Just in case catch this and and pass exit code to caller.
131 return inst.code
131 return inst.code
132 except:
132 except:
133 ui.warn(_("** unknown exception encountered, details follow\n"))
133 ui.warn(_("** unknown exception encountered, details follow\n"))
134 ui.warn(_("** report bug details to "
134 ui.warn(_("** report bug details to "
135 "http://www.selenic.com/mercurial/bts\n"))
135 "http://www.selenic.com/mercurial/bts\n"))
136 ui.warn(_("** or mercurial@selenic.com\n"))
136 ui.warn(_("** or mercurial@selenic.com\n"))
137 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
137 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
138 % version.get_version())
138 % version.get_version())
139 raise
139 raise
140
140
141 return -1
141 return -1
142
142
143 def findpossible(ui, cmd):
143 def findpossible(ui, cmd):
144 """
144 """
145 Return cmd -> (aliases, command table entry)
145 Return cmd -> (aliases, command table entry)
146 for each matching command.
146 for each matching command.
147 Return debug commands (or their aliases) only if no normal command matches.
147 Return debug commands (or their aliases) only if no normal command matches.
148 """
148 """
149 choice = {}
149 choice = {}
150 debugchoice = {}
150 debugchoice = {}
151 for e in commands.table.keys():
151 for e in commands.table.keys():
152 aliases = e.lstrip("^").split("|")
152 aliases = e.lstrip("^").split("|")
153 found = None
153 found = None
154 if cmd in aliases:
154 if cmd in aliases:
155 found = cmd
155 found = cmd
156 elif not ui.config("ui", "strict"):
156 elif not ui.config("ui", "strict"):
157 for a in aliases:
157 for a in aliases:
158 if a.startswith(cmd):
158 if a.startswith(cmd):
159 found = a
159 found = a
160 break
160 break
161 if found is not None:
161 if found is not None:
162 if aliases[0].startswith("debug") or found.startswith("debug"):
162 if aliases[0].startswith("debug") or found.startswith("debug"):
163 debugchoice[found] = (aliases, commands.table[e])
163 debugchoice[found] = (aliases, commands.table[e])
164 else:
164 else:
165 choice[found] = (aliases, commands.table[e])
165 choice[found] = (aliases, commands.table[e])
166
166
167 if not choice and debugchoice:
167 if not choice and debugchoice:
168 choice = debugchoice
168 choice = debugchoice
169
169
170 return choice
170 return choice
171
171
172 def findcmd(ui, cmd):
172 def findcmd(ui, cmd):
173 """Return (aliases, command table entry) for command string."""
173 """Return (aliases, command table entry) for command string."""
174 choice = findpossible(ui, cmd)
174 choice = findpossible(ui, cmd)
175
175
176 if choice.has_key(cmd):
176 if choice.has_key(cmd):
177 return choice[cmd]
177 return choice[cmd]
178
178
179 if len(choice) > 1:
179 if len(choice) > 1:
180 clist = choice.keys()
180 clist = choice.keys()
181 clist.sort()
181 clist.sort()
182 raise AmbiguousCommand(cmd, clist)
182 raise AmbiguousCommand(cmd, clist)
183
183
184 if choice:
184 if choice:
185 return choice.values()[0]
185 return choice.values()[0]
186
186
187 raise UnknownCommand(cmd)
187 raise UnknownCommand(cmd)
188
188
189 def findrepo():
189 def findrepo():
190 p = os.getcwd()
190 p = os.getcwd()
191 while not os.path.isdir(os.path.join(p, ".hg")):
191 while not os.path.isdir(os.path.join(p, ".hg")):
192 oldp, p = p, os.path.dirname(p)
192 oldp, p = p, os.path.dirname(p)
193 if p == oldp:
193 if p == oldp:
194 return None
194 return None
195
195
196 return p
196 return p
197
197
198 def parse(ui, args):
198 def parse(ui, args):
199 options = {}
199 options = {}
200 cmdoptions = {}
200 cmdoptions = {}
201
201
202 try:
202 try:
203 args = fancyopts.fancyopts(args, commands.globalopts, options)
203 args = fancyopts.fancyopts(args, commands.globalopts, options)
204 except fancyopts.getopt.GetoptError, inst:
204 except fancyopts.getopt.GetoptError, inst:
205 raise ParseError(None, inst)
205 raise ParseError(None, inst)
206
206
207 if args:
207 if args:
208 cmd, args = args[0], args[1:]
208 cmd, args = args[0], args[1:]
209 aliases, i = findcmd(ui, cmd)
209 aliases, i = findcmd(ui, cmd)
210 cmd = aliases[0]
210 cmd = aliases[0]
211 defaults = ui.config("defaults", cmd)
211 defaults = ui.config("defaults", cmd)
212 if defaults:
212 if defaults:
213 args = shlex.split(defaults) + args
213 args = shlex.split(defaults) + args
214 c = list(i[1])
214 c = list(i[1])
215 else:
215 else:
216 cmd = None
216 cmd = None
217 c = []
217 c = []
218
218
219 # combine global options into local
219 # combine global options into local
220 for o in commands.globalopts:
220 for o in commands.globalopts:
221 c.append((o[0], o[1], options[o[1]], o[3]))
221 c.append((o[0], o[1], options[o[1]], o[3]))
222
222
223 try:
223 try:
224 args = fancyopts.fancyopts(args, c, cmdoptions)
224 args = fancyopts.fancyopts(args, c, cmdoptions)
225 except fancyopts.getopt.GetoptError, inst:
225 except fancyopts.getopt.GetoptError, inst:
226 raise ParseError(cmd, inst)
226 raise ParseError(cmd, inst)
227
227
228 # separate global options back out
228 # separate global options back out
229 for o in commands.globalopts:
229 for o in commands.globalopts:
230 n = o[1]
230 n = o[1]
231 options[n] = cmdoptions[n]
231 options[n] = cmdoptions[n]
232 del cmdoptions[n]
232 del cmdoptions[n]
233
233
234 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
234 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
235
235
236 def parseconfig(config):
236 def parseconfig(config):
237 """parse the --config options from the command line"""
237 """parse the --config options from the command line"""
238 parsed = []
238 parsed = []
239 for cfg in config:
239 for cfg in config:
240 try:
240 try:
241 name, value = cfg.split('=', 1)
241 name, value = cfg.split('=', 1)
242 section, name = name.split('.', 1)
242 section, name = name.split('.', 1)
243 if not section or not name:
243 if not section or not name:
244 raise IndexError
244 raise IndexError
245 parsed.append((section, name, value))
245 parsed.append((section, name, value))
246 except (IndexError, ValueError):
246 except (IndexError, ValueError):
247 raise util.Abort(_('malformed --config option: %s') % cfg)
247 raise util.Abort(_('malformed --config option: %s') % cfg)
248 return parsed
248 return parsed
249
249
250 def earlygetopt(aliases, args):
250 def earlygetopt(aliases, args):
251 """Return list of values for an option (or aliases).
251 """Return list of values for an option (or aliases).
252
252
253 The values are listed in the order they appear in args.
253 The values are listed in the order they appear in args.
254 The options and values are removed from args.
254 The options and values are removed from args.
255 """
255 """
256 try:
256 try:
257 argcount = args.index("--")
257 argcount = args.index("--")
258 except ValueError:
258 except ValueError:
259 argcount = len(args)
259 argcount = len(args)
260 shortopts = [opt for opt in aliases if len(opt) == 2]
260 shortopts = [opt for opt in aliases if len(opt) == 2]
261 values = []
261 values = []
262 pos = 0
262 pos = 0
263 while pos < argcount:
263 while pos < argcount:
264 if args[pos] in aliases:
264 if args[pos] in aliases:
265 if pos + 1 >= argcount:
265 if pos + 1 >= argcount:
266 # ignore and let getopt report an error if there is no value
266 # ignore and let getopt report an error if there is no value
267 break
267 break
268 del args[pos]
268 del args[pos]
269 values.append(args.pop(pos))
269 values.append(args.pop(pos))
270 argcount -= 2
270 argcount -= 2
271 elif args[pos][:2] in shortopts:
271 elif args[pos][:2] in shortopts:
272 # short option can have no following space, e.g. hg log -Rfoo
272 # short option can have no following space, e.g. hg log -Rfoo
273 values.append(args.pop(pos)[2:])
273 values.append(args.pop(pos)[2:])
274 argcount -= 1
274 argcount -= 1
275 else:
275 else:
276 pos += 1
276 pos += 1
277 return values
277 return values
278
278
279 def dispatch(ui, args):
279 def dispatch(ui, args):
280 # read --config before doing anything else
280 # read --config before doing anything else
281 # (e.g. to change trust settings for reading .hg/hgrc)
281 # (e.g. to change trust settings for reading .hg/hgrc)
282 config = earlygetopt(['--config'], args)
282 config = earlygetopt(['--config'], args)
283 if config:
283 if config:
284 ui.updateopts(config=parseconfig(config))
284 ui.updateopts(config=parseconfig(config))
285
285
286 # check for cwd
286 # check for cwd
287 cwd = earlygetopt(['--cwd'], args)
287 cwd = earlygetopt(['--cwd'], args)
288 if cwd:
288 if cwd:
289 os.chdir(cwd[-1])
289 os.chdir(cwd[-1])
290
290
291 # read the local repository .hgrc into a local ui object
291 # read the local repository .hgrc into a local ui object
292 path = findrepo() or ""
292 path = findrepo() or ""
293 if not path:
293 if not path:
294 lui = ui
294 lui = ui
295 if path:
295 if path:
296 try:
296 try:
297 lui = commands.ui.ui(parentui=ui)
297 lui = commands.ui.ui(parentui=ui)
298 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
298 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
299 except IOError:
299 except IOError:
300 pass
300 pass
301
301
302 # now we can expand paths, even ones in .hg/hgrc
302 # now we can expand paths, even ones in .hg/hgrc
303 rpath = earlygetopt(["-R", "--repository", "--repo"], args)
303 rpath = earlygetopt(["-R", "--repository", "--repo"], args)
304 if rpath:
304 if rpath:
305 path = lui.expandpath(rpath[-1])
305 path = lui.expandpath(rpath[-1])
306 lui = commands.ui.ui(parentui=ui)
306 lui = commands.ui.ui(parentui=ui)
307 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
307 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
308
308
309 extensions.loadall(lui)
309 extensions.loadall(lui)
310 # check for fallback encoding
310 # check for fallback encoding
311 fallback = lui.config('ui', 'fallbackencoding')
311 fallback = lui.config('ui', 'fallbackencoding')
312 if fallback:
312 if fallback:
313 util._fallbackencoding = fallback
313 util._fallbackencoding = fallback
314
314
315 fullargs = args
315 fullargs = args
316 cmd, func, args, options, cmdoptions = parse(lui, args)
316 cmd, func, args, options, cmdoptions = parse(lui, args)
317
317
318 if options["config"]:
318 if options["config"]:
319 raise util.Abort(_("Option --config may not be abbreviated!"))
319 raise util.Abort(_("Option --config may not be abbreviated!"))
320 if options["cwd"]:
320 if options["cwd"]:
321 raise util.Abort(_("Option --cwd may not be abbreviated!"))
321 raise util.Abort(_("Option --cwd may not be abbreviated!"))
322 if options["repository"]:
322 if options["repository"]:
323 raise util.Abort(_(
323 raise util.Abort(_(
324 "Option -R has to be separated from other options (i.e. not -qR) "
324 "Option -R has to be separated from other options (i.e. not -qR) "
325 "and --repository may only be abbreviated as --repo!"))
325 "and --repository may only be abbreviated as --repo!"))
326
326
327 if options["encoding"]:
327 if options["encoding"]:
328 util._encoding = options["encoding"]
328 util._encoding = options["encoding"]
329 if options["encodingmode"]:
329 if options["encodingmode"]:
330 util._encodingmode = options["encodingmode"]
330 util._encodingmode = options["encodingmode"]
331 if options["time"]:
331 if options["time"]:
332 def get_times():
332 def get_times():
333 t = os.times()
333 t = os.times()
334 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
334 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
335 t = (t[0], t[1], t[2], t[3], time.clock())
335 t = (t[0], t[1], t[2], t[3], time.clock())
336 return t
336 return t
337 s = get_times()
337 s = get_times()
338 def print_time():
338 def print_time():
339 t = get_times()
339 t = get_times()
340 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
340 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
341 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
341 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
342 atexit.register(print_time)
342 atexit.register(print_time)
343
343
344 ui.updateopts(options["verbose"], options["debug"], options["quiet"],
344 ui.updateopts(options["verbose"], options["debug"], options["quiet"],
345 not options["noninteractive"], options["traceback"])
345 not options["noninteractive"], options["traceback"])
346
346
347 if options['help']:
347 if options['help']:
348 return commands.help_(ui, cmd, options['version'])
348 return commands.help_(ui, cmd, options['version'])
349 elif options['version']:
349 elif options['version']:
350 return commands.version_(ui)
350 return commands.version_(ui)
351 elif not cmd:
351 elif not cmd:
352 return commands.help_(ui, 'shortlist')
352 return commands.help_(ui, 'shortlist')
353
353
354 repo = None
354 repo = None
355 if cmd not in commands.norepo.split():
355 if cmd not in commands.norepo.split():
356 try:
356 try:
357 repo = hg.repository(ui, path=path)
357 repo = hg.repository(ui, path=path)
358 ui = repo.ui
358 ui = repo.ui
359 if not repo.local():
359 if not repo.local():
360 raise util.Abort(_("repository '%s' is not local") % path)
360 raise util.Abort(_("repository '%s' is not local") % path)
361 except hg.RepoError:
361 except hg.RepoError:
362 if cmd not in commands.optionalrepo.split():
362 if cmd not in commands.optionalrepo.split():
363 if not path:
363 if not path:
364 raise hg.RepoError(_("There is no Mercurial repository here"
364 raise hg.RepoError(_("There is no Mercurial repository here"
365 " (.hg not found)"))
365 " (.hg not found)"))
366 raise
366 raise
367 d = lambda: func(ui, repo, *args, **cmdoptions)
367 d = lambda: func(ui, repo, *args, **cmdoptions)
368 else:
368 else:
369 d = lambda: func(ui, *args, **cmdoptions)
369 d = lambda: func(ui, *args, **cmdoptions)
370
370
371 # run pre-hook, and abort if it fails
371 # run pre-hook, and abort if it fails
372 ret = hook.hook(ui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs))
372 ret = hook.hook(ui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs))
373 if ret:
373 if ret:
374 return ret
374 return ret
375 ret = runcommand(ui, options, cmd, d)
375 ret = runcommand(ui, options, cmd, d)
376 # run post-hook, passing command result
376 # run post-hook, passing command result
377 hook.hook(ui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
377 hook.hook(ui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
378 result = ret)
378 result = ret)
379 return ret
379 return ret
380
380
381 def runcommand(ui, options, cmd, cmdfunc):
381 def runcommand(ui, options, cmd, cmdfunc):
382 def checkargs():
382 def checkargs():
383 try:
383 try:
384 return cmdfunc()
384 return cmdfunc()
385 except TypeError, inst:
385 except TypeError, inst:
386 # was this an argument error?
386 # was this an argument error?
387 tb = traceback.extract_tb(sys.exc_info()[2])
387 tb = traceback.extract_tb(sys.exc_info()[2])
388 if len(tb) != 2: # no
388 if len(tb) != 2: # no
389 raise
389 raise
390 raise ParseError(cmd, _("invalid arguments"))
390 raise ParseError(cmd, _("invalid arguments"))
391
391
392 if options['profile']:
392 if options['profile']:
393 import hotshot, hotshot.stats
393 import hotshot, hotshot.stats
394 prof = hotshot.Profile("hg.prof")
394 prof = hotshot.Profile("hg.prof")
395 try:
395 try:
396 try:
396 try:
397 return prof.runcall(checkargs)
397 return prof.runcall(checkargs)
398 except:
398 except:
399 try:
399 try:
400 ui.warn(_('exception raised - generating '
400 ui.warn(_('exception raised - generating '
401 'profile anyway\n'))
401 'profile anyway\n'))
402 except:
402 except:
403 pass
403 pass
404 raise
404 raise
405 finally:
405 finally:
406 prof.close()
406 prof.close()
407 stats = hotshot.stats.load("hg.prof")
407 stats = hotshot.stats.load("hg.prof")
408 stats.strip_dirs()
408 stats.strip_dirs()
409 stats.sort_stats('time', 'calls')
409 stats.sort_stats('time', 'calls')
410 stats.print_stats(40)
410 stats.print_stats(40)
411 elif options['lsprof']:
411 elif options['lsprof']:
412 try:
412 try:
413 from mercurial import lsprof
413 from mercurial import lsprof
414 except ImportError:
414 except ImportError:
415 raise util.Abort(_(
415 raise util.Abort(_(
416 'lsprof not available - install from '
416 'lsprof not available - install from '
417 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
417 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
418 p = lsprof.Profiler()
418 p = lsprof.Profiler()
419 p.enable(subcalls=True)
419 p.enable(subcalls=True)
420 try:
420 try:
421 return checkargs()
421 return checkargs()
422 finally:
422 finally:
423 p.disable()
423 p.disable()
424 stats = lsprof.Stats(p.getstats())
424 stats = lsprof.Stats(p.getstats())
425 stats.sort()
425 stats.sort()
426 stats.pprint(top=10, file=sys.stderr, climit=5)
426 stats.pprint(top=10, file=sys.stderr, climit=5)
427 else:
427 else:
428 return checkargs()
428 return checkargs()
429
429
430 def bail_if_changed(repo):
430 def bail_if_changed(repo):
431 modified, added, removed, deleted = repo.status()[:4]
431 modified, added, removed, deleted = repo.status()[:4]
432 if modified or added or removed or deleted:
432 if modified or added or removed or deleted:
433 raise util.Abort(_("outstanding uncommitted changes"))
433 raise util.Abort(_("outstanding uncommitted changes"))
434
434
435 def logmessage(opts):
435 def logmessage(opts):
436 """ get the log message according to -m and -l option """
436 """ get the log message according to -m and -l option """
437 message = opts['message']
437 message = opts['message']
438 logfile = opts['logfile']
438 logfile = opts['logfile']
439
439
440 if message and logfile:
440 if message and logfile:
441 raise util.Abort(_('options --message and --logfile are mutually '
441 raise util.Abort(_('options --message and --logfile are mutually '
442 'exclusive'))
442 'exclusive'))
443 if not message and logfile:
443 if not message and logfile:
444 try:
444 try:
445 if logfile == '-':
445 if logfile == '-':
446 message = sys.stdin.read()
446 message = sys.stdin.read()
447 else:
447 else:
448 message = open(logfile).read()
448 message = open(logfile).read()
449 except IOError, inst:
449 except IOError, inst:
450 raise util.Abort(_("can't read commit message '%s': %s") %
450 raise util.Abort(_("can't read commit message '%s': %s") %
451 (logfile, inst.strerror))
451 (logfile, inst.strerror))
452 return message
452 return message
453
453
454 def setremoteconfig(ui, opts):
454 def setremoteconfig(ui, opts):
455 "copy remote options to ui tree"
455 "copy remote options to ui tree"
456 if opts.get('ssh'):
456 if opts.get('ssh'):
457 ui.setconfig("ui", "ssh", opts['ssh'])
457 ui.setconfig("ui", "ssh", opts['ssh'])
458 if opts.get('remotecmd'):
458 if opts.get('remotecmd'):
459 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
459 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
460
460
461 def parseurl(url, revs):
461 def parseurl(url, revs):
462 '''parse url#branch, returning url, branch + revs'''
462 '''parse url#branch, returning url, branch + revs'''
463
463
464 if '#' not in url:
464 if '#' not in url:
465 return url, (revs or None)
465 return url, (revs or None), None
466
466
467 url, rev = url.split('#', 1)
467 url, rev = url.split('#', 1)
468 return url, revs + [rev]
468 return url, revs + [rev], rev
469
469
470 def revpair(repo, revs):
470 def revpair(repo, revs):
471 '''return pair of nodes, given list of revisions. second item can
471 '''return pair of nodes, given list of revisions. second item can
472 be None, meaning use working dir.'''
472 be None, meaning use working dir.'''
473
473
474 def revfix(repo, val, defval):
474 def revfix(repo, val, defval):
475 if not val and val != 0 and defval is not None:
475 if not val and val != 0 and defval is not None:
476 val = defval
476 val = defval
477 return repo.lookup(val)
477 return repo.lookup(val)
478
478
479 if not revs:
479 if not revs:
480 return repo.dirstate.parents()[0], None
480 return repo.dirstate.parents()[0], None
481 end = None
481 end = None
482 if len(revs) == 1:
482 if len(revs) == 1:
483 if revrangesep in revs[0]:
483 if revrangesep in revs[0]:
484 start, end = revs[0].split(revrangesep, 1)
484 start, end = revs[0].split(revrangesep, 1)
485 start = revfix(repo, start, 0)
485 start = revfix(repo, start, 0)
486 end = revfix(repo, end, repo.changelog.count() - 1)
486 end = revfix(repo, end, repo.changelog.count() - 1)
487 else:
487 else:
488 start = revfix(repo, revs[0], None)
488 start = revfix(repo, revs[0], None)
489 elif len(revs) == 2:
489 elif len(revs) == 2:
490 if revrangesep in revs[0] or revrangesep in revs[1]:
490 if revrangesep in revs[0] or revrangesep in revs[1]:
491 raise util.Abort(_('too many revisions specified'))
491 raise util.Abort(_('too many revisions specified'))
492 start = revfix(repo, revs[0], None)
492 start = revfix(repo, revs[0], None)
493 end = revfix(repo, revs[1], None)
493 end = revfix(repo, revs[1], None)
494 else:
494 else:
495 raise util.Abort(_('too many revisions specified'))
495 raise util.Abort(_('too many revisions specified'))
496 return start, end
496 return start, end
497
497
498 def revrange(repo, revs):
498 def revrange(repo, revs):
499 """Yield revision as strings from a list of revision specifications."""
499 """Yield revision as strings from a list of revision specifications."""
500
500
501 def revfix(repo, val, defval):
501 def revfix(repo, val, defval):
502 if not val and val != 0 and defval is not None:
502 if not val and val != 0 and defval is not None:
503 return defval
503 return defval
504 return repo.changelog.rev(repo.lookup(val))
504 return repo.changelog.rev(repo.lookup(val))
505
505
506 seen, l = {}, []
506 seen, l = {}, []
507 for spec in revs:
507 for spec in revs:
508 if revrangesep in spec:
508 if revrangesep in spec:
509 start, end = spec.split(revrangesep, 1)
509 start, end = spec.split(revrangesep, 1)
510 start = revfix(repo, start, 0)
510 start = revfix(repo, start, 0)
511 end = revfix(repo, end, repo.changelog.count() - 1)
511 end = revfix(repo, end, repo.changelog.count() - 1)
512 step = start > end and -1 or 1
512 step = start > end and -1 or 1
513 for rev in xrange(start, end+step, step):
513 for rev in xrange(start, end+step, step):
514 if rev in seen:
514 if rev in seen:
515 continue
515 continue
516 seen[rev] = 1
516 seen[rev] = 1
517 l.append(rev)
517 l.append(rev)
518 else:
518 else:
519 rev = revfix(repo, spec, None)
519 rev = revfix(repo, spec, None)
520 if rev in seen:
520 if rev in seen:
521 continue
521 continue
522 seen[rev] = 1
522 seen[rev] = 1
523 l.append(rev)
523 l.append(rev)
524
524
525 return l
525 return l
526
526
527 def make_filename(repo, pat, node,
527 def make_filename(repo, pat, node,
528 total=None, seqno=None, revwidth=None, pathname=None):
528 total=None, seqno=None, revwidth=None, pathname=None):
529 node_expander = {
529 node_expander = {
530 'H': lambda: hex(node),
530 'H': lambda: hex(node),
531 'R': lambda: str(repo.changelog.rev(node)),
531 'R': lambda: str(repo.changelog.rev(node)),
532 'h': lambda: short(node),
532 'h': lambda: short(node),
533 }
533 }
534 expander = {
534 expander = {
535 '%': lambda: '%',
535 '%': lambda: '%',
536 'b': lambda: os.path.basename(repo.root),
536 'b': lambda: os.path.basename(repo.root),
537 }
537 }
538
538
539 try:
539 try:
540 if node:
540 if node:
541 expander.update(node_expander)
541 expander.update(node_expander)
542 if node:
542 if node:
543 expander['r'] = (lambda:
543 expander['r'] = (lambda:
544 str(repo.changelog.rev(node)).zfill(revwidth or 0))
544 str(repo.changelog.rev(node)).zfill(revwidth or 0))
545 if total is not None:
545 if total is not None:
546 expander['N'] = lambda: str(total)
546 expander['N'] = lambda: str(total)
547 if seqno is not None:
547 if seqno is not None:
548 expander['n'] = lambda: str(seqno)
548 expander['n'] = lambda: str(seqno)
549 if total is not None and seqno is not None:
549 if total is not None and seqno is not None:
550 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
550 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
551 if pathname is not None:
551 if pathname is not None:
552 expander['s'] = lambda: os.path.basename(pathname)
552 expander['s'] = lambda: os.path.basename(pathname)
553 expander['d'] = lambda: os.path.dirname(pathname) or '.'
553 expander['d'] = lambda: os.path.dirname(pathname) or '.'
554 expander['p'] = lambda: pathname
554 expander['p'] = lambda: pathname
555
555
556 newname = []
556 newname = []
557 patlen = len(pat)
557 patlen = len(pat)
558 i = 0
558 i = 0
559 while i < patlen:
559 while i < patlen:
560 c = pat[i]
560 c = pat[i]
561 if c == '%':
561 if c == '%':
562 i += 1
562 i += 1
563 c = pat[i]
563 c = pat[i]
564 c = expander[c]()
564 c = expander[c]()
565 newname.append(c)
565 newname.append(c)
566 i += 1
566 i += 1
567 return ''.join(newname)
567 return ''.join(newname)
568 except KeyError, inst:
568 except KeyError, inst:
569 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
569 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
570 inst.args[0])
570 inst.args[0])
571
571
572 def make_file(repo, pat, node=None,
572 def make_file(repo, pat, node=None,
573 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
573 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
574 if not pat or pat == '-':
574 if not pat or pat == '-':
575 return 'w' in mode and sys.stdout or sys.stdin
575 return 'w' in mode and sys.stdout or sys.stdin
576 if hasattr(pat, 'write') and 'w' in mode:
576 if hasattr(pat, 'write') and 'w' in mode:
577 return pat
577 return pat
578 if hasattr(pat, 'read') and 'r' in mode:
578 if hasattr(pat, 'read') and 'r' in mode:
579 return pat
579 return pat
580 return open(make_filename(repo, pat, node, total, seqno, revwidth,
580 return open(make_filename(repo, pat, node, total, seqno, revwidth,
581 pathname),
581 pathname),
582 mode)
582 mode)
583
583
584 def matchpats(repo, pats=[], opts={}, globbed=False, default=None):
584 def matchpats(repo, pats=[], opts={}, globbed=False, default=None):
585 cwd = repo.getcwd()
585 cwd = repo.getcwd()
586 return util.cmdmatcher(repo.root, cwd, pats or [], opts.get('include'),
586 return util.cmdmatcher(repo.root, cwd, pats or [], opts.get('include'),
587 opts.get('exclude'), globbed=globbed,
587 opts.get('exclude'), globbed=globbed,
588 default=default)
588 default=default)
589
589
590 def walk(repo, pats=[], opts={}, node=None, badmatch=None, globbed=False,
590 def walk(repo, pats=[], opts={}, node=None, badmatch=None, globbed=False,
591 default=None):
591 default=None):
592 files, matchfn, anypats = matchpats(repo, pats, opts, globbed=globbed,
592 files, matchfn, anypats = matchpats(repo, pats, opts, globbed=globbed,
593 default=default)
593 default=default)
594 exact = dict.fromkeys(files)
594 exact = dict.fromkeys(files)
595 cwd = repo.getcwd()
595 cwd = repo.getcwd()
596 for src, fn in repo.walk(node=node, files=files, match=matchfn,
596 for src, fn in repo.walk(node=node, files=files, match=matchfn,
597 badmatch=badmatch):
597 badmatch=badmatch):
598 yield src, fn, repo.pathto(fn, cwd), fn in exact
598 yield src, fn, repo.pathto(fn, cwd), fn in exact
599
599
600 def findrenames(repo, added=None, removed=None, threshold=0.5):
600 def findrenames(repo, added=None, removed=None, threshold=0.5):
601 '''find renamed files -- yields (before, after, score) tuples'''
601 '''find renamed files -- yields (before, after, score) tuples'''
602 if added is None or removed is None:
602 if added is None or removed is None:
603 added, removed = repo.status()[1:3]
603 added, removed = repo.status()[1:3]
604 ctx = repo.changectx()
604 ctx = repo.changectx()
605 for a in added:
605 for a in added:
606 aa = repo.wread(a)
606 aa = repo.wread(a)
607 bestname, bestscore = None, threshold
607 bestname, bestscore = None, threshold
608 for r in removed:
608 for r in removed:
609 rr = ctx.filectx(r).data()
609 rr = ctx.filectx(r).data()
610
610
611 # bdiff.blocks() returns blocks of matching lines
611 # bdiff.blocks() returns blocks of matching lines
612 # count the number of bytes in each
612 # count the number of bytes in each
613 equal = 0
613 equal = 0
614 alines = mdiff.splitnewlines(aa)
614 alines = mdiff.splitnewlines(aa)
615 matches = bdiff.blocks(aa, rr)
615 matches = bdiff.blocks(aa, rr)
616 for x1,x2,y1,y2 in matches:
616 for x1,x2,y1,y2 in matches:
617 for line in alines[x1:x2]:
617 for line in alines[x1:x2]:
618 equal += len(line)
618 equal += len(line)
619
619
620 lengths = len(aa) + len(rr)
620 lengths = len(aa) + len(rr)
621 if lengths:
621 if lengths:
622 myscore = equal*2.0 / lengths
622 myscore = equal*2.0 / lengths
623 if myscore >= bestscore:
623 if myscore >= bestscore:
624 bestname, bestscore = r, myscore
624 bestname, bestscore = r, myscore
625 if bestname:
625 if bestname:
626 yield bestname, a, bestscore
626 yield bestname, a, bestscore
627
627
628 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
628 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
629 similarity=None):
629 similarity=None):
630 if dry_run is None:
630 if dry_run is None:
631 dry_run = opts.get('dry_run')
631 dry_run = opts.get('dry_run')
632 if similarity is None:
632 if similarity is None:
633 similarity = float(opts.get('similarity') or 0)
633 similarity = float(opts.get('similarity') or 0)
634 add, remove = [], []
634 add, remove = [], []
635 mapping = {}
635 mapping = {}
636 for src, abs, rel, exact in walk(repo, pats, opts):
636 for src, abs, rel, exact in walk(repo, pats, opts):
637 target = repo.wjoin(abs)
637 target = repo.wjoin(abs)
638 if src == 'f' and repo.dirstate.state(abs) == '?':
638 if src == 'f' and repo.dirstate.state(abs) == '?':
639 add.append(abs)
639 add.append(abs)
640 mapping[abs] = rel, exact
640 mapping[abs] = rel, exact
641 if repo.ui.verbose or not exact:
641 if repo.ui.verbose or not exact:
642 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
642 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
643 if repo.dirstate.state(abs) != 'r' and not util.lexists(target):
643 if repo.dirstate.state(abs) != 'r' and not util.lexists(target):
644 remove.append(abs)
644 remove.append(abs)
645 mapping[abs] = rel, exact
645 mapping[abs] = rel, exact
646 if repo.ui.verbose or not exact:
646 if repo.ui.verbose or not exact:
647 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
647 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
648 if not dry_run:
648 if not dry_run:
649 repo.add(add, wlock=wlock)
649 repo.add(add, wlock=wlock)
650 repo.remove(remove, wlock=wlock)
650 repo.remove(remove, wlock=wlock)
651 if similarity > 0:
651 if similarity > 0:
652 for old, new, score in findrenames(repo, add, remove, similarity):
652 for old, new, score in findrenames(repo, add, remove, similarity):
653 oldrel, oldexact = mapping[old]
653 oldrel, oldexact = mapping[old]
654 newrel, newexact = mapping[new]
654 newrel, newexact = mapping[new]
655 if repo.ui.verbose or not oldexact or not newexact:
655 if repo.ui.verbose or not oldexact or not newexact:
656 repo.ui.status(_('recording removal of %s as rename to %s '
656 repo.ui.status(_('recording removal of %s as rename to %s '
657 '(%d%% similar)\n') %
657 '(%d%% similar)\n') %
658 (oldrel, newrel, score * 100))
658 (oldrel, newrel, score * 100))
659 if not dry_run:
659 if not dry_run:
660 repo.copy(old, new, wlock=wlock)
660 repo.copy(old, new, wlock=wlock)
661
661
662 def service(opts, parentfn=None, initfn=None, runfn=None):
662 def service(opts, parentfn=None, initfn=None, runfn=None):
663 '''Run a command as a service.'''
663 '''Run a command as a service.'''
664
664
665 if opts['daemon'] and not opts['daemon_pipefds']:
665 if opts['daemon'] and not opts['daemon_pipefds']:
666 rfd, wfd = os.pipe()
666 rfd, wfd = os.pipe()
667 args = sys.argv[:]
667 args = sys.argv[:]
668 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
668 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
669 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
669 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
670 args[0], args)
670 args[0], args)
671 os.close(wfd)
671 os.close(wfd)
672 os.read(rfd, 1)
672 os.read(rfd, 1)
673 if parentfn:
673 if parentfn:
674 return parentfn(pid)
674 return parentfn(pid)
675 else:
675 else:
676 os._exit(0)
676 os._exit(0)
677
677
678 if initfn:
678 if initfn:
679 initfn()
679 initfn()
680
680
681 if opts['pid_file']:
681 if opts['pid_file']:
682 fp = open(opts['pid_file'], 'w')
682 fp = open(opts['pid_file'], 'w')
683 fp.write(str(os.getpid()) + '\n')
683 fp.write(str(os.getpid()) + '\n')
684 fp.close()
684 fp.close()
685
685
686 if opts['daemon_pipefds']:
686 if opts['daemon_pipefds']:
687 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
687 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
688 os.close(rfd)
688 os.close(rfd)
689 try:
689 try:
690 os.setsid()
690 os.setsid()
691 except AttributeError:
691 except AttributeError:
692 pass
692 pass
693 os.write(wfd, 'y')
693 os.write(wfd, 'y')
694 os.close(wfd)
694 os.close(wfd)
695 sys.stdout.flush()
695 sys.stdout.flush()
696 sys.stderr.flush()
696 sys.stderr.flush()
697 fd = os.open(util.nulldev, os.O_RDWR)
697 fd = os.open(util.nulldev, os.O_RDWR)
698 if fd != 0: os.dup2(fd, 0)
698 if fd != 0: os.dup2(fd, 0)
699 if fd != 1: os.dup2(fd, 1)
699 if fd != 1: os.dup2(fd, 1)
700 if fd != 2: os.dup2(fd, 2)
700 if fd != 2: os.dup2(fd, 2)
701 if fd not in (0, 1, 2): os.close(fd)
701 if fd not in (0, 1, 2): os.close(fd)
702
702
703 if runfn:
703 if runfn:
704 return runfn()
704 return runfn()
705
705
706 class changeset_printer(object):
706 class changeset_printer(object):
707 '''show changeset information when templating not requested.'''
707 '''show changeset information when templating not requested.'''
708
708
709 def __init__(self, ui, repo, patch, buffered):
709 def __init__(self, ui, repo, patch, buffered):
710 self.ui = ui
710 self.ui = ui
711 self.repo = repo
711 self.repo = repo
712 self.buffered = buffered
712 self.buffered = buffered
713 self.patch = patch
713 self.patch = patch
714 self.header = {}
714 self.header = {}
715 self.hunk = {}
715 self.hunk = {}
716 self.lastheader = None
716 self.lastheader = None
717
717
718 def flush(self, rev):
718 def flush(self, rev):
719 if rev in self.header:
719 if rev in self.header:
720 h = self.header[rev]
720 h = self.header[rev]
721 if h != self.lastheader:
721 if h != self.lastheader:
722 self.lastheader = h
722 self.lastheader = h
723 self.ui.write(h)
723 self.ui.write(h)
724 del self.header[rev]
724 del self.header[rev]
725 if rev in self.hunk:
725 if rev in self.hunk:
726 self.ui.write(self.hunk[rev])
726 self.ui.write(self.hunk[rev])
727 del self.hunk[rev]
727 del self.hunk[rev]
728 return 1
728 return 1
729 return 0
729 return 0
730
730
731 def show(self, rev=0, changenode=None, copies=(), **props):
731 def show(self, rev=0, changenode=None, copies=(), **props):
732 if self.buffered:
732 if self.buffered:
733 self.ui.pushbuffer()
733 self.ui.pushbuffer()
734 self._show(rev, changenode, copies, props)
734 self._show(rev, changenode, copies, props)
735 self.hunk[rev] = self.ui.popbuffer()
735 self.hunk[rev] = self.ui.popbuffer()
736 else:
736 else:
737 self._show(rev, changenode, copies, props)
737 self._show(rev, changenode, copies, props)
738
738
739 def _show(self, rev, changenode, copies, props):
739 def _show(self, rev, changenode, copies, props):
740 '''show a single changeset or file revision'''
740 '''show a single changeset or file revision'''
741 log = self.repo.changelog
741 log = self.repo.changelog
742 if changenode is None:
742 if changenode is None:
743 changenode = log.node(rev)
743 changenode = log.node(rev)
744 elif not rev:
744 elif not rev:
745 rev = log.rev(changenode)
745 rev = log.rev(changenode)
746
746
747 if self.ui.quiet:
747 if self.ui.quiet:
748 self.ui.write("%d:%s\n" % (rev, short(changenode)))
748 self.ui.write("%d:%s\n" % (rev, short(changenode)))
749 return
749 return
750
750
751 changes = log.read(changenode)
751 changes = log.read(changenode)
752 date = util.datestr(changes[2])
752 date = util.datestr(changes[2])
753 extra = changes[5]
753 extra = changes[5]
754 branch = extra.get("branch")
754 branch = extra.get("branch")
755
755
756 hexfunc = self.ui.debugflag and hex or short
756 hexfunc = self.ui.debugflag and hex or short
757
757
758 parents = [(p, hexfunc(log.node(p)))
758 parents = [(p, hexfunc(log.node(p)))
759 for p in self._meaningful_parentrevs(log, rev)]
759 for p in self._meaningful_parentrevs(log, rev)]
760
760
761 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
761 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
762
762
763 # don't show the default branch name
763 # don't show the default branch name
764 if branch != 'default':
764 if branch != 'default':
765 branch = util.tolocal(branch)
765 branch = util.tolocal(branch)
766 self.ui.write(_("branch: %s\n") % branch)
766 self.ui.write(_("branch: %s\n") % branch)
767 for tag in self.repo.nodetags(changenode):
767 for tag in self.repo.nodetags(changenode):
768 self.ui.write(_("tag: %s\n") % tag)
768 self.ui.write(_("tag: %s\n") % tag)
769 for parent in parents:
769 for parent in parents:
770 self.ui.write(_("parent: %d:%s\n") % parent)
770 self.ui.write(_("parent: %d:%s\n") % parent)
771
771
772 if self.ui.debugflag:
772 if self.ui.debugflag:
773 self.ui.write(_("manifest: %d:%s\n") %
773 self.ui.write(_("manifest: %d:%s\n") %
774 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
774 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
775 self.ui.write(_("user: %s\n") % changes[1])
775 self.ui.write(_("user: %s\n") % changes[1])
776 self.ui.write(_("date: %s\n") % date)
776 self.ui.write(_("date: %s\n") % date)
777
777
778 if self.ui.debugflag:
778 if self.ui.debugflag:
779 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
779 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
780 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
780 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
781 files):
781 files):
782 if value:
782 if value:
783 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
783 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
784 elif changes[3] and self.ui.verbose:
784 elif changes[3] and self.ui.verbose:
785 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
785 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
786 if copies and self.ui.verbose:
786 if copies and self.ui.verbose:
787 copies = ['%s (%s)' % c for c in copies]
787 copies = ['%s (%s)' % c for c in copies]
788 self.ui.write(_("copies: %s\n") % ' '.join(copies))
788 self.ui.write(_("copies: %s\n") % ' '.join(copies))
789
789
790 if extra and self.ui.debugflag:
790 if extra and self.ui.debugflag:
791 extraitems = extra.items()
791 extraitems = extra.items()
792 extraitems.sort()
792 extraitems.sort()
793 for key, value in extraitems:
793 for key, value in extraitems:
794 self.ui.write(_("extra: %s=%s\n")
794 self.ui.write(_("extra: %s=%s\n")
795 % (key, value.encode('string_escape')))
795 % (key, value.encode('string_escape')))
796
796
797 description = changes[4].strip()
797 description = changes[4].strip()
798 if description:
798 if description:
799 if self.ui.verbose:
799 if self.ui.verbose:
800 self.ui.write(_("description:\n"))
800 self.ui.write(_("description:\n"))
801 self.ui.write(description)
801 self.ui.write(description)
802 self.ui.write("\n\n")
802 self.ui.write("\n\n")
803 else:
803 else:
804 self.ui.write(_("summary: %s\n") %
804 self.ui.write(_("summary: %s\n") %
805 description.splitlines()[0])
805 description.splitlines()[0])
806 self.ui.write("\n")
806 self.ui.write("\n")
807
807
808 self.showpatch(changenode)
808 self.showpatch(changenode)
809
809
810 def showpatch(self, node):
810 def showpatch(self, node):
811 if self.patch:
811 if self.patch:
812 prev = self.repo.changelog.parents(node)[0]
812 prev = self.repo.changelog.parents(node)[0]
813 patch.diff(self.repo, prev, node, match=self.patch, fp=self.ui,
813 patch.diff(self.repo, prev, node, match=self.patch, fp=self.ui,
814 opts=patch.diffopts(self.ui))
814 opts=patch.diffopts(self.ui))
815 self.ui.write("\n")
815 self.ui.write("\n")
816
816
817 def _meaningful_parentrevs(self, log, rev):
817 def _meaningful_parentrevs(self, log, rev):
818 """Return list of meaningful (or all if debug) parentrevs for rev.
818 """Return list of meaningful (or all if debug) parentrevs for rev.
819
819
820 For merges (two non-nullrev revisions) both parents are meaningful.
820 For merges (two non-nullrev revisions) both parents are meaningful.
821 Otherwise the first parent revision is considered meaningful if it
821 Otherwise the first parent revision is considered meaningful if it
822 is not the preceding revision.
822 is not the preceding revision.
823 """
823 """
824 parents = log.parentrevs(rev)
824 parents = log.parentrevs(rev)
825 if not self.ui.debugflag and parents[1] == nullrev:
825 if not self.ui.debugflag and parents[1] == nullrev:
826 if parents[0] >= rev - 1:
826 if parents[0] >= rev - 1:
827 parents = []
827 parents = []
828 else:
828 else:
829 parents = [parents[0]]
829 parents = [parents[0]]
830 return parents
830 return parents
831
831
832
832
833 class changeset_templater(changeset_printer):
833 class changeset_templater(changeset_printer):
834 '''format changeset information.'''
834 '''format changeset information.'''
835
835
836 def __init__(self, ui, repo, patch, mapfile, buffered):
836 def __init__(self, ui, repo, patch, mapfile, buffered):
837 changeset_printer.__init__(self, ui, repo, patch, buffered)
837 changeset_printer.__init__(self, ui, repo, patch, buffered)
838 filters = templater.common_filters.copy()
838 filters = templater.common_filters.copy()
839 filters['formatnode'] = (ui.debugflag and (lambda x: x)
839 filters['formatnode'] = (ui.debugflag and (lambda x: x)
840 or (lambda x: x[:12]))
840 or (lambda x: x[:12]))
841 self.t = templater.templater(mapfile, filters,
841 self.t = templater.templater(mapfile, filters,
842 cache={
842 cache={
843 'parent': '{rev}:{node|formatnode} ',
843 'parent': '{rev}:{node|formatnode} ',
844 'manifest': '{rev}:{node|formatnode}',
844 'manifest': '{rev}:{node|formatnode}',
845 'filecopy': '{name} ({source})'})
845 'filecopy': '{name} ({source})'})
846
846
847 def use_template(self, t):
847 def use_template(self, t):
848 '''set template string to use'''
848 '''set template string to use'''
849 self.t.cache['changeset'] = t
849 self.t.cache['changeset'] = t
850
850
851 def _show(self, rev, changenode, copies, props):
851 def _show(self, rev, changenode, copies, props):
852 '''show a single changeset or file revision'''
852 '''show a single changeset or file revision'''
853 log = self.repo.changelog
853 log = self.repo.changelog
854 if changenode is None:
854 if changenode is None:
855 changenode = log.node(rev)
855 changenode = log.node(rev)
856 elif not rev:
856 elif not rev:
857 rev = log.rev(changenode)
857 rev = log.rev(changenode)
858
858
859 changes = log.read(changenode)
859 changes = log.read(changenode)
860
860
861 def showlist(name, values, plural=None, **args):
861 def showlist(name, values, plural=None, **args):
862 '''expand set of values.
862 '''expand set of values.
863 name is name of key in template map.
863 name is name of key in template map.
864 values is list of strings or dicts.
864 values is list of strings or dicts.
865 plural is plural of name, if not simply name + 's'.
865 plural is plural of name, if not simply name + 's'.
866
866
867 expansion works like this, given name 'foo'.
867 expansion works like this, given name 'foo'.
868
868
869 if values is empty, expand 'no_foos'.
869 if values is empty, expand 'no_foos'.
870
870
871 if 'foo' not in template map, return values as a string,
871 if 'foo' not in template map, return values as a string,
872 joined by space.
872 joined by space.
873
873
874 expand 'start_foos'.
874 expand 'start_foos'.
875
875
876 for each value, expand 'foo'. if 'last_foo' in template
876 for each value, expand 'foo'. if 'last_foo' in template
877 map, expand it instead of 'foo' for last key.
877 map, expand it instead of 'foo' for last key.
878
878
879 expand 'end_foos'.
879 expand 'end_foos'.
880 '''
880 '''
881 if plural: names = plural
881 if plural: names = plural
882 else: names = name + 's'
882 else: names = name + 's'
883 if not values:
883 if not values:
884 noname = 'no_' + names
884 noname = 'no_' + names
885 if noname in self.t:
885 if noname in self.t:
886 yield self.t(noname, **args)
886 yield self.t(noname, **args)
887 return
887 return
888 if name not in self.t:
888 if name not in self.t:
889 if isinstance(values[0], str):
889 if isinstance(values[0], str):
890 yield ' '.join(values)
890 yield ' '.join(values)
891 else:
891 else:
892 for v in values:
892 for v in values:
893 yield dict(v, **args)
893 yield dict(v, **args)
894 return
894 return
895 startname = 'start_' + names
895 startname = 'start_' + names
896 if startname in self.t:
896 if startname in self.t:
897 yield self.t(startname, **args)
897 yield self.t(startname, **args)
898 vargs = args.copy()
898 vargs = args.copy()
899 def one(v, tag=name):
899 def one(v, tag=name):
900 try:
900 try:
901 vargs.update(v)
901 vargs.update(v)
902 except (AttributeError, ValueError):
902 except (AttributeError, ValueError):
903 try:
903 try:
904 for a, b in v:
904 for a, b in v:
905 vargs[a] = b
905 vargs[a] = b
906 except ValueError:
906 except ValueError:
907 vargs[name] = v
907 vargs[name] = v
908 return self.t(tag, **vargs)
908 return self.t(tag, **vargs)
909 lastname = 'last_' + name
909 lastname = 'last_' + name
910 if lastname in self.t:
910 if lastname in self.t:
911 last = values.pop()
911 last = values.pop()
912 else:
912 else:
913 last = None
913 last = None
914 for v in values:
914 for v in values:
915 yield one(v)
915 yield one(v)
916 if last is not None:
916 if last is not None:
917 yield one(last, tag=lastname)
917 yield one(last, tag=lastname)
918 endname = 'end_' + names
918 endname = 'end_' + names
919 if endname in self.t:
919 if endname in self.t:
920 yield self.t(endname, **args)
920 yield self.t(endname, **args)
921
921
922 def showbranches(**args):
922 def showbranches(**args):
923 branch = changes[5].get("branch")
923 branch = changes[5].get("branch")
924 if branch != 'default':
924 if branch != 'default':
925 branch = util.tolocal(branch)
925 branch = util.tolocal(branch)
926 return showlist('branch', [branch], plural='branches', **args)
926 return showlist('branch', [branch], plural='branches', **args)
927
927
928 def showparents(**args):
928 def showparents(**args):
929 parents = [[('rev', p), ('node', hex(log.node(p)))]
929 parents = [[('rev', p), ('node', hex(log.node(p)))]
930 for p in self._meaningful_parentrevs(log, rev)]
930 for p in self._meaningful_parentrevs(log, rev)]
931 return showlist('parent', parents, **args)
931 return showlist('parent', parents, **args)
932
932
933 def showtags(**args):
933 def showtags(**args):
934 return showlist('tag', self.repo.nodetags(changenode), **args)
934 return showlist('tag', self.repo.nodetags(changenode), **args)
935
935
936 def showextras(**args):
936 def showextras(**args):
937 extras = changes[5].items()
937 extras = changes[5].items()
938 extras.sort()
938 extras.sort()
939 for key, value in extras:
939 for key, value in extras:
940 args = args.copy()
940 args = args.copy()
941 args.update(dict(key=key, value=value))
941 args.update(dict(key=key, value=value))
942 yield self.t('extra', **args)
942 yield self.t('extra', **args)
943
943
944 def showcopies(**args):
944 def showcopies(**args):
945 c = [{'name': x[0], 'source': x[1]} for x in copies]
945 c = [{'name': x[0], 'source': x[1]} for x in copies]
946 return showlist('file_copy', c, plural='file_copies', **args)
946 return showlist('file_copy', c, plural='file_copies', **args)
947
947
948 if self.ui.debugflag:
948 if self.ui.debugflag:
949 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
949 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
950 def showfiles(**args):
950 def showfiles(**args):
951 return showlist('file', files[0], **args)
951 return showlist('file', files[0], **args)
952 def showadds(**args):
952 def showadds(**args):
953 return showlist('file_add', files[1], **args)
953 return showlist('file_add', files[1], **args)
954 def showdels(**args):
954 def showdels(**args):
955 return showlist('file_del', files[2], **args)
955 return showlist('file_del', files[2], **args)
956 def showmanifest(**args):
956 def showmanifest(**args):
957 args = args.copy()
957 args = args.copy()
958 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
958 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
959 node=hex(changes[0])))
959 node=hex(changes[0])))
960 return self.t('manifest', **args)
960 return self.t('manifest', **args)
961 else:
961 else:
962 def showfiles(**args):
962 def showfiles(**args):
963 return showlist('file', changes[3], **args)
963 return showlist('file', changes[3], **args)
964 showadds = ''
964 showadds = ''
965 showdels = ''
965 showdels = ''
966 showmanifest = ''
966 showmanifest = ''
967
967
968 defprops = {
968 defprops = {
969 'author': changes[1],
969 'author': changes[1],
970 'branches': showbranches,
970 'branches': showbranches,
971 'date': changes[2],
971 'date': changes[2],
972 'desc': changes[4].strip(),
972 'desc': changes[4].strip(),
973 'file_adds': showadds,
973 'file_adds': showadds,
974 'file_dels': showdels,
974 'file_dels': showdels,
975 'files': showfiles,
975 'files': showfiles,
976 'file_copies': showcopies,
976 'file_copies': showcopies,
977 'manifest': showmanifest,
977 'manifest': showmanifest,
978 'node': hex(changenode),
978 'node': hex(changenode),
979 'parents': showparents,
979 'parents': showparents,
980 'rev': rev,
980 'rev': rev,
981 'tags': showtags,
981 'tags': showtags,
982 'extras': showextras,
982 'extras': showextras,
983 }
983 }
984 props = props.copy()
984 props = props.copy()
985 props.update(defprops)
985 props.update(defprops)
986
986
987 try:
987 try:
988 if self.ui.debugflag and 'header_debug' in self.t:
988 if self.ui.debugflag and 'header_debug' in self.t:
989 key = 'header_debug'
989 key = 'header_debug'
990 elif self.ui.quiet and 'header_quiet' in self.t:
990 elif self.ui.quiet and 'header_quiet' in self.t:
991 key = 'header_quiet'
991 key = 'header_quiet'
992 elif self.ui.verbose and 'header_verbose' in self.t:
992 elif self.ui.verbose and 'header_verbose' in self.t:
993 key = 'header_verbose'
993 key = 'header_verbose'
994 elif 'header' in self.t:
994 elif 'header' in self.t:
995 key = 'header'
995 key = 'header'
996 else:
996 else:
997 key = ''
997 key = ''
998 if key:
998 if key:
999 h = templater.stringify(self.t(key, **props))
999 h = templater.stringify(self.t(key, **props))
1000 if self.buffered:
1000 if self.buffered:
1001 self.header[rev] = h
1001 self.header[rev] = h
1002 else:
1002 else:
1003 self.ui.write(h)
1003 self.ui.write(h)
1004 if self.ui.debugflag and 'changeset_debug' in self.t:
1004 if self.ui.debugflag and 'changeset_debug' in self.t:
1005 key = 'changeset_debug'
1005 key = 'changeset_debug'
1006 elif self.ui.quiet and 'changeset_quiet' in self.t:
1006 elif self.ui.quiet and 'changeset_quiet' in self.t:
1007 key = 'changeset_quiet'
1007 key = 'changeset_quiet'
1008 elif self.ui.verbose and 'changeset_verbose' in self.t:
1008 elif self.ui.verbose and 'changeset_verbose' in self.t:
1009 key = 'changeset_verbose'
1009 key = 'changeset_verbose'
1010 else:
1010 else:
1011 key = 'changeset'
1011 key = 'changeset'
1012 self.ui.write(templater.stringify(self.t(key, **props)))
1012 self.ui.write(templater.stringify(self.t(key, **props)))
1013 self.showpatch(changenode)
1013 self.showpatch(changenode)
1014 except KeyError, inst:
1014 except KeyError, inst:
1015 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
1015 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
1016 inst.args[0]))
1016 inst.args[0]))
1017 except SyntaxError, inst:
1017 except SyntaxError, inst:
1018 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
1018 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
1019
1019
1020 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
1020 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
1021 """show one changeset using template or regular display.
1021 """show one changeset using template or regular display.
1022
1022
1023 Display format will be the first non-empty hit of:
1023 Display format will be the first non-empty hit of:
1024 1. option 'template'
1024 1. option 'template'
1025 2. option 'style'
1025 2. option 'style'
1026 3. [ui] setting 'logtemplate'
1026 3. [ui] setting 'logtemplate'
1027 4. [ui] setting 'style'
1027 4. [ui] setting 'style'
1028 If all of these values are either the unset or the empty string,
1028 If all of these values are either the unset or the empty string,
1029 regular display via changeset_printer() is done.
1029 regular display via changeset_printer() is done.
1030 """
1030 """
1031 # options
1031 # options
1032 patch = False
1032 patch = False
1033 if opts.get('patch'):
1033 if opts.get('patch'):
1034 patch = matchfn or util.always
1034 patch = matchfn or util.always
1035
1035
1036 tmpl = opts.get('template')
1036 tmpl = opts.get('template')
1037 mapfile = None
1037 mapfile = None
1038 if tmpl:
1038 if tmpl:
1039 tmpl = templater.parsestring(tmpl, quoted=False)
1039 tmpl = templater.parsestring(tmpl, quoted=False)
1040 else:
1040 else:
1041 mapfile = opts.get('style')
1041 mapfile = opts.get('style')
1042 # ui settings
1042 # ui settings
1043 if not mapfile:
1043 if not mapfile:
1044 tmpl = ui.config('ui', 'logtemplate')
1044 tmpl = ui.config('ui', 'logtemplate')
1045 if tmpl:
1045 if tmpl:
1046 tmpl = templater.parsestring(tmpl)
1046 tmpl = templater.parsestring(tmpl)
1047 else:
1047 else:
1048 mapfile = ui.config('ui', 'style')
1048 mapfile = ui.config('ui', 'style')
1049
1049
1050 if tmpl or mapfile:
1050 if tmpl or mapfile:
1051 if mapfile:
1051 if mapfile:
1052 if not os.path.split(mapfile)[0]:
1052 if not os.path.split(mapfile)[0]:
1053 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1053 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1054 or templater.templatepath(mapfile))
1054 or templater.templatepath(mapfile))
1055 if mapname: mapfile = mapname
1055 if mapname: mapfile = mapname
1056 try:
1056 try:
1057 t = changeset_templater(ui, repo, patch, mapfile, buffered)
1057 t = changeset_templater(ui, repo, patch, mapfile, buffered)
1058 except SyntaxError, inst:
1058 except SyntaxError, inst:
1059 raise util.Abort(inst.args[0])
1059 raise util.Abort(inst.args[0])
1060 if tmpl: t.use_template(tmpl)
1060 if tmpl: t.use_template(tmpl)
1061 return t
1061 return t
1062 return changeset_printer(ui, repo, patch, buffered)
1062 return changeset_printer(ui, repo, patch, buffered)
1063
1063
1064 def finddate(ui, repo, date):
1064 def finddate(ui, repo, date):
1065 """Find the tipmost changeset that matches the given date spec"""
1065 """Find the tipmost changeset that matches the given date spec"""
1066 df = util.matchdate(date + " to " + date)
1066 df = util.matchdate(date + " to " + date)
1067 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1067 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1068 changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None})
1068 changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None})
1069 results = {}
1069 results = {}
1070 for st, rev, fns in changeiter:
1070 for st, rev, fns in changeiter:
1071 if st == 'add':
1071 if st == 'add':
1072 d = get(rev)[2]
1072 d = get(rev)[2]
1073 if df(d[0]):
1073 if df(d[0]):
1074 results[rev] = d
1074 results[rev] = d
1075 elif st == 'iter':
1075 elif st == 'iter':
1076 if rev in results:
1076 if rev in results:
1077 ui.status("Found revision %s from %s\n" %
1077 ui.status("Found revision %s from %s\n" %
1078 (rev, util.datestr(results[rev])))
1078 (rev, util.datestr(results[rev])))
1079 return str(rev)
1079 return str(rev)
1080
1080
1081 raise util.Abort(_("revision matching date not found"))
1081 raise util.Abort(_("revision matching date not found"))
1082
1082
1083 def walkchangerevs(ui, repo, pats, change, opts):
1083 def walkchangerevs(ui, repo, pats, change, opts):
1084 '''Iterate over files and the revs they changed in.
1084 '''Iterate over files and the revs they changed in.
1085
1085
1086 Callers most commonly need to iterate backwards over the history
1086 Callers most commonly need to iterate backwards over the history
1087 it is interested in. Doing so has awful (quadratic-looking)
1087 it is interested in. Doing so has awful (quadratic-looking)
1088 performance, so we use iterators in a "windowed" way.
1088 performance, so we use iterators in a "windowed" way.
1089
1089
1090 We walk a window of revisions in the desired order. Within the
1090 We walk a window of revisions in the desired order. Within the
1091 window, we first walk forwards to gather data, then in the desired
1091 window, we first walk forwards to gather data, then in the desired
1092 order (usually backwards) to display it.
1092 order (usually backwards) to display it.
1093
1093
1094 This function returns an (iterator, matchfn) tuple. The iterator
1094 This function returns an (iterator, matchfn) tuple. The iterator
1095 yields 3-tuples. They will be of one of the following forms:
1095 yields 3-tuples. They will be of one of the following forms:
1096
1096
1097 "window", incrementing, lastrev: stepping through a window,
1097 "window", incrementing, lastrev: stepping through a window,
1098 positive if walking forwards through revs, last rev in the
1098 positive if walking forwards through revs, last rev in the
1099 sequence iterated over - use to reset state for the current window
1099 sequence iterated over - use to reset state for the current window
1100
1100
1101 "add", rev, fns: out-of-order traversal of the given file names
1101 "add", rev, fns: out-of-order traversal of the given file names
1102 fns, which changed during revision rev - use to gather data for
1102 fns, which changed during revision rev - use to gather data for
1103 possible display
1103 possible display
1104
1104
1105 "iter", rev, None: in-order traversal of the revs earlier iterated
1105 "iter", rev, None: in-order traversal of the revs earlier iterated
1106 over with "add" - use to display data'''
1106 over with "add" - use to display data'''
1107
1107
1108 def increasing_windows(start, end, windowsize=8, sizelimit=512):
1108 def increasing_windows(start, end, windowsize=8, sizelimit=512):
1109 if start < end:
1109 if start < end:
1110 while start < end:
1110 while start < end:
1111 yield start, min(windowsize, end-start)
1111 yield start, min(windowsize, end-start)
1112 start += windowsize
1112 start += windowsize
1113 if windowsize < sizelimit:
1113 if windowsize < sizelimit:
1114 windowsize *= 2
1114 windowsize *= 2
1115 else:
1115 else:
1116 while start > end:
1116 while start > end:
1117 yield start, min(windowsize, start-end-1)
1117 yield start, min(windowsize, start-end-1)
1118 start -= windowsize
1118 start -= windowsize
1119 if windowsize < sizelimit:
1119 if windowsize < sizelimit:
1120 windowsize *= 2
1120 windowsize *= 2
1121
1121
1122 files, matchfn, anypats = matchpats(repo, pats, opts)
1122 files, matchfn, anypats = matchpats(repo, pats, opts)
1123 follow = opts.get('follow') or opts.get('follow_first')
1123 follow = opts.get('follow') or opts.get('follow_first')
1124
1124
1125 if repo.changelog.count() == 0:
1125 if repo.changelog.count() == 0:
1126 return [], matchfn
1126 return [], matchfn
1127
1127
1128 if follow:
1128 if follow:
1129 defrange = '%s:0' % repo.changectx().rev()
1129 defrange = '%s:0' % repo.changectx().rev()
1130 else:
1130 else:
1131 defrange = 'tip:0'
1131 defrange = 'tip:0'
1132 revs = revrange(repo, opts['rev'] or [defrange])
1132 revs = revrange(repo, opts['rev'] or [defrange])
1133 wanted = {}
1133 wanted = {}
1134 slowpath = anypats or opts.get('removed')
1134 slowpath = anypats or opts.get('removed')
1135 fncache = {}
1135 fncache = {}
1136
1136
1137 if not slowpath and not files:
1137 if not slowpath and not files:
1138 # No files, no patterns. Display all revs.
1138 # No files, no patterns. Display all revs.
1139 wanted = dict.fromkeys(revs)
1139 wanted = dict.fromkeys(revs)
1140 copies = []
1140 copies = []
1141 if not slowpath:
1141 if not slowpath:
1142 # Only files, no patterns. Check the history of each file.
1142 # Only files, no patterns. Check the history of each file.
1143 def filerevgen(filelog, node):
1143 def filerevgen(filelog, node):
1144 cl_count = repo.changelog.count()
1144 cl_count = repo.changelog.count()
1145 if node is None:
1145 if node is None:
1146 last = filelog.count() - 1
1146 last = filelog.count() - 1
1147 else:
1147 else:
1148 last = filelog.rev(node)
1148 last = filelog.rev(node)
1149 for i, window in increasing_windows(last, nullrev):
1149 for i, window in increasing_windows(last, nullrev):
1150 revs = []
1150 revs = []
1151 for j in xrange(i - window, i + 1):
1151 for j in xrange(i - window, i + 1):
1152 n = filelog.node(j)
1152 n = filelog.node(j)
1153 revs.append((filelog.linkrev(n),
1153 revs.append((filelog.linkrev(n),
1154 follow and filelog.renamed(n)))
1154 follow and filelog.renamed(n)))
1155 revs.reverse()
1155 revs.reverse()
1156 for rev in revs:
1156 for rev in revs:
1157 # only yield rev for which we have the changelog, it can
1157 # only yield rev for which we have the changelog, it can
1158 # happen while doing "hg log" during a pull or commit
1158 # happen while doing "hg log" during a pull or commit
1159 if rev[0] < cl_count:
1159 if rev[0] < cl_count:
1160 yield rev
1160 yield rev
1161 def iterfiles():
1161 def iterfiles():
1162 for filename in files:
1162 for filename in files:
1163 yield filename, None
1163 yield filename, None
1164 for filename_node in copies:
1164 for filename_node in copies:
1165 yield filename_node
1165 yield filename_node
1166 minrev, maxrev = min(revs), max(revs)
1166 minrev, maxrev = min(revs), max(revs)
1167 for file_, node in iterfiles():
1167 for file_, node in iterfiles():
1168 filelog = repo.file(file_)
1168 filelog = repo.file(file_)
1169 # A zero count may be a directory or deleted file, so
1169 # A zero count may be a directory or deleted file, so
1170 # try to find matching entries on the slow path.
1170 # try to find matching entries on the slow path.
1171 if filelog.count() == 0:
1171 if filelog.count() == 0:
1172 slowpath = True
1172 slowpath = True
1173 break
1173 break
1174 for rev, copied in filerevgen(filelog, node):
1174 for rev, copied in filerevgen(filelog, node):
1175 if rev <= maxrev:
1175 if rev <= maxrev:
1176 if rev < minrev:
1176 if rev < minrev:
1177 break
1177 break
1178 fncache.setdefault(rev, [])
1178 fncache.setdefault(rev, [])
1179 fncache[rev].append(file_)
1179 fncache[rev].append(file_)
1180 wanted[rev] = 1
1180 wanted[rev] = 1
1181 if follow and copied:
1181 if follow and copied:
1182 copies.append(copied)
1182 copies.append(copied)
1183 if slowpath:
1183 if slowpath:
1184 if follow:
1184 if follow:
1185 raise util.Abort(_('can only follow copies/renames for explicit '
1185 raise util.Abort(_('can only follow copies/renames for explicit '
1186 'file names'))
1186 'file names'))
1187
1187
1188 # The slow path checks files modified in every changeset.
1188 # The slow path checks files modified in every changeset.
1189 def changerevgen():
1189 def changerevgen():
1190 for i, window in increasing_windows(repo.changelog.count()-1,
1190 for i, window in increasing_windows(repo.changelog.count()-1,
1191 nullrev):
1191 nullrev):
1192 for j in xrange(i - window, i + 1):
1192 for j in xrange(i - window, i + 1):
1193 yield j, change(j)[3]
1193 yield j, change(j)[3]
1194
1194
1195 for rev, changefiles in changerevgen():
1195 for rev, changefiles in changerevgen():
1196 matches = filter(matchfn, changefiles)
1196 matches = filter(matchfn, changefiles)
1197 if matches:
1197 if matches:
1198 fncache[rev] = matches
1198 fncache[rev] = matches
1199 wanted[rev] = 1
1199 wanted[rev] = 1
1200
1200
1201 class followfilter:
1201 class followfilter:
1202 def __init__(self, onlyfirst=False):
1202 def __init__(self, onlyfirst=False):
1203 self.startrev = nullrev
1203 self.startrev = nullrev
1204 self.roots = []
1204 self.roots = []
1205 self.onlyfirst = onlyfirst
1205 self.onlyfirst = onlyfirst
1206
1206
1207 def match(self, rev):
1207 def match(self, rev):
1208 def realparents(rev):
1208 def realparents(rev):
1209 if self.onlyfirst:
1209 if self.onlyfirst:
1210 return repo.changelog.parentrevs(rev)[0:1]
1210 return repo.changelog.parentrevs(rev)[0:1]
1211 else:
1211 else:
1212 return filter(lambda x: x != nullrev,
1212 return filter(lambda x: x != nullrev,
1213 repo.changelog.parentrevs(rev))
1213 repo.changelog.parentrevs(rev))
1214
1214
1215 if self.startrev == nullrev:
1215 if self.startrev == nullrev:
1216 self.startrev = rev
1216 self.startrev = rev
1217 return True
1217 return True
1218
1218
1219 if rev > self.startrev:
1219 if rev > self.startrev:
1220 # forward: all descendants
1220 # forward: all descendants
1221 if not self.roots:
1221 if not self.roots:
1222 self.roots.append(self.startrev)
1222 self.roots.append(self.startrev)
1223 for parent in realparents(rev):
1223 for parent in realparents(rev):
1224 if parent in self.roots:
1224 if parent in self.roots:
1225 self.roots.append(rev)
1225 self.roots.append(rev)
1226 return True
1226 return True
1227 else:
1227 else:
1228 # backwards: all parents
1228 # backwards: all parents
1229 if not self.roots:
1229 if not self.roots:
1230 self.roots.extend(realparents(self.startrev))
1230 self.roots.extend(realparents(self.startrev))
1231 if rev in self.roots:
1231 if rev in self.roots:
1232 self.roots.remove(rev)
1232 self.roots.remove(rev)
1233 self.roots.extend(realparents(rev))
1233 self.roots.extend(realparents(rev))
1234 return True
1234 return True
1235
1235
1236 return False
1236 return False
1237
1237
1238 # it might be worthwhile to do this in the iterator if the rev range
1238 # it might be worthwhile to do this in the iterator if the rev range
1239 # is descending and the prune args are all within that range
1239 # is descending and the prune args are all within that range
1240 for rev in opts.get('prune', ()):
1240 for rev in opts.get('prune', ()):
1241 rev = repo.changelog.rev(repo.lookup(rev))
1241 rev = repo.changelog.rev(repo.lookup(rev))
1242 ff = followfilter()
1242 ff = followfilter()
1243 stop = min(revs[0], revs[-1])
1243 stop = min(revs[0], revs[-1])
1244 for x in xrange(rev, stop-1, -1):
1244 for x in xrange(rev, stop-1, -1):
1245 if ff.match(x) and x in wanted:
1245 if ff.match(x) and x in wanted:
1246 del wanted[x]
1246 del wanted[x]
1247
1247
1248 def iterate():
1248 def iterate():
1249 if follow and not files:
1249 if follow and not files:
1250 ff = followfilter(onlyfirst=opts.get('follow_first'))
1250 ff = followfilter(onlyfirst=opts.get('follow_first'))
1251 def want(rev):
1251 def want(rev):
1252 if ff.match(rev) and rev in wanted:
1252 if ff.match(rev) and rev in wanted:
1253 return True
1253 return True
1254 return False
1254 return False
1255 else:
1255 else:
1256 def want(rev):
1256 def want(rev):
1257 return rev in wanted
1257 return rev in wanted
1258
1258
1259 for i, window in increasing_windows(0, len(revs)):
1259 for i, window in increasing_windows(0, len(revs)):
1260 yield 'window', revs[0] < revs[-1], revs[-1]
1260 yield 'window', revs[0] < revs[-1], revs[-1]
1261 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
1261 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
1262 srevs = list(nrevs)
1262 srevs = list(nrevs)
1263 srevs.sort()
1263 srevs.sort()
1264 for rev in srevs:
1264 for rev in srevs:
1265 fns = fncache.get(rev)
1265 fns = fncache.get(rev)
1266 if not fns:
1266 if not fns:
1267 def fns_generator():
1267 def fns_generator():
1268 for f in change(rev)[3]:
1268 for f in change(rev)[3]:
1269 if matchfn(f):
1269 if matchfn(f):
1270 yield f
1270 yield f
1271 fns = fns_generator()
1271 fns = fns_generator()
1272 yield 'add', rev, fns
1272 yield 'add', rev, fns
1273 for rev in nrevs:
1273 for rev in nrevs:
1274 yield 'iter', rev, None
1274 yield 'iter', rev, None
1275 return iterate(), matchfn
1275 return iterate(), matchfn
@@ -1,3142 +1,3144
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 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 demandimport; demandimport.enable()
8 import demandimport; demandimport.enable()
9 from node import *
9 from node import *
10 from i18n import _
10 from i18n import _
11 import bisect, os, re, sys, urllib, shlex, stat
11 import bisect, os, re, sys, urllib, shlex, stat
12 import ui, hg, util, revlog, bundlerepo, extensions
12 import ui, hg, util, revlog, bundlerepo, extensions
13 import difflib, patch, time, help, mdiff, tempfile
13 import difflib, patch, time, help, mdiff, tempfile
14 import errno, version, socket
14 import errno, version, socket
15 import archival, changegroup, cmdutil, hgweb.server, sshserver
15 import archival, changegroup, cmdutil, hgweb.server, sshserver
16
16
17 # Commands start here, listed alphabetically
17 # Commands start here, listed alphabetically
18
18
19 def add(ui, repo, *pats, **opts):
19 def add(ui, repo, *pats, **opts):
20 """add the specified files on the next commit
20 """add the specified files on the next commit
21
21
22 Schedule files to be version controlled and added to the repository.
22 Schedule files to be version controlled and added to the repository.
23
23
24 The files will be added to the repository at the next commit. To
24 The files will be added to the repository at the next commit. To
25 undo an add before that, see hg revert.
25 undo an add before that, see hg revert.
26
26
27 If no names are given, add all files in the repository.
27 If no names are given, add all files in the repository.
28 """
28 """
29
29
30 names = []
30 names = []
31 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
31 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
32 if exact:
32 if exact:
33 if ui.verbose:
33 if ui.verbose:
34 ui.status(_('adding %s\n') % rel)
34 ui.status(_('adding %s\n') % rel)
35 names.append(abs)
35 names.append(abs)
36 elif repo.dirstate.state(abs) == '?':
36 elif repo.dirstate.state(abs) == '?':
37 ui.status(_('adding %s\n') % rel)
37 ui.status(_('adding %s\n') % rel)
38 names.append(abs)
38 names.append(abs)
39 if not opts.get('dry_run'):
39 if not opts.get('dry_run'):
40 repo.add(names)
40 repo.add(names)
41
41
42 def addremove(ui, repo, *pats, **opts):
42 def addremove(ui, repo, *pats, **opts):
43 """add all new files, delete all missing files
43 """add all new files, delete all missing files
44
44
45 Add all new files and remove all missing files from the repository.
45 Add all new files and remove all missing files from the repository.
46
46
47 New files are ignored if they match any of the patterns in .hgignore. As
47 New files are ignored if they match any of the patterns in .hgignore. As
48 with add, these changes take effect at the next commit.
48 with add, these changes take effect at the next commit.
49
49
50 Use the -s option to detect renamed files. With a parameter > 0,
50 Use the -s option to detect renamed files. With a parameter > 0,
51 this compares every removed file with every added file and records
51 this compares every removed file with every added file and records
52 those similar enough as renames. This option takes a percentage
52 those similar enough as renames. This option takes a percentage
53 between 0 (disabled) and 100 (files must be identical) as its
53 between 0 (disabled) and 100 (files must be identical) as its
54 parameter. Detecting renamed files this way can be expensive.
54 parameter. Detecting renamed files this way can be expensive.
55 """
55 """
56 try:
56 try:
57 sim = float(opts.get('similarity') or 0)
57 sim = float(opts.get('similarity') or 0)
58 except ValueError:
58 except ValueError:
59 raise util.Abort(_('similarity must be a number'))
59 raise util.Abort(_('similarity must be a number'))
60 if sim < 0 or sim > 100:
60 if sim < 0 or sim > 100:
61 raise util.Abort(_('similarity must be between 0 and 100'))
61 raise util.Abort(_('similarity must be between 0 and 100'))
62 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
62 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
63
63
64 def annotate(ui, repo, *pats, **opts):
64 def annotate(ui, repo, *pats, **opts):
65 """show changeset information per file line
65 """show changeset information per file line
66
66
67 List changes in files, showing the revision id responsible for each line
67 List changes in files, showing the revision id responsible for each line
68
68
69 This command is useful to discover who did a change or when a change took
69 This command is useful to discover who did a change or when a change took
70 place.
70 place.
71
71
72 Without the -a option, annotate will avoid processing files it
72 Without the -a option, annotate will avoid processing files it
73 detects as binary. With -a, annotate will generate an annotation
73 detects as binary. With -a, annotate will generate an annotation
74 anyway, probably with undesirable results.
74 anyway, probably with undesirable results.
75 """
75 """
76 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
76 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
77
77
78 if not pats:
78 if not pats:
79 raise util.Abort(_('at least one file name or pattern required'))
79 raise util.Abort(_('at least one file name or pattern required'))
80
80
81 opmap = [['user', lambda x: ui.shortuser(x.user())],
81 opmap = [['user', lambda x: ui.shortuser(x.user())],
82 ['number', lambda x: str(x.rev())],
82 ['number', lambda x: str(x.rev())],
83 ['changeset', lambda x: short(x.node())],
83 ['changeset', lambda x: short(x.node())],
84 ['date', getdate], ['follow', lambda x: x.path()]]
84 ['date', getdate], ['follow', lambda x: x.path()]]
85 if (not opts['user'] and not opts['changeset'] and not opts['date']
85 if (not opts['user'] and not opts['changeset'] and not opts['date']
86 and not opts['follow']):
86 and not opts['follow']):
87 opts['number'] = 1
87 opts['number'] = 1
88
88
89 ctx = repo.changectx(opts['rev'])
89 ctx = repo.changectx(opts['rev'])
90
90
91 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
91 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
92 node=ctx.node()):
92 node=ctx.node()):
93 fctx = ctx.filectx(abs)
93 fctx = ctx.filectx(abs)
94 if not opts['text'] and util.binary(fctx.data()):
94 if not opts['text'] and util.binary(fctx.data()):
95 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
95 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
96 continue
96 continue
97
97
98 lines = fctx.annotate(follow=opts.get('follow'))
98 lines = fctx.annotate(follow=opts.get('follow'))
99 pieces = []
99 pieces = []
100
100
101 for o, f in opmap:
101 for o, f in opmap:
102 if opts[o]:
102 if opts[o]:
103 l = [f(n) for n, dummy in lines]
103 l = [f(n) for n, dummy in lines]
104 if l:
104 if l:
105 m = max(map(len, l))
105 m = max(map(len, l))
106 pieces.append(["%*s" % (m, x) for x in l])
106 pieces.append(["%*s" % (m, x) for x in l])
107
107
108 if pieces:
108 if pieces:
109 for p, l in zip(zip(*pieces), lines):
109 for p, l in zip(zip(*pieces), lines):
110 ui.write("%s: %s" % (" ".join(p), l[1]))
110 ui.write("%s: %s" % (" ".join(p), l[1]))
111
111
112 def archive(ui, repo, dest, **opts):
112 def archive(ui, repo, dest, **opts):
113 '''create unversioned archive of a repository revision
113 '''create unversioned archive of a repository revision
114
114
115 By default, the revision used is the parent of the working
115 By default, the revision used is the parent of the working
116 directory; use "-r" to specify a different revision.
116 directory; use "-r" to specify a different revision.
117
117
118 To specify the type of archive to create, use "-t". Valid
118 To specify the type of archive to create, use "-t". Valid
119 types are:
119 types are:
120
120
121 "files" (default): a directory full of files
121 "files" (default): a directory full of files
122 "tar": tar archive, uncompressed
122 "tar": tar archive, uncompressed
123 "tbz2": tar archive, compressed using bzip2
123 "tbz2": tar archive, compressed using bzip2
124 "tgz": tar archive, compressed using gzip
124 "tgz": tar archive, compressed using gzip
125 "uzip": zip archive, uncompressed
125 "uzip": zip archive, uncompressed
126 "zip": zip archive, compressed using deflate
126 "zip": zip archive, compressed using deflate
127
127
128 The exact name of the destination archive or directory is given
128 The exact name of the destination archive or directory is given
129 using a format string; see "hg help export" for details.
129 using a format string; see "hg help export" for details.
130
130
131 Each member added to an archive file has a directory prefix
131 Each member added to an archive file has a directory prefix
132 prepended. Use "-p" to specify a format string for the prefix.
132 prepended. Use "-p" to specify a format string for the prefix.
133 The default is the basename of the archive, with suffixes removed.
133 The default is the basename of the archive, with suffixes removed.
134 '''
134 '''
135
135
136 ctx = repo.changectx(opts['rev'])
136 ctx = repo.changectx(opts['rev'])
137 if not ctx:
137 if not ctx:
138 raise util.Abort(_('repository has no revisions'))
138 raise util.Abort(_('repository has no revisions'))
139 node = ctx.node()
139 node = ctx.node()
140 dest = cmdutil.make_filename(repo, dest, node)
140 dest = cmdutil.make_filename(repo, dest, node)
141 if os.path.realpath(dest) == repo.root:
141 if os.path.realpath(dest) == repo.root:
142 raise util.Abort(_('repository root cannot be destination'))
142 raise util.Abort(_('repository root cannot be destination'))
143 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
143 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
144 kind = opts.get('type') or 'files'
144 kind = opts.get('type') or 'files'
145 prefix = opts['prefix']
145 prefix = opts['prefix']
146 if dest == '-':
146 if dest == '-':
147 if kind == 'files':
147 if kind == 'files':
148 raise util.Abort(_('cannot archive plain files to stdout'))
148 raise util.Abort(_('cannot archive plain files to stdout'))
149 dest = sys.stdout
149 dest = sys.stdout
150 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
150 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
151 prefix = cmdutil.make_filename(repo, prefix, node)
151 prefix = cmdutil.make_filename(repo, prefix, node)
152 archival.archive(repo, dest, node, kind, not opts['no_decode'],
152 archival.archive(repo, dest, node, kind, not opts['no_decode'],
153 matchfn, prefix)
153 matchfn, prefix)
154
154
155 def backout(ui, repo, node=None, rev=None, **opts):
155 def backout(ui, repo, node=None, rev=None, **opts):
156 '''reverse effect of earlier changeset
156 '''reverse effect of earlier changeset
157
157
158 Commit the backed out changes as a new changeset. The new
158 Commit the backed out changes as a new changeset. The new
159 changeset is a child of the backed out changeset.
159 changeset is a child of the backed out changeset.
160
160
161 If you back out a changeset other than the tip, a new head is
161 If you back out a changeset other than the tip, a new head is
162 created. This head is the parent of the working directory. If
162 created. This head is the parent of the working directory. If
163 you back out an old changeset, your working directory will appear
163 you back out an old changeset, your working directory will appear
164 old after the backout. You should merge the backout changeset
164 old after the backout. You should merge the backout changeset
165 with another head.
165 with another head.
166
166
167 The --merge option remembers the parent of the working directory
167 The --merge option remembers the parent of the working directory
168 before starting the backout, then merges the new head with that
168 before starting the backout, then merges the new head with that
169 changeset afterwards. This saves you from doing the merge by
169 changeset afterwards. This saves you from doing the merge by
170 hand. The result of this merge is not committed, as for a normal
170 hand. The result of this merge is not committed, as for a normal
171 merge.'''
171 merge.'''
172 if rev and node:
172 if rev and node:
173 raise util.Abort(_("please specify just one revision"))
173 raise util.Abort(_("please specify just one revision"))
174
174
175 if not rev:
175 if not rev:
176 rev = node
176 rev = node
177
177
178 if not rev:
178 if not rev:
179 raise util.Abort(_("please specify a revision to backout"))
179 raise util.Abort(_("please specify a revision to backout"))
180
180
181 cmdutil.bail_if_changed(repo)
181 cmdutil.bail_if_changed(repo)
182 op1, op2 = repo.dirstate.parents()
182 op1, op2 = repo.dirstate.parents()
183 if op2 != nullid:
183 if op2 != nullid:
184 raise util.Abort(_('outstanding uncommitted merge'))
184 raise util.Abort(_('outstanding uncommitted merge'))
185 node = repo.lookup(rev)
185 node = repo.lookup(rev)
186 p1, p2 = repo.changelog.parents(node)
186 p1, p2 = repo.changelog.parents(node)
187 if p1 == nullid:
187 if p1 == nullid:
188 raise util.Abort(_('cannot back out a change with no parents'))
188 raise util.Abort(_('cannot back out a change with no parents'))
189 if p2 != nullid:
189 if p2 != nullid:
190 if not opts['parent']:
190 if not opts['parent']:
191 raise util.Abort(_('cannot back out a merge changeset without '
191 raise util.Abort(_('cannot back out a merge changeset without '
192 '--parent'))
192 '--parent'))
193 p = repo.lookup(opts['parent'])
193 p = repo.lookup(opts['parent'])
194 if p not in (p1, p2):
194 if p not in (p1, p2):
195 raise util.Abort(_('%s is not a parent of %s') %
195 raise util.Abort(_('%s is not a parent of %s') %
196 (short(p), short(node)))
196 (short(p), short(node)))
197 parent = p
197 parent = p
198 else:
198 else:
199 if opts['parent']:
199 if opts['parent']:
200 raise util.Abort(_('cannot use --parent on non-merge changeset'))
200 raise util.Abort(_('cannot use --parent on non-merge changeset'))
201 parent = p1
201 parent = p1
202 hg.clean(repo, node, show_stats=False)
202 hg.clean(repo, node, show_stats=False)
203 revert_opts = opts.copy()
203 revert_opts = opts.copy()
204 revert_opts['date'] = None
204 revert_opts['date'] = None
205 revert_opts['all'] = True
205 revert_opts['all'] = True
206 revert_opts['rev'] = hex(parent)
206 revert_opts['rev'] = hex(parent)
207 revert(ui, repo, **revert_opts)
207 revert(ui, repo, **revert_opts)
208 commit_opts = opts.copy()
208 commit_opts = opts.copy()
209 commit_opts['addremove'] = False
209 commit_opts['addremove'] = False
210 if not commit_opts['message'] and not commit_opts['logfile']:
210 if not commit_opts['message'] and not commit_opts['logfile']:
211 commit_opts['message'] = _("Backed out changeset %s") % (short(node))
211 commit_opts['message'] = _("Backed out changeset %s") % (short(node))
212 commit_opts['force_editor'] = True
212 commit_opts['force_editor'] = True
213 commit(ui, repo, **commit_opts)
213 commit(ui, repo, **commit_opts)
214 def nice(node):
214 def nice(node):
215 return '%d:%s' % (repo.changelog.rev(node), short(node))
215 return '%d:%s' % (repo.changelog.rev(node), short(node))
216 ui.status(_('changeset %s backs out changeset %s\n') %
216 ui.status(_('changeset %s backs out changeset %s\n') %
217 (nice(repo.changelog.tip()), nice(node)))
217 (nice(repo.changelog.tip()), nice(node)))
218 if op1 != node:
218 if op1 != node:
219 if opts['merge']:
219 if opts['merge']:
220 ui.status(_('merging with changeset %s\n') % nice(op1))
220 ui.status(_('merging with changeset %s\n') % nice(op1))
221 hg.merge(repo, hex(op1))
221 hg.merge(repo, hex(op1))
222 else:
222 else:
223 ui.status(_('the backout changeset is a new head - '
223 ui.status(_('the backout changeset is a new head - '
224 'do not forget to merge\n'))
224 'do not forget to merge\n'))
225 ui.status(_('(use "backout --merge" '
225 ui.status(_('(use "backout --merge" '
226 'if you want to auto-merge)\n'))
226 'if you want to auto-merge)\n'))
227
227
228 def branch(ui, repo, label=None, **opts):
228 def branch(ui, repo, label=None, **opts):
229 """set or show the current branch name
229 """set or show the current branch name
230
230
231 With no argument, show the current branch name. With one argument,
231 With no argument, show the current branch name. With one argument,
232 set the working directory branch name (the branch does not exist in
232 set the working directory branch name (the branch does not exist in
233 the repository until the next commit).
233 the repository until the next commit).
234
234
235 Unless --force is specified, branch will not let you set a
235 Unless --force is specified, branch will not let you set a
236 branch name that shadows an existing branch.
236 branch name that shadows an existing branch.
237 """
237 """
238
238
239 if label:
239 if label:
240 if not opts.get('force') and label in repo.branchtags():
240 if not opts.get('force') and label in repo.branchtags():
241 if label not in [p.branch() for p in repo.workingctx().parents()]:
241 if label not in [p.branch() for p in repo.workingctx().parents()]:
242 raise util.Abort(_('a branch of the same name already exists'
242 raise util.Abort(_('a branch of the same name already exists'
243 ' (use --force to override)'))
243 ' (use --force to override)'))
244 repo.dirstate.setbranch(util.fromlocal(label))
244 repo.dirstate.setbranch(util.fromlocal(label))
245 ui.status(_('marked working directory as branch %s\n') % label)
245 ui.status(_('marked working directory as branch %s\n') % label)
246 else:
246 else:
247 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
247 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
248
248
249 def branches(ui, repo, active=False):
249 def branches(ui, repo, active=False):
250 """list repository named branches
250 """list repository named branches
251
251
252 List the repository's named branches, indicating which ones are
252 List the repository's named branches, indicating which ones are
253 inactive. If active is specified, only show active branches.
253 inactive. If active is specified, only show active branches.
254
254
255 A branch is considered active if it contains unmerged heads.
255 A branch is considered active if it contains unmerged heads.
256 """
256 """
257 b = repo.branchtags()
257 b = repo.branchtags()
258 heads = dict.fromkeys(repo.heads(), 1)
258 heads = dict.fromkeys(repo.heads(), 1)
259 l = [((n in heads), repo.changelog.rev(n), n, t) for t, n in b.items()]
259 l = [((n in heads), repo.changelog.rev(n), n, t) for t, n in b.items()]
260 l.sort()
260 l.sort()
261 l.reverse()
261 l.reverse()
262 for ishead, r, n, t in l:
262 for ishead, r, n, t in l:
263 if active and not ishead:
263 if active and not ishead:
264 # If we're only displaying active branches, abort the loop on
264 # If we're only displaying active branches, abort the loop on
265 # encountering the first inactive head
265 # encountering the first inactive head
266 break
266 break
267 else:
267 else:
268 hexfunc = ui.debugflag and hex or short
268 hexfunc = ui.debugflag and hex or short
269 if ui.quiet:
269 if ui.quiet:
270 ui.write("%s\n" % t)
270 ui.write("%s\n" % t)
271 else:
271 else:
272 spaces = " " * (30 - util.locallen(t))
272 spaces = " " * (30 - util.locallen(t))
273 # The code only gets here if inactive branches are being
273 # The code only gets here if inactive branches are being
274 # displayed or the branch is active.
274 # displayed or the branch is active.
275 isinactive = ((not ishead) and " (inactive)") or ''
275 isinactive = ((not ishead) and " (inactive)") or ''
276 ui.write("%s%s %s:%s%s\n" % (t, spaces, r, hexfunc(n), isinactive))
276 ui.write("%s%s %s:%s%s\n" % (t, spaces, r, hexfunc(n), isinactive))
277
277
278 def bundle(ui, repo, fname, dest=None, **opts):
278 def bundle(ui, repo, fname, dest=None, **opts):
279 """create a changegroup file
279 """create a changegroup file
280
280
281 Generate a compressed changegroup file collecting changesets not
281 Generate a compressed changegroup file collecting changesets not
282 found in the other repository.
282 found in the other repository.
283
283
284 If no destination repository is specified the destination is assumed
284 If no destination repository is specified the destination is assumed
285 to have all the nodes specified by one or more --base parameters.
285 to have all the nodes specified by one or more --base parameters.
286
286
287 The bundle file can then be transferred using conventional means and
287 The bundle file can then be transferred using conventional means and
288 applied to another repository with the unbundle or pull command.
288 applied to another repository with the unbundle or pull command.
289 This is useful when direct push and pull are not available or when
289 This is useful when direct push and pull are not available or when
290 exporting an entire repository is undesirable.
290 exporting an entire repository is undesirable.
291
291
292 Applying bundles preserves all changeset contents including
292 Applying bundles preserves all changeset contents including
293 permissions, copy/rename information, and revision history.
293 permissions, copy/rename information, and revision history.
294 """
294 """
295 revs = opts.get('rev') or None
295 revs = opts.get('rev') or None
296 if revs:
296 if revs:
297 revs = [repo.lookup(rev) for rev in revs]
297 revs = [repo.lookup(rev) for rev in revs]
298 base = opts.get('base')
298 base = opts.get('base')
299 if base:
299 if base:
300 if dest:
300 if dest:
301 raise util.Abort(_("--base is incompatible with specifiying "
301 raise util.Abort(_("--base is incompatible with specifiying "
302 "a destination"))
302 "a destination"))
303 base = [repo.lookup(rev) for rev in base]
303 base = [repo.lookup(rev) for rev in base]
304 # create the right base
304 # create the right base
305 # XXX: nodesbetween / changegroup* should be "fixed" instead
305 # XXX: nodesbetween / changegroup* should be "fixed" instead
306 o = []
306 o = []
307 has = {nullid: None}
307 has = {nullid: None}
308 for n in base:
308 for n in base:
309 has.update(repo.changelog.reachable(n))
309 has.update(repo.changelog.reachable(n))
310 if revs:
310 if revs:
311 visit = list(revs)
311 visit = list(revs)
312 else:
312 else:
313 visit = repo.changelog.heads()
313 visit = repo.changelog.heads()
314 seen = {}
314 seen = {}
315 while visit:
315 while visit:
316 n = visit.pop(0)
316 n = visit.pop(0)
317 parents = [p for p in repo.changelog.parents(n) if p not in has]
317 parents = [p for p in repo.changelog.parents(n) if p not in has]
318 if len(parents) == 0:
318 if len(parents) == 0:
319 o.insert(0, n)
319 o.insert(0, n)
320 else:
320 else:
321 for p in parents:
321 for p in parents:
322 if p not in seen:
322 if p not in seen:
323 seen[p] = 1
323 seen[p] = 1
324 visit.append(p)
324 visit.append(p)
325 else:
325 else:
326 cmdutil.setremoteconfig(ui, opts)
326 cmdutil.setremoteconfig(ui, opts)
327 dest, revs = cmdutil.parseurl(
327 dest, revs, checkout = cmdutil.parseurl(
328 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
328 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
329 other = hg.repository(ui, dest)
329 other = hg.repository(ui, dest)
330 o = repo.findoutgoing(other, force=opts['force'])
330 o = repo.findoutgoing(other, force=opts['force'])
331
331
332 if revs:
332 if revs:
333 cg = repo.changegroupsubset(o, revs, 'bundle')
333 cg = repo.changegroupsubset(o, revs, 'bundle')
334 else:
334 else:
335 cg = repo.changegroup(o, 'bundle')
335 cg = repo.changegroup(o, 'bundle')
336 changegroup.writebundle(cg, fname, "HG10BZ")
336 changegroup.writebundle(cg, fname, "HG10BZ")
337
337
338 def cat(ui, repo, file1, *pats, **opts):
338 def cat(ui, repo, file1, *pats, **opts):
339 """output the current or given revision of files
339 """output the current or given revision of files
340
340
341 Print the specified files as they were at the given revision.
341 Print the specified files as they were at the given revision.
342 If no revision is given, the parent of the working directory is used,
342 If no revision is given, the parent of the working directory is used,
343 or tip if no revision is checked out.
343 or tip if no revision is checked out.
344
344
345 Output may be to a file, in which case the name of the file is
345 Output may be to a file, in which case the name of the file is
346 given using a format string. The formatting rules are the same as
346 given using a format string. The formatting rules are the same as
347 for the export command, with the following additions:
347 for the export command, with the following additions:
348
348
349 %s basename of file being printed
349 %s basename of file being printed
350 %d dirname of file being printed, or '.' if in repo root
350 %d dirname of file being printed, or '.' if in repo root
351 %p root-relative path name of file being printed
351 %p root-relative path name of file being printed
352 """
352 """
353 ctx = repo.changectx(opts['rev'])
353 ctx = repo.changectx(opts['rev'])
354 err = 1
354 err = 1
355 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
355 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
356 ctx.node()):
356 ctx.node()):
357 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
357 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
358 fp.write(ctx.filectx(abs).data())
358 fp.write(ctx.filectx(abs).data())
359 err = 0
359 err = 0
360 return err
360 return err
361
361
362 def clone(ui, source, dest=None, **opts):
362 def clone(ui, source, dest=None, **opts):
363 """make a copy of an existing repository
363 """make a copy of an existing repository
364
364
365 Create a copy of an existing repository in a new directory.
365 Create a copy of an existing repository in a new directory.
366
366
367 If no destination directory name is specified, it defaults to the
367 If no destination directory name is specified, it defaults to the
368 basename of the source.
368 basename of the source.
369
369
370 The location of the source is added to the new repository's
370 The location of the source is added to the new repository's
371 .hg/hgrc file, as the default to be used for future pulls.
371 .hg/hgrc file, as the default to be used for future pulls.
372
372
373 For efficiency, hardlinks are used for cloning whenever the source
373 For efficiency, hardlinks are used for cloning whenever the source
374 and destination are on the same filesystem (note this applies only
374 and destination are on the same filesystem (note this applies only
375 to the repository data, not to the checked out files). Some
375 to the repository data, not to the checked out files). Some
376 filesystems, such as AFS, implement hardlinking incorrectly, but
376 filesystems, such as AFS, implement hardlinking incorrectly, but
377 do not report errors. In these cases, use the --pull option to
377 do not report errors. In these cases, use the --pull option to
378 avoid hardlinking.
378 avoid hardlinking.
379
379
380 You can safely clone repositories and checked out files using full
380 You can safely clone repositories and checked out files using full
381 hardlinks with
381 hardlinks with
382
382
383 $ cp -al REPO REPOCLONE
383 $ cp -al REPO REPOCLONE
384
384
385 which is the fastest way to clone. However, the operation is not
385 which is the fastest way to clone. However, the operation is not
386 atomic (making sure REPO is not modified during the operation is
386 atomic (making sure REPO is not modified during the operation is
387 up to you) and you have to make sure your editor breaks hardlinks
387 up to you) and you have to make sure your editor breaks hardlinks
388 (Emacs and most Linux Kernel tools do so).
388 (Emacs and most Linux Kernel tools do so).
389
389
390 If you use the -r option to clone up to a specific revision, no
390 If you use the -r option to clone up to a specific revision, no
391 subsequent revisions will be present in the cloned repository.
391 subsequent revisions will be present in the cloned repository.
392 This option implies --pull, even on local repositories.
392 This option implies --pull, even on local repositories.
393
393
394 See pull for valid source format details.
394 See pull for valid source format details.
395
395
396 It is possible to specify an ssh:// URL as the destination, but no
396 It is possible to specify an ssh:// URL as the destination, but no
397 .hg/hgrc and working directory will be created on the remote side.
397 .hg/hgrc and working directory will be created on the remote side.
398 Look at the help text for the pull command for important details
398 Look at the help text for the pull command for important details
399 about ssh:// URLs.
399 about ssh:// URLs.
400 """
400 """
401 cmdutil.setremoteconfig(ui, opts)
401 cmdutil.setremoteconfig(ui, opts)
402 hg.clone(ui, source, dest,
402 hg.clone(ui, source, dest,
403 pull=opts['pull'],
403 pull=opts['pull'],
404 stream=opts['uncompressed'],
404 stream=opts['uncompressed'],
405 rev=opts['rev'],
405 rev=opts['rev'],
406 update=not opts['noupdate'])
406 update=not opts['noupdate'])
407
407
408 def commit(ui, repo, *pats, **opts):
408 def commit(ui, repo, *pats, **opts):
409 """commit the specified files or all outstanding changes
409 """commit the specified files or all outstanding changes
410
410
411 Commit changes to the given files into the repository.
411 Commit changes to the given files into the repository.
412
412
413 If a list of files is omitted, all changes reported by "hg status"
413 If a list of files is omitted, all changes reported by "hg status"
414 will be committed.
414 will be committed.
415
415
416 If no commit message is specified, the editor configured in your hgrc
416 If no commit message is specified, the editor configured in your hgrc
417 or in the EDITOR environment variable is started to enter a message.
417 or in the EDITOR environment variable is started to enter a message.
418 """
418 """
419 message = cmdutil.logmessage(opts)
419 message = cmdutil.logmessage(opts)
420
420
421 if opts['addremove']:
421 if opts['addremove']:
422 cmdutil.addremove(repo, pats, opts)
422 cmdutil.addremove(repo, pats, opts)
423 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
423 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
424 if pats:
424 if pats:
425 status = repo.status(files=fns, match=match)
425 status = repo.status(files=fns, match=match)
426 modified, added, removed, deleted, unknown = status[:5]
426 modified, added, removed, deleted, unknown = status[:5]
427 files = modified + added + removed
427 files = modified + added + removed
428 slist = None
428 slist = None
429 for f in fns:
429 for f in fns:
430 if f == '.':
430 if f == '.':
431 continue
431 continue
432 if f not in files:
432 if f not in files:
433 rf = repo.wjoin(f)
433 rf = repo.wjoin(f)
434 try:
434 try:
435 mode = os.lstat(rf)[stat.ST_MODE]
435 mode = os.lstat(rf)[stat.ST_MODE]
436 except OSError:
436 except OSError:
437 raise util.Abort(_("file %s not found!") % rf)
437 raise util.Abort(_("file %s not found!") % rf)
438 if stat.S_ISDIR(mode):
438 if stat.S_ISDIR(mode):
439 name = f + '/'
439 name = f + '/'
440 if slist is None:
440 if slist is None:
441 slist = list(files)
441 slist = list(files)
442 slist.sort()
442 slist.sort()
443 i = bisect.bisect(slist, name)
443 i = bisect.bisect(slist, name)
444 if i >= len(slist) or not slist[i].startswith(name):
444 if i >= len(slist) or not slist[i].startswith(name):
445 raise util.Abort(_("no match under directory %s!")
445 raise util.Abort(_("no match under directory %s!")
446 % rf)
446 % rf)
447 elif not (stat.S_ISREG(mode) or stat.S_ISLNK(mode)):
447 elif not (stat.S_ISREG(mode) or stat.S_ISLNK(mode)):
448 raise util.Abort(_("can't commit %s: "
448 raise util.Abort(_("can't commit %s: "
449 "unsupported file type!") % rf)
449 "unsupported file type!") % rf)
450 elif repo.dirstate.state(f) == '?':
450 elif repo.dirstate.state(f) == '?':
451 raise util.Abort(_("file %s not tracked!") % rf)
451 raise util.Abort(_("file %s not tracked!") % rf)
452 else:
452 else:
453 files = []
453 files = []
454 try:
454 try:
455 repo.commit(files, message, opts['user'], opts['date'], match,
455 repo.commit(files, message, opts['user'], opts['date'], match,
456 force_editor=opts.get('force_editor'))
456 force_editor=opts.get('force_editor'))
457 except ValueError, inst:
457 except ValueError, inst:
458 raise util.Abort(str(inst))
458 raise util.Abort(str(inst))
459
459
460 def docopy(ui, repo, pats, opts, wlock):
460 def docopy(ui, repo, pats, opts, wlock):
461 # called with the repo lock held
461 # called with the repo lock held
462 #
462 #
463 # hgsep => pathname that uses "/" to separate directories
463 # hgsep => pathname that uses "/" to separate directories
464 # ossep => pathname that uses os.sep to separate directories
464 # ossep => pathname that uses os.sep to separate directories
465 cwd = repo.getcwd()
465 cwd = repo.getcwd()
466 errors = 0
466 errors = 0
467 copied = []
467 copied = []
468 targets = {}
468 targets = {}
469
469
470 # abs: hgsep
470 # abs: hgsep
471 # rel: ossep
471 # rel: ossep
472 # return: hgsep
472 # return: hgsep
473 def okaytocopy(abs, rel, exact):
473 def okaytocopy(abs, rel, exact):
474 reasons = {'?': _('is not managed'),
474 reasons = {'?': _('is not managed'),
475 'r': _('has been marked for remove')}
475 'r': _('has been marked for remove')}
476 state = repo.dirstate.state(abs)
476 state = repo.dirstate.state(abs)
477 reason = reasons.get(state)
477 reason = reasons.get(state)
478 if reason:
478 if reason:
479 if exact:
479 if exact:
480 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
480 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
481 else:
481 else:
482 if state == 'a':
482 if state == 'a':
483 origsrc = repo.dirstate.copied(abs)
483 origsrc = repo.dirstate.copied(abs)
484 if origsrc is not None:
484 if origsrc is not None:
485 return origsrc
485 return origsrc
486 return abs
486 return abs
487
487
488 # origsrc: hgsep
488 # origsrc: hgsep
489 # abssrc: hgsep
489 # abssrc: hgsep
490 # relsrc: ossep
490 # relsrc: ossep
491 # otarget: ossep
491 # otarget: ossep
492 def copy(origsrc, abssrc, relsrc, otarget, exact):
492 def copy(origsrc, abssrc, relsrc, otarget, exact):
493 abstarget = util.canonpath(repo.root, cwd, otarget)
493 abstarget = util.canonpath(repo.root, cwd, otarget)
494 reltarget = repo.pathto(abstarget, cwd)
494 reltarget = repo.pathto(abstarget, cwd)
495 prevsrc = targets.get(abstarget)
495 prevsrc = targets.get(abstarget)
496 src = repo.wjoin(abssrc)
496 src = repo.wjoin(abssrc)
497 target = repo.wjoin(abstarget)
497 target = repo.wjoin(abstarget)
498 if prevsrc is not None:
498 if prevsrc is not None:
499 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
499 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
500 (reltarget, repo.pathto(abssrc, cwd),
500 (reltarget, repo.pathto(abssrc, cwd),
501 repo.pathto(prevsrc, cwd)))
501 repo.pathto(prevsrc, cwd)))
502 return
502 return
503 if (not opts['after'] and os.path.exists(target) or
503 if (not opts['after'] and os.path.exists(target) or
504 opts['after'] and repo.dirstate.state(abstarget) not in '?ar'):
504 opts['after'] and repo.dirstate.state(abstarget) not in '?ar'):
505 if not opts['force']:
505 if not opts['force']:
506 ui.warn(_('%s: not overwriting - file exists\n') %
506 ui.warn(_('%s: not overwriting - file exists\n') %
507 reltarget)
507 reltarget)
508 return
508 return
509 if not opts['after'] and not opts.get('dry_run'):
509 if not opts['after'] and not opts.get('dry_run'):
510 os.unlink(target)
510 os.unlink(target)
511 if opts['after']:
511 if opts['after']:
512 if not os.path.exists(target):
512 if not os.path.exists(target):
513 return
513 return
514 else:
514 else:
515 targetdir = os.path.dirname(target) or '.'
515 targetdir = os.path.dirname(target) or '.'
516 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
516 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
517 os.makedirs(targetdir)
517 os.makedirs(targetdir)
518 try:
518 try:
519 restore = repo.dirstate.state(abstarget) == 'r'
519 restore = repo.dirstate.state(abstarget) == 'r'
520 if restore and not opts.get('dry_run'):
520 if restore and not opts.get('dry_run'):
521 repo.undelete([abstarget], wlock)
521 repo.undelete([abstarget], wlock)
522 try:
522 try:
523 if not opts.get('dry_run'):
523 if not opts.get('dry_run'):
524 util.copyfile(src, target)
524 util.copyfile(src, target)
525 restore = False
525 restore = False
526 finally:
526 finally:
527 if restore:
527 if restore:
528 repo.remove([abstarget], wlock=wlock)
528 repo.remove([abstarget], wlock=wlock)
529 except IOError, inst:
529 except IOError, inst:
530 if inst.errno == errno.ENOENT:
530 if inst.errno == errno.ENOENT:
531 ui.warn(_('%s: deleted in working copy\n') % relsrc)
531 ui.warn(_('%s: deleted in working copy\n') % relsrc)
532 else:
532 else:
533 ui.warn(_('%s: cannot copy - %s\n') %
533 ui.warn(_('%s: cannot copy - %s\n') %
534 (relsrc, inst.strerror))
534 (relsrc, inst.strerror))
535 errors += 1
535 errors += 1
536 return
536 return
537 if ui.verbose or not exact:
537 if ui.verbose or not exact:
538 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
538 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
539 targets[abstarget] = abssrc
539 targets[abstarget] = abssrc
540 if abstarget != origsrc:
540 if abstarget != origsrc:
541 if repo.dirstate.state(origsrc) == 'a':
541 if repo.dirstate.state(origsrc) == 'a':
542 if not ui.quiet:
542 if not ui.quiet:
543 ui.warn(_("%s has not been committed yet, so no copy "
543 ui.warn(_("%s has not been committed yet, so no copy "
544 "data will be stored for %s.\n")
544 "data will be stored for %s.\n")
545 % (repo.pathto(origsrc, cwd), reltarget))
545 % (repo.pathto(origsrc, cwd), reltarget))
546 if abstarget not in repo.dirstate and not opts.get('dry_run'):
546 if abstarget not in repo.dirstate and not opts.get('dry_run'):
547 repo.add([abstarget], wlock)
547 repo.add([abstarget], wlock)
548 elif not opts.get('dry_run'):
548 elif not opts.get('dry_run'):
549 repo.copy(origsrc, abstarget, wlock)
549 repo.copy(origsrc, abstarget, wlock)
550 copied.append((abssrc, relsrc, exact))
550 copied.append((abssrc, relsrc, exact))
551
551
552 # pat: ossep
552 # pat: ossep
553 # dest ossep
553 # dest ossep
554 # srcs: list of (hgsep, hgsep, ossep, bool)
554 # srcs: list of (hgsep, hgsep, ossep, bool)
555 # return: function that takes hgsep and returns ossep
555 # return: function that takes hgsep and returns ossep
556 def targetpathfn(pat, dest, srcs):
556 def targetpathfn(pat, dest, srcs):
557 if os.path.isdir(pat):
557 if os.path.isdir(pat):
558 abspfx = util.canonpath(repo.root, cwd, pat)
558 abspfx = util.canonpath(repo.root, cwd, pat)
559 abspfx = util.localpath(abspfx)
559 abspfx = util.localpath(abspfx)
560 if destdirexists:
560 if destdirexists:
561 striplen = len(os.path.split(abspfx)[0])
561 striplen = len(os.path.split(abspfx)[0])
562 else:
562 else:
563 striplen = len(abspfx)
563 striplen = len(abspfx)
564 if striplen:
564 if striplen:
565 striplen += len(os.sep)
565 striplen += len(os.sep)
566 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
566 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
567 elif destdirexists:
567 elif destdirexists:
568 res = lambda p: os.path.join(dest,
568 res = lambda p: os.path.join(dest,
569 os.path.basename(util.localpath(p)))
569 os.path.basename(util.localpath(p)))
570 else:
570 else:
571 res = lambda p: dest
571 res = lambda p: dest
572 return res
572 return res
573
573
574 # pat: ossep
574 # pat: ossep
575 # dest ossep
575 # dest ossep
576 # srcs: list of (hgsep, hgsep, ossep, bool)
576 # srcs: list of (hgsep, hgsep, ossep, bool)
577 # return: function that takes hgsep and returns ossep
577 # return: function that takes hgsep and returns ossep
578 def targetpathafterfn(pat, dest, srcs):
578 def targetpathafterfn(pat, dest, srcs):
579 if util.patkind(pat, None)[0]:
579 if util.patkind(pat, None)[0]:
580 # a mercurial pattern
580 # a mercurial pattern
581 res = lambda p: os.path.join(dest,
581 res = lambda p: os.path.join(dest,
582 os.path.basename(util.localpath(p)))
582 os.path.basename(util.localpath(p)))
583 else:
583 else:
584 abspfx = util.canonpath(repo.root, cwd, pat)
584 abspfx = util.canonpath(repo.root, cwd, pat)
585 if len(abspfx) < len(srcs[0][0]):
585 if len(abspfx) < len(srcs[0][0]):
586 # A directory. Either the target path contains the last
586 # A directory. Either the target path contains the last
587 # component of the source path or it does not.
587 # component of the source path or it does not.
588 def evalpath(striplen):
588 def evalpath(striplen):
589 score = 0
589 score = 0
590 for s in srcs:
590 for s in srcs:
591 t = os.path.join(dest, util.localpath(s[0])[striplen:])
591 t = os.path.join(dest, util.localpath(s[0])[striplen:])
592 if os.path.exists(t):
592 if os.path.exists(t):
593 score += 1
593 score += 1
594 return score
594 return score
595
595
596 abspfx = util.localpath(abspfx)
596 abspfx = util.localpath(abspfx)
597 striplen = len(abspfx)
597 striplen = len(abspfx)
598 if striplen:
598 if striplen:
599 striplen += len(os.sep)
599 striplen += len(os.sep)
600 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
600 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
601 score = evalpath(striplen)
601 score = evalpath(striplen)
602 striplen1 = len(os.path.split(abspfx)[0])
602 striplen1 = len(os.path.split(abspfx)[0])
603 if striplen1:
603 if striplen1:
604 striplen1 += len(os.sep)
604 striplen1 += len(os.sep)
605 if evalpath(striplen1) > score:
605 if evalpath(striplen1) > score:
606 striplen = striplen1
606 striplen = striplen1
607 res = lambda p: os.path.join(dest,
607 res = lambda p: os.path.join(dest,
608 util.localpath(p)[striplen:])
608 util.localpath(p)[striplen:])
609 else:
609 else:
610 # a file
610 # a file
611 if destdirexists:
611 if destdirexists:
612 res = lambda p: os.path.join(dest,
612 res = lambda p: os.path.join(dest,
613 os.path.basename(util.localpath(p)))
613 os.path.basename(util.localpath(p)))
614 else:
614 else:
615 res = lambda p: dest
615 res = lambda p: dest
616 return res
616 return res
617
617
618
618
619 pats = util.expand_glob(pats)
619 pats = util.expand_glob(pats)
620 if not pats:
620 if not pats:
621 raise util.Abort(_('no source or destination specified'))
621 raise util.Abort(_('no source or destination specified'))
622 if len(pats) == 1:
622 if len(pats) == 1:
623 raise util.Abort(_('no destination specified'))
623 raise util.Abort(_('no destination specified'))
624 dest = pats.pop()
624 dest = pats.pop()
625 destdirexists = os.path.isdir(dest)
625 destdirexists = os.path.isdir(dest)
626 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
626 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
627 raise util.Abort(_('with multiple sources, destination must be an '
627 raise util.Abort(_('with multiple sources, destination must be an '
628 'existing directory'))
628 'existing directory'))
629 if opts['after']:
629 if opts['after']:
630 tfn = targetpathafterfn
630 tfn = targetpathafterfn
631 else:
631 else:
632 tfn = targetpathfn
632 tfn = targetpathfn
633 copylist = []
633 copylist = []
634 for pat in pats:
634 for pat in pats:
635 srcs = []
635 srcs = []
636 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts,
636 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts,
637 globbed=True):
637 globbed=True):
638 origsrc = okaytocopy(abssrc, relsrc, exact)
638 origsrc = okaytocopy(abssrc, relsrc, exact)
639 if origsrc:
639 if origsrc:
640 srcs.append((origsrc, abssrc, relsrc, exact))
640 srcs.append((origsrc, abssrc, relsrc, exact))
641 if not srcs:
641 if not srcs:
642 continue
642 continue
643 copylist.append((tfn(pat, dest, srcs), srcs))
643 copylist.append((tfn(pat, dest, srcs), srcs))
644 if not copylist:
644 if not copylist:
645 raise util.Abort(_('no files to copy'))
645 raise util.Abort(_('no files to copy'))
646
646
647 for targetpath, srcs in copylist:
647 for targetpath, srcs in copylist:
648 for origsrc, abssrc, relsrc, exact in srcs:
648 for origsrc, abssrc, relsrc, exact in srcs:
649 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
649 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
650
650
651 if errors:
651 if errors:
652 ui.warn(_('(consider using --after)\n'))
652 ui.warn(_('(consider using --after)\n'))
653 return errors, copied
653 return errors, copied
654
654
655 def copy(ui, repo, *pats, **opts):
655 def copy(ui, repo, *pats, **opts):
656 """mark files as copied for the next commit
656 """mark files as copied for the next commit
657
657
658 Mark dest as having copies of source files. If dest is a
658 Mark dest as having copies of source files. If dest is a
659 directory, copies are put in that directory. If dest is a file,
659 directory, copies are put in that directory. If dest is a file,
660 there can only be one source.
660 there can only be one source.
661
661
662 By default, this command copies the contents of files as they
662 By default, this command copies the contents of files as they
663 stand in the working directory. If invoked with --after, the
663 stand in the working directory. If invoked with --after, the
664 operation is recorded, but no copying is performed.
664 operation is recorded, but no copying is performed.
665
665
666 This command takes effect in the next commit. To undo a copy
666 This command takes effect in the next commit. To undo a copy
667 before that, see hg revert.
667 before that, see hg revert.
668 """
668 """
669 wlock = repo.wlock(0)
669 wlock = repo.wlock(0)
670 errs, copied = docopy(ui, repo, pats, opts, wlock)
670 errs, copied = docopy(ui, repo, pats, opts, wlock)
671 return errs
671 return errs
672
672
673 def debugancestor(ui, index, rev1, rev2):
673 def debugancestor(ui, index, rev1, rev2):
674 """find the ancestor revision of two revisions in a given index"""
674 """find the ancestor revision of two revisions in a given index"""
675 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
675 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
676 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
676 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
677 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
677 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
678
678
679 def debugcomplete(ui, cmd='', **opts):
679 def debugcomplete(ui, cmd='', **opts):
680 """returns the completion list associated with the given command"""
680 """returns the completion list associated with the given command"""
681
681
682 if opts['options']:
682 if opts['options']:
683 options = []
683 options = []
684 otables = [globalopts]
684 otables = [globalopts]
685 if cmd:
685 if cmd:
686 aliases, entry = cmdutil.findcmd(ui, cmd)
686 aliases, entry = cmdutil.findcmd(ui, cmd)
687 otables.append(entry[1])
687 otables.append(entry[1])
688 for t in otables:
688 for t in otables:
689 for o in t:
689 for o in t:
690 if o[0]:
690 if o[0]:
691 options.append('-%s' % o[0])
691 options.append('-%s' % o[0])
692 options.append('--%s' % o[1])
692 options.append('--%s' % o[1])
693 ui.write("%s\n" % "\n".join(options))
693 ui.write("%s\n" % "\n".join(options))
694 return
694 return
695
695
696 clist = cmdutil.findpossible(ui, cmd).keys()
696 clist = cmdutil.findpossible(ui, cmd).keys()
697 clist.sort()
697 clist.sort()
698 ui.write("%s\n" % "\n".join(clist))
698 ui.write("%s\n" % "\n".join(clist))
699
699
700 def debugrebuildstate(ui, repo, rev=""):
700 def debugrebuildstate(ui, repo, rev=""):
701 """rebuild the dirstate as it would look like for the given revision"""
701 """rebuild the dirstate as it would look like for the given revision"""
702 if rev == "":
702 if rev == "":
703 rev = repo.changelog.tip()
703 rev = repo.changelog.tip()
704 ctx = repo.changectx(rev)
704 ctx = repo.changectx(rev)
705 files = ctx.manifest()
705 files = ctx.manifest()
706 wlock = repo.wlock()
706 wlock = repo.wlock()
707 repo.dirstate.rebuild(rev, files)
707 repo.dirstate.rebuild(rev, files)
708
708
709 def debugcheckstate(ui, repo):
709 def debugcheckstate(ui, repo):
710 """validate the correctness of the current dirstate"""
710 """validate the correctness of the current dirstate"""
711 parent1, parent2 = repo.dirstate.parents()
711 parent1, parent2 = repo.dirstate.parents()
712 dc = repo.dirstate
712 dc = repo.dirstate
713 m1 = repo.changectx(parent1).manifest()
713 m1 = repo.changectx(parent1).manifest()
714 m2 = repo.changectx(parent2).manifest()
714 m2 = repo.changectx(parent2).manifest()
715 errors = 0
715 errors = 0
716 for f in dc:
716 for f in dc:
717 state = repo.dirstate.state(f)
717 state = repo.dirstate.state(f)
718 if state in "nr" and f not in m1:
718 if state in "nr" and f not in m1:
719 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
719 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
720 errors += 1
720 errors += 1
721 if state in "a" and f in m1:
721 if state in "a" and f in m1:
722 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
722 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
723 errors += 1
723 errors += 1
724 if state in "m" and f not in m1 and f not in m2:
724 if state in "m" and f not in m1 and f not in m2:
725 ui.warn(_("%s in state %s, but not in either manifest\n") %
725 ui.warn(_("%s in state %s, but not in either manifest\n") %
726 (f, state))
726 (f, state))
727 errors += 1
727 errors += 1
728 for f in m1:
728 for f in m1:
729 state = repo.dirstate.state(f)
729 state = repo.dirstate.state(f)
730 if state not in "nrm":
730 if state not in "nrm":
731 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
731 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
732 errors += 1
732 errors += 1
733 if errors:
733 if errors:
734 error = _(".hg/dirstate inconsistent with current parent's manifest")
734 error = _(".hg/dirstate inconsistent with current parent's manifest")
735 raise util.Abort(error)
735 raise util.Abort(error)
736
736
737 def showconfig(ui, repo, *values, **opts):
737 def showconfig(ui, repo, *values, **opts):
738 """show combined config settings from all hgrc files
738 """show combined config settings from all hgrc files
739
739
740 With no args, print names and values of all config items.
740 With no args, print names and values of all config items.
741
741
742 With one arg of the form section.name, print just the value of
742 With one arg of the form section.name, print just the value of
743 that config item.
743 that config item.
744
744
745 With multiple args, print names and values of all config items
745 With multiple args, print names and values of all config items
746 with matching section names."""
746 with matching section names."""
747
747
748 untrusted = bool(opts.get('untrusted'))
748 untrusted = bool(opts.get('untrusted'))
749 if values:
749 if values:
750 if len([v for v in values if '.' in v]) > 1:
750 if len([v for v in values if '.' in v]) > 1:
751 raise util.Abort(_('only one config item permitted'))
751 raise util.Abort(_('only one config item permitted'))
752 for section, name, value in ui.walkconfig(untrusted=untrusted):
752 for section, name, value in ui.walkconfig(untrusted=untrusted):
753 sectname = section + '.' + name
753 sectname = section + '.' + name
754 if values:
754 if values:
755 for v in values:
755 for v in values:
756 if v == section:
756 if v == section:
757 ui.write('%s=%s\n' % (sectname, value))
757 ui.write('%s=%s\n' % (sectname, value))
758 elif v == sectname:
758 elif v == sectname:
759 ui.write(value, '\n')
759 ui.write(value, '\n')
760 else:
760 else:
761 ui.write('%s=%s\n' % (sectname, value))
761 ui.write('%s=%s\n' % (sectname, value))
762
762
763 def debugsetparents(ui, repo, rev1, rev2=None):
763 def debugsetparents(ui, repo, rev1, rev2=None):
764 """manually set the parents of the current working directory
764 """manually set the parents of the current working directory
765
765
766 This is useful for writing repository conversion tools, but should
766 This is useful for writing repository conversion tools, but should
767 be used with care.
767 be used with care.
768 """
768 """
769
769
770 if not rev2:
770 if not rev2:
771 rev2 = hex(nullid)
771 rev2 = hex(nullid)
772
772
773 wlock = repo.wlock()
773 wlock = repo.wlock()
774 try:
774 try:
775 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
775 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
776 finally:
776 finally:
777 wlock.release()
777 wlock.release()
778
778
779 def debugstate(ui, repo):
779 def debugstate(ui, repo):
780 """show the contents of the current dirstate"""
780 """show the contents of the current dirstate"""
781 dc = repo.dirstate
781 dc = repo.dirstate
782 for file_ in dc:
782 for file_ in dc:
783 if dc[file_][3] == -1:
783 if dc[file_][3] == -1:
784 # Pad or slice to locale representation
784 # Pad or slice to locale representation
785 locale_len = len(time.strftime("%x %X", time.localtime(0)))
785 locale_len = len(time.strftime("%x %X", time.localtime(0)))
786 timestr = 'unset'
786 timestr = 'unset'
787 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
787 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
788 else:
788 else:
789 timestr = time.strftime("%x %X", time.localtime(dc[file_][3]))
789 timestr = time.strftime("%x %X", time.localtime(dc[file_][3]))
790 ui.write("%c %3o %10d %s %s\n"
790 ui.write("%c %3o %10d %s %s\n"
791 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
791 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
792 timestr, file_))
792 timestr, file_))
793 for f in repo.dirstate.copies():
793 for f in repo.dirstate.copies():
794 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
794 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
795
795
796 def debugdata(ui, file_, rev):
796 def debugdata(ui, file_, rev):
797 """dump the contents of a data file revision"""
797 """dump the contents of a data file revision"""
798 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
798 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
799 try:
799 try:
800 ui.write(r.revision(r.lookup(rev)))
800 ui.write(r.revision(r.lookup(rev)))
801 except KeyError:
801 except KeyError:
802 raise util.Abort(_('invalid revision identifier %s') % rev)
802 raise util.Abort(_('invalid revision identifier %s') % rev)
803
803
804 def debugdate(ui, date, range=None, **opts):
804 def debugdate(ui, date, range=None, **opts):
805 """parse and display a date"""
805 """parse and display a date"""
806 if opts["extended"]:
806 if opts["extended"]:
807 d = util.parsedate(date, util.extendeddateformats)
807 d = util.parsedate(date, util.extendeddateformats)
808 else:
808 else:
809 d = util.parsedate(date)
809 d = util.parsedate(date)
810 ui.write("internal: %s %s\n" % d)
810 ui.write("internal: %s %s\n" % d)
811 ui.write("standard: %s\n" % util.datestr(d))
811 ui.write("standard: %s\n" % util.datestr(d))
812 if range:
812 if range:
813 m = util.matchdate(range)
813 m = util.matchdate(range)
814 ui.write("match: %s\n" % m(d[0]))
814 ui.write("match: %s\n" % m(d[0]))
815
815
816 def debugindex(ui, file_):
816 def debugindex(ui, file_):
817 """dump the contents of an index file"""
817 """dump the contents of an index file"""
818 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
818 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
819 ui.write(" rev offset length base linkrev" +
819 ui.write(" rev offset length base linkrev" +
820 " nodeid p1 p2\n")
820 " nodeid p1 p2\n")
821 for i in xrange(r.count()):
821 for i in xrange(r.count()):
822 node = r.node(i)
822 node = r.node(i)
823 pp = r.parents(node)
823 pp = r.parents(node)
824 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
824 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
825 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
825 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
826 short(node), short(pp[0]), short(pp[1])))
826 short(node), short(pp[0]), short(pp[1])))
827
827
828 def debugindexdot(ui, file_):
828 def debugindexdot(ui, file_):
829 """dump an index DAG as a .dot file"""
829 """dump an index DAG as a .dot file"""
830 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
830 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
831 ui.write("digraph G {\n")
831 ui.write("digraph G {\n")
832 for i in xrange(r.count()):
832 for i in xrange(r.count()):
833 node = r.node(i)
833 node = r.node(i)
834 pp = r.parents(node)
834 pp = r.parents(node)
835 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
835 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
836 if pp[1] != nullid:
836 if pp[1] != nullid:
837 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
837 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
838 ui.write("}\n")
838 ui.write("}\n")
839
839
840 def debuginstall(ui):
840 def debuginstall(ui):
841 '''test Mercurial installation'''
841 '''test Mercurial installation'''
842
842
843 def writetemp(contents):
843 def writetemp(contents):
844 (fd, name) = tempfile.mkstemp()
844 (fd, name) = tempfile.mkstemp()
845 f = os.fdopen(fd, "wb")
845 f = os.fdopen(fd, "wb")
846 f.write(contents)
846 f.write(contents)
847 f.close()
847 f.close()
848 return name
848 return name
849
849
850 problems = 0
850 problems = 0
851
851
852 # encoding
852 # encoding
853 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
853 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
854 try:
854 try:
855 util.fromlocal("test")
855 util.fromlocal("test")
856 except util.Abort, inst:
856 except util.Abort, inst:
857 ui.write(" %s\n" % inst)
857 ui.write(" %s\n" % inst)
858 ui.write(_(" (check that your locale is properly set)\n"))
858 ui.write(_(" (check that your locale is properly set)\n"))
859 problems += 1
859 problems += 1
860
860
861 # compiled modules
861 # compiled modules
862 ui.status(_("Checking extensions...\n"))
862 ui.status(_("Checking extensions...\n"))
863 try:
863 try:
864 import bdiff, mpatch, base85
864 import bdiff, mpatch, base85
865 except Exception, inst:
865 except Exception, inst:
866 ui.write(" %s\n" % inst)
866 ui.write(" %s\n" % inst)
867 ui.write(_(" One or more extensions could not be found"))
867 ui.write(_(" One or more extensions could not be found"))
868 ui.write(_(" (check that you compiled the extensions)\n"))
868 ui.write(_(" (check that you compiled the extensions)\n"))
869 problems += 1
869 problems += 1
870
870
871 # templates
871 # templates
872 ui.status(_("Checking templates...\n"))
872 ui.status(_("Checking templates...\n"))
873 try:
873 try:
874 import templater
874 import templater
875 t = templater.templater(templater.templatepath("map-cmdline.default"))
875 t = templater.templater(templater.templatepath("map-cmdline.default"))
876 except Exception, inst:
876 except Exception, inst:
877 ui.write(" %s\n" % inst)
877 ui.write(" %s\n" % inst)
878 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
878 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
879 problems += 1
879 problems += 1
880
880
881 # patch
881 # patch
882 ui.status(_("Checking patch...\n"))
882 ui.status(_("Checking patch...\n"))
883 patcher = ui.config('ui', 'patch')
883 patcher = ui.config('ui', 'patch')
884 patcher = ((patcher and util.find_exe(patcher)) or
884 patcher = ((patcher and util.find_exe(patcher)) or
885 util.find_exe('gpatch') or
885 util.find_exe('gpatch') or
886 util.find_exe('patch'))
886 util.find_exe('patch'))
887 if not patcher:
887 if not patcher:
888 ui.write(_(" Can't find patch or gpatch in PATH\n"))
888 ui.write(_(" Can't find patch or gpatch in PATH\n"))
889 ui.write(_(" (specify a patch utility in your .hgrc file)\n"))
889 ui.write(_(" (specify a patch utility in your .hgrc file)\n"))
890 problems += 1
890 problems += 1
891 else:
891 else:
892 # actually attempt a patch here
892 # actually attempt a patch here
893 a = "1\n2\n3\n4\n"
893 a = "1\n2\n3\n4\n"
894 b = "1\n2\n3\ninsert\n4\n"
894 b = "1\n2\n3\ninsert\n4\n"
895 fa = writetemp(a)
895 fa = writetemp(a)
896 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa))
896 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa))
897 fd = writetemp(d)
897 fd = writetemp(d)
898
898
899 files = {}
899 files = {}
900 try:
900 try:
901 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
901 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
902 except util.Abort, e:
902 except util.Abort, e:
903 ui.write(_(" patch call failed:\n"))
903 ui.write(_(" patch call failed:\n"))
904 ui.write(" " + str(e) + "\n")
904 ui.write(" " + str(e) + "\n")
905 problems += 1
905 problems += 1
906 else:
906 else:
907 if list(files) != [os.path.basename(fa)]:
907 if list(files) != [os.path.basename(fa)]:
908 ui.write(_(" unexpected patch output!"))
908 ui.write(_(" unexpected patch output!"))
909 ui.write(_(" (you may have an incompatible version of patch)\n"))
909 ui.write(_(" (you may have an incompatible version of patch)\n"))
910 problems += 1
910 problems += 1
911 a = file(fa).read()
911 a = file(fa).read()
912 if a != b:
912 if a != b:
913 ui.write(_(" patch test failed!"))
913 ui.write(_(" patch test failed!"))
914 ui.write(_(" (you may have an incompatible version of patch)\n"))
914 ui.write(_(" (you may have an incompatible version of patch)\n"))
915 problems += 1
915 problems += 1
916
916
917 os.unlink(fa)
917 os.unlink(fa)
918 os.unlink(fd)
918 os.unlink(fd)
919
919
920 # merge helper
920 # merge helper
921 ui.status(_("Checking merge helper...\n"))
921 ui.status(_("Checking merge helper...\n"))
922 cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge")
922 cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge")
923 or "hgmerge")
923 or "hgmerge")
924 cmdpath = util.find_exe(cmd) or util.find_exe(cmd.split()[0])
924 cmdpath = util.find_exe(cmd) or util.find_exe(cmd.split()[0])
925 if not cmdpath:
925 if not cmdpath:
926 if cmd == 'hgmerge':
926 if cmd == 'hgmerge':
927 ui.write(_(" No merge helper set and can't find default"
927 ui.write(_(" No merge helper set and can't find default"
928 " hgmerge script in PATH\n"))
928 " hgmerge script in PATH\n"))
929 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
929 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
930 else:
930 else:
931 ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd)
931 ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd)
932 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
932 ui.write(_(" (specify a merge helper in your .hgrc file)\n"))
933 problems += 1
933 problems += 1
934 else:
934 else:
935 # actually attempt a patch here
935 # actually attempt a patch here
936 fa = writetemp("1\n2\n3\n4\n")
936 fa = writetemp("1\n2\n3\n4\n")
937 fl = writetemp("1\n2\n3\ninsert\n4\n")
937 fl = writetemp("1\n2\n3\ninsert\n4\n")
938 fr = writetemp("begin\n1\n2\n3\n4\n")
938 fr = writetemp("begin\n1\n2\n3\n4\n")
939 r = util.system('%s "%s" "%s" "%s"' % (cmd, fl, fa, fr))
939 r = util.system('%s "%s" "%s" "%s"' % (cmd, fl, fa, fr))
940 if r:
940 if r:
941 ui.write(_(" Got unexpected merge error %d!\n") % r)
941 ui.write(_(" Got unexpected merge error %d!\n") % r)
942 problems += 1
942 problems += 1
943 m = file(fl).read()
943 m = file(fl).read()
944 if m != "begin\n1\n2\n3\ninsert\n4\n":
944 if m != "begin\n1\n2\n3\ninsert\n4\n":
945 ui.write(_(" Got unexpected merge results!\n"))
945 ui.write(_(" Got unexpected merge results!\n"))
946 ui.write(_(" (your merge helper may have the"
946 ui.write(_(" (your merge helper may have the"
947 " wrong argument order)\n"))
947 " wrong argument order)\n"))
948 ui.write(_(" Result: %r\n") % m)
948 ui.write(_(" Result: %r\n") % m)
949 problems += 1
949 problems += 1
950 os.unlink(fa)
950 os.unlink(fa)
951 os.unlink(fl)
951 os.unlink(fl)
952 os.unlink(fr)
952 os.unlink(fr)
953
953
954 # editor
954 # editor
955 ui.status(_("Checking commit editor...\n"))
955 ui.status(_("Checking commit editor...\n"))
956 editor = (os.environ.get("HGEDITOR") or
956 editor = (os.environ.get("HGEDITOR") or
957 ui.config("ui", "editor") or
957 ui.config("ui", "editor") or
958 os.environ.get("EDITOR", "vi"))
958 os.environ.get("EDITOR", "vi"))
959 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
959 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
960 if not cmdpath:
960 if not cmdpath:
961 if editor == 'vi':
961 if editor == 'vi':
962 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
962 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
963 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
963 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
964 else:
964 else:
965 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
965 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
966 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
966 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
967 problems += 1
967 problems += 1
968
968
969 # check username
969 # check username
970 ui.status(_("Checking username...\n"))
970 ui.status(_("Checking username...\n"))
971 user = os.environ.get("HGUSER")
971 user = os.environ.get("HGUSER")
972 if user is None:
972 if user is None:
973 user = ui.config("ui", "username")
973 user = ui.config("ui", "username")
974 if user is None:
974 if user is None:
975 user = os.environ.get("EMAIL")
975 user = os.environ.get("EMAIL")
976 if not user:
976 if not user:
977 ui.warn(" ")
977 ui.warn(" ")
978 ui.username()
978 ui.username()
979 ui.write(_(" (specify a username in your .hgrc file)\n"))
979 ui.write(_(" (specify a username in your .hgrc file)\n"))
980
980
981 if not problems:
981 if not problems:
982 ui.status(_("No problems detected\n"))
982 ui.status(_("No problems detected\n"))
983 else:
983 else:
984 ui.write(_("%s problems detected,"
984 ui.write(_("%s problems detected,"
985 " please check your install!\n") % problems)
985 " please check your install!\n") % problems)
986
986
987 return problems
987 return problems
988
988
989 def debugrename(ui, repo, file1, *pats, **opts):
989 def debugrename(ui, repo, file1, *pats, **opts):
990 """dump rename information"""
990 """dump rename information"""
991
991
992 ctx = repo.changectx(opts.get('rev', 'tip'))
992 ctx = repo.changectx(opts.get('rev', 'tip'))
993 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
993 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
994 ctx.node()):
994 ctx.node()):
995 m = ctx.filectx(abs).renamed()
995 m = ctx.filectx(abs).renamed()
996 if m:
996 if m:
997 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
997 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
998 else:
998 else:
999 ui.write(_("%s not renamed\n") % rel)
999 ui.write(_("%s not renamed\n") % rel)
1000
1000
1001 def debugwalk(ui, repo, *pats, **opts):
1001 def debugwalk(ui, repo, *pats, **opts):
1002 """show how files match on given patterns"""
1002 """show how files match on given patterns"""
1003 items = list(cmdutil.walk(repo, pats, opts))
1003 items = list(cmdutil.walk(repo, pats, opts))
1004 if not items:
1004 if not items:
1005 return
1005 return
1006 fmt = '%%s %%-%ds %%-%ds %%s' % (
1006 fmt = '%%s %%-%ds %%-%ds %%s' % (
1007 max([len(abs) for (src, abs, rel, exact) in items]),
1007 max([len(abs) for (src, abs, rel, exact) in items]),
1008 max([len(rel) for (src, abs, rel, exact) in items]))
1008 max([len(rel) for (src, abs, rel, exact) in items]))
1009 for src, abs, rel, exact in items:
1009 for src, abs, rel, exact in items:
1010 line = fmt % (src, abs, rel, exact and 'exact' or '')
1010 line = fmt % (src, abs, rel, exact and 'exact' or '')
1011 ui.write("%s\n" % line.rstrip())
1011 ui.write("%s\n" % line.rstrip())
1012
1012
1013 def diff(ui, repo, *pats, **opts):
1013 def diff(ui, repo, *pats, **opts):
1014 """diff repository (or selected files)
1014 """diff repository (or selected files)
1015
1015
1016 Show differences between revisions for the specified files.
1016 Show differences between revisions for the specified files.
1017
1017
1018 Differences between files are shown using the unified diff format.
1018 Differences between files are shown using the unified diff format.
1019
1019
1020 NOTE: diff may generate unexpected results for merges, as it will
1020 NOTE: diff may generate unexpected results for merges, as it will
1021 default to comparing against the working directory's first parent
1021 default to comparing against the working directory's first parent
1022 changeset if no revisions are specified.
1022 changeset if no revisions are specified.
1023
1023
1024 When two revision arguments are given, then changes are shown
1024 When two revision arguments are given, then changes are shown
1025 between those revisions. If only one revision is specified then
1025 between those revisions. If only one revision is specified then
1026 that revision is compared to the working directory, and, when no
1026 that revision is compared to the working directory, and, when no
1027 revisions are specified, the working directory files are compared
1027 revisions are specified, the working directory files are compared
1028 to its parent.
1028 to its parent.
1029
1029
1030 Without the -a option, diff will avoid generating diffs of files
1030 Without the -a option, diff will avoid generating diffs of files
1031 it detects as binary. With -a, diff will generate a diff anyway,
1031 it detects as binary. With -a, diff will generate a diff anyway,
1032 probably with undesirable results.
1032 probably with undesirable results.
1033 """
1033 """
1034 node1, node2 = cmdutil.revpair(repo, opts['rev'])
1034 node1, node2 = cmdutil.revpair(repo, opts['rev'])
1035
1035
1036 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1036 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1037
1037
1038 patch.diff(repo, node1, node2, fns, match=matchfn,
1038 patch.diff(repo, node1, node2, fns, match=matchfn,
1039 opts=patch.diffopts(ui, opts))
1039 opts=patch.diffopts(ui, opts))
1040
1040
1041 def export(ui, repo, *changesets, **opts):
1041 def export(ui, repo, *changesets, **opts):
1042 """dump the header and diffs for one or more changesets
1042 """dump the header and diffs for one or more changesets
1043
1043
1044 Print the changeset header and diffs for one or more revisions.
1044 Print the changeset header and diffs for one or more revisions.
1045
1045
1046 The information shown in the changeset header is: author,
1046 The information shown in the changeset header is: author,
1047 changeset hash, parent(s) and commit comment.
1047 changeset hash, parent(s) and commit comment.
1048
1048
1049 NOTE: export may generate unexpected diff output for merge changesets,
1049 NOTE: export may generate unexpected diff output for merge changesets,
1050 as it will compare the merge changeset against its first parent only.
1050 as it will compare the merge changeset against its first parent only.
1051
1051
1052 Output may be to a file, in which case the name of the file is
1052 Output may be to a file, in which case the name of the file is
1053 given using a format string. The formatting rules are as follows:
1053 given using a format string. The formatting rules are as follows:
1054
1054
1055 %% literal "%" character
1055 %% literal "%" character
1056 %H changeset hash (40 bytes of hexadecimal)
1056 %H changeset hash (40 bytes of hexadecimal)
1057 %N number of patches being generated
1057 %N number of patches being generated
1058 %R changeset revision number
1058 %R changeset revision number
1059 %b basename of the exporting repository
1059 %b basename of the exporting repository
1060 %h short-form changeset hash (12 bytes of hexadecimal)
1060 %h short-form changeset hash (12 bytes of hexadecimal)
1061 %n zero-padded sequence number, starting at 1
1061 %n zero-padded sequence number, starting at 1
1062 %r zero-padded changeset revision number
1062 %r zero-padded changeset revision number
1063
1063
1064 Without the -a option, export will avoid generating diffs of files
1064 Without the -a option, export will avoid generating diffs of files
1065 it detects as binary. With -a, export will generate a diff anyway,
1065 it detects as binary. With -a, export will generate a diff anyway,
1066 probably with undesirable results.
1066 probably with undesirable results.
1067
1067
1068 With the --switch-parent option, the diff will be against the second
1068 With the --switch-parent option, the diff will be against the second
1069 parent. It can be useful to review a merge.
1069 parent. It can be useful to review a merge.
1070 """
1070 """
1071 if not changesets:
1071 if not changesets:
1072 raise util.Abort(_("export requires at least one changeset"))
1072 raise util.Abort(_("export requires at least one changeset"))
1073 revs = cmdutil.revrange(repo, changesets)
1073 revs = cmdutil.revrange(repo, changesets)
1074 if len(revs) > 1:
1074 if len(revs) > 1:
1075 ui.note(_('exporting patches:\n'))
1075 ui.note(_('exporting patches:\n'))
1076 else:
1076 else:
1077 ui.note(_('exporting patch:\n'))
1077 ui.note(_('exporting patch:\n'))
1078 patch.export(repo, revs, template=opts['output'],
1078 patch.export(repo, revs, template=opts['output'],
1079 switch_parent=opts['switch_parent'],
1079 switch_parent=opts['switch_parent'],
1080 opts=patch.diffopts(ui, opts))
1080 opts=patch.diffopts(ui, opts))
1081
1081
1082 def grep(ui, repo, pattern, *pats, **opts):
1082 def grep(ui, repo, pattern, *pats, **opts):
1083 """search for a pattern in specified files and revisions
1083 """search for a pattern in specified files and revisions
1084
1084
1085 Search revisions of files for a regular expression.
1085 Search revisions of files for a regular expression.
1086
1086
1087 This command behaves differently than Unix grep. It only accepts
1087 This command behaves differently than Unix grep. It only accepts
1088 Python/Perl regexps. It searches repository history, not the
1088 Python/Perl regexps. It searches repository history, not the
1089 working directory. It always prints the revision number in which
1089 working directory. It always prints the revision number in which
1090 a match appears.
1090 a match appears.
1091
1091
1092 By default, grep only prints output for the first revision of a
1092 By default, grep only prints output for the first revision of a
1093 file in which it finds a match. To get it to print every revision
1093 file in which it finds a match. To get it to print every revision
1094 that contains a change in match status ("-" for a match that
1094 that contains a change in match status ("-" for a match that
1095 becomes a non-match, or "+" for a non-match that becomes a match),
1095 becomes a non-match, or "+" for a non-match that becomes a match),
1096 use the --all flag.
1096 use the --all flag.
1097 """
1097 """
1098 reflags = 0
1098 reflags = 0
1099 if opts['ignore_case']:
1099 if opts['ignore_case']:
1100 reflags |= re.I
1100 reflags |= re.I
1101 try:
1101 try:
1102 regexp = re.compile(pattern, reflags)
1102 regexp = re.compile(pattern, reflags)
1103 except Exception, inst:
1103 except Exception, inst:
1104 ui.warn(_("grep: invalid match pattern: %s!\n") % inst)
1104 ui.warn(_("grep: invalid match pattern: %s!\n") % inst)
1105 return None
1105 return None
1106 sep, eol = ':', '\n'
1106 sep, eol = ':', '\n'
1107 if opts['print0']:
1107 if opts['print0']:
1108 sep = eol = '\0'
1108 sep = eol = '\0'
1109
1109
1110 fcache = {}
1110 fcache = {}
1111 def getfile(fn):
1111 def getfile(fn):
1112 if fn not in fcache:
1112 if fn not in fcache:
1113 fcache[fn] = repo.file(fn)
1113 fcache[fn] = repo.file(fn)
1114 return fcache[fn]
1114 return fcache[fn]
1115
1115
1116 def matchlines(body):
1116 def matchlines(body):
1117 begin = 0
1117 begin = 0
1118 linenum = 0
1118 linenum = 0
1119 while True:
1119 while True:
1120 match = regexp.search(body, begin)
1120 match = regexp.search(body, begin)
1121 if not match:
1121 if not match:
1122 break
1122 break
1123 mstart, mend = match.span()
1123 mstart, mend = match.span()
1124 linenum += body.count('\n', begin, mstart) + 1
1124 linenum += body.count('\n', begin, mstart) + 1
1125 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1125 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1126 lend = body.find('\n', mend)
1126 lend = body.find('\n', mend)
1127 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1127 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1128 begin = lend + 1
1128 begin = lend + 1
1129
1129
1130 class linestate(object):
1130 class linestate(object):
1131 def __init__(self, line, linenum, colstart, colend):
1131 def __init__(self, line, linenum, colstart, colend):
1132 self.line = line
1132 self.line = line
1133 self.linenum = linenum
1133 self.linenum = linenum
1134 self.colstart = colstart
1134 self.colstart = colstart
1135 self.colend = colend
1135 self.colend = colend
1136
1136
1137 def __eq__(self, other):
1137 def __eq__(self, other):
1138 return self.line == other.line
1138 return self.line == other.line
1139
1139
1140 matches = {}
1140 matches = {}
1141 copies = {}
1141 copies = {}
1142 def grepbody(fn, rev, body):
1142 def grepbody(fn, rev, body):
1143 matches[rev].setdefault(fn, [])
1143 matches[rev].setdefault(fn, [])
1144 m = matches[rev][fn]
1144 m = matches[rev][fn]
1145 for lnum, cstart, cend, line in matchlines(body):
1145 for lnum, cstart, cend, line in matchlines(body):
1146 s = linestate(line, lnum, cstart, cend)
1146 s = linestate(line, lnum, cstart, cend)
1147 m.append(s)
1147 m.append(s)
1148
1148
1149 def difflinestates(a, b):
1149 def difflinestates(a, b):
1150 sm = difflib.SequenceMatcher(None, a, b)
1150 sm = difflib.SequenceMatcher(None, a, b)
1151 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1151 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1152 if tag == 'insert':
1152 if tag == 'insert':
1153 for i in xrange(blo, bhi):
1153 for i in xrange(blo, bhi):
1154 yield ('+', b[i])
1154 yield ('+', b[i])
1155 elif tag == 'delete':
1155 elif tag == 'delete':
1156 for i in xrange(alo, ahi):
1156 for i in xrange(alo, ahi):
1157 yield ('-', a[i])
1157 yield ('-', a[i])
1158 elif tag == 'replace':
1158 elif tag == 'replace':
1159 for i in xrange(alo, ahi):
1159 for i in xrange(alo, ahi):
1160 yield ('-', a[i])
1160 yield ('-', a[i])
1161 for i in xrange(blo, bhi):
1161 for i in xrange(blo, bhi):
1162 yield ('+', b[i])
1162 yield ('+', b[i])
1163
1163
1164 prev = {}
1164 prev = {}
1165 def display(fn, rev, states, prevstates):
1165 def display(fn, rev, states, prevstates):
1166 found = False
1166 found = False
1167 filerevmatches = {}
1167 filerevmatches = {}
1168 r = prev.get(fn, -1)
1168 r = prev.get(fn, -1)
1169 if opts['all']:
1169 if opts['all']:
1170 iter = difflinestates(states, prevstates)
1170 iter = difflinestates(states, prevstates)
1171 else:
1171 else:
1172 iter = [('', l) for l in prevstates]
1172 iter = [('', l) for l in prevstates]
1173 for change, l in iter:
1173 for change, l in iter:
1174 cols = [fn, str(r)]
1174 cols = [fn, str(r)]
1175 if opts['line_number']:
1175 if opts['line_number']:
1176 cols.append(str(l.linenum))
1176 cols.append(str(l.linenum))
1177 if opts['all']:
1177 if opts['all']:
1178 cols.append(change)
1178 cols.append(change)
1179 if opts['user']:
1179 if opts['user']:
1180 cols.append(ui.shortuser(get(r)[1]))
1180 cols.append(ui.shortuser(get(r)[1]))
1181 if opts['files_with_matches']:
1181 if opts['files_with_matches']:
1182 c = (fn, r)
1182 c = (fn, r)
1183 if c in filerevmatches:
1183 if c in filerevmatches:
1184 continue
1184 continue
1185 filerevmatches[c] = 1
1185 filerevmatches[c] = 1
1186 else:
1186 else:
1187 cols.append(l.line)
1187 cols.append(l.line)
1188 ui.write(sep.join(cols), eol)
1188 ui.write(sep.join(cols), eol)
1189 found = True
1189 found = True
1190 return found
1190 return found
1191
1191
1192 fstate = {}
1192 fstate = {}
1193 skip = {}
1193 skip = {}
1194 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1194 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1195 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1195 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1196 found = False
1196 found = False
1197 follow = opts.get('follow')
1197 follow = opts.get('follow')
1198 for st, rev, fns in changeiter:
1198 for st, rev, fns in changeiter:
1199 if st == 'window':
1199 if st == 'window':
1200 matches.clear()
1200 matches.clear()
1201 elif st == 'add':
1201 elif st == 'add':
1202 mf = repo.changectx(rev).manifest()
1202 mf = repo.changectx(rev).manifest()
1203 matches[rev] = {}
1203 matches[rev] = {}
1204 for fn in fns:
1204 for fn in fns:
1205 if fn in skip:
1205 if fn in skip:
1206 continue
1206 continue
1207 try:
1207 try:
1208 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1208 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1209 fstate.setdefault(fn, [])
1209 fstate.setdefault(fn, [])
1210 if follow:
1210 if follow:
1211 copied = getfile(fn).renamed(mf[fn])
1211 copied = getfile(fn).renamed(mf[fn])
1212 if copied:
1212 if copied:
1213 copies.setdefault(rev, {})[fn] = copied[0]
1213 copies.setdefault(rev, {})[fn] = copied[0]
1214 except KeyError:
1214 except KeyError:
1215 pass
1215 pass
1216 elif st == 'iter':
1216 elif st == 'iter':
1217 states = matches[rev].items()
1217 states = matches[rev].items()
1218 states.sort()
1218 states.sort()
1219 for fn, m in states:
1219 for fn, m in states:
1220 copy = copies.get(rev, {}).get(fn)
1220 copy = copies.get(rev, {}).get(fn)
1221 if fn in skip:
1221 if fn in skip:
1222 if copy:
1222 if copy:
1223 skip[copy] = True
1223 skip[copy] = True
1224 continue
1224 continue
1225 if fn in prev or fstate[fn]:
1225 if fn in prev or fstate[fn]:
1226 r = display(fn, rev, m, fstate[fn])
1226 r = display(fn, rev, m, fstate[fn])
1227 found = found or r
1227 found = found or r
1228 if r and not opts['all']:
1228 if r and not opts['all']:
1229 skip[fn] = True
1229 skip[fn] = True
1230 if copy:
1230 if copy:
1231 skip[copy] = True
1231 skip[copy] = True
1232 fstate[fn] = m
1232 fstate[fn] = m
1233 if copy:
1233 if copy:
1234 fstate[copy] = m
1234 fstate[copy] = m
1235 prev[fn] = rev
1235 prev[fn] = rev
1236
1236
1237 fstate = fstate.items()
1237 fstate = fstate.items()
1238 fstate.sort()
1238 fstate.sort()
1239 for fn, state in fstate:
1239 for fn, state in fstate:
1240 if fn in skip:
1240 if fn in skip:
1241 continue
1241 continue
1242 if fn not in copies.get(prev[fn], {}):
1242 if fn not in copies.get(prev[fn], {}):
1243 found = display(fn, rev, {}, state) or found
1243 found = display(fn, rev, {}, state) or found
1244 return (not found and 1) or 0
1244 return (not found and 1) or 0
1245
1245
1246 def heads(ui, repo, *branchrevs, **opts):
1246 def heads(ui, repo, *branchrevs, **opts):
1247 """show current repository heads or show branch heads
1247 """show current repository heads or show branch heads
1248
1248
1249 With no arguments, show all repository head changesets.
1249 With no arguments, show all repository head changesets.
1250
1250
1251 If branch or revisions names are given this will show the heads of
1251 If branch or revisions names are given this will show the heads of
1252 the specified branches or the branches those revisions are tagged
1252 the specified branches or the branches those revisions are tagged
1253 with.
1253 with.
1254
1254
1255 Repository "heads" are changesets that don't have child
1255 Repository "heads" are changesets that don't have child
1256 changesets. They are where development generally takes place and
1256 changesets. They are where development generally takes place and
1257 are the usual targets for update and merge operations.
1257 are the usual targets for update and merge operations.
1258
1258
1259 Branch heads are changesets that have a given branch tag, but have
1259 Branch heads are changesets that have a given branch tag, but have
1260 no child changesets with that tag. They are usually where
1260 no child changesets with that tag. They are usually where
1261 development on the given branch takes place.
1261 development on the given branch takes place.
1262 """
1262 """
1263 if opts['rev']:
1263 if opts['rev']:
1264 start = repo.lookup(opts['rev'])
1264 start = repo.lookup(opts['rev'])
1265 else:
1265 else:
1266 start = None
1266 start = None
1267 if not branchrevs:
1267 if not branchrevs:
1268 # Assume we're looking repo-wide heads if no revs were specified.
1268 # Assume we're looking repo-wide heads if no revs were specified.
1269 heads = repo.heads(start)
1269 heads = repo.heads(start)
1270 else:
1270 else:
1271 heads = []
1271 heads = []
1272 visitedset = util.set()
1272 visitedset = util.set()
1273 for branchrev in branchrevs:
1273 for branchrev in branchrevs:
1274 branch = repo.changectx(branchrev).branch()
1274 branch = repo.changectx(branchrev).branch()
1275 if branch in visitedset:
1275 if branch in visitedset:
1276 continue
1276 continue
1277 visitedset.add(branch)
1277 visitedset.add(branch)
1278 bheads = repo.branchheads(branch, start)
1278 bheads = repo.branchheads(branch, start)
1279 if not bheads:
1279 if not bheads:
1280 if branch != branchrev:
1280 if branch != branchrev:
1281 ui.warn(_("no changes on branch %s containing %s are "
1281 ui.warn(_("no changes on branch %s containing %s are "
1282 "reachable from %s\n")
1282 "reachable from %s\n")
1283 % (branch, branchrev, opts['rev']))
1283 % (branch, branchrev, opts['rev']))
1284 else:
1284 else:
1285 ui.warn(_("no changes on branch %s are reachable from %s\n")
1285 ui.warn(_("no changes on branch %s are reachable from %s\n")
1286 % (branch, opts['rev']))
1286 % (branch, opts['rev']))
1287 heads.extend(bheads)
1287 heads.extend(bheads)
1288 if not heads:
1288 if not heads:
1289 return 1
1289 return 1
1290 displayer = cmdutil.show_changeset(ui, repo, opts)
1290 displayer = cmdutil.show_changeset(ui, repo, opts)
1291 for n in heads:
1291 for n in heads:
1292 displayer.show(changenode=n)
1292 displayer.show(changenode=n)
1293
1293
1294 def help_(ui, name=None, with_version=False):
1294 def help_(ui, name=None, with_version=False):
1295 """show help for a command, extension, or list of commands
1295 """show help for a command, extension, or list of commands
1296
1296
1297 With no arguments, print a list of commands and short help.
1297 With no arguments, print a list of commands and short help.
1298
1298
1299 Given a command name, print help for that command.
1299 Given a command name, print help for that command.
1300
1300
1301 Given an extension name, print help for that extension, and the
1301 Given an extension name, print help for that extension, and the
1302 commands it provides."""
1302 commands it provides."""
1303 option_lists = []
1303 option_lists = []
1304
1304
1305 def addglobalopts(aliases):
1305 def addglobalopts(aliases):
1306 if ui.verbose:
1306 if ui.verbose:
1307 option_lists.append((_("global options:"), globalopts))
1307 option_lists.append((_("global options:"), globalopts))
1308 if name == 'shortlist':
1308 if name == 'shortlist':
1309 option_lists.append((_('use "hg help" for the full list '
1309 option_lists.append((_('use "hg help" for the full list '
1310 'of commands'), ()))
1310 'of commands'), ()))
1311 else:
1311 else:
1312 if name == 'shortlist':
1312 if name == 'shortlist':
1313 msg = _('use "hg help" for the full list of commands '
1313 msg = _('use "hg help" for the full list of commands '
1314 'or "hg -v" for details')
1314 'or "hg -v" for details')
1315 elif aliases:
1315 elif aliases:
1316 msg = _('use "hg -v help%s" to show aliases and '
1316 msg = _('use "hg -v help%s" to show aliases and '
1317 'global options') % (name and " " + name or "")
1317 'global options') % (name and " " + name or "")
1318 else:
1318 else:
1319 msg = _('use "hg -v help %s" to show global options') % name
1319 msg = _('use "hg -v help %s" to show global options') % name
1320 option_lists.append((msg, ()))
1320 option_lists.append((msg, ()))
1321
1321
1322 def helpcmd(name):
1322 def helpcmd(name):
1323 if with_version:
1323 if with_version:
1324 version_(ui)
1324 version_(ui)
1325 ui.write('\n')
1325 ui.write('\n')
1326 aliases, i = cmdutil.findcmd(ui, name)
1326 aliases, i = cmdutil.findcmd(ui, name)
1327 # synopsis
1327 # synopsis
1328 ui.write("%s\n\n" % i[2])
1328 ui.write("%s\n\n" % i[2])
1329
1329
1330 # description
1330 # description
1331 doc = i[0].__doc__
1331 doc = i[0].__doc__
1332 if not doc:
1332 if not doc:
1333 doc = _("(No help text available)")
1333 doc = _("(No help text available)")
1334 if ui.quiet:
1334 if ui.quiet:
1335 doc = doc.splitlines(0)[0]
1335 doc = doc.splitlines(0)[0]
1336 ui.write("%s\n" % doc.rstrip())
1336 ui.write("%s\n" % doc.rstrip())
1337
1337
1338 if not ui.quiet:
1338 if not ui.quiet:
1339 # aliases
1339 # aliases
1340 if len(aliases) > 1:
1340 if len(aliases) > 1:
1341 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1341 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1342
1342
1343 # options
1343 # options
1344 if i[1]:
1344 if i[1]:
1345 option_lists.append((_("options:\n"), i[1]))
1345 option_lists.append((_("options:\n"), i[1]))
1346
1346
1347 addglobalopts(False)
1347 addglobalopts(False)
1348
1348
1349 def helplist(header, select=None):
1349 def helplist(header, select=None):
1350 h = {}
1350 h = {}
1351 cmds = {}
1351 cmds = {}
1352 for c, e in table.items():
1352 for c, e in table.items():
1353 f = c.split("|", 1)[0]
1353 f = c.split("|", 1)[0]
1354 if select and not select(f):
1354 if select and not select(f):
1355 continue
1355 continue
1356 if name == "shortlist" and not f.startswith("^"):
1356 if name == "shortlist" and not f.startswith("^"):
1357 continue
1357 continue
1358 f = f.lstrip("^")
1358 f = f.lstrip("^")
1359 if not ui.debugflag and f.startswith("debug"):
1359 if not ui.debugflag and f.startswith("debug"):
1360 continue
1360 continue
1361 doc = e[0].__doc__
1361 doc = e[0].__doc__
1362 if not doc:
1362 if not doc:
1363 doc = _("(No help text available)")
1363 doc = _("(No help text available)")
1364 h[f] = doc.splitlines(0)[0].rstrip()
1364 h[f] = doc.splitlines(0)[0].rstrip()
1365 cmds[f] = c.lstrip("^")
1365 cmds[f] = c.lstrip("^")
1366
1366
1367 if not h:
1367 if not h:
1368 ui.status(_('no commands defined\n'))
1368 ui.status(_('no commands defined\n'))
1369 return
1369 return
1370
1370
1371 ui.status(header)
1371 ui.status(header)
1372 fns = h.keys()
1372 fns = h.keys()
1373 fns.sort()
1373 fns.sort()
1374 m = max(map(len, fns))
1374 m = max(map(len, fns))
1375 for f in fns:
1375 for f in fns:
1376 if ui.verbose:
1376 if ui.verbose:
1377 commands = cmds[f].replace("|",", ")
1377 commands = cmds[f].replace("|",", ")
1378 ui.write(" %s:\n %s\n"%(commands, h[f]))
1378 ui.write(" %s:\n %s\n"%(commands, h[f]))
1379 else:
1379 else:
1380 ui.write(' %-*s %s\n' % (m, f, h[f]))
1380 ui.write(' %-*s %s\n' % (m, f, h[f]))
1381
1381
1382 if not ui.quiet:
1382 if not ui.quiet:
1383 addglobalopts(True)
1383 addglobalopts(True)
1384
1384
1385 def helptopic(name):
1385 def helptopic(name):
1386 v = None
1386 v = None
1387 for i in help.helptable:
1387 for i in help.helptable:
1388 l = i.split('|')
1388 l = i.split('|')
1389 if name in l:
1389 if name in l:
1390 v = i
1390 v = i
1391 header = l[-1]
1391 header = l[-1]
1392 if not v:
1392 if not v:
1393 raise cmdutil.UnknownCommand(name)
1393 raise cmdutil.UnknownCommand(name)
1394
1394
1395 # description
1395 # description
1396 doc = help.helptable[v]
1396 doc = help.helptable[v]
1397 if not doc:
1397 if not doc:
1398 doc = _("(No help text available)")
1398 doc = _("(No help text available)")
1399 if callable(doc):
1399 if callable(doc):
1400 doc = doc()
1400 doc = doc()
1401
1401
1402 ui.write("%s\n" % header)
1402 ui.write("%s\n" % header)
1403 ui.write("%s\n" % doc.rstrip())
1403 ui.write("%s\n" % doc.rstrip())
1404
1404
1405 def helpext(name):
1405 def helpext(name):
1406 try:
1406 try:
1407 mod = extensions.find(name)
1407 mod = extensions.find(name)
1408 except KeyError:
1408 except KeyError:
1409 raise cmdutil.UnknownCommand(name)
1409 raise cmdutil.UnknownCommand(name)
1410
1410
1411 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1411 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1412 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1412 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1413 for d in doc[1:]:
1413 for d in doc[1:]:
1414 ui.write(d, '\n')
1414 ui.write(d, '\n')
1415
1415
1416 ui.status('\n')
1416 ui.status('\n')
1417
1417
1418 try:
1418 try:
1419 ct = mod.cmdtable
1419 ct = mod.cmdtable
1420 except AttributeError:
1420 except AttributeError:
1421 ct = {}
1421 ct = {}
1422
1422
1423 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1423 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1424 helplist(_('list of commands:\n\n'), modcmds.has_key)
1424 helplist(_('list of commands:\n\n'), modcmds.has_key)
1425
1425
1426 if name and name != 'shortlist':
1426 if name and name != 'shortlist':
1427 i = None
1427 i = None
1428 for f in (helpcmd, helptopic, helpext):
1428 for f in (helpcmd, helptopic, helpext):
1429 try:
1429 try:
1430 f(name)
1430 f(name)
1431 i = None
1431 i = None
1432 break
1432 break
1433 except cmdutil.UnknownCommand, inst:
1433 except cmdutil.UnknownCommand, inst:
1434 i = inst
1434 i = inst
1435 if i:
1435 if i:
1436 raise i
1436 raise i
1437
1437
1438 else:
1438 else:
1439 # program name
1439 # program name
1440 if ui.verbose or with_version:
1440 if ui.verbose or with_version:
1441 version_(ui)
1441 version_(ui)
1442 else:
1442 else:
1443 ui.status(_("Mercurial Distributed SCM\n"))
1443 ui.status(_("Mercurial Distributed SCM\n"))
1444 ui.status('\n')
1444 ui.status('\n')
1445
1445
1446 # list of commands
1446 # list of commands
1447 if name == "shortlist":
1447 if name == "shortlist":
1448 header = _('basic commands:\n\n')
1448 header = _('basic commands:\n\n')
1449 else:
1449 else:
1450 header = _('list of commands:\n\n')
1450 header = _('list of commands:\n\n')
1451
1451
1452 helplist(header)
1452 helplist(header)
1453
1453
1454 # list all option lists
1454 # list all option lists
1455 opt_output = []
1455 opt_output = []
1456 for title, options in option_lists:
1456 for title, options in option_lists:
1457 opt_output.append(("\n%s" % title, None))
1457 opt_output.append(("\n%s" % title, None))
1458 for shortopt, longopt, default, desc in options:
1458 for shortopt, longopt, default, desc in options:
1459 if "DEPRECATED" in desc and not ui.verbose: continue
1459 if "DEPRECATED" in desc and not ui.verbose: continue
1460 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1460 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1461 longopt and " --%s" % longopt),
1461 longopt and " --%s" % longopt),
1462 "%s%s" % (desc,
1462 "%s%s" % (desc,
1463 default
1463 default
1464 and _(" (default: %s)") % default
1464 and _(" (default: %s)") % default
1465 or "")))
1465 or "")))
1466
1466
1467 if opt_output:
1467 if opt_output:
1468 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1468 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1469 for first, second in opt_output:
1469 for first, second in opt_output:
1470 if second:
1470 if second:
1471 ui.write(" %-*s %s\n" % (opts_len, first, second))
1471 ui.write(" %-*s %s\n" % (opts_len, first, second))
1472 else:
1472 else:
1473 ui.write("%s\n" % first)
1473 ui.write("%s\n" % first)
1474
1474
1475 def identify(ui, repo, source=None,
1475 def identify(ui, repo, source=None,
1476 rev=None, num=None, id=None, branch=None, tags=None):
1476 rev=None, num=None, id=None, branch=None, tags=None):
1477 """identify the working copy or specified revision
1477 """identify the working copy or specified revision
1478
1478
1479 With no revision, print a summary of the current state of the repo.
1479 With no revision, print a summary of the current state of the repo.
1480
1480
1481 With a path, do a lookup in another repository.
1481 With a path, do a lookup in another repository.
1482
1482
1483 This summary identifies the repository state using one or two parent
1483 This summary identifies the repository state using one or two parent
1484 hash identifiers, followed by a "+" if there are uncommitted changes
1484 hash identifiers, followed by a "+" if there are uncommitted changes
1485 in the working directory, a list of tags for this revision and a branch
1485 in the working directory, a list of tags for this revision and a branch
1486 name for non-default branches.
1486 name for non-default branches.
1487 """
1487 """
1488
1488
1489 hexfunc = ui.debugflag and hex or short
1489 hexfunc = ui.debugflag and hex or short
1490 default = not (num or id or branch or tags)
1490 default = not (num or id or branch or tags)
1491 output = []
1491 output = []
1492
1492
1493 if source:
1493 if source:
1494 source, revs = cmdutil.parseurl(ui.expandpath(source), [])
1494 source, revs, checkout = cmdutil.parseurl(ui.expandpath(source), [])
1495 srepo = hg.repository(ui, source)
1495 srepo = hg.repository(ui, source)
1496 if not rev and revs:
1496 if not rev and revs:
1497 rev = revs[0]
1497 rev = revs[0]
1498 if not rev:
1498 if not rev:
1499 rev = "tip"
1499 rev = "tip"
1500 if num or branch or tags:
1500 if num or branch or tags:
1501 raise util.Abort(
1501 raise util.Abort(
1502 "can't query remote revision number, branch, or tags")
1502 "can't query remote revision number, branch, or tags")
1503 output = [hexfunc(srepo.lookup(rev))]
1503 output = [hexfunc(srepo.lookup(rev))]
1504 elif not rev:
1504 elif not rev:
1505 ctx = repo.workingctx()
1505 ctx = repo.workingctx()
1506 parents = ctx.parents()
1506 parents = ctx.parents()
1507 changed = False
1507 changed = False
1508 if default or id or num:
1508 if default or id or num:
1509 changed = ctx.files() + ctx.deleted()
1509 changed = ctx.files() + ctx.deleted()
1510 if default or id:
1510 if default or id:
1511 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1511 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1512 (changed) and "+" or "")]
1512 (changed) and "+" or "")]
1513 if num:
1513 if num:
1514 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1514 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1515 (changed) and "+" or ""))
1515 (changed) and "+" or ""))
1516 else:
1516 else:
1517 ctx = repo.changectx(rev)
1517 ctx = repo.changectx(rev)
1518 if default or id:
1518 if default or id:
1519 output = [hexfunc(ctx.node())]
1519 output = [hexfunc(ctx.node())]
1520 if num:
1520 if num:
1521 output.append(str(ctx.rev()))
1521 output.append(str(ctx.rev()))
1522
1522
1523 if not source and default and not ui.quiet:
1523 if not source and default and not ui.quiet:
1524 b = util.tolocal(ctx.branch())
1524 b = util.tolocal(ctx.branch())
1525 if b != 'default':
1525 if b != 'default':
1526 output.append("(%s)" % b)
1526 output.append("(%s)" % b)
1527
1527
1528 # multiple tags for a single parent separated by '/'
1528 # multiple tags for a single parent separated by '/'
1529 t = "/".join(ctx.tags())
1529 t = "/".join(ctx.tags())
1530 if t:
1530 if t:
1531 output.append(t)
1531 output.append(t)
1532
1532
1533 if branch:
1533 if branch:
1534 output.append(util.tolocal(ctx.branch()))
1534 output.append(util.tolocal(ctx.branch()))
1535
1535
1536 if tags:
1536 if tags:
1537 output.extend(ctx.tags())
1537 output.extend(ctx.tags())
1538
1538
1539 ui.write("%s\n" % ' '.join(output))
1539 ui.write("%s\n" % ' '.join(output))
1540
1540
1541 def import_(ui, repo, patch1, *patches, **opts):
1541 def import_(ui, repo, patch1, *patches, **opts):
1542 """import an ordered set of patches
1542 """import an ordered set of patches
1543
1543
1544 Import a list of patches and commit them individually.
1544 Import a list of patches and commit them individually.
1545
1545
1546 If there are outstanding changes in the working directory, import
1546 If there are outstanding changes in the working directory, import
1547 will abort unless given the -f flag.
1547 will abort unless given the -f flag.
1548
1548
1549 You can import a patch straight from a mail message. Even patches
1549 You can import a patch straight from a mail message. Even patches
1550 as attachments work (body part must be type text/plain or
1550 as attachments work (body part must be type text/plain or
1551 text/x-patch to be used). From and Subject headers of email
1551 text/x-patch to be used). From and Subject headers of email
1552 message are used as default committer and commit message. All
1552 message are used as default committer and commit message. All
1553 text/plain body parts before first diff are added to commit
1553 text/plain body parts before first diff are added to commit
1554 message.
1554 message.
1555
1555
1556 If the imported patch was generated by hg export, user and description
1556 If the imported patch was generated by hg export, user and description
1557 from patch override values from message headers and body. Values
1557 from patch override values from message headers and body. Values
1558 given on command line with -m and -u override these.
1558 given on command line with -m and -u override these.
1559
1559
1560 If --exact is specified, import will set the working directory
1560 If --exact is specified, import will set the working directory
1561 to the parent of each patch before applying it, and will abort
1561 to the parent of each patch before applying it, and will abort
1562 if the resulting changeset has a different ID than the one
1562 if the resulting changeset has a different ID than the one
1563 recorded in the patch. This may happen due to character set
1563 recorded in the patch. This may happen due to character set
1564 problems or other deficiencies in the text patch format.
1564 problems or other deficiencies in the text patch format.
1565
1565
1566 To read a patch from standard input, use patch name "-".
1566 To read a patch from standard input, use patch name "-".
1567 """
1567 """
1568 patches = (patch1,) + patches
1568 patches = (patch1,) + patches
1569
1569
1570 if opts.get('exact') or not opts['force']:
1570 if opts.get('exact') or not opts['force']:
1571 cmdutil.bail_if_changed(repo)
1571 cmdutil.bail_if_changed(repo)
1572
1572
1573 d = opts["base"]
1573 d = opts["base"]
1574 strip = opts["strip"]
1574 strip = opts["strip"]
1575
1575
1576 wlock = repo.wlock()
1576 wlock = repo.wlock()
1577 lock = repo.lock()
1577 lock = repo.lock()
1578
1578
1579 for p in patches:
1579 for p in patches:
1580 pf = os.path.join(d, p)
1580 pf = os.path.join(d, p)
1581
1581
1582 if pf == '-':
1582 if pf == '-':
1583 ui.status(_("applying patch from stdin\n"))
1583 ui.status(_("applying patch from stdin\n"))
1584 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, sys.stdin)
1584 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, sys.stdin)
1585 else:
1585 else:
1586 ui.status(_("applying %s\n") % p)
1586 ui.status(_("applying %s\n") % p)
1587 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, file(pf, 'rb'))
1587 tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, file(pf, 'rb'))
1588
1588
1589 if tmpname is None:
1589 if tmpname is None:
1590 raise util.Abort(_('no diffs found'))
1590 raise util.Abort(_('no diffs found'))
1591
1591
1592 try:
1592 try:
1593 cmdline_message = cmdutil.logmessage(opts)
1593 cmdline_message = cmdutil.logmessage(opts)
1594 if cmdline_message:
1594 if cmdline_message:
1595 # pickup the cmdline msg
1595 # pickup the cmdline msg
1596 message = cmdline_message
1596 message = cmdline_message
1597 elif message:
1597 elif message:
1598 # pickup the patch msg
1598 # pickup the patch msg
1599 message = message.strip()
1599 message = message.strip()
1600 else:
1600 else:
1601 # launch the editor
1601 # launch the editor
1602 message = None
1602 message = None
1603 ui.debug(_('message:\n%s\n') % message)
1603 ui.debug(_('message:\n%s\n') % message)
1604
1604
1605 wp = repo.workingctx().parents()
1605 wp = repo.workingctx().parents()
1606 if opts.get('exact'):
1606 if opts.get('exact'):
1607 if not nodeid or not p1:
1607 if not nodeid or not p1:
1608 raise util.Abort(_('not a mercurial patch'))
1608 raise util.Abort(_('not a mercurial patch'))
1609 p1 = repo.lookup(p1)
1609 p1 = repo.lookup(p1)
1610 p2 = repo.lookup(p2 or hex(nullid))
1610 p2 = repo.lookup(p2 or hex(nullid))
1611
1611
1612 if p1 != wp[0].node():
1612 if p1 != wp[0].node():
1613 hg.clean(repo, p1, wlock=wlock)
1613 hg.clean(repo, p1, wlock=wlock)
1614 repo.dirstate.setparents(p1, p2)
1614 repo.dirstate.setparents(p1, p2)
1615 elif p2:
1615 elif p2:
1616 try:
1616 try:
1617 p1 = repo.lookup(p1)
1617 p1 = repo.lookup(p1)
1618 p2 = repo.lookup(p2)
1618 p2 = repo.lookup(p2)
1619 if p1 == wp[0].node():
1619 if p1 == wp[0].node():
1620 repo.dirstate.setparents(p1, p2)
1620 repo.dirstate.setparents(p1, p2)
1621 except hg.RepoError:
1621 except hg.RepoError:
1622 pass
1622 pass
1623 if opts.get('exact') or opts.get('import_branch'):
1623 if opts.get('exact') or opts.get('import_branch'):
1624 repo.dirstate.setbranch(branch or 'default')
1624 repo.dirstate.setbranch(branch or 'default')
1625
1625
1626 files = {}
1626 files = {}
1627 try:
1627 try:
1628 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1628 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1629 files=files)
1629 files=files)
1630 finally:
1630 finally:
1631 files = patch.updatedir(ui, repo, files, wlock=wlock)
1631 files = patch.updatedir(ui, repo, files, wlock=wlock)
1632 n = repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1632 n = repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1633 if opts.get('exact'):
1633 if opts.get('exact'):
1634 if hex(n) != nodeid:
1634 if hex(n) != nodeid:
1635 repo.rollback(wlock=wlock, lock=lock)
1635 repo.rollback(wlock=wlock, lock=lock)
1636 raise util.Abort(_('patch is damaged or loses information'))
1636 raise util.Abort(_('patch is damaged or loses information'))
1637 finally:
1637 finally:
1638 os.unlink(tmpname)
1638 os.unlink(tmpname)
1639
1639
1640 def incoming(ui, repo, source="default", **opts):
1640 def incoming(ui, repo, source="default", **opts):
1641 """show new changesets found in source
1641 """show new changesets found in source
1642
1642
1643 Show new changesets found in the specified path/URL or the default
1643 Show new changesets found in the specified path/URL or the default
1644 pull location. These are the changesets that would be pulled if a pull
1644 pull location. These are the changesets that would be pulled if a pull
1645 was requested.
1645 was requested.
1646
1646
1647 For remote repository, using --bundle avoids downloading the changesets
1647 For remote repository, using --bundle avoids downloading the changesets
1648 twice if the incoming is followed by a pull.
1648 twice if the incoming is followed by a pull.
1649
1649
1650 See pull for valid source format details.
1650 See pull for valid source format details.
1651 """
1651 """
1652 source, revs = cmdutil.parseurl(ui.expandpath(source), opts['rev'])
1652 source, revs, checkout = cmdutil.parseurl(ui.expandpath(source),
1653 opts['rev'])
1653 cmdutil.setremoteconfig(ui, opts)
1654 cmdutil.setremoteconfig(ui, opts)
1654
1655
1655 other = hg.repository(ui, source)
1656 other = hg.repository(ui, source)
1656 ui.status(_('comparing with %s\n') % source)
1657 ui.status(_('comparing with %s\n') % source)
1657 if revs:
1658 if revs:
1658 if 'lookup' in other.capabilities:
1659 if 'lookup' in other.capabilities:
1659 revs = [other.lookup(rev) for rev in revs]
1660 revs = [other.lookup(rev) for rev in revs]
1660 else:
1661 else:
1661 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1662 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1662 raise util.Abort(error)
1663 raise util.Abort(error)
1663 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1664 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1664 if not incoming:
1665 if not incoming:
1665 try:
1666 try:
1666 os.unlink(opts["bundle"])
1667 os.unlink(opts["bundle"])
1667 except:
1668 except:
1668 pass
1669 pass
1669 ui.status(_("no changes found\n"))
1670 ui.status(_("no changes found\n"))
1670 return 1
1671 return 1
1671
1672
1672 cleanup = None
1673 cleanup = None
1673 try:
1674 try:
1674 fname = opts["bundle"]
1675 fname = opts["bundle"]
1675 if fname or not other.local():
1676 if fname or not other.local():
1676 # create a bundle (uncompressed if other repo is not local)
1677 # create a bundle (uncompressed if other repo is not local)
1677 if revs is None:
1678 if revs is None:
1678 cg = other.changegroup(incoming, "incoming")
1679 cg = other.changegroup(incoming, "incoming")
1679 else:
1680 else:
1680 if 'changegroupsubset' not in other.capabilities:
1681 if 'changegroupsubset' not in other.capabilities:
1681 raise util.Abort(_("Partial incoming cannot be done because other repository doesn't support changegroupsubset."))
1682 raise util.Abort(_("Partial incoming cannot be done because other repository doesn't support changegroupsubset."))
1682 cg = other.changegroupsubset(incoming, revs, 'incoming')
1683 cg = other.changegroupsubset(incoming, revs, 'incoming')
1683 bundletype = other.local() and "HG10BZ" or "HG10UN"
1684 bundletype = other.local() and "HG10BZ" or "HG10UN"
1684 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1685 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1685 # keep written bundle?
1686 # keep written bundle?
1686 if opts["bundle"]:
1687 if opts["bundle"]:
1687 cleanup = None
1688 cleanup = None
1688 if not other.local():
1689 if not other.local():
1689 # use the created uncompressed bundlerepo
1690 # use the created uncompressed bundlerepo
1690 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1691 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1691
1692
1692 o = other.changelog.nodesbetween(incoming, revs)[0]
1693 o = other.changelog.nodesbetween(incoming, revs)[0]
1693 if opts['newest_first']:
1694 if opts['newest_first']:
1694 o.reverse()
1695 o.reverse()
1695 displayer = cmdutil.show_changeset(ui, other, opts)
1696 displayer = cmdutil.show_changeset(ui, other, opts)
1696 for n in o:
1697 for n in o:
1697 parents = [p for p in other.changelog.parents(n) if p != nullid]
1698 parents = [p for p in other.changelog.parents(n) if p != nullid]
1698 if opts['no_merges'] and len(parents) == 2:
1699 if opts['no_merges'] and len(parents) == 2:
1699 continue
1700 continue
1700 displayer.show(changenode=n)
1701 displayer.show(changenode=n)
1701 finally:
1702 finally:
1702 if hasattr(other, 'close'):
1703 if hasattr(other, 'close'):
1703 other.close()
1704 other.close()
1704 if cleanup:
1705 if cleanup:
1705 os.unlink(cleanup)
1706 os.unlink(cleanup)
1706
1707
1707 def init(ui, dest=".", **opts):
1708 def init(ui, dest=".", **opts):
1708 """create a new repository in the given directory
1709 """create a new repository in the given directory
1709
1710
1710 Initialize a new repository in the given directory. If the given
1711 Initialize a new repository in the given directory. If the given
1711 directory does not exist, it is created.
1712 directory does not exist, it is created.
1712
1713
1713 If no directory is given, the current directory is used.
1714 If no directory is given, the current directory is used.
1714
1715
1715 It is possible to specify an ssh:// URL as the destination.
1716 It is possible to specify an ssh:// URL as the destination.
1716 Look at the help text for the pull command for important details
1717 Look at the help text for the pull command for important details
1717 about ssh:// URLs.
1718 about ssh:// URLs.
1718 """
1719 """
1719 cmdutil.setremoteconfig(ui, opts)
1720 cmdutil.setremoteconfig(ui, opts)
1720 hg.repository(ui, dest, create=1)
1721 hg.repository(ui, dest, create=1)
1721
1722
1722 def locate(ui, repo, *pats, **opts):
1723 def locate(ui, repo, *pats, **opts):
1723 """locate files matching specific patterns
1724 """locate files matching specific patterns
1724
1725
1725 Print all files under Mercurial control whose names match the
1726 Print all files under Mercurial control whose names match the
1726 given patterns.
1727 given patterns.
1727
1728
1728 This command searches the entire repository by default. To search
1729 This command searches the entire repository by default. To search
1729 just the current directory and its subdirectories, use
1730 just the current directory and its subdirectories, use
1730 "--include .".
1731 "--include .".
1731
1732
1732 If no patterns are given to match, this command prints all file
1733 If no patterns are given to match, this command prints all file
1733 names.
1734 names.
1734
1735
1735 If you want to feed the output of this command into the "xargs"
1736 If you want to feed the output of this command into the "xargs"
1736 command, use the "-0" option to both this command and "xargs".
1737 command, use the "-0" option to both this command and "xargs".
1737 This will avoid the problem of "xargs" treating single filenames
1738 This will avoid the problem of "xargs" treating single filenames
1738 that contain white space as multiple filenames.
1739 that contain white space as multiple filenames.
1739 """
1740 """
1740 end = opts['print0'] and '\0' or '\n'
1741 end = opts['print0'] and '\0' or '\n'
1741 rev = opts['rev']
1742 rev = opts['rev']
1742 if rev:
1743 if rev:
1743 node = repo.lookup(rev)
1744 node = repo.lookup(rev)
1744 else:
1745 else:
1745 node = None
1746 node = None
1746
1747
1747 ret = 1
1748 ret = 1
1748 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1749 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1749 badmatch=util.always,
1750 badmatch=util.always,
1750 default='relglob'):
1751 default='relglob'):
1751 if src == 'b':
1752 if src == 'b':
1752 continue
1753 continue
1753 if not node and repo.dirstate.state(abs) == '?':
1754 if not node and repo.dirstate.state(abs) == '?':
1754 continue
1755 continue
1755 if opts['fullpath']:
1756 if opts['fullpath']:
1756 ui.write(os.path.join(repo.root, abs), end)
1757 ui.write(os.path.join(repo.root, abs), end)
1757 else:
1758 else:
1758 ui.write(((pats and rel) or abs), end)
1759 ui.write(((pats and rel) or abs), end)
1759 ret = 0
1760 ret = 0
1760
1761
1761 return ret
1762 return ret
1762
1763
1763 def log(ui, repo, *pats, **opts):
1764 def log(ui, repo, *pats, **opts):
1764 """show revision history of entire repository or files
1765 """show revision history of entire repository or files
1765
1766
1766 Print the revision history of the specified files or the entire
1767 Print the revision history of the specified files or the entire
1767 project.
1768 project.
1768
1769
1769 File history is shown without following rename or copy history of
1770 File history is shown without following rename or copy history of
1770 files. Use -f/--follow with a file name to follow history across
1771 files. Use -f/--follow with a file name to follow history across
1771 renames and copies. --follow without a file name will only show
1772 renames and copies. --follow without a file name will only show
1772 ancestors or descendants of the starting revision. --follow-first
1773 ancestors or descendants of the starting revision. --follow-first
1773 only follows the first parent of merge revisions.
1774 only follows the first parent of merge revisions.
1774
1775
1775 If no revision range is specified, the default is tip:0 unless
1776 If no revision range is specified, the default is tip:0 unless
1776 --follow is set, in which case the working directory parent is
1777 --follow is set, in which case the working directory parent is
1777 used as the starting revision.
1778 used as the starting revision.
1778
1779
1779 By default this command outputs: changeset id and hash, tags,
1780 By default this command outputs: changeset id and hash, tags,
1780 non-trivial parents, user, date and time, and a summary for each
1781 non-trivial parents, user, date and time, and a summary for each
1781 commit. When the -v/--verbose switch is used, the list of changed
1782 commit. When the -v/--verbose switch is used, the list of changed
1782 files and full commit message is shown.
1783 files and full commit message is shown.
1783
1784
1784 NOTE: log -p may generate unexpected diff output for merge
1785 NOTE: log -p may generate unexpected diff output for merge
1785 changesets, as it will compare the merge changeset against its
1786 changesets, as it will compare the merge changeset against its
1786 first parent only. Also, the files: list will only reflect files
1787 first parent only. Also, the files: list will only reflect files
1787 that are different from BOTH parents.
1788 that are different from BOTH parents.
1788
1789
1789 """
1790 """
1790
1791
1791 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1792 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1792 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1793 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1793
1794
1794 if opts['limit']:
1795 if opts['limit']:
1795 try:
1796 try:
1796 limit = int(opts['limit'])
1797 limit = int(opts['limit'])
1797 except ValueError:
1798 except ValueError:
1798 raise util.Abort(_('limit must be a positive integer'))
1799 raise util.Abort(_('limit must be a positive integer'))
1799 if limit <= 0: raise util.Abort(_('limit must be positive'))
1800 if limit <= 0: raise util.Abort(_('limit must be positive'))
1800 else:
1801 else:
1801 limit = sys.maxint
1802 limit = sys.maxint
1802 count = 0
1803 count = 0
1803
1804
1804 if opts['copies'] and opts['rev']:
1805 if opts['copies'] and opts['rev']:
1805 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1806 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1806 else:
1807 else:
1807 endrev = repo.changelog.count()
1808 endrev = repo.changelog.count()
1808 rcache = {}
1809 rcache = {}
1809 ncache = {}
1810 ncache = {}
1810 dcache = []
1811 dcache = []
1811 def getrenamed(fn, rev, man):
1812 def getrenamed(fn, rev, man):
1812 '''looks up all renames for a file (up to endrev) the first
1813 '''looks up all renames for a file (up to endrev) the first
1813 time the file is given. It indexes on the changerev and only
1814 time the file is given. It indexes on the changerev and only
1814 parses the manifest if linkrev != changerev.
1815 parses the manifest if linkrev != changerev.
1815 Returns rename info for fn at changerev rev.'''
1816 Returns rename info for fn at changerev rev.'''
1816 if fn not in rcache:
1817 if fn not in rcache:
1817 rcache[fn] = {}
1818 rcache[fn] = {}
1818 ncache[fn] = {}
1819 ncache[fn] = {}
1819 fl = repo.file(fn)
1820 fl = repo.file(fn)
1820 for i in xrange(fl.count()):
1821 for i in xrange(fl.count()):
1821 node = fl.node(i)
1822 node = fl.node(i)
1822 lr = fl.linkrev(node)
1823 lr = fl.linkrev(node)
1823 renamed = fl.renamed(node)
1824 renamed = fl.renamed(node)
1824 rcache[fn][lr] = renamed
1825 rcache[fn][lr] = renamed
1825 if renamed:
1826 if renamed:
1826 ncache[fn][node] = renamed
1827 ncache[fn][node] = renamed
1827 if lr >= endrev:
1828 if lr >= endrev:
1828 break
1829 break
1829 if rev in rcache[fn]:
1830 if rev in rcache[fn]:
1830 return rcache[fn][rev]
1831 return rcache[fn][rev]
1831 mr = repo.manifest.rev(man)
1832 mr = repo.manifest.rev(man)
1832 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1833 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1833 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1834 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1834 if not dcache or dcache[0] != man:
1835 if not dcache or dcache[0] != man:
1835 dcache[:] = [man, repo.manifest.readdelta(man)]
1836 dcache[:] = [man, repo.manifest.readdelta(man)]
1836 if fn in dcache[1]:
1837 if fn in dcache[1]:
1837 return ncache[fn].get(dcache[1][fn])
1838 return ncache[fn].get(dcache[1][fn])
1838 return None
1839 return None
1839
1840
1840 df = False
1841 df = False
1841 if opts["date"]:
1842 if opts["date"]:
1842 df = util.matchdate(opts["date"])
1843 df = util.matchdate(opts["date"])
1843
1844
1844 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1845 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1845 for st, rev, fns in changeiter:
1846 for st, rev, fns in changeiter:
1846 if st == 'add':
1847 if st == 'add':
1847 changenode = repo.changelog.node(rev)
1848 changenode = repo.changelog.node(rev)
1848 parents = [p for p in repo.changelog.parentrevs(rev)
1849 parents = [p for p in repo.changelog.parentrevs(rev)
1849 if p != nullrev]
1850 if p != nullrev]
1850 if opts['no_merges'] and len(parents) == 2:
1851 if opts['no_merges'] and len(parents) == 2:
1851 continue
1852 continue
1852 if opts['only_merges'] and len(parents) != 2:
1853 if opts['only_merges'] and len(parents) != 2:
1853 continue
1854 continue
1854
1855
1855 if df:
1856 if df:
1856 changes = get(rev)
1857 changes = get(rev)
1857 if not df(changes[2][0]):
1858 if not df(changes[2][0]):
1858 continue
1859 continue
1859
1860
1860 if opts['keyword']:
1861 if opts['keyword']:
1861 changes = get(rev)
1862 changes = get(rev)
1862 miss = 0
1863 miss = 0
1863 for k in [kw.lower() for kw in opts['keyword']]:
1864 for k in [kw.lower() for kw in opts['keyword']]:
1864 if not (k in changes[1].lower() or
1865 if not (k in changes[1].lower() or
1865 k in changes[4].lower() or
1866 k in changes[4].lower() or
1866 k in " ".join(changes[3]).lower()):
1867 k in " ".join(changes[3]).lower()):
1867 miss = 1
1868 miss = 1
1868 break
1869 break
1869 if miss:
1870 if miss:
1870 continue
1871 continue
1871
1872
1872 copies = []
1873 copies = []
1873 if opts.get('copies') and rev:
1874 if opts.get('copies') and rev:
1874 mf = get(rev)[0]
1875 mf = get(rev)[0]
1875 for fn in get(rev)[3]:
1876 for fn in get(rev)[3]:
1876 rename = getrenamed(fn, rev, mf)
1877 rename = getrenamed(fn, rev, mf)
1877 if rename:
1878 if rename:
1878 copies.append((fn, rename[0]))
1879 copies.append((fn, rename[0]))
1879 displayer.show(rev, changenode, copies=copies)
1880 displayer.show(rev, changenode, copies=copies)
1880 elif st == 'iter':
1881 elif st == 'iter':
1881 if count == limit: break
1882 if count == limit: break
1882 if displayer.flush(rev):
1883 if displayer.flush(rev):
1883 count += 1
1884 count += 1
1884
1885
1885 def manifest(ui, repo, rev=None):
1886 def manifest(ui, repo, rev=None):
1886 """output the current or given revision of the project manifest
1887 """output the current or given revision of the project manifest
1887
1888
1888 Print a list of version controlled files for the given revision.
1889 Print a list of version controlled files for the given revision.
1889 If no revision is given, the parent of the working directory is used,
1890 If no revision is given, the parent of the working directory is used,
1890 or tip if no revision is checked out.
1891 or tip if no revision is checked out.
1891
1892
1892 The manifest is the list of files being version controlled. If no revision
1893 The manifest is the list of files being version controlled. If no revision
1893 is given then the first parent of the working directory is used.
1894 is given then the first parent of the working directory is used.
1894
1895
1895 With -v flag, print file permissions. With --debug flag, print
1896 With -v flag, print file permissions. With --debug flag, print
1896 file revision hashes.
1897 file revision hashes.
1897 """
1898 """
1898
1899
1899 m = repo.changectx(rev).manifest()
1900 m = repo.changectx(rev).manifest()
1900 files = m.keys()
1901 files = m.keys()
1901 files.sort()
1902 files.sort()
1902
1903
1903 for f in files:
1904 for f in files:
1904 if ui.debugflag:
1905 if ui.debugflag:
1905 ui.write("%40s " % hex(m[f]))
1906 ui.write("%40s " % hex(m[f]))
1906 if ui.verbose:
1907 if ui.verbose:
1907 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1908 ui.write("%3s " % (m.execf(f) and "755" or "644"))
1908 ui.write("%s\n" % f)
1909 ui.write("%s\n" % f)
1909
1910
1910 def merge(ui, repo, node=None, force=None, rev=None):
1911 def merge(ui, repo, node=None, force=None, rev=None):
1911 """merge working directory with another revision
1912 """merge working directory with another revision
1912
1913
1913 Merge the contents of the current working directory and the
1914 Merge the contents of the current working directory and the
1914 requested revision. Files that changed between either parent are
1915 requested revision. Files that changed between either parent are
1915 marked as changed for the next commit and a commit must be
1916 marked as changed for the next commit and a commit must be
1916 performed before any further updates are allowed.
1917 performed before any further updates are allowed.
1917
1918
1918 If no revision is specified, the working directory's parent is a
1919 If no revision is specified, the working directory's parent is a
1919 head revision, and the repository contains exactly one other head,
1920 head revision, and the repository contains exactly one other head,
1920 the other head is merged with by default. Otherwise, an explicit
1921 the other head is merged with by default. Otherwise, an explicit
1921 revision to merge with must be provided.
1922 revision to merge with must be provided.
1922 """
1923 """
1923
1924
1924 if rev and node:
1925 if rev and node:
1925 raise util.Abort(_("please specify just one revision"))
1926 raise util.Abort(_("please specify just one revision"))
1926
1927
1927 if not node:
1928 if not node:
1928 node = rev
1929 node = rev
1929
1930
1930 if not node:
1931 if not node:
1931 heads = repo.heads()
1932 heads = repo.heads()
1932 if len(heads) > 2:
1933 if len(heads) > 2:
1933 raise util.Abort(_('repo has %d heads - '
1934 raise util.Abort(_('repo has %d heads - '
1934 'please merge with an explicit rev') %
1935 'please merge with an explicit rev') %
1935 len(heads))
1936 len(heads))
1936 if len(heads) == 1:
1937 if len(heads) == 1:
1937 raise util.Abort(_('there is nothing to merge - '
1938 raise util.Abort(_('there is nothing to merge - '
1938 'use "hg update" instead'))
1939 'use "hg update" instead'))
1939 parent = repo.dirstate.parents()[0]
1940 parent = repo.dirstate.parents()[0]
1940 if parent not in heads:
1941 if parent not in heads:
1941 raise util.Abort(_('working dir not at a head rev - '
1942 raise util.Abort(_('working dir not at a head rev - '
1942 'use "hg update" or merge with an explicit rev'))
1943 'use "hg update" or merge with an explicit rev'))
1943 node = parent == heads[0] and heads[-1] or heads[0]
1944 node = parent == heads[0] and heads[-1] or heads[0]
1944 return hg.merge(repo, node, force=force)
1945 return hg.merge(repo, node, force=force)
1945
1946
1946 def outgoing(ui, repo, dest=None, **opts):
1947 def outgoing(ui, repo, dest=None, **opts):
1947 """show changesets not found in destination
1948 """show changesets not found in destination
1948
1949
1949 Show changesets not found in the specified destination repository or
1950 Show changesets not found in the specified destination repository or
1950 the default push location. These are the changesets that would be pushed
1951 the default push location. These are the changesets that would be pushed
1951 if a push was requested.
1952 if a push was requested.
1952
1953
1953 See pull for valid destination format details.
1954 See pull for valid destination format details.
1954 """
1955 """
1955 dest, revs = cmdutil.parseurl(
1956 dest, revs, checkout = cmdutil.parseurl(
1956 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
1957 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
1957 cmdutil.setremoteconfig(ui, opts)
1958 cmdutil.setremoteconfig(ui, opts)
1958 if revs:
1959 if revs:
1959 revs = [repo.lookup(rev) for rev in revs]
1960 revs = [repo.lookup(rev) for rev in revs]
1960
1961
1961 other = hg.repository(ui, dest)
1962 other = hg.repository(ui, dest)
1962 ui.status(_('comparing with %s\n') % dest)
1963 ui.status(_('comparing with %s\n') % dest)
1963 o = repo.findoutgoing(other, force=opts['force'])
1964 o = repo.findoutgoing(other, force=opts['force'])
1964 if not o:
1965 if not o:
1965 ui.status(_("no changes found\n"))
1966 ui.status(_("no changes found\n"))
1966 return 1
1967 return 1
1967 o = repo.changelog.nodesbetween(o, revs)[0]
1968 o = repo.changelog.nodesbetween(o, revs)[0]
1968 if opts['newest_first']:
1969 if opts['newest_first']:
1969 o.reverse()
1970 o.reverse()
1970 displayer = cmdutil.show_changeset(ui, repo, opts)
1971 displayer = cmdutil.show_changeset(ui, repo, opts)
1971 for n in o:
1972 for n in o:
1972 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1973 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1973 if opts['no_merges'] and len(parents) == 2:
1974 if opts['no_merges'] and len(parents) == 2:
1974 continue
1975 continue
1975 displayer.show(changenode=n)
1976 displayer.show(changenode=n)
1976
1977
1977 def parents(ui, repo, file_=None, **opts):
1978 def parents(ui, repo, file_=None, **opts):
1978 """show the parents of the working dir or revision
1979 """show the parents of the working dir or revision
1979
1980
1980 Print the working directory's parent revisions. If a
1981 Print the working directory's parent revisions. If a
1981 revision is given via --rev, the parent of that revision
1982 revision is given via --rev, the parent of that revision
1982 will be printed. If a file argument is given, revision in
1983 will be printed. If a file argument is given, revision in
1983 which the file was last changed (before the working directory
1984 which the file was last changed (before the working directory
1984 revision or the argument to --rev if given) is printed.
1985 revision or the argument to --rev if given) is printed.
1985 """
1986 """
1986 rev = opts.get('rev')
1987 rev = opts.get('rev')
1987 if file_:
1988 if file_:
1988 files, match, anypats = cmdutil.matchpats(repo, (file_,), opts)
1989 files, match, anypats = cmdutil.matchpats(repo, (file_,), opts)
1989 if anypats or len(files) != 1:
1990 if anypats or len(files) != 1:
1990 raise util.Abort(_('can only specify an explicit file name'))
1991 raise util.Abort(_('can only specify an explicit file name'))
1991 ctx = repo.filectx(files[0], changeid=rev)
1992 ctx = repo.filectx(files[0], changeid=rev)
1992 elif rev:
1993 elif rev:
1993 ctx = repo.changectx(rev)
1994 ctx = repo.changectx(rev)
1994 else:
1995 else:
1995 ctx = repo.workingctx()
1996 ctx = repo.workingctx()
1996 p = [cp.node() for cp in ctx.parents()]
1997 p = [cp.node() for cp in ctx.parents()]
1997
1998
1998 displayer = cmdutil.show_changeset(ui, repo, opts)
1999 displayer = cmdutil.show_changeset(ui, repo, opts)
1999 for n in p:
2000 for n in p:
2000 if n != nullid:
2001 if n != nullid:
2001 displayer.show(changenode=n)
2002 displayer.show(changenode=n)
2002
2003
2003 def paths(ui, repo, search=None):
2004 def paths(ui, repo, search=None):
2004 """show definition of symbolic path names
2005 """show definition of symbolic path names
2005
2006
2006 Show definition of symbolic path name NAME. If no name is given, show
2007 Show definition of symbolic path name NAME. If no name is given, show
2007 definition of available names.
2008 definition of available names.
2008
2009
2009 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2010 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2010 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2011 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2011 """
2012 """
2012 if search:
2013 if search:
2013 for name, path in ui.configitems("paths"):
2014 for name, path in ui.configitems("paths"):
2014 if name == search:
2015 if name == search:
2015 ui.write("%s\n" % path)
2016 ui.write("%s\n" % path)
2016 return
2017 return
2017 ui.warn(_("not found!\n"))
2018 ui.warn(_("not found!\n"))
2018 return 1
2019 return 1
2019 else:
2020 else:
2020 for name, path in ui.configitems("paths"):
2021 for name, path in ui.configitems("paths"):
2021 ui.write("%s = %s\n" % (name, path))
2022 ui.write("%s = %s\n" % (name, path))
2022
2023
2023 def postincoming(ui, repo, modheads, optupdate):
2024 def postincoming(ui, repo, modheads, optupdate):
2024 if modheads == 0:
2025 if modheads == 0:
2025 return
2026 return
2026 if optupdate:
2027 if optupdate:
2027 if modheads <= 1:
2028 if modheads <= 1:
2028 return hg.update(repo, None)
2029 return hg.update(repo, None)
2029 else:
2030 else:
2030 ui.status(_("not updating, since new heads added\n"))
2031 ui.status(_("not updating, since new heads added\n"))
2031 if modheads > 1:
2032 if modheads > 1:
2032 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2033 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2033 else:
2034 else:
2034 ui.status(_("(run 'hg update' to get a working copy)\n"))
2035 ui.status(_("(run 'hg update' to get a working copy)\n"))
2035
2036
2036 def pull(ui, repo, source="default", **opts):
2037 def pull(ui, repo, source="default", **opts):
2037 """pull changes from the specified source
2038 """pull changes from the specified source
2038
2039
2039 Pull changes from a remote repository to a local one.
2040 Pull changes from a remote repository to a local one.
2040
2041
2041 This finds all changes from the repository at the specified path
2042 This finds all changes from the repository at the specified path
2042 or URL and adds them to the local repository. By default, this
2043 or URL and adds them to the local repository. By default, this
2043 does not update the copy of the project in the working directory.
2044 does not update the copy of the project in the working directory.
2044
2045
2045 Valid URLs are of the form:
2046 Valid URLs are of the form:
2046
2047
2047 local/filesystem/path (or file://local/filesystem/path)
2048 local/filesystem/path (or file://local/filesystem/path)
2048 http://[user@]host[:port]/[path]
2049 http://[user@]host[:port]/[path]
2049 https://[user@]host[:port]/[path]
2050 https://[user@]host[:port]/[path]
2050 ssh://[user@]host[:port]/[path]
2051 ssh://[user@]host[:port]/[path]
2051 static-http://host[:port]/[path]
2052 static-http://host[:port]/[path]
2052
2053
2053 Paths in the local filesystem can either point to Mercurial
2054 Paths in the local filesystem can either point to Mercurial
2054 repositories or to bundle files (as created by 'hg bundle' or
2055 repositories or to bundle files (as created by 'hg bundle' or
2055 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
2056 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
2056 allows access to a Mercurial repository where you simply use a web
2057 allows access to a Mercurial repository where you simply use a web
2057 server to publish the .hg directory as static content.
2058 server to publish the .hg directory as static content.
2058
2059
2059 An optional identifier after # indicates a particular branch, tag,
2060 An optional identifier after # indicates a particular branch, tag,
2060 or changeset to pull.
2061 or changeset to pull.
2061
2062
2062 Some notes about using SSH with Mercurial:
2063 Some notes about using SSH with Mercurial:
2063 - SSH requires an accessible shell account on the destination machine
2064 - SSH requires an accessible shell account on the destination machine
2064 and a copy of hg in the remote path or specified with as remotecmd.
2065 and a copy of hg in the remote path or specified with as remotecmd.
2065 - path is relative to the remote user's home directory by default.
2066 - path is relative to the remote user's home directory by default.
2066 Use an extra slash at the start of a path to specify an absolute path:
2067 Use an extra slash at the start of a path to specify an absolute path:
2067 ssh://example.com//tmp/repository
2068 ssh://example.com//tmp/repository
2068 - Mercurial doesn't use its own compression via SSH; the right thing
2069 - Mercurial doesn't use its own compression via SSH; the right thing
2069 to do is to configure it in your ~/.ssh/config, e.g.:
2070 to do is to configure it in your ~/.ssh/config, e.g.:
2070 Host *.mylocalnetwork.example.com
2071 Host *.mylocalnetwork.example.com
2071 Compression no
2072 Compression no
2072 Host *
2073 Host *
2073 Compression yes
2074 Compression yes
2074 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2075 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2075 with the --ssh command line option.
2076 with the --ssh command line option.
2076 """
2077 """
2077 source, revs = cmdutil.parseurl(ui.expandpath(source), opts['rev'])
2078 source, revs, checkout = cmdutil.parseurl(ui.expandpath(source),
2079 opts['rev'])
2078 cmdutil.setremoteconfig(ui, opts)
2080 cmdutil.setremoteconfig(ui, opts)
2079
2081
2080 other = hg.repository(ui, source)
2082 other = hg.repository(ui, source)
2081 ui.status(_('pulling from %s\n') % (source))
2083 ui.status(_('pulling from %s\n') % (source))
2082 if revs:
2084 if revs:
2083 if 'lookup' in other.capabilities:
2085 if 'lookup' in other.capabilities:
2084 revs = [other.lookup(rev) for rev in revs]
2086 revs = [other.lookup(rev) for rev in revs]
2085 else:
2087 else:
2086 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
2088 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
2087 raise util.Abort(error)
2089 raise util.Abort(error)
2088
2090
2089 modheads = repo.pull(other, heads=revs, force=opts['force'])
2091 modheads = repo.pull(other, heads=revs, force=opts['force'])
2090 return postincoming(ui, repo, modheads, opts['update'])
2092 return postincoming(ui, repo, modheads, opts['update'])
2091
2093
2092 def push(ui, repo, dest=None, **opts):
2094 def push(ui, repo, dest=None, **opts):
2093 """push changes to the specified destination
2095 """push changes to the specified destination
2094
2096
2095 Push changes from the local repository to the given destination.
2097 Push changes from the local repository to the given destination.
2096
2098
2097 This is the symmetrical operation for pull. It helps to move
2099 This is the symmetrical operation for pull. It helps to move
2098 changes from the current repository to a different one. If the
2100 changes from the current repository to a different one. If the
2099 destination is local this is identical to a pull in that directory
2101 destination is local this is identical to a pull in that directory
2100 from the current one.
2102 from the current one.
2101
2103
2102 By default, push will refuse to run if it detects the result would
2104 By default, push will refuse to run if it detects the result would
2103 increase the number of remote heads. This generally indicates the
2105 increase the number of remote heads. This generally indicates the
2104 the client has forgotten to sync and merge before pushing.
2106 the client has forgotten to sync and merge before pushing.
2105
2107
2106 Valid URLs are of the form:
2108 Valid URLs are of the form:
2107
2109
2108 local/filesystem/path (or file://local/filesystem/path)
2110 local/filesystem/path (or file://local/filesystem/path)
2109 ssh://[user@]host[:port]/[path]
2111 ssh://[user@]host[:port]/[path]
2110 http://[user@]host[:port]/[path]
2112 http://[user@]host[:port]/[path]
2111 https://[user@]host[:port]/[path]
2113 https://[user@]host[:port]/[path]
2112
2114
2113 An optional identifier after # indicates a particular branch, tag,
2115 An optional identifier after # indicates a particular branch, tag,
2114 or changeset to push.
2116 or changeset to push.
2115
2117
2116 Look at the help text for the pull command for important details
2118 Look at the help text for the pull command for important details
2117 about ssh:// URLs.
2119 about ssh:// URLs.
2118
2120
2119 Pushing to http:// and https:// URLs is only possible, if this
2121 Pushing to http:// and https:// URLs is only possible, if this
2120 feature is explicitly enabled on the remote Mercurial server.
2122 feature is explicitly enabled on the remote Mercurial server.
2121 """
2123 """
2122 dest, revs = cmdutil.parseurl(
2124 dest, revs, checkout = cmdutil.parseurl(
2123 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
2125 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
2124 cmdutil.setremoteconfig(ui, opts)
2126 cmdutil.setremoteconfig(ui, opts)
2125
2127
2126 other = hg.repository(ui, dest)
2128 other = hg.repository(ui, dest)
2127 ui.status('pushing to %s\n' % (dest))
2129 ui.status('pushing to %s\n' % (dest))
2128 if revs:
2130 if revs:
2129 revs = [repo.lookup(rev) for rev in revs]
2131 revs = [repo.lookup(rev) for rev in revs]
2130 r = repo.push(other, opts['force'], revs=revs)
2132 r = repo.push(other, opts['force'], revs=revs)
2131 return r == 0
2133 return r == 0
2132
2134
2133 def rawcommit(ui, repo, *pats, **opts):
2135 def rawcommit(ui, repo, *pats, **opts):
2134 """raw commit interface (DEPRECATED)
2136 """raw commit interface (DEPRECATED)
2135
2137
2136 (DEPRECATED)
2138 (DEPRECATED)
2137 Lowlevel commit, for use in helper scripts.
2139 Lowlevel commit, for use in helper scripts.
2138
2140
2139 This command is not intended to be used by normal users, as it is
2141 This command is not intended to be used by normal users, as it is
2140 primarily useful for importing from other SCMs.
2142 primarily useful for importing from other SCMs.
2141
2143
2142 This command is now deprecated and will be removed in a future
2144 This command is now deprecated and will be removed in a future
2143 release, please use debugsetparents and commit instead.
2145 release, please use debugsetparents and commit instead.
2144 """
2146 """
2145
2147
2146 ui.warn(_("(the rawcommit command is deprecated)\n"))
2148 ui.warn(_("(the rawcommit command is deprecated)\n"))
2147
2149
2148 message = cmdutil.logmessage(opts)
2150 message = cmdutil.logmessage(opts)
2149
2151
2150 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2152 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2151 if opts['files']:
2153 if opts['files']:
2152 files += open(opts['files']).read().splitlines()
2154 files += open(opts['files']).read().splitlines()
2153
2155
2154 parents = [repo.lookup(p) for p in opts['parent']]
2156 parents = [repo.lookup(p) for p in opts['parent']]
2155
2157
2156 try:
2158 try:
2157 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2159 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2158 except ValueError, inst:
2160 except ValueError, inst:
2159 raise util.Abort(str(inst))
2161 raise util.Abort(str(inst))
2160
2162
2161 def recover(ui, repo):
2163 def recover(ui, repo):
2162 """roll back an interrupted transaction
2164 """roll back an interrupted transaction
2163
2165
2164 Recover from an interrupted commit or pull.
2166 Recover from an interrupted commit or pull.
2165
2167
2166 This command tries to fix the repository status after an interrupted
2168 This command tries to fix the repository status after an interrupted
2167 operation. It should only be necessary when Mercurial suggests it.
2169 operation. It should only be necessary when Mercurial suggests it.
2168 """
2170 """
2169 if repo.recover():
2171 if repo.recover():
2170 return hg.verify(repo)
2172 return hg.verify(repo)
2171 return 1
2173 return 1
2172
2174
2173 def remove(ui, repo, *pats, **opts):
2175 def remove(ui, repo, *pats, **opts):
2174 """remove the specified files on the next commit
2176 """remove the specified files on the next commit
2175
2177
2176 Schedule the indicated files for removal from the repository.
2178 Schedule the indicated files for removal from the repository.
2177
2179
2178 This only removes files from the current branch, not from the
2180 This only removes files from the current branch, not from the
2179 entire project history. If the files still exist in the working
2181 entire project history. If the files still exist in the working
2180 directory, they will be deleted from it. If invoked with --after,
2182 directory, they will be deleted from it. If invoked with --after,
2181 files are marked as removed, but not actually unlinked unless --force
2183 files are marked as removed, but not actually unlinked unless --force
2182 is also given. Without exact file names, --after will only mark
2184 is also given. Without exact file names, --after will only mark
2183 files as removed if they are no longer in the working directory.
2185 files as removed if they are no longer in the working directory.
2184
2186
2185 This command schedules the files to be removed at the next commit.
2187 This command schedules the files to be removed at the next commit.
2186 To undo a remove before that, see hg revert.
2188 To undo a remove before that, see hg revert.
2187
2189
2188 Modified files and added files are not removed by default. To
2190 Modified files and added files are not removed by default. To
2189 remove them, use the -f/--force option.
2191 remove them, use the -f/--force option.
2190 """
2192 """
2191 names = []
2193 names = []
2192 if not opts['after'] and not pats:
2194 if not opts['after'] and not pats:
2193 raise util.Abort(_('no files specified'))
2195 raise util.Abort(_('no files specified'))
2194 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2196 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2195 exact = dict.fromkeys(files)
2197 exact = dict.fromkeys(files)
2196 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2198 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2197 modified, added, removed, deleted, unknown = mardu
2199 modified, added, removed, deleted, unknown = mardu
2198 remove, forget = [], []
2200 remove, forget = [], []
2199 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2201 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2200 reason = None
2202 reason = None
2201 if abs in modified and not opts['force']:
2203 if abs in modified and not opts['force']:
2202 reason = _('is modified (use -f to force removal)')
2204 reason = _('is modified (use -f to force removal)')
2203 elif abs in added:
2205 elif abs in added:
2204 if opts['force']:
2206 if opts['force']:
2205 forget.append(abs)
2207 forget.append(abs)
2206 continue
2208 continue
2207 reason = _('has been marked for add (use -f to force removal)')
2209 reason = _('has been marked for add (use -f to force removal)')
2208 elif repo.dirstate.state(abs) == '?':
2210 elif repo.dirstate.state(abs) == '?':
2209 reason = _('is not managed')
2211 reason = _('is not managed')
2210 elif opts['after'] and not exact and abs not in deleted:
2212 elif opts['after'] and not exact and abs not in deleted:
2211 continue
2213 continue
2212 elif abs in removed:
2214 elif abs in removed:
2213 continue
2215 continue
2214 if reason:
2216 if reason:
2215 if exact:
2217 if exact:
2216 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2218 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2217 else:
2219 else:
2218 if ui.verbose or not exact:
2220 if ui.verbose or not exact:
2219 ui.status(_('removing %s\n') % rel)
2221 ui.status(_('removing %s\n') % rel)
2220 remove.append(abs)
2222 remove.append(abs)
2221 repo.forget(forget)
2223 repo.forget(forget)
2222 repo.remove(remove, unlink=opts['force'] or not opts['after'])
2224 repo.remove(remove, unlink=opts['force'] or not opts['after'])
2223
2225
2224 def rename(ui, repo, *pats, **opts):
2226 def rename(ui, repo, *pats, **opts):
2225 """rename files; equivalent of copy + remove
2227 """rename files; equivalent of copy + remove
2226
2228
2227 Mark dest as copies of sources; mark sources for deletion. If
2229 Mark dest as copies of sources; mark sources for deletion. If
2228 dest is a directory, copies are put in that directory. If dest is
2230 dest is a directory, copies are put in that directory. If dest is
2229 a file, there can only be one source.
2231 a file, there can only be one source.
2230
2232
2231 By default, this command copies the contents of files as they
2233 By default, this command copies the contents of files as they
2232 stand in the working directory. If invoked with --after, the
2234 stand in the working directory. If invoked with --after, the
2233 operation is recorded, but no copying is performed.
2235 operation is recorded, but no copying is performed.
2234
2236
2235 This command takes effect in the next commit. To undo a rename
2237 This command takes effect in the next commit. To undo a rename
2236 before that, see hg revert.
2238 before that, see hg revert.
2237 """
2239 """
2238 wlock = repo.wlock(0)
2240 wlock = repo.wlock(0)
2239 errs, copied = docopy(ui, repo, pats, opts, wlock)
2241 errs, copied = docopy(ui, repo, pats, opts, wlock)
2240 names = []
2242 names = []
2241 for abs, rel, exact in copied:
2243 for abs, rel, exact in copied:
2242 if ui.verbose or not exact:
2244 if ui.verbose or not exact:
2243 ui.status(_('removing %s\n') % rel)
2245 ui.status(_('removing %s\n') % rel)
2244 names.append(abs)
2246 names.append(abs)
2245 if not opts.get('dry_run'):
2247 if not opts.get('dry_run'):
2246 repo.remove(names, True, wlock=wlock)
2248 repo.remove(names, True, wlock=wlock)
2247 return errs
2249 return errs
2248
2250
2249 def revert(ui, repo, *pats, **opts):
2251 def revert(ui, repo, *pats, **opts):
2250 """revert files or dirs to their states as of some revision
2252 """revert files or dirs to their states as of some revision
2251
2253
2252 With no revision specified, revert the named files or directories
2254 With no revision specified, revert the named files or directories
2253 to the contents they had in the parent of the working directory.
2255 to the contents they had in the parent of the working directory.
2254 This restores the contents of the affected files to an unmodified
2256 This restores the contents of the affected files to an unmodified
2255 state and unschedules adds, removes, copies, and renames. If the
2257 state and unschedules adds, removes, copies, and renames. If the
2256 working directory has two parents, you must explicitly specify the
2258 working directory has two parents, you must explicitly specify the
2257 revision to revert to.
2259 revision to revert to.
2258
2260
2259 Modified files are saved with a .orig suffix before reverting.
2261 Modified files are saved with a .orig suffix before reverting.
2260 To disable these backups, use --no-backup.
2262 To disable these backups, use --no-backup.
2261
2263
2262 Using the -r option, revert the given files or directories to their
2264 Using the -r option, revert the given files or directories to their
2263 contents as of a specific revision. This can be helpful to "roll
2265 contents as of a specific revision. This can be helpful to "roll
2264 back" some or all of a change that should not have been committed.
2266 back" some or all of a change that should not have been committed.
2265
2267
2266 Revert modifies the working directory. It does not commit any
2268 Revert modifies the working directory. It does not commit any
2267 changes, or change the parent of the working directory. If you
2269 changes, or change the parent of the working directory. If you
2268 revert to a revision other than the parent of the working
2270 revert to a revision other than the parent of the working
2269 directory, the reverted files will thus appear modified
2271 directory, the reverted files will thus appear modified
2270 afterwards.
2272 afterwards.
2271
2273
2272 If a file has been deleted, it is restored. If the executable
2274 If a file has been deleted, it is restored. If the executable
2273 mode of a file was changed, it is reset.
2275 mode of a file was changed, it is reset.
2274
2276
2275 If names are given, all files matching the names are reverted.
2277 If names are given, all files matching the names are reverted.
2276
2278
2277 If no arguments are given, no files are reverted.
2279 If no arguments are given, no files are reverted.
2278 """
2280 """
2279
2281
2280 if opts["date"]:
2282 if opts["date"]:
2281 if opts["rev"]:
2283 if opts["rev"]:
2282 raise util.Abort(_("you can't specify a revision and a date"))
2284 raise util.Abort(_("you can't specify a revision and a date"))
2283 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2285 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2284
2286
2285 if not pats and not opts['all']:
2287 if not pats and not opts['all']:
2286 raise util.Abort(_('no files or directories specified; '
2288 raise util.Abort(_('no files or directories specified; '
2287 'use --all to revert the whole repo'))
2289 'use --all to revert the whole repo'))
2288
2290
2289 parent, p2 = repo.dirstate.parents()
2291 parent, p2 = repo.dirstate.parents()
2290 if not opts['rev'] and p2 != nullid:
2292 if not opts['rev'] and p2 != nullid:
2291 raise util.Abort(_('uncommitted merge - please provide a '
2293 raise util.Abort(_('uncommitted merge - please provide a '
2292 'specific revision'))
2294 'specific revision'))
2293 ctx = repo.changectx(opts['rev'])
2295 ctx = repo.changectx(opts['rev'])
2294 node = ctx.node()
2296 node = ctx.node()
2295 mf = ctx.manifest()
2297 mf = ctx.manifest()
2296 if node == parent:
2298 if node == parent:
2297 pmf = mf
2299 pmf = mf
2298 else:
2300 else:
2299 pmf = None
2301 pmf = None
2300
2302
2301 wlock = repo.wlock()
2303 wlock = repo.wlock()
2302
2304
2303 # need all matching names in dirstate and manifest of target rev,
2305 # need all matching names in dirstate and manifest of target rev,
2304 # so have to walk both. do not print errors if files exist in one
2306 # so have to walk both. do not print errors if files exist in one
2305 # but not other.
2307 # but not other.
2306
2308
2307 names = {}
2309 names = {}
2308 target_only = {}
2310 target_only = {}
2309
2311
2310 # walk dirstate.
2312 # walk dirstate.
2311
2313
2312 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2314 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2313 badmatch=mf.has_key):
2315 badmatch=mf.has_key):
2314 names[abs] = (rel, exact)
2316 names[abs] = (rel, exact)
2315 if src == 'b':
2317 if src == 'b':
2316 target_only[abs] = True
2318 target_only[abs] = True
2317
2319
2318 # walk target manifest.
2320 # walk target manifest.
2319
2321
2320 def badmatch(path):
2322 def badmatch(path):
2321 if path in names:
2323 if path in names:
2322 return True
2324 return True
2323 path_ = path + '/'
2325 path_ = path + '/'
2324 for f in names:
2326 for f in names:
2325 if f.startswith(path_):
2327 if f.startswith(path_):
2326 return True
2328 return True
2327 return False
2329 return False
2328
2330
2329 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2331 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2330 badmatch=badmatch):
2332 badmatch=badmatch):
2331 if abs in names or src == 'b':
2333 if abs in names or src == 'b':
2332 continue
2334 continue
2333 names[abs] = (rel, exact)
2335 names[abs] = (rel, exact)
2334 target_only[abs] = True
2336 target_only[abs] = True
2335
2337
2336 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2338 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2337 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2339 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2338
2340
2339 revert = ([], _('reverting %s\n'))
2341 revert = ([], _('reverting %s\n'))
2340 add = ([], _('adding %s\n'))
2342 add = ([], _('adding %s\n'))
2341 remove = ([], _('removing %s\n'))
2343 remove = ([], _('removing %s\n'))
2342 forget = ([], _('forgetting %s\n'))
2344 forget = ([], _('forgetting %s\n'))
2343 undelete = ([], _('undeleting %s\n'))
2345 undelete = ([], _('undeleting %s\n'))
2344 update = {}
2346 update = {}
2345
2347
2346 disptable = (
2348 disptable = (
2347 # dispatch table:
2349 # dispatch table:
2348 # file state
2350 # file state
2349 # action if in target manifest
2351 # action if in target manifest
2350 # action if not in target manifest
2352 # action if not in target manifest
2351 # make backup if in target manifest
2353 # make backup if in target manifest
2352 # make backup if not in target manifest
2354 # make backup if not in target manifest
2353 (modified, revert, remove, True, True),
2355 (modified, revert, remove, True, True),
2354 (added, revert, forget, True, False),
2356 (added, revert, forget, True, False),
2355 (removed, undelete, None, False, False),
2357 (removed, undelete, None, False, False),
2356 (deleted, revert, remove, False, False),
2358 (deleted, revert, remove, False, False),
2357 (unknown, add, None, True, False),
2359 (unknown, add, None, True, False),
2358 (target_only, add, None, False, False),
2360 (target_only, add, None, False, False),
2359 )
2361 )
2360
2362
2361 entries = names.items()
2363 entries = names.items()
2362 entries.sort()
2364 entries.sort()
2363
2365
2364 for abs, (rel, exact) in entries:
2366 for abs, (rel, exact) in entries:
2365 mfentry = mf.get(abs)
2367 mfentry = mf.get(abs)
2366 target = repo.wjoin(abs)
2368 target = repo.wjoin(abs)
2367 def handle(xlist, dobackup):
2369 def handle(xlist, dobackup):
2368 xlist[0].append(abs)
2370 xlist[0].append(abs)
2369 update[abs] = 1
2371 update[abs] = 1
2370 if dobackup and not opts['no_backup'] and util.lexists(target):
2372 if dobackup and not opts['no_backup'] and util.lexists(target):
2371 bakname = "%s.orig" % rel
2373 bakname = "%s.orig" % rel
2372 ui.note(_('saving current version of %s as %s\n') %
2374 ui.note(_('saving current version of %s as %s\n') %
2373 (rel, bakname))
2375 (rel, bakname))
2374 if not opts.get('dry_run'):
2376 if not opts.get('dry_run'):
2375 util.copyfile(target, bakname)
2377 util.copyfile(target, bakname)
2376 if ui.verbose or not exact:
2378 if ui.verbose or not exact:
2377 ui.status(xlist[1] % rel)
2379 ui.status(xlist[1] % rel)
2378 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2380 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2379 if abs not in table: continue
2381 if abs not in table: continue
2380 # file has changed in dirstate
2382 # file has changed in dirstate
2381 if mfentry:
2383 if mfentry:
2382 handle(hitlist, backuphit)
2384 handle(hitlist, backuphit)
2383 elif misslist is not None:
2385 elif misslist is not None:
2384 handle(misslist, backupmiss)
2386 handle(misslist, backupmiss)
2385 else:
2387 else:
2386 if exact: ui.warn(_('file not managed: %s\n') % rel)
2388 if exact: ui.warn(_('file not managed: %s\n') % rel)
2387 break
2389 break
2388 else:
2390 else:
2389 # file has not changed in dirstate
2391 # file has not changed in dirstate
2390 if node == parent:
2392 if node == parent:
2391 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2393 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2392 continue
2394 continue
2393 if pmf is None:
2395 if pmf is None:
2394 # only need parent manifest in this unlikely case,
2396 # only need parent manifest in this unlikely case,
2395 # so do not read by default
2397 # so do not read by default
2396 pmf = repo.changectx(parent).manifest()
2398 pmf = repo.changectx(parent).manifest()
2397 if abs in pmf:
2399 if abs in pmf:
2398 if mfentry:
2400 if mfentry:
2399 # if version of file is same in parent and target
2401 # if version of file is same in parent and target
2400 # manifests, do nothing
2402 # manifests, do nothing
2401 if pmf[abs] != mfentry:
2403 if pmf[abs] != mfentry:
2402 handle(revert, False)
2404 handle(revert, False)
2403 else:
2405 else:
2404 handle(remove, False)
2406 handle(remove, False)
2405
2407
2406 if not opts.get('dry_run'):
2408 if not opts.get('dry_run'):
2407 repo.dirstate.forget(forget[0])
2409 repo.dirstate.forget(forget[0])
2408 r = hg.revert(repo, node, update.has_key, wlock)
2410 r = hg.revert(repo, node, update.has_key, wlock)
2409 repo.dirstate.update(add[0], 'a')
2411 repo.dirstate.update(add[0], 'a')
2410 repo.dirstate.update(undelete[0], 'n')
2412 repo.dirstate.update(undelete[0], 'n')
2411 repo.dirstate.update(remove[0], 'r')
2413 repo.dirstate.update(remove[0], 'r')
2412 return r
2414 return r
2413
2415
2414 def rollback(ui, repo):
2416 def rollback(ui, repo):
2415 """roll back the last transaction in this repository
2417 """roll back the last transaction in this repository
2416
2418
2417 Roll back the last transaction in this repository, restoring the
2419 Roll back the last transaction in this repository, restoring the
2418 project to its state prior to the transaction.
2420 project to its state prior to the transaction.
2419
2421
2420 Transactions are used to encapsulate the effects of all commands
2422 Transactions are used to encapsulate the effects of all commands
2421 that create new changesets or propagate existing changesets into a
2423 that create new changesets or propagate existing changesets into a
2422 repository. For example, the following commands are transactional,
2424 repository. For example, the following commands are transactional,
2423 and their effects can be rolled back:
2425 and their effects can be rolled back:
2424
2426
2425 commit
2427 commit
2426 import
2428 import
2427 pull
2429 pull
2428 push (with this repository as destination)
2430 push (with this repository as destination)
2429 unbundle
2431 unbundle
2430
2432
2431 This command should be used with care. There is only one level of
2433 This command should be used with care. There is only one level of
2432 rollback, and there is no way to undo a rollback. It will also
2434 rollback, and there is no way to undo a rollback. It will also
2433 restore the dirstate at the time of the last transaction, which
2435 restore the dirstate at the time of the last transaction, which
2434 may lose subsequent dirstate changes.
2436 may lose subsequent dirstate changes.
2435
2437
2436 This command is not intended for use on public repositories. Once
2438 This command is not intended for use on public repositories. Once
2437 changes are visible for pull by other users, rolling a transaction
2439 changes are visible for pull by other users, rolling a transaction
2438 back locally is ineffective (someone else may already have pulled
2440 back locally is ineffective (someone else may already have pulled
2439 the changes). Furthermore, a race is possible with readers of the
2441 the changes). Furthermore, a race is possible with readers of the
2440 repository; for example an in-progress pull from the repository
2442 repository; for example an in-progress pull from the repository
2441 may fail if a rollback is performed.
2443 may fail if a rollback is performed.
2442 """
2444 """
2443 repo.rollback()
2445 repo.rollback()
2444
2446
2445 def root(ui, repo):
2447 def root(ui, repo):
2446 """print the root (top) of the current working dir
2448 """print the root (top) of the current working dir
2447
2449
2448 Print the root directory of the current repository.
2450 Print the root directory of the current repository.
2449 """
2451 """
2450 ui.write(repo.root + "\n")
2452 ui.write(repo.root + "\n")
2451
2453
2452 def serve(ui, repo, **opts):
2454 def serve(ui, repo, **opts):
2453 """export the repository via HTTP
2455 """export the repository via HTTP
2454
2456
2455 Start a local HTTP repository browser and pull server.
2457 Start a local HTTP repository browser and pull server.
2456
2458
2457 By default, the server logs accesses to stdout and errors to
2459 By default, the server logs accesses to stdout and errors to
2458 stderr. Use the "-A" and "-E" options to log to files.
2460 stderr. Use the "-A" and "-E" options to log to files.
2459 """
2461 """
2460
2462
2461 if opts["stdio"]:
2463 if opts["stdio"]:
2462 if repo is None:
2464 if repo is None:
2463 raise hg.RepoError(_("There is no Mercurial repository here"
2465 raise hg.RepoError(_("There is no Mercurial repository here"
2464 " (.hg not found)"))
2466 " (.hg not found)"))
2465 s = sshserver.sshserver(ui, repo)
2467 s = sshserver.sshserver(ui, repo)
2466 s.serve_forever()
2468 s.serve_forever()
2467
2469
2468 parentui = ui.parentui or ui
2470 parentui = ui.parentui or ui
2469 optlist = ("name templates style address port ipv6"
2471 optlist = ("name templates style address port ipv6"
2470 " accesslog errorlog webdir_conf")
2472 " accesslog errorlog webdir_conf")
2471 for o in optlist.split():
2473 for o in optlist.split():
2472 if opts[o]:
2474 if opts[o]:
2473 parentui.setconfig("web", o, str(opts[o]))
2475 parentui.setconfig("web", o, str(opts[o]))
2474 if (repo is not None) and (repo.ui != parentui):
2476 if (repo is not None) and (repo.ui != parentui):
2475 repo.ui.setconfig("web", o, str(opts[o]))
2477 repo.ui.setconfig("web", o, str(opts[o]))
2476
2478
2477 if repo is None and not ui.config("web", "webdir_conf"):
2479 if repo is None and not ui.config("web", "webdir_conf"):
2478 raise hg.RepoError(_("There is no Mercurial repository here"
2480 raise hg.RepoError(_("There is no Mercurial repository here"
2479 " (.hg not found)"))
2481 " (.hg not found)"))
2480
2482
2481 class service:
2483 class service:
2482 def init(self):
2484 def init(self):
2483 util.set_signal_handler()
2485 util.set_signal_handler()
2484 try:
2486 try:
2485 self.httpd = hgweb.server.create_server(parentui, repo)
2487 self.httpd = hgweb.server.create_server(parentui, repo)
2486 except socket.error, inst:
2488 except socket.error, inst:
2487 raise util.Abort(_('cannot start server: ') + inst.args[1])
2489 raise util.Abort(_('cannot start server: ') + inst.args[1])
2488
2490
2489 if not ui.verbose: return
2491 if not ui.verbose: return
2490
2492
2491 if self.httpd.port != 80:
2493 if self.httpd.port != 80:
2492 ui.status(_('listening at http://%s:%d/\n') %
2494 ui.status(_('listening at http://%s:%d/\n') %
2493 (self.httpd.addr, self.httpd.port))
2495 (self.httpd.addr, self.httpd.port))
2494 else:
2496 else:
2495 ui.status(_('listening at http://%s/\n') % self.httpd.addr)
2497 ui.status(_('listening at http://%s/\n') % self.httpd.addr)
2496
2498
2497 def run(self):
2499 def run(self):
2498 self.httpd.serve_forever()
2500 self.httpd.serve_forever()
2499
2501
2500 service = service()
2502 service = service()
2501
2503
2502 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2504 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2503
2505
2504 def status(ui, repo, *pats, **opts):
2506 def status(ui, repo, *pats, **opts):
2505 """show changed files in the working directory
2507 """show changed files in the working directory
2506
2508
2507 Show status of files in the repository. If names are given, only
2509 Show status of files in the repository. If names are given, only
2508 files that match are shown. Files that are clean or ignored, are
2510 files that match are shown. Files that are clean or ignored, are
2509 not listed unless -c (clean), -i (ignored) or -A is given.
2511 not listed unless -c (clean), -i (ignored) or -A is given.
2510
2512
2511 NOTE: status may appear to disagree with diff if permissions have
2513 NOTE: status may appear to disagree with diff if permissions have
2512 changed or a merge has occurred. The standard diff format does not
2514 changed or a merge has occurred. The standard diff format does not
2513 report permission changes and diff only reports changes relative
2515 report permission changes and diff only reports changes relative
2514 to one merge parent.
2516 to one merge parent.
2515
2517
2516 If one revision is given, it is used as the base revision.
2518 If one revision is given, it is used as the base revision.
2517 If two revisions are given, the difference between them is shown.
2519 If two revisions are given, the difference between them is shown.
2518
2520
2519 The codes used to show the status of files are:
2521 The codes used to show the status of files are:
2520 M = modified
2522 M = modified
2521 A = added
2523 A = added
2522 R = removed
2524 R = removed
2523 C = clean
2525 C = clean
2524 ! = deleted, but still tracked
2526 ! = deleted, but still tracked
2525 ? = not tracked
2527 ? = not tracked
2526 I = ignored (not shown by default)
2528 I = ignored (not shown by default)
2527 = the previous added file was copied from here
2529 = the previous added file was copied from here
2528 """
2530 """
2529
2531
2530 all = opts['all']
2532 all = opts['all']
2531 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2533 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2532
2534
2533 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2535 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2534 cwd = (pats and repo.getcwd()) or ''
2536 cwd = (pats and repo.getcwd()) or ''
2535 modified, added, removed, deleted, unknown, ignored, clean = [
2537 modified, added, removed, deleted, unknown, ignored, clean = [
2536 n for n in repo.status(node1=node1, node2=node2, files=files,
2538 n for n in repo.status(node1=node1, node2=node2, files=files,
2537 match=matchfn,
2539 match=matchfn,
2538 list_ignored=all or opts['ignored'],
2540 list_ignored=all or opts['ignored'],
2539 list_clean=all or opts['clean'])]
2541 list_clean=all or opts['clean'])]
2540
2542
2541 changetypes = (('modified', 'M', modified),
2543 changetypes = (('modified', 'M', modified),
2542 ('added', 'A', added),
2544 ('added', 'A', added),
2543 ('removed', 'R', removed),
2545 ('removed', 'R', removed),
2544 ('deleted', '!', deleted),
2546 ('deleted', '!', deleted),
2545 ('unknown', '?', unknown),
2547 ('unknown', '?', unknown),
2546 ('ignored', 'I', ignored))
2548 ('ignored', 'I', ignored))
2547
2549
2548 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2550 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2549
2551
2550 end = opts['print0'] and '\0' or '\n'
2552 end = opts['print0'] and '\0' or '\n'
2551
2553
2552 for opt, char, changes in ([ct for ct in explicit_changetypes
2554 for opt, char, changes in ([ct for ct in explicit_changetypes
2553 if all or opts[ct[0]]]
2555 if all or opts[ct[0]]]
2554 or changetypes):
2556 or changetypes):
2555 if opts['no_status']:
2557 if opts['no_status']:
2556 format = "%%s%s" % end
2558 format = "%%s%s" % end
2557 else:
2559 else:
2558 format = "%s %%s%s" % (char, end)
2560 format = "%s %%s%s" % (char, end)
2559
2561
2560 for f in changes:
2562 for f in changes:
2561 ui.write(format % repo.pathto(f, cwd))
2563 ui.write(format % repo.pathto(f, cwd))
2562 if ((all or opts.get('copies')) and not opts.get('no_status')):
2564 if ((all or opts.get('copies')) and not opts.get('no_status')):
2563 copied = repo.dirstate.copied(f)
2565 copied = repo.dirstate.copied(f)
2564 if copied:
2566 if copied:
2565 ui.write(' %s%s' % (repo.pathto(copied, cwd), end))
2567 ui.write(' %s%s' % (repo.pathto(copied, cwd), end))
2566
2568
2567 def tag(ui, repo, name, rev_=None, **opts):
2569 def tag(ui, repo, name, rev_=None, **opts):
2568 """add a tag for the current or given revision
2570 """add a tag for the current or given revision
2569
2571
2570 Name a particular revision using <name>.
2572 Name a particular revision using <name>.
2571
2573
2572 Tags are used to name particular revisions of the repository and are
2574 Tags are used to name particular revisions of the repository and are
2573 very useful to compare different revision, to go back to significant
2575 very useful to compare different revision, to go back to significant
2574 earlier versions or to mark branch points as releases, etc.
2576 earlier versions or to mark branch points as releases, etc.
2575
2577
2576 If no revision is given, the parent of the working directory is used,
2578 If no revision is given, the parent of the working directory is used,
2577 or tip if no revision is checked out.
2579 or tip if no revision is checked out.
2578
2580
2579 To facilitate version control, distribution, and merging of tags,
2581 To facilitate version control, distribution, and merging of tags,
2580 they are stored as a file named ".hgtags" which is managed
2582 they are stored as a file named ".hgtags" which is managed
2581 similarly to other project files and can be hand-edited if
2583 similarly to other project files and can be hand-edited if
2582 necessary. The file '.hg/localtags' is used for local tags (not
2584 necessary. The file '.hg/localtags' is used for local tags (not
2583 shared among repositories).
2585 shared among repositories).
2584 """
2586 """
2585 if name in ['tip', '.', 'null']:
2587 if name in ['tip', '.', 'null']:
2586 raise util.Abort(_("the name '%s' is reserved") % name)
2588 raise util.Abort(_("the name '%s' is reserved") % name)
2587 if rev_ is not None:
2589 if rev_ is not None:
2588 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2590 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2589 "please use 'hg tag [-r REV] NAME' instead\n"))
2591 "please use 'hg tag [-r REV] NAME' instead\n"))
2590 if opts['rev']:
2592 if opts['rev']:
2591 raise util.Abort(_("use only one form to specify the revision"))
2593 raise util.Abort(_("use only one form to specify the revision"))
2592 if opts['rev'] and opts['remove']:
2594 if opts['rev'] and opts['remove']:
2593 raise util.Abort(_("--rev and --remove are incompatible"))
2595 raise util.Abort(_("--rev and --remove are incompatible"))
2594 if opts['rev']:
2596 if opts['rev']:
2595 rev_ = opts['rev']
2597 rev_ = opts['rev']
2596 message = opts['message']
2598 message = opts['message']
2597 if opts['remove']:
2599 if opts['remove']:
2598 if not name in repo.tags():
2600 if not name in repo.tags():
2599 raise util.Abort(_('tag %s does not exist') % name)
2601 raise util.Abort(_('tag %s does not exist') % name)
2600 rev_ = nullid
2602 rev_ = nullid
2601 if not message:
2603 if not message:
2602 message = _('Removed tag %s') % name
2604 message = _('Removed tag %s') % name
2603 elif name in repo.tags() and not opts['force']:
2605 elif name in repo.tags() and not opts['force']:
2604 raise util.Abort(_('a tag named %s already exists (use -f to force)')
2606 raise util.Abort(_('a tag named %s already exists (use -f to force)')
2605 % name)
2607 % name)
2606 if not rev_ and repo.dirstate.parents()[1] != nullid:
2608 if not rev_ and repo.dirstate.parents()[1] != nullid:
2607 raise util.Abort(_('uncommitted merge - please provide a '
2609 raise util.Abort(_('uncommitted merge - please provide a '
2608 'specific revision'))
2610 'specific revision'))
2609 r = repo.changectx(rev_).node()
2611 r = repo.changectx(rev_).node()
2610
2612
2611 if not message:
2613 if not message:
2612 message = _('Added tag %s for changeset %s') % (name, short(r))
2614 message = _('Added tag %s for changeset %s') % (name, short(r))
2613
2615
2614 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2616 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2615
2617
2616 def tags(ui, repo):
2618 def tags(ui, repo):
2617 """list repository tags
2619 """list repository tags
2618
2620
2619 List the repository tags.
2621 List the repository tags.
2620
2622
2621 This lists both regular and local tags.
2623 This lists both regular and local tags.
2622 """
2624 """
2623
2625
2624 l = repo.tagslist()
2626 l = repo.tagslist()
2625 l.reverse()
2627 l.reverse()
2626 hexfunc = ui.debugflag and hex or short
2628 hexfunc = ui.debugflag and hex or short
2627 for t, n in l:
2629 for t, n in l:
2628 try:
2630 try:
2629 hn = hexfunc(n)
2631 hn = hexfunc(n)
2630 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2632 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2631 except revlog.LookupError:
2633 except revlog.LookupError:
2632 r = " ?:%s" % hn
2634 r = " ?:%s" % hn
2633 if ui.quiet:
2635 if ui.quiet:
2634 ui.write("%s\n" % t)
2636 ui.write("%s\n" % t)
2635 else:
2637 else:
2636 spaces = " " * (30 - util.locallen(t))
2638 spaces = " " * (30 - util.locallen(t))
2637 ui.write("%s%s %s\n" % (t, spaces, r))
2639 ui.write("%s%s %s\n" % (t, spaces, r))
2638
2640
2639 def tip(ui, repo, **opts):
2641 def tip(ui, repo, **opts):
2640 """show the tip revision
2642 """show the tip revision
2641
2643
2642 Show the tip revision.
2644 Show the tip revision.
2643 """
2645 """
2644 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2646 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2645
2647
2646 def unbundle(ui, repo, fname1, *fnames, **opts):
2648 def unbundle(ui, repo, fname1, *fnames, **opts):
2647 """apply one or more changegroup files
2649 """apply one or more changegroup files
2648
2650
2649 Apply one or more compressed changegroup files generated by the
2651 Apply one or more compressed changegroup files generated by the
2650 bundle command.
2652 bundle command.
2651 """
2653 """
2652 fnames = (fname1,) + fnames
2654 fnames = (fname1,) + fnames
2653 result = None
2655 result = None
2654 for fname in fnames:
2656 for fname in fnames:
2655 if os.path.exists(fname):
2657 if os.path.exists(fname):
2656 f = open(fname, "rb")
2658 f = open(fname, "rb")
2657 else:
2659 else:
2658 f = urllib.urlopen(fname)
2660 f = urllib.urlopen(fname)
2659 gen = changegroup.readbundle(f, fname)
2661 gen = changegroup.readbundle(f, fname)
2660 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2662 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2661
2663
2662 return postincoming(ui, repo, modheads, opts['update'])
2664 return postincoming(ui, repo, modheads, opts['update'])
2663
2665
2664 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2666 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2665 """update working directory
2667 """update working directory
2666
2668
2667 Update the working directory to the specified revision, or the
2669 Update the working directory to the specified revision, or the
2668 tip of the current branch if none is specified.
2670 tip of the current branch if none is specified.
2669
2671
2670 If there are no outstanding changes in the working directory and
2672 If there are no outstanding changes in the working directory and
2671 there is a linear relationship between the current version and the
2673 there is a linear relationship between the current version and the
2672 requested version, the result is the requested version.
2674 requested version, the result is the requested version.
2673
2675
2674 To merge the working directory with another revision, use the
2676 To merge the working directory with another revision, use the
2675 merge command.
2677 merge command.
2676
2678
2677 By default, update will refuse to run if doing so would require
2679 By default, update will refuse to run if doing so would require
2678 discarding local changes.
2680 discarding local changes.
2679 """
2681 """
2680 if rev and node:
2682 if rev and node:
2681 raise util.Abort(_("please specify just one revision"))
2683 raise util.Abort(_("please specify just one revision"))
2682
2684
2683 if not rev:
2685 if not rev:
2684 rev = node
2686 rev = node
2685
2687
2686 if date:
2688 if date:
2687 if rev:
2689 if rev:
2688 raise util.Abort(_("you can't specify a revision and a date"))
2690 raise util.Abort(_("you can't specify a revision and a date"))
2689 rev = cmdutil.finddate(ui, repo, date)
2691 rev = cmdutil.finddate(ui, repo, date)
2690
2692
2691 if clean:
2693 if clean:
2692 return hg.clean(repo, rev)
2694 return hg.clean(repo, rev)
2693 else:
2695 else:
2694 return hg.update(repo, rev)
2696 return hg.update(repo, rev)
2695
2697
2696 def verify(ui, repo):
2698 def verify(ui, repo):
2697 """verify the integrity of the repository
2699 """verify the integrity of the repository
2698
2700
2699 Verify the integrity of the current repository.
2701 Verify the integrity of the current repository.
2700
2702
2701 This will perform an extensive check of the repository's
2703 This will perform an extensive check of the repository's
2702 integrity, validating the hashes and checksums of each entry in
2704 integrity, validating the hashes and checksums of each entry in
2703 the changelog, manifest, and tracked files, as well as the
2705 the changelog, manifest, and tracked files, as well as the
2704 integrity of their crosslinks and indices.
2706 integrity of their crosslinks and indices.
2705 """
2707 """
2706 return hg.verify(repo)
2708 return hg.verify(repo)
2707
2709
2708 def version_(ui):
2710 def version_(ui):
2709 """output version and copyright information"""
2711 """output version and copyright information"""
2710 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2712 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2711 % version.get_version())
2713 % version.get_version())
2712 ui.status(_(
2714 ui.status(_(
2713 "\nCopyright (C) 2005-2007 Matt Mackall <mpm@selenic.com> and others\n"
2715 "\nCopyright (C) 2005-2007 Matt Mackall <mpm@selenic.com> and others\n"
2714 "This is free software; see the source for copying conditions. "
2716 "This is free software; see the source for copying conditions. "
2715 "There is NO\nwarranty; "
2717 "There is NO\nwarranty; "
2716 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2718 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2717 ))
2719 ))
2718
2720
2719 # Command options and aliases are listed here, alphabetically
2721 # Command options and aliases are listed here, alphabetically
2720
2722
2721 globalopts = [
2723 globalopts = [
2722 ('R', 'repository', '',
2724 ('R', 'repository', '',
2723 _('repository root directory or symbolic path name')),
2725 _('repository root directory or symbolic path name')),
2724 ('', 'cwd', '', _('change working directory')),
2726 ('', 'cwd', '', _('change working directory')),
2725 ('y', 'noninteractive', None,
2727 ('y', 'noninteractive', None,
2726 _('do not prompt, assume \'yes\' for any required answers')),
2728 _('do not prompt, assume \'yes\' for any required answers')),
2727 ('q', 'quiet', None, _('suppress output')),
2729 ('q', 'quiet', None, _('suppress output')),
2728 ('v', 'verbose', None, _('enable additional output')),
2730 ('v', 'verbose', None, _('enable additional output')),
2729 ('', 'config', [], _('set/override config option')),
2731 ('', 'config', [], _('set/override config option')),
2730 ('', 'debug', None, _('enable debugging output')),
2732 ('', 'debug', None, _('enable debugging output')),
2731 ('', 'debugger', None, _('start debugger')),
2733 ('', 'debugger', None, _('start debugger')),
2732 ('', 'encoding', util._encoding, _('set the charset encoding')),
2734 ('', 'encoding', util._encoding, _('set the charset encoding')),
2733 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2735 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2734 ('', 'lsprof', None, _('print improved command execution profile')),
2736 ('', 'lsprof', None, _('print improved command execution profile')),
2735 ('', 'traceback', None, _('print traceback on exception')),
2737 ('', 'traceback', None, _('print traceback on exception')),
2736 ('', 'time', None, _('time how long the command takes')),
2738 ('', 'time', None, _('time how long the command takes')),
2737 ('', 'profile', None, _('print command execution profile')),
2739 ('', 'profile', None, _('print command execution profile')),
2738 ('', 'version', None, _('output version information and exit')),
2740 ('', 'version', None, _('output version information and exit')),
2739 ('h', 'help', None, _('display help and exit')),
2741 ('h', 'help', None, _('display help and exit')),
2740 ]
2742 ]
2741
2743
2742 dryrunopts = [('n', 'dry-run', None,
2744 dryrunopts = [('n', 'dry-run', None,
2743 _('do not perform actions, just print output'))]
2745 _('do not perform actions, just print output'))]
2744
2746
2745 remoteopts = [
2747 remoteopts = [
2746 ('e', 'ssh', '', _('specify ssh command to use')),
2748 ('e', 'ssh', '', _('specify ssh command to use')),
2747 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2749 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2748 ]
2750 ]
2749
2751
2750 walkopts = [
2752 walkopts = [
2751 ('I', 'include', [], _('include names matching the given patterns')),
2753 ('I', 'include', [], _('include names matching the given patterns')),
2752 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2754 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2753 ]
2755 ]
2754
2756
2755 commitopts = [
2757 commitopts = [
2756 ('m', 'message', '', _('use <text> as commit message')),
2758 ('m', 'message', '', _('use <text> as commit message')),
2757 ('l', 'logfile', '', _('read commit message from <file>')),
2759 ('l', 'logfile', '', _('read commit message from <file>')),
2758 ]
2760 ]
2759
2761
2760 table = {
2762 table = {
2761 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2763 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2762 "addremove":
2764 "addremove":
2763 (addremove,
2765 (addremove,
2764 [('s', 'similarity', '',
2766 [('s', 'similarity', '',
2765 _('guess renamed files by similarity (0<=s<=100)')),
2767 _('guess renamed files by similarity (0<=s<=100)')),
2766 ] + walkopts + dryrunopts,
2768 ] + walkopts + dryrunopts,
2767 _('hg addremove [OPTION]... [FILE]...')),
2769 _('hg addremove [OPTION]... [FILE]...')),
2768 "^annotate":
2770 "^annotate":
2769 (annotate,
2771 (annotate,
2770 [('r', 'rev', '', _('annotate the specified revision')),
2772 [('r', 'rev', '', _('annotate the specified revision')),
2771 ('f', 'follow', None, _('follow file copies and renames')),
2773 ('f', 'follow', None, _('follow file copies and renames')),
2772 ('a', 'text', None, _('treat all files as text')),
2774 ('a', 'text', None, _('treat all files as text')),
2773 ('u', 'user', None, _('list the author')),
2775 ('u', 'user', None, _('list the author')),
2774 ('d', 'date', None, _('list the date')),
2776 ('d', 'date', None, _('list the date')),
2775 ('n', 'number', None, _('list the revision number (default)')),
2777 ('n', 'number', None, _('list the revision number (default)')),
2776 ('c', 'changeset', None, _('list the changeset')),
2778 ('c', 'changeset', None, _('list the changeset')),
2777 ] + walkopts,
2779 ] + walkopts,
2778 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] FILE...')),
2780 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] FILE...')),
2779 "archive":
2781 "archive":
2780 (archive,
2782 (archive,
2781 [('', 'no-decode', None, _('do not pass files through decoders')),
2783 [('', 'no-decode', None, _('do not pass files through decoders')),
2782 ('p', 'prefix', '', _('directory prefix for files in archive')),
2784 ('p', 'prefix', '', _('directory prefix for files in archive')),
2783 ('r', 'rev', '', _('revision to distribute')),
2785 ('r', 'rev', '', _('revision to distribute')),
2784 ('t', 'type', '', _('type of distribution to create')),
2786 ('t', 'type', '', _('type of distribution to create')),
2785 ] + walkopts,
2787 ] + walkopts,
2786 _('hg archive [OPTION]... DEST')),
2788 _('hg archive [OPTION]... DEST')),
2787 "backout":
2789 "backout":
2788 (backout,
2790 (backout,
2789 [('', 'merge', None,
2791 [('', 'merge', None,
2790 _('merge with old dirstate parent after backout')),
2792 _('merge with old dirstate parent after backout')),
2791 ('d', 'date', '', _('record datecode as commit date')),
2793 ('d', 'date', '', _('record datecode as commit date')),
2792 ('', 'parent', '', _('parent to choose when backing out merge')),
2794 ('', 'parent', '', _('parent to choose when backing out merge')),
2793 ('u', 'user', '', _('record user as committer')),
2795 ('u', 'user', '', _('record user as committer')),
2794 ('r', 'rev', '', _('revision to backout')),
2796 ('r', 'rev', '', _('revision to backout')),
2795 ] + walkopts + commitopts,
2797 ] + walkopts + commitopts,
2796 _('hg backout [OPTION]... [-r] REV')),
2798 _('hg backout [OPTION]... [-r] REV')),
2797 "branch":
2799 "branch":
2798 (branch,
2800 (branch,
2799 [('f', 'force', None,
2801 [('f', 'force', None,
2800 _('set branch name even if it shadows an existing branch'))],
2802 _('set branch name even if it shadows an existing branch'))],
2801 _('hg branch [NAME]')),
2803 _('hg branch [NAME]')),
2802 "branches":
2804 "branches":
2803 (branches,
2805 (branches,
2804 [('a', 'active', False,
2806 [('a', 'active', False,
2805 _('show only branches that have unmerged heads'))],
2807 _('show only branches that have unmerged heads'))],
2806 _('hg branches [-a]')),
2808 _('hg branches [-a]')),
2807 "bundle":
2809 "bundle":
2808 (bundle,
2810 (bundle,
2809 [('f', 'force', None,
2811 [('f', 'force', None,
2810 _('run even when remote repository is unrelated')),
2812 _('run even when remote repository is unrelated')),
2811 ('r', 'rev', [],
2813 ('r', 'rev', [],
2812 _('a changeset you would like to bundle')),
2814 _('a changeset you would like to bundle')),
2813 ('', 'base', [],
2815 ('', 'base', [],
2814 _('a base changeset to specify instead of a destination')),
2816 _('a base changeset to specify instead of a destination')),
2815 ] + remoteopts,
2817 ] + remoteopts,
2816 _('hg bundle [-f] [-r REV]... [--base REV]... FILE [DEST]')),
2818 _('hg bundle [-f] [-r REV]... [--base REV]... FILE [DEST]')),
2817 "cat":
2819 "cat":
2818 (cat,
2820 (cat,
2819 [('o', 'output', '', _('print output to file with formatted name')),
2821 [('o', 'output', '', _('print output to file with formatted name')),
2820 ('r', 'rev', '', _('print the given revision')),
2822 ('r', 'rev', '', _('print the given revision')),
2821 ] + walkopts,
2823 ] + walkopts,
2822 _('hg cat [OPTION]... FILE...')),
2824 _('hg cat [OPTION]... FILE...')),
2823 "^clone":
2825 "^clone":
2824 (clone,
2826 (clone,
2825 [('U', 'noupdate', None, _('do not update the new working directory')),
2827 [('U', 'noupdate', None, _('do not update the new working directory')),
2826 ('r', 'rev', [],
2828 ('r', 'rev', [],
2827 _('a changeset you would like to have after cloning')),
2829 _('a changeset you would like to have after cloning')),
2828 ('', 'pull', None, _('use pull protocol to copy metadata')),
2830 ('', 'pull', None, _('use pull protocol to copy metadata')),
2829 ('', 'uncompressed', None,
2831 ('', 'uncompressed', None,
2830 _('use uncompressed transfer (fast over LAN)')),
2832 _('use uncompressed transfer (fast over LAN)')),
2831 ] + remoteopts,
2833 ] + remoteopts,
2832 _('hg clone [OPTION]... SOURCE [DEST]')),
2834 _('hg clone [OPTION]... SOURCE [DEST]')),
2833 "^commit|ci":
2835 "^commit|ci":
2834 (commit,
2836 (commit,
2835 [('A', 'addremove', None,
2837 [('A', 'addremove', None,
2836 _('mark new/missing files as added/removed before committing')),
2838 _('mark new/missing files as added/removed before committing')),
2837 ('d', 'date', '', _('record datecode as commit date')),
2839 ('d', 'date', '', _('record datecode as commit date')),
2838 ('u', 'user', '', _('record user as commiter')),
2840 ('u', 'user', '', _('record user as commiter')),
2839 ] + walkopts + commitopts,
2841 ] + walkopts + commitopts,
2840 _('hg commit [OPTION]... [FILE]...')),
2842 _('hg commit [OPTION]... [FILE]...')),
2841 "copy|cp":
2843 "copy|cp":
2842 (copy,
2844 (copy,
2843 [('A', 'after', None, _('record a copy that has already occurred')),
2845 [('A', 'after', None, _('record a copy that has already occurred')),
2844 ('f', 'force', None,
2846 ('f', 'force', None,
2845 _('forcibly copy over an existing managed file')),
2847 _('forcibly copy over an existing managed file')),
2846 ] + walkopts + dryrunopts,
2848 ] + walkopts + dryrunopts,
2847 _('hg copy [OPTION]... [SOURCE]... DEST')),
2849 _('hg copy [OPTION]... [SOURCE]... DEST')),
2848 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2850 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2849 "debugcomplete":
2851 "debugcomplete":
2850 (debugcomplete,
2852 (debugcomplete,
2851 [('o', 'options', None, _('show the command options'))],
2853 [('o', 'options', None, _('show the command options'))],
2852 _('debugcomplete [-o] CMD')),
2854 _('debugcomplete [-o] CMD')),
2853 "debuginstall": (debuginstall, [], _('debuginstall')),
2855 "debuginstall": (debuginstall, [], _('debuginstall')),
2854 "debugrebuildstate":
2856 "debugrebuildstate":
2855 (debugrebuildstate,
2857 (debugrebuildstate,
2856 [('r', 'rev', '', _('revision to rebuild to'))],
2858 [('r', 'rev', '', _('revision to rebuild to'))],
2857 _('debugrebuildstate [-r REV] [REV]')),
2859 _('debugrebuildstate [-r REV] [REV]')),
2858 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2860 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2859 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2861 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2860 "debugstate": (debugstate, [], _('debugstate')),
2862 "debugstate": (debugstate, [], _('debugstate')),
2861 "debugdate":
2863 "debugdate":
2862 (debugdate,
2864 (debugdate,
2863 [('e', 'extended', None, _('try extended date formats'))],
2865 [('e', 'extended', None, _('try extended date formats'))],
2864 _('debugdate [-e] DATE [RANGE]')),
2866 _('debugdate [-e] DATE [RANGE]')),
2865 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2867 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2866 "debugindex": (debugindex, [], _('debugindex FILE')),
2868 "debugindex": (debugindex, [], _('debugindex FILE')),
2867 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2869 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2868 "debugrename":
2870 "debugrename":
2869 (debugrename,
2871 (debugrename,
2870 [('r', 'rev', '', _('revision to debug'))],
2872 [('r', 'rev', '', _('revision to debug'))],
2871 _('debugrename [-r REV] FILE')),
2873 _('debugrename [-r REV] FILE')),
2872 "debugwalk": (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2874 "debugwalk": (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2873 "^diff":
2875 "^diff":
2874 (diff,
2876 (diff,
2875 [('r', 'rev', [], _('revision')),
2877 [('r', 'rev', [], _('revision')),
2876 ('a', 'text', None, _('treat all files as text')),
2878 ('a', 'text', None, _('treat all files as text')),
2877 ('p', 'show-function', None,
2879 ('p', 'show-function', None,
2878 _('show which function each change is in')),
2880 _('show which function each change is in')),
2879 ('g', 'git', None, _('use git extended diff format')),
2881 ('g', 'git', None, _('use git extended diff format')),
2880 ('', 'nodates', None, _("don't include dates in diff headers")),
2882 ('', 'nodates', None, _("don't include dates in diff headers")),
2881 ('w', 'ignore-all-space', None,
2883 ('w', 'ignore-all-space', None,
2882 _('ignore white space when comparing lines')),
2884 _('ignore white space when comparing lines')),
2883 ('b', 'ignore-space-change', None,
2885 ('b', 'ignore-space-change', None,
2884 _('ignore changes in the amount of white space')),
2886 _('ignore changes in the amount of white space')),
2885 ('B', 'ignore-blank-lines', None,
2887 ('B', 'ignore-blank-lines', None,
2886 _('ignore changes whose lines are all blank')),
2888 _('ignore changes whose lines are all blank')),
2887 ] + walkopts,
2889 ] + walkopts,
2888 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2890 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2889 "^export":
2891 "^export":
2890 (export,
2892 (export,
2891 [('o', 'output', '', _('print output to file with formatted name')),
2893 [('o', 'output', '', _('print output to file with formatted name')),
2892 ('a', 'text', None, _('treat all files as text')),
2894 ('a', 'text', None, _('treat all files as text')),
2893 ('g', 'git', None, _('use git extended diff format')),
2895 ('g', 'git', None, _('use git extended diff format')),
2894 ('', 'nodates', None, _("don't include dates in diff headers")),
2896 ('', 'nodates', None, _("don't include dates in diff headers")),
2895 ('', 'switch-parent', None, _('diff against the second parent'))],
2897 ('', 'switch-parent', None, _('diff against the second parent'))],
2896 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2898 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2897 "grep":
2899 "grep":
2898 (grep,
2900 (grep,
2899 [('0', 'print0', None, _('end fields with NUL')),
2901 [('0', 'print0', None, _('end fields with NUL')),
2900 ('', 'all', None, _('print all revisions that match')),
2902 ('', 'all', None, _('print all revisions that match')),
2901 ('f', 'follow', None,
2903 ('f', 'follow', None,
2902 _('follow changeset history, or file history across copies and renames')),
2904 _('follow changeset history, or file history across copies and renames')),
2903 ('i', 'ignore-case', None, _('ignore case when matching')),
2905 ('i', 'ignore-case', None, _('ignore case when matching')),
2904 ('l', 'files-with-matches', None,
2906 ('l', 'files-with-matches', None,
2905 _('print only filenames and revs that match')),
2907 _('print only filenames and revs that match')),
2906 ('n', 'line-number', None, _('print matching line numbers')),
2908 ('n', 'line-number', None, _('print matching line numbers')),
2907 ('r', 'rev', [], _('search in given revision range')),
2909 ('r', 'rev', [], _('search in given revision range')),
2908 ('u', 'user', None, _('print user who committed change')),
2910 ('u', 'user', None, _('print user who committed change')),
2909 ] + walkopts,
2911 ] + walkopts,
2910 _('hg grep [OPTION]... PATTERN [FILE]...')),
2912 _('hg grep [OPTION]... PATTERN [FILE]...')),
2911 "heads":
2913 "heads":
2912 (heads,
2914 (heads,
2913 [('', 'style', '', _('display using template map file')),
2915 [('', 'style', '', _('display using template map file')),
2914 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2916 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2915 ('', 'template', '', _('display with template'))],
2917 ('', 'template', '', _('display with template'))],
2916 _('hg heads [-r REV] [REV]...')),
2918 _('hg heads [-r REV] [REV]...')),
2917 "help": (help_, [], _('hg help [COMMAND]')),
2919 "help": (help_, [], _('hg help [COMMAND]')),
2918 "identify|id":
2920 "identify|id":
2919 (identify,
2921 (identify,
2920 [('r', 'rev', '', _('identify the specified rev')),
2922 [('r', 'rev', '', _('identify the specified rev')),
2921 ('n', 'num', None, _('show local revision number')),
2923 ('n', 'num', None, _('show local revision number')),
2922 ('i', 'id', None, _('show global revision id')),
2924 ('i', 'id', None, _('show global revision id')),
2923 ('b', 'branch', None, _('show branch')),
2925 ('b', 'branch', None, _('show branch')),
2924 ('t', 'tags', None, _('show tags'))],
2926 ('t', 'tags', None, _('show tags'))],
2925 _('hg identify [-nibt] [-r REV] [SOURCE]')),
2927 _('hg identify [-nibt] [-r REV] [SOURCE]')),
2926 "import|patch":
2928 "import|patch":
2927 (import_,
2929 (import_,
2928 [('p', 'strip', 1,
2930 [('p', 'strip', 1,
2929 _('directory strip option for patch. This has the same\n'
2931 _('directory strip option for patch. This has the same\n'
2930 'meaning as the corresponding patch option')),
2932 'meaning as the corresponding patch option')),
2931 ('b', 'base', '', _('base path')),
2933 ('b', 'base', '', _('base path')),
2932 ('f', 'force', None,
2934 ('f', 'force', None,
2933 _('skip check for outstanding uncommitted changes')),
2935 _('skip check for outstanding uncommitted changes')),
2934 ('', 'exact', None,
2936 ('', 'exact', None,
2935 _('apply patch to the nodes from which it was generated')),
2937 _('apply patch to the nodes from which it was generated')),
2936 ('', 'import-branch', None,
2938 ('', 'import-branch', None,
2937 _('Use any branch information in patch (implied by --exact)'))] + commitopts,
2939 _('Use any branch information in patch (implied by --exact)'))] + commitopts,
2938 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2940 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2939 "incoming|in": (incoming,
2941 "incoming|in": (incoming,
2940 [('M', 'no-merges', None, _('do not show merges')),
2942 [('M', 'no-merges', None, _('do not show merges')),
2941 ('f', 'force', None,
2943 ('f', 'force', None,
2942 _('run even when remote repository is unrelated')),
2944 _('run even when remote repository is unrelated')),
2943 ('', 'style', '', _('display using template map file')),
2945 ('', 'style', '', _('display using template map file')),
2944 ('n', 'newest-first', None, _('show newest record first')),
2946 ('n', 'newest-first', None, _('show newest record first')),
2945 ('', 'bundle', '', _('file to store the bundles into')),
2947 ('', 'bundle', '', _('file to store the bundles into')),
2946 ('p', 'patch', None, _('show patch')),
2948 ('p', 'patch', None, _('show patch')),
2947 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2949 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2948 ('', 'template', '', _('display with template')),
2950 ('', 'template', '', _('display with template')),
2949 ] + remoteopts,
2951 ] + remoteopts,
2950 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2952 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2951 ' [--bundle FILENAME] [SOURCE]')),
2953 ' [--bundle FILENAME] [SOURCE]')),
2952 "^init":
2954 "^init":
2953 (init,
2955 (init,
2954 remoteopts,
2956 remoteopts,
2955 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2957 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2956 "locate":
2958 "locate":
2957 (locate,
2959 (locate,
2958 [('r', 'rev', '', _('search the repository as it stood at rev')),
2960 [('r', 'rev', '', _('search the repository as it stood at rev')),
2959 ('0', 'print0', None,
2961 ('0', 'print0', None,
2960 _('end filenames with NUL, for use with xargs')),
2962 _('end filenames with NUL, for use with xargs')),
2961 ('f', 'fullpath', None,
2963 ('f', 'fullpath', None,
2962 _('print complete paths from the filesystem root')),
2964 _('print complete paths from the filesystem root')),
2963 ] + walkopts,
2965 ] + walkopts,
2964 _('hg locate [OPTION]... [PATTERN]...')),
2966 _('hg locate [OPTION]... [PATTERN]...')),
2965 "^log|history":
2967 "^log|history":
2966 (log,
2968 (log,
2967 [('f', 'follow', None,
2969 [('f', 'follow', None,
2968 _('follow changeset history, or file history across copies and renames')),
2970 _('follow changeset history, or file history across copies and renames')),
2969 ('', 'follow-first', None,
2971 ('', 'follow-first', None,
2970 _('only follow the first parent of merge changesets')),
2972 _('only follow the first parent of merge changesets')),
2971 ('d', 'date', '', _('show revs matching date spec')),
2973 ('d', 'date', '', _('show revs matching date spec')),
2972 ('C', 'copies', None, _('show copied files')),
2974 ('C', 'copies', None, _('show copied files')),
2973 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
2975 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
2974 ('l', 'limit', '', _('limit number of changes displayed')),
2976 ('l', 'limit', '', _('limit number of changes displayed')),
2975 ('r', 'rev', [], _('show the specified revision or range')),
2977 ('r', 'rev', [], _('show the specified revision or range')),
2976 ('', 'removed', None, _('include revs where files were removed')),
2978 ('', 'removed', None, _('include revs where files were removed')),
2977 ('M', 'no-merges', None, _('do not show merges')),
2979 ('M', 'no-merges', None, _('do not show merges')),
2978 ('', 'style', '', _('display using template map file')),
2980 ('', 'style', '', _('display using template map file')),
2979 ('m', 'only-merges', None, _('show only merges')),
2981 ('m', 'only-merges', None, _('show only merges')),
2980 ('p', 'patch', None, _('show patch')),
2982 ('p', 'patch', None, _('show patch')),
2981 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2983 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2982 ('', 'template', '', _('display with template')),
2984 ('', 'template', '', _('display with template')),
2983 ] + walkopts,
2985 ] + walkopts,
2984 _('hg log [OPTION]... [FILE]')),
2986 _('hg log [OPTION]... [FILE]')),
2985 "manifest": (manifest, [], _('hg manifest [REV]')),
2987 "manifest": (manifest, [], _('hg manifest [REV]')),
2986 "^merge":
2988 "^merge":
2987 (merge,
2989 (merge,
2988 [('f', 'force', None, _('force a merge with outstanding changes')),
2990 [('f', 'force', None, _('force a merge with outstanding changes')),
2989 ('r', 'rev', '', _('revision to merge')),
2991 ('r', 'rev', '', _('revision to merge')),
2990 ],
2992 ],
2991 _('hg merge [-f] [[-r] REV]')),
2993 _('hg merge [-f] [[-r] REV]')),
2992 "outgoing|out": (outgoing,
2994 "outgoing|out": (outgoing,
2993 [('M', 'no-merges', None, _('do not show merges')),
2995 [('M', 'no-merges', None, _('do not show merges')),
2994 ('f', 'force', None,
2996 ('f', 'force', None,
2995 _('run even when remote repository is unrelated')),
2997 _('run even when remote repository is unrelated')),
2996 ('p', 'patch', None, _('show patch')),
2998 ('p', 'patch', None, _('show patch')),
2997 ('', 'style', '', _('display using template map file')),
2999 ('', 'style', '', _('display using template map file')),
2998 ('r', 'rev', [], _('a specific revision you would like to push')),
3000 ('r', 'rev', [], _('a specific revision you would like to push')),
2999 ('n', 'newest-first', None, _('show newest record first')),
3001 ('n', 'newest-first', None, _('show newest record first')),
3000 ('', 'template', '', _('display with template')),
3002 ('', 'template', '', _('display with template')),
3001 ] + remoteopts,
3003 ] + remoteopts,
3002 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3004 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3003 "^parents":
3005 "^parents":
3004 (parents,
3006 (parents,
3005 [('r', 'rev', '', _('show parents from the specified rev')),
3007 [('r', 'rev', '', _('show parents from the specified rev')),
3006 ('', 'style', '', _('display using template map file')),
3008 ('', 'style', '', _('display using template map file')),
3007 ('', 'template', '', _('display with template'))],
3009 ('', 'template', '', _('display with template'))],
3008 _('hg parents [-r REV] [FILE]')),
3010 _('hg parents [-r REV] [FILE]')),
3009 "paths": (paths, [], _('hg paths [NAME]')),
3011 "paths": (paths, [], _('hg paths [NAME]')),
3010 "^pull":
3012 "^pull":
3011 (pull,
3013 (pull,
3012 [('u', 'update', None,
3014 [('u', 'update', None,
3013 _('update to new tip if changesets were pulled')),
3015 _('update to new tip if changesets were pulled')),
3014 ('f', 'force', None,
3016 ('f', 'force', None,
3015 _('run even when remote repository is unrelated')),
3017 _('run even when remote repository is unrelated')),
3016 ('r', 'rev', [],
3018 ('r', 'rev', [],
3017 _('a specific revision up to which you would like to pull')),
3019 _('a specific revision up to which you would like to pull')),
3018 ] + remoteopts,
3020 ] + remoteopts,
3019 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3021 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3020 "^push":
3022 "^push":
3021 (push,
3023 (push,
3022 [('f', 'force', None, _('force push')),
3024 [('f', 'force', None, _('force push')),
3023 ('r', 'rev', [], _('a specific revision you would like to push')),
3025 ('r', 'rev', [], _('a specific revision you would like to push')),
3024 ] + remoteopts,
3026 ] + remoteopts,
3025 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3027 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3026 "debugrawcommit|rawcommit":
3028 "debugrawcommit|rawcommit":
3027 (rawcommit,
3029 (rawcommit,
3028 [('p', 'parent', [], _('parent')),
3030 [('p', 'parent', [], _('parent')),
3029 ('d', 'date', '', _('date code')),
3031 ('d', 'date', '', _('date code')),
3030 ('u', 'user', '', _('user')),
3032 ('u', 'user', '', _('user')),
3031 ('F', 'files', '', _('file list'))
3033 ('F', 'files', '', _('file list'))
3032 ] + commitopts,
3034 ] + commitopts,
3033 _('hg debugrawcommit [OPTION]... [FILE]...')),
3035 _('hg debugrawcommit [OPTION]... [FILE]...')),
3034 "recover": (recover, [], _('hg recover')),
3036 "recover": (recover, [], _('hg recover')),
3035 "^remove|rm":
3037 "^remove|rm":
3036 (remove,
3038 (remove,
3037 [('A', 'after', None, _('record remove that has already occurred')),
3039 [('A', 'after', None, _('record remove that has already occurred')),
3038 ('f', 'force', None, _('remove file even if modified')),
3040 ('f', 'force', None, _('remove file even if modified')),
3039 ] + walkopts,
3041 ] + walkopts,
3040 _('hg remove [OPTION]... FILE...')),
3042 _('hg remove [OPTION]... FILE...')),
3041 "rename|mv":
3043 "rename|mv":
3042 (rename,
3044 (rename,
3043 [('A', 'after', None, _('record a rename that has already occurred')),
3045 [('A', 'after', None, _('record a rename that has already occurred')),
3044 ('f', 'force', None,
3046 ('f', 'force', None,
3045 _('forcibly copy over an existing managed file')),
3047 _('forcibly copy over an existing managed file')),
3046 ] + walkopts + dryrunopts,
3048 ] + walkopts + dryrunopts,
3047 _('hg rename [OPTION]... SOURCE... DEST')),
3049 _('hg rename [OPTION]... SOURCE... DEST')),
3048 "^revert":
3050 "^revert":
3049 (revert,
3051 (revert,
3050 [('a', 'all', None, _('revert all changes when no arguments given')),
3052 [('a', 'all', None, _('revert all changes when no arguments given')),
3051 ('d', 'date', '', _('tipmost revision matching date')),
3053 ('d', 'date', '', _('tipmost revision matching date')),
3052 ('r', 'rev', '', _('revision to revert to')),
3054 ('r', 'rev', '', _('revision to revert to')),
3053 ('', 'no-backup', None, _('do not save backup copies of files')),
3055 ('', 'no-backup', None, _('do not save backup copies of files')),
3054 ] + walkopts + dryrunopts,
3056 ] + walkopts + dryrunopts,
3055 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3057 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3056 "rollback": (rollback, [], _('hg rollback')),
3058 "rollback": (rollback, [], _('hg rollback')),
3057 "root": (root, [], _('hg root')),
3059 "root": (root, [], _('hg root')),
3058 "showconfig|debugconfig":
3060 "showconfig|debugconfig":
3059 (showconfig,
3061 (showconfig,
3060 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3062 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3061 _('showconfig [-u] [NAME]...')),
3063 _('showconfig [-u] [NAME]...')),
3062 "^serve":
3064 "^serve":
3063 (serve,
3065 (serve,
3064 [('A', 'accesslog', '', _('name of access log file to write to')),
3066 [('A', 'accesslog', '', _('name of access log file to write to')),
3065 ('d', 'daemon', None, _('run server in background')),
3067 ('d', 'daemon', None, _('run server in background')),
3066 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3068 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3067 ('E', 'errorlog', '', _('name of error log file to write to')),
3069 ('E', 'errorlog', '', _('name of error log file to write to')),
3068 ('p', 'port', 0, _('port to use (default: 8000)')),
3070 ('p', 'port', 0, _('port to use (default: 8000)')),
3069 ('a', 'address', '', _('address to use')),
3071 ('a', 'address', '', _('address to use')),
3070 ('n', 'name', '',
3072 ('n', 'name', '',
3071 _('name to show in web pages (default: working dir)')),
3073 _('name to show in web pages (default: working dir)')),
3072 ('', 'webdir-conf', '', _('name of the webdir config file'
3074 ('', 'webdir-conf', '', _('name of the webdir config file'
3073 ' (serve more than one repo)')),
3075 ' (serve more than one repo)')),
3074 ('', 'pid-file', '', _('name of file to write process ID to')),
3076 ('', 'pid-file', '', _('name of file to write process ID to')),
3075 ('', 'stdio', None, _('for remote clients')),
3077 ('', 'stdio', None, _('for remote clients')),
3076 ('t', 'templates', '', _('web templates to use')),
3078 ('t', 'templates', '', _('web templates to use')),
3077 ('', 'style', '', _('template style to use')),
3079 ('', 'style', '', _('template style to use')),
3078 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
3080 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
3079 _('hg serve [OPTION]...')),
3081 _('hg serve [OPTION]...')),
3080 "^status|st":
3082 "^status|st":
3081 (status,
3083 (status,
3082 [('A', 'all', None, _('show status of all files')),
3084 [('A', 'all', None, _('show status of all files')),
3083 ('m', 'modified', None, _('show only modified files')),
3085 ('m', 'modified', None, _('show only modified files')),
3084 ('a', 'added', None, _('show only added files')),
3086 ('a', 'added', None, _('show only added files')),
3085 ('r', 'removed', None, _('show only removed files')),
3087 ('r', 'removed', None, _('show only removed files')),
3086 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3088 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3087 ('c', 'clean', None, _('show only files without changes')),
3089 ('c', 'clean', None, _('show only files without changes')),
3088 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3090 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3089 ('i', 'ignored', None, _('show only ignored files')),
3091 ('i', 'ignored', None, _('show only ignored files')),
3090 ('n', 'no-status', None, _('hide status prefix')),
3092 ('n', 'no-status', None, _('hide status prefix')),
3091 ('C', 'copies', None, _('show source of copied files')),
3093 ('C', 'copies', None, _('show source of copied files')),
3092 ('0', 'print0', None,
3094 ('0', 'print0', None,
3093 _('end filenames with NUL, for use with xargs')),
3095 _('end filenames with NUL, for use with xargs')),
3094 ('', 'rev', [], _('show difference from revision')),
3096 ('', 'rev', [], _('show difference from revision')),
3095 ] + walkopts,
3097 ] + walkopts,
3096 _('hg status [OPTION]... [FILE]...')),
3098 _('hg status [OPTION]... [FILE]...')),
3097 "tag":
3099 "tag":
3098 (tag,
3100 (tag,
3099 [('f', 'force', None, _('replace existing tag')),
3101 [('f', 'force', None, _('replace existing tag')),
3100 ('l', 'local', None, _('make the tag local')),
3102 ('l', 'local', None, _('make the tag local')),
3101 ('m', 'message', '', _('message for tag commit log entry')),
3103 ('m', 'message', '', _('message for tag commit log entry')),
3102 ('d', 'date', '', _('record datecode as commit date')),
3104 ('d', 'date', '', _('record datecode as commit date')),
3103 ('u', 'user', '', _('record user as commiter')),
3105 ('u', 'user', '', _('record user as commiter')),
3104 ('r', 'rev', '', _('revision to tag')),
3106 ('r', 'rev', '', _('revision to tag')),
3105 ('', 'remove', None, _('remove a tag'))],
3107 ('', 'remove', None, _('remove a tag'))],
3106 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3108 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3107 "tags": (tags, [], _('hg tags')),
3109 "tags": (tags, [], _('hg tags')),
3108 "tip":
3110 "tip":
3109 (tip,
3111 (tip,
3110 [('', 'style', '', _('display using template map file')),
3112 [('', 'style', '', _('display using template map file')),
3111 ('p', 'patch', None, _('show patch')),
3113 ('p', 'patch', None, _('show patch')),
3112 ('', 'template', '', _('display with template'))],
3114 ('', 'template', '', _('display with template'))],
3113 _('hg tip [-p]')),
3115 _('hg tip [-p]')),
3114 "unbundle":
3116 "unbundle":
3115 (unbundle,
3117 (unbundle,
3116 [('u', 'update', None,
3118 [('u', 'update', None,
3117 _('update to new tip if changesets were unbundled'))],
3119 _('update to new tip if changesets were unbundled'))],
3118 _('hg unbundle [-u] FILE...')),
3120 _('hg unbundle [-u] FILE...')),
3119 "^update|up|checkout|co":
3121 "^update|up|checkout|co":
3120 (update,
3122 (update,
3121 [('C', 'clean', None, _('overwrite locally modified files')),
3123 [('C', 'clean', None, _('overwrite locally modified files')),
3122 ('d', 'date', '', _('tipmost revision matching date')),
3124 ('d', 'date', '', _('tipmost revision matching date')),
3123 ('r', 'rev', '', _('revision'))],
3125 ('r', 'rev', '', _('revision'))],
3124 _('hg update [-C] [-d DATE] [[-r] REV]')),
3126 _('hg update [-C] [-d DATE] [[-r] REV]')),
3125 "verify": (verify, [], _('hg verify')),
3127 "verify": (verify, [], _('hg verify')),
3126 "version": (version_, [], _('hg version')),
3128 "version": (version_, [], _('hg version')),
3127 }
3129 }
3128
3130
3129 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3131 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3130 " debugindex debugindexdot debugdate debuginstall")
3132 " debugindex debugindexdot debugdate debuginstall")
3131 optionalrepo = ("paths serve showconfig")
3133 optionalrepo = ("paths serve showconfig")
3132
3134
3133 def dispatch(args):
3135 def dispatch(args):
3134 try:
3136 try:
3135 u = ui.ui(traceback='--traceback' in args)
3137 u = ui.ui(traceback='--traceback' in args)
3136 except util.Abort, inst:
3138 except util.Abort, inst:
3137 sys.stderr.write(_("abort: %s\n") % inst)
3139 sys.stderr.write(_("abort: %s\n") % inst)
3138 return -1
3140 return -1
3139 return cmdutil.runcatch(u, args)
3141 return cmdutil.runcatch(u, args)
3140
3142
3141 def run():
3143 def run():
3142 sys.exit(dispatch(sys.argv[1:]))
3144 sys.exit(dispatch(sys.argv[1:]))
@@ -1,290 +1,290
1 # hg.py - repository classes for mercurial
1 # hg.py - repository classes for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 from node import *
9 from node import *
10 from repo import *
10 from repo import *
11 from i18n import _
11 from i18n import _
12 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo
12 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo
13 import errno, lock, os, shutil, util, cmdutil
13 import errno, lock, os, shutil, util, cmdutil
14 import merge as _merge
14 import merge as _merge
15 import verify as _verify
15 import verify as _verify
16
16
17 def _local(path):
17 def _local(path):
18 return (os.path.isfile(util.drop_scheme('file', path)) and
18 return (os.path.isfile(util.drop_scheme('file', path)) and
19 bundlerepo or localrepo)
19 bundlerepo or localrepo)
20
20
21 schemes = {
21 schemes = {
22 'bundle': bundlerepo,
22 'bundle': bundlerepo,
23 'file': _local,
23 'file': _local,
24 'hg': httprepo,
24 'hg': httprepo,
25 'http': httprepo,
25 'http': httprepo,
26 'https': httprepo,
26 'https': httprepo,
27 'old-http': statichttprepo,
27 'old-http': statichttprepo,
28 'ssh': sshrepo,
28 'ssh': sshrepo,
29 'static-http': statichttprepo,
29 'static-http': statichttprepo,
30 }
30 }
31
31
32 def _lookup(path):
32 def _lookup(path):
33 scheme = 'file'
33 scheme = 'file'
34 if path:
34 if path:
35 c = path.find(':')
35 c = path.find(':')
36 if c > 0:
36 if c > 0:
37 scheme = path[:c]
37 scheme = path[:c]
38 thing = schemes.get(scheme) or schemes['file']
38 thing = schemes.get(scheme) or schemes['file']
39 try:
39 try:
40 return thing(path)
40 return thing(path)
41 except TypeError:
41 except TypeError:
42 return thing
42 return thing
43
43
44 def islocal(repo):
44 def islocal(repo):
45 '''return true if repo or path is local'''
45 '''return true if repo or path is local'''
46 if isinstance(repo, str):
46 if isinstance(repo, str):
47 try:
47 try:
48 return _lookup(repo).islocal(repo)
48 return _lookup(repo).islocal(repo)
49 except AttributeError:
49 except AttributeError:
50 return False
50 return False
51 return repo.local()
51 return repo.local()
52
52
53 repo_setup_hooks = []
53 repo_setup_hooks = []
54
54
55 def repository(ui, path='', create=False):
55 def repository(ui, path='', create=False):
56 """return a repository object for the specified path"""
56 """return a repository object for the specified path"""
57 repo = _lookup(path).instance(ui, path, create)
57 repo = _lookup(path).instance(ui, path, create)
58 ui = getattr(repo, "ui", ui)
58 ui = getattr(repo, "ui", ui)
59 for hook in repo_setup_hooks:
59 for hook in repo_setup_hooks:
60 hook(ui, repo)
60 hook(ui, repo)
61 return repo
61 return repo
62
62
63 def defaultdest(source):
63 def defaultdest(source):
64 '''return default destination of clone if none is given'''
64 '''return default destination of clone if none is given'''
65 return os.path.basename(os.path.normpath(source))
65 return os.path.basename(os.path.normpath(source))
66
66
67 def clone(ui, source, dest=None, pull=False, rev=None, update=True,
67 def clone(ui, source, dest=None, pull=False, rev=None, update=True,
68 stream=False):
68 stream=False):
69 """Make a copy of an existing repository.
69 """Make a copy of an existing repository.
70
70
71 Create a copy of an existing repository in a new directory. The
71 Create a copy of an existing repository in a new directory. The
72 source and destination are URLs, as passed to the repository
72 source and destination are URLs, as passed to the repository
73 function. Returns a pair of repository objects, the source and
73 function. Returns a pair of repository objects, the source and
74 newly created destination.
74 newly created destination.
75
75
76 The location of the source is added to the new repository's
76 The location of the source is added to the new repository's
77 .hg/hgrc file, as the default to be used for future pulls and
77 .hg/hgrc file, as the default to be used for future pulls and
78 pushes.
78 pushes.
79
79
80 If an exception is raised, the partly cloned/updated destination
80 If an exception is raised, the partly cloned/updated destination
81 repository will be deleted.
81 repository will be deleted.
82
82
83 Arguments:
83 Arguments:
84
84
85 source: repository object or URL
85 source: repository object or URL
86
86
87 dest: URL of destination repository to create (defaults to base
87 dest: URL of destination repository to create (defaults to base
88 name of source repository)
88 name of source repository)
89
89
90 pull: always pull from source repository, even in local case
90 pull: always pull from source repository, even in local case
91
91
92 stream: stream raw data uncompressed from repository (fast over
92 stream: stream raw data uncompressed from repository (fast over
93 LAN, slow over WAN)
93 LAN, slow over WAN)
94
94
95 rev: revision to clone up to (implies pull=True)
95 rev: revision to clone up to (implies pull=True)
96
96
97 update: update working directory after clone completes, if
97 update: update working directory after clone completes, if
98 destination is local repository
98 destination is local repository
99 """
99 """
100
100
101 origsource = source
101 origsource = source
102 source, rev = cmdutil.parseurl(ui.expandpath(source), rev)
102 source, rev, checkout = cmdutil.parseurl(ui.expandpath(source), rev)
103
103
104 if isinstance(source, str):
104 if isinstance(source, str):
105 src_repo = repository(ui, source)
105 src_repo = repository(ui, source)
106 else:
106 else:
107 src_repo = source
107 src_repo = source
108 source = src_repo.url()
108 source = src_repo.url()
109
109
110 if dest is None:
110 if dest is None:
111 dest = defaultdest(source)
111 dest = defaultdest(source)
112 ui.status(_("destination directory: %s\n") % dest)
112 ui.status(_("destination directory: %s\n") % dest)
113
113
114 def localpath(path):
114 def localpath(path):
115 if path.startswith('file://'):
115 if path.startswith('file://'):
116 return path[7:]
116 return path[7:]
117 if path.startswith('file:'):
117 if path.startswith('file:'):
118 return path[5:]
118 return path[5:]
119 return path
119 return path
120
120
121 dest = localpath(dest)
121 dest = localpath(dest)
122 source = localpath(source)
122 source = localpath(source)
123
123
124 if os.path.exists(dest):
124 if os.path.exists(dest):
125 raise util.Abort(_("destination '%s' already exists") % dest)
125 raise util.Abort(_("destination '%s' already exists") % dest)
126
126
127 class DirCleanup(object):
127 class DirCleanup(object):
128 def __init__(self, dir_):
128 def __init__(self, dir_):
129 self.rmtree = shutil.rmtree
129 self.rmtree = shutil.rmtree
130 self.dir_ = dir_
130 self.dir_ = dir_
131 def close(self):
131 def close(self):
132 self.dir_ = None
132 self.dir_ = None
133 def __del__(self):
133 def __del__(self):
134 if self.dir_:
134 if self.dir_:
135 self.rmtree(self.dir_, True)
135 self.rmtree(self.dir_, True)
136
136
137 dir_cleanup = None
137 dir_cleanup = None
138 if islocal(dest):
138 if islocal(dest):
139 dir_cleanup = DirCleanup(dest)
139 dir_cleanup = DirCleanup(dest)
140
140
141 abspath = origsource
141 abspath = origsource
142 copy = False
142 copy = False
143 if src_repo.local() and islocal(dest):
143 if src_repo.local() and islocal(dest):
144 abspath = os.path.abspath(origsource)
144 abspath = os.path.abspath(origsource)
145 copy = not pull and not rev
145 copy = not pull and not rev
146
146
147 src_lock, dest_lock = None, None
147 src_lock, dest_lock = None, None
148 if copy:
148 if copy:
149 try:
149 try:
150 # we use a lock here because if we race with commit, we
150 # we use a lock here because if we race with commit, we
151 # can end up with extra data in the cloned revlogs that's
151 # can end up with extra data in the cloned revlogs that's
152 # not pointed to by changesets, thus causing verify to
152 # not pointed to by changesets, thus causing verify to
153 # fail
153 # fail
154 src_lock = src_repo.lock()
154 src_lock = src_repo.lock()
155 except lock.LockException:
155 except lock.LockException:
156 copy = False
156 copy = False
157
157
158 if copy:
158 if copy:
159 def force_copy(src, dst):
159 def force_copy(src, dst):
160 try:
160 try:
161 util.copyfiles(src, dst)
161 util.copyfiles(src, dst)
162 except OSError, inst:
162 except OSError, inst:
163 if inst.errno != errno.ENOENT:
163 if inst.errno != errno.ENOENT:
164 raise
164 raise
165
165
166 src_store = os.path.realpath(src_repo.spath)
166 src_store = os.path.realpath(src_repo.spath)
167 if not os.path.exists(dest):
167 if not os.path.exists(dest):
168 os.mkdir(dest)
168 os.mkdir(dest)
169 dest_path = os.path.realpath(os.path.join(dest, ".hg"))
169 dest_path = os.path.realpath(os.path.join(dest, ".hg"))
170 os.mkdir(dest_path)
170 os.mkdir(dest_path)
171 if src_repo.spath != src_repo.path:
171 if src_repo.spath != src_repo.path:
172 dest_store = os.path.join(dest_path, "store")
172 dest_store = os.path.join(dest_path, "store")
173 os.mkdir(dest_store)
173 os.mkdir(dest_store)
174 else:
174 else:
175 dest_store = dest_path
175 dest_store = dest_path
176 # copy the requires file
176 # copy the requires file
177 force_copy(src_repo.join("requires"),
177 force_copy(src_repo.join("requires"),
178 os.path.join(dest_path, "requires"))
178 os.path.join(dest_path, "requires"))
179 # we lock here to avoid premature writing to the target
179 # we lock here to avoid premature writing to the target
180 dest_lock = lock.lock(os.path.join(dest_store, "lock"))
180 dest_lock = lock.lock(os.path.join(dest_store, "lock"))
181
181
182 files = ("data",
182 files = ("data",
183 "00manifest.d", "00manifest.i",
183 "00manifest.d", "00manifest.i",
184 "00changelog.d", "00changelog.i")
184 "00changelog.d", "00changelog.i")
185 for f in files:
185 for f in files:
186 src = os.path.join(src_store, f)
186 src = os.path.join(src_store, f)
187 dst = os.path.join(dest_store, f)
187 dst = os.path.join(dest_store, f)
188 force_copy(src, dst)
188 force_copy(src, dst)
189
189
190 # we need to re-init the repo after manually copying the data
190 # we need to re-init the repo after manually copying the data
191 # into it
191 # into it
192 dest_repo = repository(ui, dest)
192 dest_repo = repository(ui, dest)
193
193
194 else:
194 else:
195 dest_repo = repository(ui, dest, create=True)
195 dest_repo = repository(ui, dest, create=True)
196
196
197 revs = None
197 revs = None
198 if rev:
198 if rev:
199 if 'lookup' not in src_repo.capabilities:
199 if 'lookup' not in src_repo.capabilities:
200 raise util.Abort(_("src repository does not support revision "
200 raise util.Abort(_("src repository does not support revision "
201 "lookup and so doesn't support clone by "
201 "lookup and so doesn't support clone by "
202 "revision"))
202 "revision"))
203 revs = [src_repo.lookup(r) for r in rev]
203 revs = [src_repo.lookup(r) for r in rev]
204
204
205 if dest_repo.local():
205 if dest_repo.local():
206 dest_repo.clone(src_repo, heads=revs, stream=stream)
206 dest_repo.clone(src_repo, heads=revs, stream=stream)
207 elif src_repo.local():
207 elif src_repo.local():
208 src_repo.push(dest_repo, revs=revs)
208 src_repo.push(dest_repo, revs=revs)
209 else:
209 else:
210 raise util.Abort(_("clone from remote to remote not supported"))
210 raise util.Abort(_("clone from remote to remote not supported"))
211
211
212 if src_lock:
212 if src_lock:
213 src_lock.release()
213 src_lock.release()
214
214
215 if dir_cleanup:
215 if dir_cleanup:
216 dir_cleanup.close()
216 dir_cleanup.close()
217
217
218 if dest_repo.local():
218 if dest_repo.local():
219 fp = dest_repo.opener("hgrc", "w", text=True)
219 fp = dest_repo.opener("hgrc", "w", text=True)
220 fp.write("[paths]\n")
220 fp.write("[paths]\n")
221 fp.write("default = %s\n" % abspath)
221 fp.write("default = %s\n" % abspath)
222 fp.close()
222 fp.close()
223
223
224 if dest_lock:
224 if dest_lock:
225 dest_lock.release()
225 dest_lock.release()
226
226
227 if update:
227 if update:
228 try:
228 try:
229 checkout = dest_repo.lookup("default")
229 checkout = dest_repo.lookup("default")
230 except:
230 except:
231 checkout = dest_repo.changelog.tip()
231 checkout = dest_repo.changelog.tip()
232 _update(dest_repo, checkout)
232 _update(dest_repo, checkout)
233
233
234 return src_repo, dest_repo
234 return src_repo, dest_repo
235
235
236 def _showstats(repo, stats):
236 def _showstats(repo, stats):
237 stats = ((stats[0], _("updated")),
237 stats = ((stats[0], _("updated")),
238 (stats[1], _("merged")),
238 (stats[1], _("merged")),
239 (stats[2], _("removed")),
239 (stats[2], _("removed")),
240 (stats[3], _("unresolved")))
240 (stats[3], _("unresolved")))
241 note = ", ".join([_("%d files %s") % s for s in stats])
241 note = ", ".join([_("%d files %s") % s for s in stats])
242 repo.ui.status("%s\n" % note)
242 repo.ui.status("%s\n" % note)
243
243
244 def _update(repo, node): return update(repo, node)
244 def _update(repo, node): return update(repo, node)
245
245
246 def update(repo, node):
246 def update(repo, node):
247 """update the working directory to node, merging linear changes"""
247 """update the working directory to node, merging linear changes"""
248 pl = repo.parents()
248 pl = repo.parents()
249 stats = _merge.update(repo, node, False, False, None, None)
249 stats = _merge.update(repo, node, False, False, None, None)
250 _showstats(repo, stats)
250 _showstats(repo, stats)
251 if stats[3]:
251 if stats[3]:
252 repo.ui.status(_("There are unresolved merges with"
252 repo.ui.status(_("There are unresolved merges with"
253 " locally modified files.\n"))
253 " locally modified files.\n"))
254 if stats[1]:
254 if stats[1]:
255 repo.ui.status(_("You can finish the partial merge using:\n"))
255 repo.ui.status(_("You can finish the partial merge using:\n"))
256 else:
256 else:
257 repo.ui.status(_("You can redo the full merge using:\n"))
257 repo.ui.status(_("You can redo the full merge using:\n"))
258 # len(pl)==1, otherwise _merge.update() would have raised util.Abort:
258 # len(pl)==1, otherwise _merge.update() would have raised util.Abort:
259 repo.ui.status(_(" hg update %s\n hg update %s\n")
259 repo.ui.status(_(" hg update %s\n hg update %s\n")
260 % (pl[0].rev(), repo.changectx(node).rev()))
260 % (pl[0].rev(), repo.changectx(node).rev()))
261 return stats[3]
261 return stats[3]
262
262
263 def clean(repo, node, wlock=None, show_stats=True):
263 def clean(repo, node, wlock=None, show_stats=True):
264 """forcibly switch the working directory to node, clobbering changes"""
264 """forcibly switch the working directory to node, clobbering changes"""
265 stats = _merge.update(repo, node, False, True, None, wlock)
265 stats = _merge.update(repo, node, False, True, None, wlock)
266 if show_stats: _showstats(repo, stats)
266 if show_stats: _showstats(repo, stats)
267 return stats[3]
267 return stats[3]
268
268
269 def merge(repo, node, force=None, remind=True, wlock=None):
269 def merge(repo, node, force=None, remind=True, wlock=None):
270 """branch merge with node, resolving changes"""
270 """branch merge with node, resolving changes"""
271 stats = _merge.update(repo, node, True, force, False, wlock)
271 stats = _merge.update(repo, node, True, force, False, wlock)
272 _showstats(repo, stats)
272 _showstats(repo, stats)
273 if stats[3]:
273 if stats[3]:
274 pl = repo.parents()
274 pl = repo.parents()
275 repo.ui.status(_("There are unresolved merges,"
275 repo.ui.status(_("There are unresolved merges,"
276 " you can redo the full merge using:\n"
276 " you can redo the full merge using:\n"
277 " hg update -C %s\n"
277 " hg update -C %s\n"
278 " hg merge %s\n")
278 " hg merge %s\n")
279 % (pl[0].rev(), pl[1].rev()))
279 % (pl[0].rev(), pl[1].rev()))
280 elif remind:
280 elif remind:
281 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
281 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
282 return stats[3]
282 return stats[3]
283
283
284 def revert(repo, node, choose, wlock):
284 def revert(repo, node, choose, wlock):
285 """revert changes to revision in node without updating dirstate"""
285 """revert changes to revision in node without updating dirstate"""
286 return _merge.update(repo, node, False, True, choose, wlock)[3]
286 return _merge.update(repo, node, False, True, choose, wlock)[3]
287
287
288 def verify(repo):
288 def verify(repo):
289 """verify the consistency of a repository"""
289 """verify the consistency of a repository"""
290 return _verify.verify(repo)
290 return _verify.verify(repo)
General Comments 0
You need to be logged in to leave comments. Login now