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