##// END OF EJS Templates
i18n: remove translation of debug messages
David Soria Parra -
r14708:8083f4d0 stable
parent child Browse files
Show More
@@ -1,5144 +1,5144 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge
18 import dagparser, context, simplemerge
19 import random, setdiscovery, treediscovery, dagutil
19 import random, setdiscovery, treediscovery, dagutil
20
20
21 table = {}
21 table = {}
22
22
23 command = cmdutil.command(table)
23 command = cmdutil.command(table)
24
24
25 # common command options
25 # common command options
26
26
27 globalopts = [
27 globalopts = [
28 ('R', 'repository', '',
28 ('R', 'repository', '',
29 _('repository root directory or name of overlay bundle file'),
29 _('repository root directory or name of overlay bundle file'),
30 _('REPO')),
30 _('REPO')),
31 ('', 'cwd', '',
31 ('', 'cwd', '',
32 _('change working directory'), _('DIR')),
32 _('change working directory'), _('DIR')),
33 ('y', 'noninteractive', None,
33 ('y', 'noninteractive', None,
34 _('do not prompt, assume \'yes\' for any required answers')),
34 _('do not prompt, assume \'yes\' for any required answers')),
35 ('q', 'quiet', None, _('suppress output')),
35 ('q', 'quiet', None, _('suppress output')),
36 ('v', 'verbose', None, _('enable additional output')),
36 ('v', 'verbose', None, _('enable additional output')),
37 ('', 'config', [],
37 ('', 'config', [],
38 _('set/override config option (use \'section.name=value\')'),
38 _('set/override config option (use \'section.name=value\')'),
39 _('CONFIG')),
39 _('CONFIG')),
40 ('', 'debug', None, _('enable debugging output')),
40 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debugger', None, _('start debugger')),
41 ('', 'debugger', None, _('start debugger')),
42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 _('ENCODE')),
43 _('ENCODE')),
44 ('', 'encodingmode', encoding.encodingmode,
44 ('', 'encodingmode', encoding.encodingmode,
45 _('set the charset encoding mode'), _('MODE')),
45 _('set the charset encoding mode'), _('MODE')),
46 ('', 'traceback', None, _('always print a traceback on exception')),
46 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'time', None, _('time how long the command takes')),
47 ('', 'time', None, _('time how long the command takes')),
48 ('', 'profile', None, _('print command execution profile')),
48 ('', 'profile', None, _('print command execution profile')),
49 ('', 'version', None, _('output version information and exit')),
49 ('', 'version', None, _('output version information and exit')),
50 ('h', 'help', None, _('display help and exit')),
50 ('h', 'help', None, _('display help and exit')),
51 ]
51 ]
52
52
53 dryrunopts = [('n', 'dry-run', None,
53 dryrunopts = [('n', 'dry-run', None,
54 _('do not perform actions, just print output'))]
54 _('do not perform actions, just print output'))]
55
55
56 remoteopts = [
56 remoteopts = [
57 ('e', 'ssh', '',
57 ('e', 'ssh', '',
58 _('specify ssh command to use'), _('CMD')),
58 _('specify ssh command to use'), _('CMD')),
59 ('', 'remotecmd', '',
59 ('', 'remotecmd', '',
60 _('specify hg command to run on the remote side'), _('CMD')),
60 _('specify hg command to run on the remote side'), _('CMD')),
61 ('', 'insecure', None,
61 ('', 'insecure', None,
62 _('do not verify server certificate (ignoring web.cacerts config)')),
62 _('do not verify server certificate (ignoring web.cacerts config)')),
63 ]
63 ]
64
64
65 walkopts = [
65 walkopts = [
66 ('I', 'include', [],
66 ('I', 'include', [],
67 _('include names matching the given patterns'), _('PATTERN')),
67 _('include names matching the given patterns'), _('PATTERN')),
68 ('X', 'exclude', [],
68 ('X', 'exclude', [],
69 _('exclude names matching the given patterns'), _('PATTERN')),
69 _('exclude names matching the given patterns'), _('PATTERN')),
70 ]
70 ]
71
71
72 commitopts = [
72 commitopts = [
73 ('m', 'message', '',
73 ('m', 'message', '',
74 _('use text as commit message'), _('TEXT')),
74 _('use text as commit message'), _('TEXT')),
75 ('l', 'logfile', '',
75 ('l', 'logfile', '',
76 _('read commit message from file'), _('FILE')),
76 _('read commit message from file'), _('FILE')),
77 ]
77 ]
78
78
79 commitopts2 = [
79 commitopts2 = [
80 ('d', 'date', '',
80 ('d', 'date', '',
81 _('record the specified date as commit date'), _('DATE')),
81 _('record the specified date as commit date'), _('DATE')),
82 ('u', 'user', '',
82 ('u', 'user', '',
83 _('record the specified user as committer'), _('USER')),
83 _('record the specified user as committer'), _('USER')),
84 ]
84 ]
85
85
86 templateopts = [
86 templateopts = [
87 ('', 'style', '',
87 ('', 'style', '',
88 _('display using template map file'), _('STYLE')),
88 _('display using template map file'), _('STYLE')),
89 ('', 'template', '',
89 ('', 'template', '',
90 _('display with template'), _('TEMPLATE')),
90 _('display with template'), _('TEMPLATE')),
91 ]
91 ]
92
92
93 logopts = [
93 logopts = [
94 ('p', 'patch', None, _('show patch')),
94 ('p', 'patch', None, _('show patch')),
95 ('g', 'git', None, _('use git extended diff format')),
95 ('g', 'git', None, _('use git extended diff format')),
96 ('l', 'limit', '',
96 ('l', 'limit', '',
97 _('limit number of changes displayed'), _('NUM')),
97 _('limit number of changes displayed'), _('NUM')),
98 ('M', 'no-merges', None, _('do not show merges')),
98 ('M', 'no-merges', None, _('do not show merges')),
99 ('', 'stat', None, _('output diffstat-style summary of changes')),
99 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ] + templateopts
100 ] + templateopts
101
101
102 diffopts = [
102 diffopts = [
103 ('a', 'text', None, _('treat all files as text')),
103 ('a', 'text', None, _('treat all files as text')),
104 ('g', 'git', None, _('use git extended diff format')),
104 ('g', 'git', None, _('use git extended diff format')),
105 ('', 'nodates', None, _('omit dates from diff headers'))
105 ('', 'nodates', None, _('omit dates from diff headers'))
106 ]
106 ]
107
107
108 diffopts2 = [
108 diffopts2 = [
109 ('p', 'show-function', None, _('show which function each change is in')),
109 ('p', 'show-function', None, _('show which function each change is in')),
110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
111 ('w', 'ignore-all-space', None,
111 ('w', 'ignore-all-space', None,
112 _('ignore white space when comparing lines')),
112 _('ignore white space when comparing lines')),
113 ('b', 'ignore-space-change', None,
113 ('b', 'ignore-space-change', None,
114 _('ignore changes in the amount of white space')),
114 _('ignore changes in the amount of white space')),
115 ('B', 'ignore-blank-lines', None,
115 ('B', 'ignore-blank-lines', None,
116 _('ignore changes whose lines are all blank')),
116 _('ignore changes whose lines are all blank')),
117 ('U', 'unified', '',
117 ('U', 'unified', '',
118 _('number of lines of context to show'), _('NUM')),
118 _('number of lines of context to show'), _('NUM')),
119 ('', 'stat', None, _('output diffstat-style summary of changes')),
119 ('', 'stat', None, _('output diffstat-style summary of changes')),
120 ]
120 ]
121
121
122 similarityopts = [
122 similarityopts = [
123 ('s', 'similarity', '',
123 ('s', 'similarity', '',
124 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
124 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
125 ]
125 ]
126
126
127 subrepoopts = [
127 subrepoopts = [
128 ('S', 'subrepos', None,
128 ('S', 'subrepos', None,
129 _('recurse into subrepositories'))
129 _('recurse into subrepositories'))
130 ]
130 ]
131
131
132 # Commands start here, listed alphabetically
132 # Commands start here, listed alphabetically
133
133
134 @command('^add',
134 @command('^add',
135 walkopts + subrepoopts + dryrunopts,
135 walkopts + subrepoopts + dryrunopts,
136 _('[OPTION]... [FILE]...'))
136 _('[OPTION]... [FILE]...'))
137 def add(ui, repo, *pats, **opts):
137 def add(ui, repo, *pats, **opts):
138 """add the specified files on the next commit
138 """add the specified files on the next commit
139
139
140 Schedule files to be version controlled and added to the
140 Schedule files to be version controlled and added to the
141 repository.
141 repository.
142
142
143 The files will be added to the repository at the next commit. To
143 The files will be added to the repository at the next commit. To
144 undo an add before that, see :hg:`forget`.
144 undo an add before that, see :hg:`forget`.
145
145
146 If no names are given, add all files to the repository.
146 If no names are given, add all files to the repository.
147
147
148 .. container:: verbose
148 .. container:: verbose
149
149
150 An example showing how new (unknown) files are added
150 An example showing how new (unknown) files are added
151 automatically by :hg:`add`::
151 automatically by :hg:`add`::
152
152
153 $ ls
153 $ ls
154 foo.c
154 foo.c
155 $ hg status
155 $ hg status
156 ? foo.c
156 ? foo.c
157 $ hg add
157 $ hg add
158 adding foo.c
158 adding foo.c
159 $ hg status
159 $ hg status
160 A foo.c
160 A foo.c
161
161
162 Returns 0 if all files are successfully added.
162 Returns 0 if all files are successfully added.
163 """
163 """
164
164
165 m = scmutil.match(repo[None], pats, opts)
165 m = scmutil.match(repo[None], pats, opts)
166 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
166 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
167 opts.get('subrepos'), prefix="")
167 opts.get('subrepos'), prefix="")
168 return rejected and 1 or 0
168 return rejected and 1 or 0
169
169
170 @command('addremove',
170 @command('addremove',
171 similarityopts + walkopts + dryrunopts,
171 similarityopts + walkopts + dryrunopts,
172 _('[OPTION]... [FILE]...'))
172 _('[OPTION]... [FILE]...'))
173 def addremove(ui, repo, *pats, **opts):
173 def addremove(ui, repo, *pats, **opts):
174 """add all new files, delete all missing files
174 """add all new files, delete all missing files
175
175
176 Add all new files and remove all missing files from the
176 Add all new files and remove all missing files from the
177 repository.
177 repository.
178
178
179 New files are ignored if they match any of the patterns in
179 New files are ignored if they match any of the patterns in
180 ``.hgignore``. As with add, these changes take effect at the next
180 ``.hgignore``. As with add, these changes take effect at the next
181 commit.
181 commit.
182
182
183 Use the -s/--similarity option to detect renamed files. With a
183 Use the -s/--similarity option to detect renamed files. With a
184 parameter greater than 0, this compares every removed file with
184 parameter greater than 0, this compares every removed file with
185 every added file and records those similar enough as renames. This
185 every added file and records those similar enough as renames. This
186 option takes a percentage between 0 (disabled) and 100 (files must
186 option takes a percentage between 0 (disabled) and 100 (files must
187 be identical) as its parameter. Detecting renamed files this way
187 be identical) as its parameter. Detecting renamed files this way
188 can be expensive. After using this option, :hg:`status -C` can be
188 can be expensive. After using this option, :hg:`status -C` can be
189 used to check which files were identified as moved or renamed.
189 used to check which files were identified as moved or renamed.
190
190
191 Returns 0 if all files are successfully added.
191 Returns 0 if all files are successfully added.
192 """
192 """
193 try:
193 try:
194 sim = float(opts.get('similarity') or 100)
194 sim = float(opts.get('similarity') or 100)
195 except ValueError:
195 except ValueError:
196 raise util.Abort(_('similarity must be a number'))
196 raise util.Abort(_('similarity must be a number'))
197 if sim < 0 or sim > 100:
197 if sim < 0 or sim > 100:
198 raise util.Abort(_('similarity must be between 0 and 100'))
198 raise util.Abort(_('similarity must be between 0 and 100'))
199 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
199 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
200
200
201 @command('^annotate|blame',
201 @command('^annotate|blame',
202 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
202 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
203 ('', 'follow', None,
203 ('', 'follow', None,
204 _('follow copies/renames and list the filename (DEPRECATED)')),
204 _('follow copies/renames and list the filename (DEPRECATED)')),
205 ('', 'no-follow', None, _("don't follow copies and renames")),
205 ('', 'no-follow', None, _("don't follow copies and renames")),
206 ('a', 'text', None, _('treat all files as text')),
206 ('a', 'text', None, _('treat all files as text')),
207 ('u', 'user', None, _('list the author (long with -v)')),
207 ('u', 'user', None, _('list the author (long with -v)')),
208 ('f', 'file', None, _('list the filename')),
208 ('f', 'file', None, _('list the filename')),
209 ('d', 'date', None, _('list the date (short with -q)')),
209 ('d', 'date', None, _('list the date (short with -q)')),
210 ('n', 'number', None, _('list the revision number (default)')),
210 ('n', 'number', None, _('list the revision number (default)')),
211 ('c', 'changeset', None, _('list the changeset')),
211 ('c', 'changeset', None, _('list the changeset')),
212 ('l', 'line-number', None, _('show line number at the first appearance'))
212 ('l', 'line-number', None, _('show line number at the first appearance'))
213 ] + walkopts,
213 ] + walkopts,
214 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
214 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
215 def annotate(ui, repo, *pats, **opts):
215 def annotate(ui, repo, *pats, **opts):
216 """show changeset information by line for each file
216 """show changeset information by line for each file
217
217
218 List changes in files, showing the revision id responsible for
218 List changes in files, showing the revision id responsible for
219 each line
219 each line
220
220
221 This command is useful for discovering when a change was made and
221 This command is useful for discovering when a change was made and
222 by whom.
222 by whom.
223
223
224 Without the -a/--text option, annotate will avoid processing files
224 Without the -a/--text option, annotate will avoid processing files
225 it detects as binary. With -a, annotate will annotate the file
225 it detects as binary. With -a, annotate will annotate the file
226 anyway, although the results will probably be neither useful
226 anyway, although the results will probably be neither useful
227 nor desirable.
227 nor desirable.
228
228
229 Returns 0 on success.
229 Returns 0 on success.
230 """
230 """
231 if opts.get('follow'):
231 if opts.get('follow'):
232 # --follow is deprecated and now just an alias for -f/--file
232 # --follow is deprecated and now just an alias for -f/--file
233 # to mimic the behavior of Mercurial before version 1.5
233 # to mimic the behavior of Mercurial before version 1.5
234 opts['file'] = True
234 opts['file'] = True
235
235
236 datefunc = ui.quiet and util.shortdate or util.datestr
236 datefunc = ui.quiet and util.shortdate or util.datestr
237 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
237 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
238
238
239 if not pats:
239 if not pats:
240 raise util.Abort(_('at least one filename or pattern is required'))
240 raise util.Abort(_('at least one filename or pattern is required'))
241
241
242 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
242 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
243 ('number', ' ', lambda x: str(x[0].rev())),
243 ('number', ' ', lambda x: str(x[0].rev())),
244 ('changeset', ' ', lambda x: short(x[0].node())),
244 ('changeset', ' ', lambda x: short(x[0].node())),
245 ('date', ' ', getdate),
245 ('date', ' ', getdate),
246 ('file', ' ', lambda x: x[0].path()),
246 ('file', ' ', lambda x: x[0].path()),
247 ('line_number', ':', lambda x: str(x[1])),
247 ('line_number', ':', lambda x: str(x[1])),
248 ]
248 ]
249
249
250 if (not opts.get('user') and not opts.get('changeset')
250 if (not opts.get('user') and not opts.get('changeset')
251 and not opts.get('date') and not opts.get('file')):
251 and not opts.get('date') and not opts.get('file')):
252 opts['number'] = True
252 opts['number'] = True
253
253
254 linenumber = opts.get('line_number') is not None
254 linenumber = opts.get('line_number') is not None
255 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
255 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
256 raise util.Abort(_('at least one of -n/-c is required for -l'))
256 raise util.Abort(_('at least one of -n/-c is required for -l'))
257
257
258 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
258 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
259 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
259 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
260
260
261 def bad(x, y):
261 def bad(x, y):
262 raise util.Abort("%s: %s" % (x, y))
262 raise util.Abort("%s: %s" % (x, y))
263
263
264 ctx = scmutil.revsingle(repo, opts.get('rev'))
264 ctx = scmutil.revsingle(repo, opts.get('rev'))
265 m = scmutil.match(ctx, pats, opts)
265 m = scmutil.match(ctx, pats, opts)
266 m.bad = bad
266 m.bad = bad
267 follow = not opts.get('no_follow')
267 follow = not opts.get('no_follow')
268 for abs in ctx.walk(m):
268 for abs in ctx.walk(m):
269 fctx = ctx[abs]
269 fctx = ctx[abs]
270 if not opts.get('text') and util.binary(fctx.data()):
270 if not opts.get('text') and util.binary(fctx.data()):
271 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
271 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
272 continue
272 continue
273
273
274 lines = fctx.annotate(follow=follow, linenumber=linenumber)
274 lines = fctx.annotate(follow=follow, linenumber=linenumber)
275 pieces = []
275 pieces = []
276
276
277 for f, sep in funcmap:
277 for f, sep in funcmap:
278 l = [f(n) for n, dummy in lines]
278 l = [f(n) for n, dummy in lines]
279 if l:
279 if l:
280 sized = [(x, encoding.colwidth(x)) for x in l]
280 sized = [(x, encoding.colwidth(x)) for x in l]
281 ml = max([w for x, w in sized])
281 ml = max([w for x, w in sized])
282 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
282 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
283 for x, w in sized])
283 for x, w in sized])
284
284
285 if pieces:
285 if pieces:
286 for p, l in zip(zip(*pieces), lines):
286 for p, l in zip(zip(*pieces), lines):
287 ui.write("%s: %s" % ("".join(p), l[1]))
287 ui.write("%s: %s" % ("".join(p), l[1]))
288
288
289 @command('archive',
289 @command('archive',
290 [('', 'no-decode', None, _('do not pass files through decoders')),
290 [('', 'no-decode', None, _('do not pass files through decoders')),
291 ('p', 'prefix', '', _('directory prefix for files in archive'),
291 ('p', 'prefix', '', _('directory prefix for files in archive'),
292 _('PREFIX')),
292 _('PREFIX')),
293 ('r', 'rev', '', _('revision to distribute'), _('REV')),
293 ('r', 'rev', '', _('revision to distribute'), _('REV')),
294 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
294 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
295 ] + subrepoopts + walkopts,
295 ] + subrepoopts + walkopts,
296 _('[OPTION]... DEST'))
296 _('[OPTION]... DEST'))
297 def archive(ui, repo, dest, **opts):
297 def archive(ui, repo, dest, **opts):
298 '''create an unversioned archive of a repository revision
298 '''create an unversioned archive of a repository revision
299
299
300 By default, the revision used is the parent of the working
300 By default, the revision used is the parent of the working
301 directory; use -r/--rev to specify a different revision.
301 directory; use -r/--rev to specify a different revision.
302
302
303 The archive type is automatically detected based on file
303 The archive type is automatically detected based on file
304 extension (or override using -t/--type).
304 extension (or override using -t/--type).
305
305
306 Valid types are:
306 Valid types are:
307
307
308 :``files``: a directory full of files (default)
308 :``files``: a directory full of files (default)
309 :``tar``: tar archive, uncompressed
309 :``tar``: tar archive, uncompressed
310 :``tbz2``: tar archive, compressed using bzip2
310 :``tbz2``: tar archive, compressed using bzip2
311 :``tgz``: tar archive, compressed using gzip
311 :``tgz``: tar archive, compressed using gzip
312 :``uzip``: zip archive, uncompressed
312 :``uzip``: zip archive, uncompressed
313 :``zip``: zip archive, compressed using deflate
313 :``zip``: zip archive, compressed using deflate
314
314
315 The exact name of the destination archive or directory is given
315 The exact name of the destination archive or directory is given
316 using a format string; see :hg:`help export` for details.
316 using a format string; see :hg:`help export` for details.
317
317
318 Each member added to an archive file has a directory prefix
318 Each member added to an archive file has a directory prefix
319 prepended. Use -p/--prefix to specify a format string for the
319 prepended. Use -p/--prefix to specify a format string for the
320 prefix. The default is the basename of the archive, with suffixes
320 prefix. The default is the basename of the archive, with suffixes
321 removed.
321 removed.
322
322
323 Returns 0 on success.
323 Returns 0 on success.
324 '''
324 '''
325
325
326 ctx = scmutil.revsingle(repo, opts.get('rev'))
326 ctx = scmutil.revsingle(repo, opts.get('rev'))
327 if not ctx:
327 if not ctx:
328 raise util.Abort(_('no working directory: please specify a revision'))
328 raise util.Abort(_('no working directory: please specify a revision'))
329 node = ctx.node()
329 node = ctx.node()
330 dest = cmdutil.makefilename(repo, dest, node)
330 dest = cmdutil.makefilename(repo, dest, node)
331 if os.path.realpath(dest) == repo.root:
331 if os.path.realpath(dest) == repo.root:
332 raise util.Abort(_('repository root cannot be destination'))
332 raise util.Abort(_('repository root cannot be destination'))
333
333
334 kind = opts.get('type') or archival.guesskind(dest) or 'files'
334 kind = opts.get('type') or archival.guesskind(dest) or 'files'
335 prefix = opts.get('prefix')
335 prefix = opts.get('prefix')
336
336
337 if dest == '-':
337 if dest == '-':
338 if kind == 'files':
338 if kind == 'files':
339 raise util.Abort(_('cannot archive plain files to stdout'))
339 raise util.Abort(_('cannot archive plain files to stdout'))
340 dest = ui.fout
340 dest = ui.fout
341 if not prefix:
341 if not prefix:
342 prefix = os.path.basename(repo.root) + '-%h'
342 prefix = os.path.basename(repo.root) + '-%h'
343
343
344 prefix = cmdutil.makefilename(repo, prefix, node)
344 prefix = cmdutil.makefilename(repo, prefix, node)
345 matchfn = scmutil.match(ctx, [], opts)
345 matchfn = scmutil.match(ctx, [], opts)
346 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
346 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
347 matchfn, prefix, subrepos=opts.get('subrepos'))
347 matchfn, prefix, subrepos=opts.get('subrepos'))
348
348
349 @command('backout',
349 @command('backout',
350 [('', 'merge', None, _('merge with old dirstate parent after backout')),
350 [('', 'merge', None, _('merge with old dirstate parent after backout')),
351 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
351 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
352 ('t', 'tool', '', _('specify merge tool')),
352 ('t', 'tool', '', _('specify merge tool')),
353 ('r', 'rev', '', _('revision to backout'), _('REV')),
353 ('r', 'rev', '', _('revision to backout'), _('REV')),
354 ] + walkopts + commitopts + commitopts2,
354 ] + walkopts + commitopts + commitopts2,
355 _('[OPTION]... [-r] REV'))
355 _('[OPTION]... [-r] REV'))
356 def backout(ui, repo, node=None, rev=None, **opts):
356 def backout(ui, repo, node=None, rev=None, **opts):
357 '''reverse effect of earlier changeset
357 '''reverse effect of earlier changeset
358
358
359 Prepare a new changeset with the effect of REV undone in the
359 Prepare a new changeset with the effect of REV undone in the
360 current working directory.
360 current working directory.
361
361
362 If REV is the parent of the working directory, then this new changeset
362 If REV is the parent of the working directory, then this new changeset
363 is committed automatically. Otherwise, hg needs to merge the
363 is committed automatically. Otherwise, hg needs to merge the
364 changes and the merged result is left uncommitted.
364 changes and the merged result is left uncommitted.
365
365
366 By default, the pending changeset will have one parent,
366 By default, the pending changeset will have one parent,
367 maintaining a linear history. With --merge, the pending changeset
367 maintaining a linear history. With --merge, the pending changeset
368 will instead have two parents: the old parent of the working
368 will instead have two parents: the old parent of the working
369 directory and a new child of REV that simply undoes REV.
369 directory and a new child of REV that simply undoes REV.
370
370
371 Before version 1.7, the behavior without --merge was equivalent to
371 Before version 1.7, the behavior without --merge was equivalent to
372 specifying --merge followed by :hg:`update --clean .` to cancel
372 specifying --merge followed by :hg:`update --clean .` to cancel
373 the merge and leave the child of REV as a head to be merged
373 the merge and leave the child of REV as a head to be merged
374 separately.
374 separately.
375
375
376 See :hg:`help dates` for a list of formats valid for -d/--date.
376 See :hg:`help dates` for a list of formats valid for -d/--date.
377
377
378 Returns 0 on success.
378 Returns 0 on success.
379 '''
379 '''
380 if rev and node:
380 if rev and node:
381 raise util.Abort(_("please specify just one revision"))
381 raise util.Abort(_("please specify just one revision"))
382
382
383 if not rev:
383 if not rev:
384 rev = node
384 rev = node
385
385
386 if not rev:
386 if not rev:
387 raise util.Abort(_("please specify a revision to backout"))
387 raise util.Abort(_("please specify a revision to backout"))
388
388
389 date = opts.get('date')
389 date = opts.get('date')
390 if date:
390 if date:
391 opts['date'] = util.parsedate(date)
391 opts['date'] = util.parsedate(date)
392
392
393 cmdutil.bailifchanged(repo)
393 cmdutil.bailifchanged(repo)
394 node = scmutil.revsingle(repo, rev).node()
394 node = scmutil.revsingle(repo, rev).node()
395
395
396 op1, op2 = repo.dirstate.parents()
396 op1, op2 = repo.dirstate.parents()
397 a = repo.changelog.ancestor(op1, node)
397 a = repo.changelog.ancestor(op1, node)
398 if a != node:
398 if a != node:
399 raise util.Abort(_('cannot backout change on a different branch'))
399 raise util.Abort(_('cannot backout change on a different branch'))
400
400
401 p1, p2 = repo.changelog.parents(node)
401 p1, p2 = repo.changelog.parents(node)
402 if p1 == nullid:
402 if p1 == nullid:
403 raise util.Abort(_('cannot backout a change with no parents'))
403 raise util.Abort(_('cannot backout a change with no parents'))
404 if p2 != nullid:
404 if p2 != nullid:
405 if not opts.get('parent'):
405 if not opts.get('parent'):
406 raise util.Abort(_('cannot backout a merge changeset without '
406 raise util.Abort(_('cannot backout a merge changeset without '
407 '--parent'))
407 '--parent'))
408 p = repo.lookup(opts['parent'])
408 p = repo.lookup(opts['parent'])
409 if p not in (p1, p2):
409 if p not in (p1, p2):
410 raise util.Abort(_('%s is not a parent of %s') %
410 raise util.Abort(_('%s is not a parent of %s') %
411 (short(p), short(node)))
411 (short(p), short(node)))
412 parent = p
412 parent = p
413 else:
413 else:
414 if opts.get('parent'):
414 if opts.get('parent'):
415 raise util.Abort(_('cannot use --parent on non-merge changeset'))
415 raise util.Abort(_('cannot use --parent on non-merge changeset'))
416 parent = p1
416 parent = p1
417
417
418 # the backout should appear on the same branch
418 # the backout should appear on the same branch
419 branch = repo.dirstate.branch()
419 branch = repo.dirstate.branch()
420 hg.clean(repo, node, show_stats=False)
420 hg.clean(repo, node, show_stats=False)
421 repo.dirstate.setbranch(branch)
421 repo.dirstate.setbranch(branch)
422 revert_opts = opts.copy()
422 revert_opts = opts.copy()
423 revert_opts['date'] = None
423 revert_opts['date'] = None
424 revert_opts['all'] = True
424 revert_opts['all'] = True
425 revert_opts['rev'] = hex(parent)
425 revert_opts['rev'] = hex(parent)
426 revert_opts['no_backup'] = None
426 revert_opts['no_backup'] = None
427 revert(ui, repo, **revert_opts)
427 revert(ui, repo, **revert_opts)
428 if not opts.get('merge') and op1 != node:
428 if not opts.get('merge') and op1 != node:
429 try:
429 try:
430 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
430 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
431 return hg.update(repo, op1)
431 return hg.update(repo, op1)
432 finally:
432 finally:
433 ui.setconfig('ui', 'forcemerge', '')
433 ui.setconfig('ui', 'forcemerge', '')
434
434
435 commit_opts = opts.copy()
435 commit_opts = opts.copy()
436 commit_opts['addremove'] = False
436 commit_opts['addremove'] = False
437 if not commit_opts['message'] and not commit_opts['logfile']:
437 if not commit_opts['message'] and not commit_opts['logfile']:
438 # we don't translate commit messages
438 # we don't translate commit messages
439 commit_opts['message'] = "Backed out changeset %s" % short(node)
439 commit_opts['message'] = "Backed out changeset %s" % short(node)
440 commit_opts['force_editor'] = True
440 commit_opts['force_editor'] = True
441 commit(ui, repo, **commit_opts)
441 commit(ui, repo, **commit_opts)
442 def nice(node):
442 def nice(node):
443 return '%d:%s' % (repo.changelog.rev(node), short(node))
443 return '%d:%s' % (repo.changelog.rev(node), short(node))
444 ui.status(_('changeset %s backs out changeset %s\n') %
444 ui.status(_('changeset %s backs out changeset %s\n') %
445 (nice(repo.changelog.tip()), nice(node)))
445 (nice(repo.changelog.tip()), nice(node)))
446 if opts.get('merge') and op1 != node:
446 if opts.get('merge') and op1 != node:
447 hg.clean(repo, op1, show_stats=False)
447 hg.clean(repo, op1, show_stats=False)
448 ui.status(_('merging with changeset %s\n')
448 ui.status(_('merging with changeset %s\n')
449 % nice(repo.changelog.tip()))
449 % nice(repo.changelog.tip()))
450 try:
450 try:
451 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
451 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
452 return hg.merge(repo, hex(repo.changelog.tip()))
452 return hg.merge(repo, hex(repo.changelog.tip()))
453 finally:
453 finally:
454 ui.setconfig('ui', 'forcemerge', '')
454 ui.setconfig('ui', 'forcemerge', '')
455 return 0
455 return 0
456
456
457 @command('bisect',
457 @command('bisect',
458 [('r', 'reset', False, _('reset bisect state')),
458 [('r', 'reset', False, _('reset bisect state')),
459 ('g', 'good', False, _('mark changeset good')),
459 ('g', 'good', False, _('mark changeset good')),
460 ('b', 'bad', False, _('mark changeset bad')),
460 ('b', 'bad', False, _('mark changeset bad')),
461 ('s', 'skip', False, _('skip testing changeset')),
461 ('s', 'skip', False, _('skip testing changeset')),
462 ('e', 'extend', False, _('extend the bisect range')),
462 ('e', 'extend', False, _('extend the bisect range')),
463 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
463 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
464 ('U', 'noupdate', False, _('do not update to target'))],
464 ('U', 'noupdate', False, _('do not update to target'))],
465 _("[-gbsr] [-U] [-c CMD] [REV]"))
465 _("[-gbsr] [-U] [-c CMD] [REV]"))
466 def bisect(ui, repo, rev=None, extra=None, command=None,
466 def bisect(ui, repo, rev=None, extra=None, command=None,
467 reset=None, good=None, bad=None, skip=None, extend=None,
467 reset=None, good=None, bad=None, skip=None, extend=None,
468 noupdate=None):
468 noupdate=None):
469 """subdivision search of changesets
469 """subdivision search of changesets
470
470
471 This command helps to find changesets which introduce problems. To
471 This command helps to find changesets which introduce problems. To
472 use, mark the earliest changeset you know exhibits the problem as
472 use, mark the earliest changeset you know exhibits the problem as
473 bad, then mark the latest changeset which is free from the problem
473 bad, then mark the latest changeset which is free from the problem
474 as good. Bisect will update your working directory to a revision
474 as good. Bisect will update your working directory to a revision
475 for testing (unless the -U/--noupdate option is specified). Once
475 for testing (unless the -U/--noupdate option is specified). Once
476 you have performed tests, mark the working directory as good or
476 you have performed tests, mark the working directory as good or
477 bad, and bisect will either update to another candidate changeset
477 bad, and bisect will either update to another candidate changeset
478 or announce that it has found the bad revision.
478 or announce that it has found the bad revision.
479
479
480 As a shortcut, you can also use the revision argument to mark a
480 As a shortcut, you can also use the revision argument to mark a
481 revision as good or bad without checking it out first.
481 revision as good or bad without checking it out first.
482
482
483 If you supply a command, it will be used for automatic bisection.
483 If you supply a command, it will be used for automatic bisection.
484 Its exit status will be used to mark revisions as good or bad:
484 Its exit status will be used to mark revisions as good or bad:
485 status 0 means good, 125 means to skip the revision, 127
485 status 0 means good, 125 means to skip the revision, 127
486 (command not found) will abort the bisection, and any other
486 (command not found) will abort the bisection, and any other
487 non-zero exit status means the revision is bad.
487 non-zero exit status means the revision is bad.
488
488
489 Returns 0 on success.
489 Returns 0 on success.
490 """
490 """
491 def extendbisectrange(nodes, good):
491 def extendbisectrange(nodes, good):
492 # bisect is incomplete when it ends on a merge node and
492 # bisect is incomplete when it ends on a merge node and
493 # one of the parent was not checked.
493 # one of the parent was not checked.
494 parents = repo[nodes[0]].parents()
494 parents = repo[nodes[0]].parents()
495 if len(parents) > 1:
495 if len(parents) > 1:
496 side = good and state['bad'] or state['good']
496 side = good and state['bad'] or state['good']
497 num = len(set(i.node() for i in parents) & set(side))
497 num = len(set(i.node() for i in parents) & set(side))
498 if num == 1:
498 if num == 1:
499 return parents[0].ancestor(parents[1])
499 return parents[0].ancestor(parents[1])
500 return None
500 return None
501
501
502 def print_result(nodes, good):
502 def print_result(nodes, good):
503 displayer = cmdutil.show_changeset(ui, repo, {})
503 displayer = cmdutil.show_changeset(ui, repo, {})
504 if len(nodes) == 1:
504 if len(nodes) == 1:
505 # narrowed it down to a single revision
505 # narrowed it down to a single revision
506 if good:
506 if good:
507 ui.write(_("The first good revision is:\n"))
507 ui.write(_("The first good revision is:\n"))
508 else:
508 else:
509 ui.write(_("The first bad revision is:\n"))
509 ui.write(_("The first bad revision is:\n"))
510 displayer.show(repo[nodes[0]])
510 displayer.show(repo[nodes[0]])
511 extendnode = extendbisectrange(nodes, good)
511 extendnode = extendbisectrange(nodes, good)
512 if extendnode is not None:
512 if extendnode is not None:
513 ui.write(_('Not all ancestors of this changeset have been'
513 ui.write(_('Not all ancestors of this changeset have been'
514 ' checked.\nUse bisect --extend to continue the '
514 ' checked.\nUse bisect --extend to continue the '
515 'bisection from\nthe common ancestor, %s.\n')
515 'bisection from\nthe common ancestor, %s.\n')
516 % extendnode)
516 % extendnode)
517 else:
517 else:
518 # multiple possible revisions
518 # multiple possible revisions
519 if good:
519 if good:
520 ui.write(_("Due to skipped revisions, the first "
520 ui.write(_("Due to skipped revisions, the first "
521 "good revision could be any of:\n"))
521 "good revision could be any of:\n"))
522 else:
522 else:
523 ui.write(_("Due to skipped revisions, the first "
523 ui.write(_("Due to skipped revisions, the first "
524 "bad revision could be any of:\n"))
524 "bad revision could be any of:\n"))
525 for n in nodes:
525 for n in nodes:
526 displayer.show(repo[n])
526 displayer.show(repo[n])
527 displayer.close()
527 displayer.close()
528
528
529 def check_state(state, interactive=True):
529 def check_state(state, interactive=True):
530 if not state['good'] or not state['bad']:
530 if not state['good'] or not state['bad']:
531 if (good or bad or skip or reset) and interactive:
531 if (good or bad or skip or reset) and interactive:
532 return
532 return
533 if not state['good']:
533 if not state['good']:
534 raise util.Abort(_('cannot bisect (no known good revisions)'))
534 raise util.Abort(_('cannot bisect (no known good revisions)'))
535 else:
535 else:
536 raise util.Abort(_('cannot bisect (no known bad revisions)'))
536 raise util.Abort(_('cannot bisect (no known bad revisions)'))
537 return True
537 return True
538
538
539 # backward compatibility
539 # backward compatibility
540 if rev in "good bad reset init".split():
540 if rev in "good bad reset init".split():
541 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
541 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
542 cmd, rev, extra = rev, extra, None
542 cmd, rev, extra = rev, extra, None
543 if cmd == "good":
543 if cmd == "good":
544 good = True
544 good = True
545 elif cmd == "bad":
545 elif cmd == "bad":
546 bad = True
546 bad = True
547 else:
547 else:
548 reset = True
548 reset = True
549 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
549 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
550 raise util.Abort(_('incompatible arguments'))
550 raise util.Abort(_('incompatible arguments'))
551
551
552 if reset:
552 if reset:
553 p = repo.join("bisect.state")
553 p = repo.join("bisect.state")
554 if os.path.exists(p):
554 if os.path.exists(p):
555 os.unlink(p)
555 os.unlink(p)
556 return
556 return
557
557
558 state = hbisect.load_state(repo)
558 state = hbisect.load_state(repo)
559
559
560 if command:
560 if command:
561 changesets = 1
561 changesets = 1
562 try:
562 try:
563 while changesets:
563 while changesets:
564 # update state
564 # update state
565 status = util.system(command)
565 status = util.system(command)
566 if status == 125:
566 if status == 125:
567 transition = "skip"
567 transition = "skip"
568 elif status == 0:
568 elif status == 0:
569 transition = "good"
569 transition = "good"
570 # status < 0 means process was killed
570 # status < 0 means process was killed
571 elif status == 127:
571 elif status == 127:
572 raise util.Abort(_("failed to execute %s") % command)
572 raise util.Abort(_("failed to execute %s") % command)
573 elif status < 0:
573 elif status < 0:
574 raise util.Abort(_("%s killed") % command)
574 raise util.Abort(_("%s killed") % command)
575 else:
575 else:
576 transition = "bad"
576 transition = "bad"
577 ctx = scmutil.revsingle(repo, rev)
577 ctx = scmutil.revsingle(repo, rev)
578 rev = None # clear for future iterations
578 rev = None # clear for future iterations
579 state[transition].append(ctx.node())
579 state[transition].append(ctx.node())
580 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
580 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
581 check_state(state, interactive=False)
581 check_state(state, interactive=False)
582 # bisect
582 # bisect
583 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
583 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
584 # update to next check
584 # update to next check
585 cmdutil.bailifchanged(repo)
585 cmdutil.bailifchanged(repo)
586 hg.clean(repo, nodes[0], show_stats=False)
586 hg.clean(repo, nodes[0], show_stats=False)
587 finally:
587 finally:
588 hbisect.save_state(repo, state)
588 hbisect.save_state(repo, state)
589 print_result(nodes, good)
589 print_result(nodes, good)
590 return
590 return
591
591
592 # update state
592 # update state
593
593
594 if rev:
594 if rev:
595 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
595 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
596 else:
596 else:
597 nodes = [repo.lookup('.')]
597 nodes = [repo.lookup('.')]
598
598
599 if good or bad or skip:
599 if good or bad or skip:
600 if good:
600 if good:
601 state['good'] += nodes
601 state['good'] += nodes
602 elif bad:
602 elif bad:
603 state['bad'] += nodes
603 state['bad'] += nodes
604 elif skip:
604 elif skip:
605 state['skip'] += nodes
605 state['skip'] += nodes
606 hbisect.save_state(repo, state)
606 hbisect.save_state(repo, state)
607
607
608 if not check_state(state):
608 if not check_state(state):
609 return
609 return
610
610
611 # actually bisect
611 # actually bisect
612 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
612 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
613 if extend:
613 if extend:
614 if not changesets:
614 if not changesets:
615 extendnode = extendbisectrange(nodes, good)
615 extendnode = extendbisectrange(nodes, good)
616 if extendnode is not None:
616 if extendnode is not None:
617 ui.write(_("Extending search to changeset %d:%s\n"
617 ui.write(_("Extending search to changeset %d:%s\n"
618 % (extendnode.rev(), extendnode)))
618 % (extendnode.rev(), extendnode)))
619 if noupdate:
619 if noupdate:
620 return
620 return
621 cmdutil.bailifchanged(repo)
621 cmdutil.bailifchanged(repo)
622 return hg.clean(repo, extendnode.node())
622 return hg.clean(repo, extendnode.node())
623 raise util.Abort(_("nothing to extend"))
623 raise util.Abort(_("nothing to extend"))
624
624
625 if changesets == 0:
625 if changesets == 0:
626 print_result(nodes, good)
626 print_result(nodes, good)
627 else:
627 else:
628 assert len(nodes) == 1 # only a single node can be tested next
628 assert len(nodes) == 1 # only a single node can be tested next
629 node = nodes[0]
629 node = nodes[0]
630 # compute the approximate number of remaining tests
630 # compute the approximate number of remaining tests
631 tests, size = 0, 2
631 tests, size = 0, 2
632 while size <= changesets:
632 while size <= changesets:
633 tests, size = tests + 1, size * 2
633 tests, size = tests + 1, size * 2
634 rev = repo.changelog.rev(node)
634 rev = repo.changelog.rev(node)
635 ui.write(_("Testing changeset %d:%s "
635 ui.write(_("Testing changeset %d:%s "
636 "(%d changesets remaining, ~%d tests)\n")
636 "(%d changesets remaining, ~%d tests)\n")
637 % (rev, short(node), changesets, tests))
637 % (rev, short(node), changesets, tests))
638 if not noupdate:
638 if not noupdate:
639 cmdutil.bailifchanged(repo)
639 cmdutil.bailifchanged(repo)
640 return hg.clean(repo, node)
640 return hg.clean(repo, node)
641
641
642 @command('bookmarks',
642 @command('bookmarks',
643 [('f', 'force', False, _('force')),
643 [('f', 'force', False, _('force')),
644 ('r', 'rev', '', _('revision'), _('REV')),
644 ('r', 'rev', '', _('revision'), _('REV')),
645 ('d', 'delete', False, _('delete a given bookmark')),
645 ('d', 'delete', False, _('delete a given bookmark')),
646 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
646 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
647 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
647 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
648 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
648 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
649 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
649 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
650 rename=None, inactive=False):
650 rename=None, inactive=False):
651 '''track a line of development with movable markers
651 '''track a line of development with movable markers
652
652
653 Bookmarks are pointers to certain commits that move when
653 Bookmarks are pointers to certain commits that move when
654 committing. Bookmarks are local. They can be renamed, copied and
654 committing. Bookmarks are local. They can be renamed, copied and
655 deleted. It is possible to use bookmark names in :hg:`merge` and
655 deleted. It is possible to use bookmark names in :hg:`merge` and
656 :hg:`update` to merge and update respectively to a given bookmark.
656 :hg:`update` to merge and update respectively to a given bookmark.
657
657
658 You can use :hg:`bookmark NAME` to set a bookmark on the working
658 You can use :hg:`bookmark NAME` to set a bookmark on the working
659 directory's parent revision with the given name. If you specify
659 directory's parent revision with the given name. If you specify
660 a revision using -r REV (where REV may be an existing bookmark),
660 a revision using -r REV (where REV may be an existing bookmark),
661 the bookmark is assigned to that revision.
661 the bookmark is assigned to that revision.
662
662
663 Bookmarks can be pushed and pulled between repositories (see :hg:`help
663 Bookmarks can be pushed and pulled between repositories (see :hg:`help
664 push` and :hg:`help pull`). This requires both the local and remote
664 push` and :hg:`help pull`). This requires both the local and remote
665 repositories to support bookmarks. For versions prior to 1.8, this means
665 repositories to support bookmarks. For versions prior to 1.8, this means
666 the bookmarks extension must be enabled.
666 the bookmarks extension must be enabled.
667 '''
667 '''
668 hexfn = ui.debugflag and hex or short
668 hexfn = ui.debugflag and hex or short
669 marks = repo._bookmarks
669 marks = repo._bookmarks
670 cur = repo.changectx('.').node()
670 cur = repo.changectx('.').node()
671
671
672 if rename:
672 if rename:
673 if rename not in marks:
673 if rename not in marks:
674 raise util.Abort(_("bookmark '%s' does not exist") % rename)
674 raise util.Abort(_("bookmark '%s' does not exist") % rename)
675 if mark in marks and not force:
675 if mark in marks and not force:
676 raise util.Abort(_("bookmark '%s' already exists "
676 raise util.Abort(_("bookmark '%s' already exists "
677 "(use -f to force)") % mark)
677 "(use -f to force)") % mark)
678 if mark is None:
678 if mark is None:
679 raise util.Abort(_("new bookmark name required"))
679 raise util.Abort(_("new bookmark name required"))
680 marks[mark] = marks[rename]
680 marks[mark] = marks[rename]
681 if repo._bookmarkcurrent == rename and not inactive:
681 if repo._bookmarkcurrent == rename and not inactive:
682 bookmarks.setcurrent(repo, mark)
682 bookmarks.setcurrent(repo, mark)
683 del marks[rename]
683 del marks[rename]
684 bookmarks.write(repo)
684 bookmarks.write(repo)
685 return
685 return
686
686
687 if delete:
687 if delete:
688 if mark is None:
688 if mark is None:
689 raise util.Abort(_("bookmark name required"))
689 raise util.Abort(_("bookmark name required"))
690 if mark not in marks:
690 if mark not in marks:
691 raise util.Abort(_("bookmark '%s' does not exist") % mark)
691 raise util.Abort(_("bookmark '%s' does not exist") % mark)
692 if mark == repo._bookmarkcurrent:
692 if mark == repo._bookmarkcurrent:
693 bookmarks.setcurrent(repo, None)
693 bookmarks.setcurrent(repo, None)
694 del marks[mark]
694 del marks[mark]
695 bookmarks.write(repo)
695 bookmarks.write(repo)
696 return
696 return
697
697
698 if mark is not None:
698 if mark is not None:
699 if "\n" in mark:
699 if "\n" in mark:
700 raise util.Abort(_("bookmark name cannot contain newlines"))
700 raise util.Abort(_("bookmark name cannot contain newlines"))
701 mark = mark.strip()
701 mark = mark.strip()
702 if not mark:
702 if not mark:
703 raise util.Abort(_("bookmark names cannot consist entirely of "
703 raise util.Abort(_("bookmark names cannot consist entirely of "
704 "whitespace"))
704 "whitespace"))
705 if inactive and mark == repo._bookmarkcurrent:
705 if inactive and mark == repo._bookmarkcurrent:
706 bookmarks.setcurrent(repo, None)
706 bookmarks.setcurrent(repo, None)
707 return
707 return
708 if mark in marks and not force:
708 if mark in marks and not force:
709 raise util.Abort(_("bookmark '%s' already exists "
709 raise util.Abort(_("bookmark '%s' already exists "
710 "(use -f to force)") % mark)
710 "(use -f to force)") % mark)
711 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
711 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
712 and not force):
712 and not force):
713 raise util.Abort(
713 raise util.Abort(
714 _("a bookmark cannot have the name of an existing branch"))
714 _("a bookmark cannot have the name of an existing branch"))
715 if rev:
715 if rev:
716 marks[mark] = repo.lookup(rev)
716 marks[mark] = repo.lookup(rev)
717 else:
717 else:
718 marks[mark] = repo.changectx('.').node()
718 marks[mark] = repo.changectx('.').node()
719 if not inactive and repo.changectx('.').node() == marks[mark]:
719 if not inactive and repo.changectx('.').node() == marks[mark]:
720 bookmarks.setcurrent(repo, mark)
720 bookmarks.setcurrent(repo, mark)
721 bookmarks.write(repo)
721 bookmarks.write(repo)
722 return
722 return
723
723
724 if mark is None:
724 if mark is None:
725 if rev:
725 if rev:
726 raise util.Abort(_("bookmark name required"))
726 raise util.Abort(_("bookmark name required"))
727 if len(marks) == 0:
727 if len(marks) == 0:
728 ui.status(_("no bookmarks set\n"))
728 ui.status(_("no bookmarks set\n"))
729 else:
729 else:
730 for bmark, n in sorted(marks.iteritems()):
730 for bmark, n in sorted(marks.iteritems()):
731 current = repo._bookmarkcurrent
731 current = repo._bookmarkcurrent
732 if bmark == current and n == cur:
732 if bmark == current and n == cur:
733 prefix, label = '*', 'bookmarks.current'
733 prefix, label = '*', 'bookmarks.current'
734 else:
734 else:
735 prefix, label = ' ', ''
735 prefix, label = ' ', ''
736
736
737 if ui.quiet:
737 if ui.quiet:
738 ui.write("%s\n" % bmark, label=label)
738 ui.write("%s\n" % bmark, label=label)
739 else:
739 else:
740 ui.write(" %s %-25s %d:%s\n" % (
740 ui.write(" %s %-25s %d:%s\n" % (
741 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
741 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
742 label=label)
742 label=label)
743 return
743 return
744
744
745 @command('branch',
745 @command('branch',
746 [('f', 'force', None,
746 [('f', 'force', None,
747 _('set branch name even if it shadows an existing branch')),
747 _('set branch name even if it shadows an existing branch')),
748 ('C', 'clean', None, _('reset branch name to parent branch name'))],
748 ('C', 'clean', None, _('reset branch name to parent branch name'))],
749 _('[-fC] [NAME]'))
749 _('[-fC] [NAME]'))
750 def branch(ui, repo, label=None, **opts):
750 def branch(ui, repo, label=None, **opts):
751 """set or show the current branch name
751 """set or show the current branch name
752
752
753 With no argument, show the current branch name. With one argument,
753 With no argument, show the current branch name. With one argument,
754 set the working directory branch name (the branch will not exist
754 set the working directory branch name (the branch will not exist
755 in the repository until the next commit). Standard practice
755 in the repository until the next commit). Standard practice
756 recommends that primary development take place on the 'default'
756 recommends that primary development take place on the 'default'
757 branch.
757 branch.
758
758
759 Unless -f/--force is specified, branch will not let you set a
759 Unless -f/--force is specified, branch will not let you set a
760 branch name that already exists, even if it's inactive.
760 branch name that already exists, even if it's inactive.
761
761
762 Use -C/--clean to reset the working directory branch to that of
762 Use -C/--clean to reset the working directory branch to that of
763 the parent of the working directory, negating a previous branch
763 the parent of the working directory, negating a previous branch
764 change.
764 change.
765
765
766 Use the command :hg:`update` to switch to an existing branch. Use
766 Use the command :hg:`update` to switch to an existing branch. Use
767 :hg:`commit --close-branch` to mark this branch as closed.
767 :hg:`commit --close-branch` to mark this branch as closed.
768
768
769 .. note::
769 .. note::
770
770
771 Branch names are permanent. Use :hg:`bookmark` to create a
771 Branch names are permanent. Use :hg:`bookmark` to create a
772 light-weight bookmark instead. See :hg:`help glossary` for more
772 light-weight bookmark instead. See :hg:`help glossary` for more
773 information about named branches and bookmarks.
773 information about named branches and bookmarks.
774
774
775 Returns 0 on success.
775 Returns 0 on success.
776 """
776 """
777
777
778 if opts.get('clean'):
778 if opts.get('clean'):
779 label = repo[None].p1().branch()
779 label = repo[None].p1().branch()
780 repo.dirstate.setbranch(label)
780 repo.dirstate.setbranch(label)
781 ui.status(_('reset working directory to branch %s\n') % label)
781 ui.status(_('reset working directory to branch %s\n') % label)
782 elif label:
782 elif label:
783 if not opts.get('force') and label in repo.branchtags():
783 if not opts.get('force') and label in repo.branchtags():
784 if label not in [p.branch() for p in repo.parents()]:
784 if label not in [p.branch() for p in repo.parents()]:
785 raise util.Abort(_('a branch of the same name already exists'),
785 raise util.Abort(_('a branch of the same name already exists'),
786 # i18n: "it" refers to an existing branch
786 # i18n: "it" refers to an existing branch
787 hint=_("use 'hg update' to switch to it"))
787 hint=_("use 'hg update' to switch to it"))
788 repo.dirstate.setbranch(label)
788 repo.dirstate.setbranch(label)
789 ui.status(_('marked working directory as branch %s\n') % label)
789 ui.status(_('marked working directory as branch %s\n') % label)
790 else:
790 else:
791 ui.write("%s\n" % repo.dirstate.branch())
791 ui.write("%s\n" % repo.dirstate.branch())
792
792
793 @command('branches',
793 @command('branches',
794 [('a', 'active', False, _('show only branches that have unmerged heads')),
794 [('a', 'active', False, _('show only branches that have unmerged heads')),
795 ('c', 'closed', False, _('show normal and closed branches'))],
795 ('c', 'closed', False, _('show normal and closed branches'))],
796 _('[-ac]'))
796 _('[-ac]'))
797 def branches(ui, repo, active=False, closed=False):
797 def branches(ui, repo, active=False, closed=False):
798 """list repository named branches
798 """list repository named branches
799
799
800 List the repository's named branches, indicating which ones are
800 List the repository's named branches, indicating which ones are
801 inactive. If -c/--closed is specified, also list branches which have
801 inactive. If -c/--closed is specified, also list branches which have
802 been marked closed (see :hg:`commit --close-branch`).
802 been marked closed (see :hg:`commit --close-branch`).
803
803
804 If -a/--active is specified, only show active branches. A branch
804 If -a/--active is specified, only show active branches. A branch
805 is considered active if it contains repository heads.
805 is considered active if it contains repository heads.
806
806
807 Use the command :hg:`update` to switch to an existing branch.
807 Use the command :hg:`update` to switch to an existing branch.
808
808
809 Returns 0.
809 Returns 0.
810 """
810 """
811
811
812 hexfunc = ui.debugflag and hex or short
812 hexfunc = ui.debugflag and hex or short
813 activebranches = [repo[n].branch() for n in repo.heads()]
813 activebranches = [repo[n].branch() for n in repo.heads()]
814 def testactive(tag, node):
814 def testactive(tag, node):
815 realhead = tag in activebranches
815 realhead = tag in activebranches
816 open = node in repo.branchheads(tag, closed=False)
816 open = node in repo.branchheads(tag, closed=False)
817 return realhead and open
817 return realhead and open
818 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
818 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
819 for tag, node in repo.branchtags().items()],
819 for tag, node in repo.branchtags().items()],
820 reverse=True)
820 reverse=True)
821
821
822 for isactive, node, tag in branches:
822 for isactive, node, tag in branches:
823 if (not active) or isactive:
823 if (not active) or isactive:
824 if ui.quiet:
824 if ui.quiet:
825 ui.write("%s\n" % tag)
825 ui.write("%s\n" % tag)
826 else:
826 else:
827 hn = repo.lookup(node)
827 hn = repo.lookup(node)
828 if isactive:
828 if isactive:
829 label = 'branches.active'
829 label = 'branches.active'
830 notice = ''
830 notice = ''
831 elif hn not in repo.branchheads(tag, closed=False):
831 elif hn not in repo.branchheads(tag, closed=False):
832 if not closed:
832 if not closed:
833 continue
833 continue
834 label = 'branches.closed'
834 label = 'branches.closed'
835 notice = _(' (closed)')
835 notice = _(' (closed)')
836 else:
836 else:
837 label = 'branches.inactive'
837 label = 'branches.inactive'
838 notice = _(' (inactive)')
838 notice = _(' (inactive)')
839 if tag == repo.dirstate.branch():
839 if tag == repo.dirstate.branch():
840 label = 'branches.current'
840 label = 'branches.current'
841 rev = str(node).rjust(31 - encoding.colwidth(tag))
841 rev = str(node).rjust(31 - encoding.colwidth(tag))
842 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
842 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
843 tag = ui.label(tag, label)
843 tag = ui.label(tag, label)
844 ui.write("%s %s%s\n" % (tag, rev, notice))
844 ui.write("%s %s%s\n" % (tag, rev, notice))
845
845
846 @command('bundle',
846 @command('bundle',
847 [('f', 'force', None, _('run even when the destination is unrelated')),
847 [('f', 'force', None, _('run even when the destination is unrelated')),
848 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
848 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
849 _('REV')),
849 _('REV')),
850 ('b', 'branch', [], _('a specific branch you would like to bundle'),
850 ('b', 'branch', [], _('a specific branch you would like to bundle'),
851 _('BRANCH')),
851 _('BRANCH')),
852 ('', 'base', [],
852 ('', 'base', [],
853 _('a base changeset assumed to be available at the destination'),
853 _('a base changeset assumed to be available at the destination'),
854 _('REV')),
854 _('REV')),
855 ('a', 'all', None, _('bundle all changesets in the repository')),
855 ('a', 'all', None, _('bundle all changesets in the repository')),
856 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
856 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
857 ] + remoteopts,
857 ] + remoteopts,
858 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
858 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
859 def bundle(ui, repo, fname, dest=None, **opts):
859 def bundle(ui, repo, fname, dest=None, **opts):
860 """create a changegroup file
860 """create a changegroup file
861
861
862 Generate a compressed changegroup file collecting changesets not
862 Generate a compressed changegroup file collecting changesets not
863 known to be in another repository.
863 known to be in another repository.
864
864
865 If you omit the destination repository, then hg assumes the
865 If you omit the destination repository, then hg assumes the
866 destination will have all the nodes you specify with --base
866 destination will have all the nodes you specify with --base
867 parameters. To create a bundle containing all changesets, use
867 parameters. To create a bundle containing all changesets, use
868 -a/--all (or --base null).
868 -a/--all (or --base null).
869
869
870 You can change compression method with the -t/--type option.
870 You can change compression method with the -t/--type option.
871 The available compression methods are: none, bzip2, and
871 The available compression methods are: none, bzip2, and
872 gzip (by default, bundles are compressed using bzip2).
872 gzip (by default, bundles are compressed using bzip2).
873
873
874 The bundle file can then be transferred using conventional means
874 The bundle file can then be transferred using conventional means
875 and applied to another repository with the unbundle or pull
875 and applied to another repository with the unbundle or pull
876 command. This is useful when direct push and pull are not
876 command. This is useful when direct push and pull are not
877 available or when exporting an entire repository is undesirable.
877 available or when exporting an entire repository is undesirable.
878
878
879 Applying bundles preserves all changeset contents including
879 Applying bundles preserves all changeset contents including
880 permissions, copy/rename information, and revision history.
880 permissions, copy/rename information, and revision history.
881
881
882 Returns 0 on success, 1 if no changes found.
882 Returns 0 on success, 1 if no changes found.
883 """
883 """
884 revs = None
884 revs = None
885 if 'rev' in opts:
885 if 'rev' in opts:
886 revs = scmutil.revrange(repo, opts['rev'])
886 revs = scmutil.revrange(repo, opts['rev'])
887
887
888 if opts.get('all'):
888 if opts.get('all'):
889 base = ['null']
889 base = ['null']
890 else:
890 else:
891 base = scmutil.revrange(repo, opts.get('base'))
891 base = scmutil.revrange(repo, opts.get('base'))
892 if base:
892 if base:
893 if dest:
893 if dest:
894 raise util.Abort(_("--base is incompatible with specifying "
894 raise util.Abort(_("--base is incompatible with specifying "
895 "a destination"))
895 "a destination"))
896 common = [repo.lookup(rev) for rev in base]
896 common = [repo.lookup(rev) for rev in base]
897 heads = revs and map(repo.lookup, revs) or revs
897 heads = revs and map(repo.lookup, revs) or revs
898 else:
898 else:
899 dest = ui.expandpath(dest or 'default-push', dest or 'default')
899 dest = ui.expandpath(dest or 'default-push', dest or 'default')
900 dest, branches = hg.parseurl(dest, opts.get('branch'))
900 dest, branches = hg.parseurl(dest, opts.get('branch'))
901 other = hg.peer(repo, opts, dest)
901 other = hg.peer(repo, opts, dest)
902 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
902 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
903 heads = revs and map(repo.lookup, revs) or revs
903 heads = revs and map(repo.lookup, revs) or revs
904 common, outheads = discovery.findcommonoutgoing(repo, other,
904 common, outheads = discovery.findcommonoutgoing(repo, other,
905 onlyheads=heads,
905 onlyheads=heads,
906 force=opts.get('force'))
906 force=opts.get('force'))
907
907
908 cg = repo.getbundle('bundle', common=common, heads=heads)
908 cg = repo.getbundle('bundle', common=common, heads=heads)
909 if not cg:
909 if not cg:
910 ui.status(_("no changes found\n"))
910 ui.status(_("no changes found\n"))
911 return 1
911 return 1
912
912
913 bundletype = opts.get('type', 'bzip2').lower()
913 bundletype = opts.get('type', 'bzip2').lower()
914 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
914 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
915 bundletype = btypes.get(bundletype)
915 bundletype = btypes.get(bundletype)
916 if bundletype not in changegroup.bundletypes:
916 if bundletype not in changegroup.bundletypes:
917 raise util.Abort(_('unknown bundle type specified with --type'))
917 raise util.Abort(_('unknown bundle type specified with --type'))
918
918
919 changegroup.writebundle(cg, fname, bundletype)
919 changegroup.writebundle(cg, fname, bundletype)
920
920
921 @command('cat',
921 @command('cat',
922 [('o', 'output', '',
922 [('o', 'output', '',
923 _('print output to file with formatted name'), _('FORMAT')),
923 _('print output to file with formatted name'), _('FORMAT')),
924 ('r', 'rev', '', _('print the given revision'), _('REV')),
924 ('r', 'rev', '', _('print the given revision'), _('REV')),
925 ('', 'decode', None, _('apply any matching decode filter')),
925 ('', 'decode', None, _('apply any matching decode filter')),
926 ] + walkopts,
926 ] + walkopts,
927 _('[OPTION]... FILE...'))
927 _('[OPTION]... FILE...'))
928 def cat(ui, repo, file1, *pats, **opts):
928 def cat(ui, repo, file1, *pats, **opts):
929 """output the current or given revision of files
929 """output the current or given revision of files
930
930
931 Print the specified files as they were at the given revision. If
931 Print the specified files as they were at the given revision. If
932 no revision is given, the parent of the working directory is used,
932 no revision is given, the parent of the working directory is used,
933 or tip if no revision is checked out.
933 or tip if no revision is checked out.
934
934
935 Output may be to a file, in which case the name of the file is
935 Output may be to a file, in which case the name of the file is
936 given using a format string. The formatting rules are the same as
936 given using a format string. The formatting rules are the same as
937 for the export command, with the following additions:
937 for the export command, with the following additions:
938
938
939 :``%s``: basename of file being printed
939 :``%s``: basename of file being printed
940 :``%d``: dirname of file being printed, or '.' if in repository root
940 :``%d``: dirname of file being printed, or '.' if in repository root
941 :``%p``: root-relative path name of file being printed
941 :``%p``: root-relative path name of file being printed
942
942
943 Returns 0 on success.
943 Returns 0 on success.
944 """
944 """
945 ctx = scmutil.revsingle(repo, opts.get('rev'))
945 ctx = scmutil.revsingle(repo, opts.get('rev'))
946 err = 1
946 err = 1
947 m = scmutil.match(ctx, (file1,) + pats, opts)
947 m = scmutil.match(ctx, (file1,) + pats, opts)
948 for abs in ctx.walk(m):
948 for abs in ctx.walk(m):
949 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
949 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
950 pathname=abs)
950 pathname=abs)
951 data = ctx[abs].data()
951 data = ctx[abs].data()
952 if opts.get('decode'):
952 if opts.get('decode'):
953 data = repo.wwritedata(abs, data)
953 data = repo.wwritedata(abs, data)
954 fp.write(data)
954 fp.write(data)
955 fp.close()
955 fp.close()
956 err = 0
956 err = 0
957 return err
957 return err
958
958
959 @command('^clone',
959 @command('^clone',
960 [('U', 'noupdate', None,
960 [('U', 'noupdate', None,
961 _('the clone will include an empty working copy (only a repository)')),
961 _('the clone will include an empty working copy (only a repository)')),
962 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
962 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
963 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
963 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
964 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
964 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
965 ('', 'pull', None, _('use pull protocol to copy metadata')),
965 ('', 'pull', None, _('use pull protocol to copy metadata')),
966 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
966 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
967 ] + remoteopts,
967 ] + remoteopts,
968 _('[OPTION]... SOURCE [DEST]'))
968 _('[OPTION]... SOURCE [DEST]'))
969 def clone(ui, source, dest=None, **opts):
969 def clone(ui, source, dest=None, **opts):
970 """make a copy of an existing repository
970 """make a copy of an existing repository
971
971
972 Create a copy of an existing repository in a new directory.
972 Create a copy of an existing repository in a new directory.
973
973
974 If no destination directory name is specified, it defaults to the
974 If no destination directory name is specified, it defaults to the
975 basename of the source.
975 basename of the source.
976
976
977 The location of the source is added to the new repository's
977 The location of the source is added to the new repository's
978 ``.hg/hgrc`` file, as the default to be used for future pulls.
978 ``.hg/hgrc`` file, as the default to be used for future pulls.
979
979
980 See :hg:`help urls` for valid source format details.
980 See :hg:`help urls` for valid source format details.
981
981
982 It is possible to specify an ``ssh://`` URL as the destination, but no
982 It is possible to specify an ``ssh://`` URL as the destination, but no
983 ``.hg/hgrc`` and working directory will be created on the remote side.
983 ``.hg/hgrc`` and working directory will be created on the remote side.
984 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
984 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
985
985
986 A set of changesets (tags, or branch names) to pull may be specified
986 A set of changesets (tags, or branch names) to pull may be specified
987 by listing each changeset (tag, or branch name) with -r/--rev.
987 by listing each changeset (tag, or branch name) with -r/--rev.
988 If -r/--rev is used, the cloned repository will contain only a subset
988 If -r/--rev is used, the cloned repository will contain only a subset
989 of the changesets of the source repository. Only the set of changesets
989 of the changesets of the source repository. Only the set of changesets
990 defined by all -r/--rev options (including all their ancestors)
990 defined by all -r/--rev options (including all their ancestors)
991 will be pulled into the destination repository.
991 will be pulled into the destination repository.
992 No subsequent changesets (including subsequent tags) will be present
992 No subsequent changesets (including subsequent tags) will be present
993 in the destination.
993 in the destination.
994
994
995 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
995 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
996 local source repositories.
996 local source repositories.
997
997
998 For efficiency, hardlinks are used for cloning whenever the source
998 For efficiency, hardlinks are used for cloning whenever the source
999 and destination are on the same filesystem (note this applies only
999 and destination are on the same filesystem (note this applies only
1000 to the repository data, not to the working directory). Some
1000 to the repository data, not to the working directory). Some
1001 filesystems, such as AFS, implement hardlinking incorrectly, but
1001 filesystems, such as AFS, implement hardlinking incorrectly, but
1002 do not report errors. In these cases, use the --pull option to
1002 do not report errors. In these cases, use the --pull option to
1003 avoid hardlinking.
1003 avoid hardlinking.
1004
1004
1005 In some cases, you can clone repositories and the working directory
1005 In some cases, you can clone repositories and the working directory
1006 using full hardlinks with ::
1006 using full hardlinks with ::
1007
1007
1008 $ cp -al REPO REPOCLONE
1008 $ cp -al REPO REPOCLONE
1009
1009
1010 This is the fastest way to clone, but it is not always safe. The
1010 This is the fastest way to clone, but it is not always safe. The
1011 operation is not atomic (making sure REPO is not modified during
1011 operation is not atomic (making sure REPO is not modified during
1012 the operation is up to you) and you have to make sure your editor
1012 the operation is up to you) and you have to make sure your editor
1013 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
1013 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
1014 this is not compatible with certain extensions that place their
1014 this is not compatible with certain extensions that place their
1015 metadata under the .hg directory, such as mq.
1015 metadata under the .hg directory, such as mq.
1016
1016
1017 Mercurial will update the working directory to the first applicable
1017 Mercurial will update the working directory to the first applicable
1018 revision from this list:
1018 revision from this list:
1019
1019
1020 a) null if -U or the source repository has no changesets
1020 a) null if -U or the source repository has no changesets
1021 b) if -u . and the source repository is local, the first parent of
1021 b) if -u . and the source repository is local, the first parent of
1022 the source repository's working directory
1022 the source repository's working directory
1023 c) the changeset specified with -u (if a branch name, this means the
1023 c) the changeset specified with -u (if a branch name, this means the
1024 latest head of that branch)
1024 latest head of that branch)
1025 d) the changeset specified with -r
1025 d) the changeset specified with -r
1026 e) the tipmost head specified with -b
1026 e) the tipmost head specified with -b
1027 f) the tipmost head specified with the url#branch source syntax
1027 f) the tipmost head specified with the url#branch source syntax
1028 g) the tipmost head of the default branch
1028 g) the tipmost head of the default branch
1029 h) tip
1029 h) tip
1030
1030
1031 Returns 0 on success.
1031 Returns 0 on success.
1032 """
1032 """
1033 if opts.get('noupdate') and opts.get('updaterev'):
1033 if opts.get('noupdate') and opts.get('updaterev'):
1034 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1034 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1035
1035
1036 r = hg.clone(ui, opts, source, dest,
1036 r = hg.clone(ui, opts, source, dest,
1037 pull=opts.get('pull'),
1037 pull=opts.get('pull'),
1038 stream=opts.get('uncompressed'),
1038 stream=opts.get('uncompressed'),
1039 rev=opts.get('rev'),
1039 rev=opts.get('rev'),
1040 update=opts.get('updaterev') or not opts.get('noupdate'),
1040 update=opts.get('updaterev') or not opts.get('noupdate'),
1041 branch=opts.get('branch'))
1041 branch=opts.get('branch'))
1042
1042
1043 return r is None
1043 return r is None
1044
1044
1045 @command('^commit|ci',
1045 @command('^commit|ci',
1046 [('A', 'addremove', None,
1046 [('A', 'addremove', None,
1047 _('mark new/missing files as added/removed before committing')),
1047 _('mark new/missing files as added/removed before committing')),
1048 ('', 'close-branch', None,
1048 ('', 'close-branch', None,
1049 _('mark a branch as closed, hiding it from the branch list')),
1049 _('mark a branch as closed, hiding it from the branch list')),
1050 ] + walkopts + commitopts + commitopts2,
1050 ] + walkopts + commitopts + commitopts2,
1051 _('[OPTION]... [FILE]...'))
1051 _('[OPTION]... [FILE]...'))
1052 def commit(ui, repo, *pats, **opts):
1052 def commit(ui, repo, *pats, **opts):
1053 """commit the specified files or all outstanding changes
1053 """commit the specified files or all outstanding changes
1054
1054
1055 Commit changes to the given files into the repository. Unlike a
1055 Commit changes to the given files into the repository. Unlike a
1056 centralized SCM, this operation is a local operation. See
1056 centralized SCM, this operation is a local operation. See
1057 :hg:`push` for a way to actively distribute your changes.
1057 :hg:`push` for a way to actively distribute your changes.
1058
1058
1059 If a list of files is omitted, all changes reported by :hg:`status`
1059 If a list of files is omitted, all changes reported by :hg:`status`
1060 will be committed.
1060 will be committed.
1061
1061
1062 If you are committing the result of a merge, do not provide any
1062 If you are committing the result of a merge, do not provide any
1063 filenames or -I/-X filters.
1063 filenames or -I/-X filters.
1064
1064
1065 If no commit message is specified, Mercurial starts your
1065 If no commit message is specified, Mercurial starts your
1066 configured editor where you can enter a message. In case your
1066 configured editor where you can enter a message. In case your
1067 commit fails, you will find a backup of your message in
1067 commit fails, you will find a backup of your message in
1068 ``.hg/last-message.txt``.
1068 ``.hg/last-message.txt``.
1069
1069
1070 See :hg:`help dates` for a list of formats valid for -d/--date.
1070 See :hg:`help dates` for a list of formats valid for -d/--date.
1071
1071
1072 Returns 0 on success, 1 if nothing changed.
1072 Returns 0 on success, 1 if nothing changed.
1073 """
1073 """
1074 extra = {}
1074 extra = {}
1075 if opts.get('close_branch'):
1075 if opts.get('close_branch'):
1076 if repo['.'].node() not in repo.branchheads():
1076 if repo['.'].node() not in repo.branchheads():
1077 # The topo heads set is included in the branch heads set of the
1077 # The topo heads set is included in the branch heads set of the
1078 # current branch, so it's sufficient to test branchheads
1078 # current branch, so it's sufficient to test branchheads
1079 raise util.Abort(_('can only close branch heads'))
1079 raise util.Abort(_('can only close branch heads'))
1080 extra['close'] = 1
1080 extra['close'] = 1
1081 e = cmdutil.commiteditor
1081 e = cmdutil.commiteditor
1082 if opts.get('force_editor'):
1082 if opts.get('force_editor'):
1083 e = cmdutil.commitforceeditor
1083 e = cmdutil.commitforceeditor
1084
1084
1085 def commitfunc(ui, repo, message, match, opts):
1085 def commitfunc(ui, repo, message, match, opts):
1086 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1086 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1087 editor=e, extra=extra)
1087 editor=e, extra=extra)
1088
1088
1089 branch = repo[None].branch()
1089 branch = repo[None].branch()
1090 bheads = repo.branchheads(branch)
1090 bheads = repo.branchheads(branch)
1091
1091
1092 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1092 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1093 if not node:
1093 if not node:
1094 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1094 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1095 if stat[3]:
1095 if stat[3]:
1096 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1096 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1097 % len(stat[3]))
1097 % len(stat[3]))
1098 else:
1098 else:
1099 ui.status(_("nothing changed\n"))
1099 ui.status(_("nothing changed\n"))
1100 return 1
1100 return 1
1101
1101
1102 ctx = repo[node]
1102 ctx = repo[node]
1103 parents = ctx.parents()
1103 parents = ctx.parents()
1104
1104
1105 if bheads and not [x for x in parents
1105 if bheads and not [x for x in parents
1106 if x.node() in bheads and x.branch() == branch]:
1106 if x.node() in bheads and x.branch() == branch]:
1107 ui.status(_('created new head\n'))
1107 ui.status(_('created new head\n'))
1108 # The message is not printed for initial roots. For the other
1108 # The message is not printed for initial roots. For the other
1109 # changesets, it is printed in the following situations:
1109 # changesets, it is printed in the following situations:
1110 #
1110 #
1111 # Par column: for the 2 parents with ...
1111 # Par column: for the 2 parents with ...
1112 # N: null or no parent
1112 # N: null or no parent
1113 # B: parent is on another named branch
1113 # B: parent is on another named branch
1114 # C: parent is a regular non head changeset
1114 # C: parent is a regular non head changeset
1115 # H: parent was a branch head of the current branch
1115 # H: parent was a branch head of the current branch
1116 # Msg column: whether we print "created new head" message
1116 # Msg column: whether we print "created new head" message
1117 # In the following, it is assumed that there already exists some
1117 # In the following, it is assumed that there already exists some
1118 # initial branch heads of the current branch, otherwise nothing is
1118 # initial branch heads of the current branch, otherwise nothing is
1119 # printed anyway.
1119 # printed anyway.
1120 #
1120 #
1121 # Par Msg Comment
1121 # Par Msg Comment
1122 # NN y additional topo root
1122 # NN y additional topo root
1123 #
1123 #
1124 # BN y additional branch root
1124 # BN y additional branch root
1125 # CN y additional topo head
1125 # CN y additional topo head
1126 # HN n usual case
1126 # HN n usual case
1127 #
1127 #
1128 # BB y weird additional branch root
1128 # BB y weird additional branch root
1129 # CB y branch merge
1129 # CB y branch merge
1130 # HB n merge with named branch
1130 # HB n merge with named branch
1131 #
1131 #
1132 # CC y additional head from merge
1132 # CC y additional head from merge
1133 # CH n merge with a head
1133 # CH n merge with a head
1134 #
1134 #
1135 # HH n head merge: head count decreases
1135 # HH n head merge: head count decreases
1136
1136
1137 if not opts.get('close_branch'):
1137 if not opts.get('close_branch'):
1138 for r in parents:
1138 for r in parents:
1139 if r.extra().get('close') and r.branch() == branch:
1139 if r.extra().get('close') and r.branch() == branch:
1140 ui.status(_('reopening closed branch head %d\n') % r)
1140 ui.status(_('reopening closed branch head %d\n') % r)
1141
1141
1142 if ui.debugflag:
1142 if ui.debugflag:
1143 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1143 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1144 elif ui.verbose:
1144 elif ui.verbose:
1145 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1145 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1146
1146
1147 @command('copy|cp',
1147 @command('copy|cp',
1148 [('A', 'after', None, _('record a copy that has already occurred')),
1148 [('A', 'after', None, _('record a copy that has already occurred')),
1149 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1149 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1150 ] + walkopts + dryrunopts,
1150 ] + walkopts + dryrunopts,
1151 _('[OPTION]... [SOURCE]... DEST'))
1151 _('[OPTION]... [SOURCE]... DEST'))
1152 def copy(ui, repo, *pats, **opts):
1152 def copy(ui, repo, *pats, **opts):
1153 """mark files as copied for the next commit
1153 """mark files as copied for the next commit
1154
1154
1155 Mark dest as having copies of source files. If dest is a
1155 Mark dest as having copies of source files. If dest is a
1156 directory, copies are put in that directory. If dest is a file,
1156 directory, copies are put in that directory. If dest is a file,
1157 the source must be a single file.
1157 the source must be a single file.
1158
1158
1159 By default, this command copies the contents of files as they
1159 By default, this command copies the contents of files as they
1160 exist in the working directory. If invoked with -A/--after, the
1160 exist in the working directory. If invoked with -A/--after, the
1161 operation is recorded, but no copying is performed.
1161 operation is recorded, but no copying is performed.
1162
1162
1163 This command takes effect with the next commit. To undo a copy
1163 This command takes effect with the next commit. To undo a copy
1164 before that, see :hg:`revert`.
1164 before that, see :hg:`revert`.
1165
1165
1166 Returns 0 on success, 1 if errors are encountered.
1166 Returns 0 on success, 1 if errors are encountered.
1167 """
1167 """
1168 wlock = repo.wlock(False)
1168 wlock = repo.wlock(False)
1169 try:
1169 try:
1170 return cmdutil.copy(ui, repo, pats, opts)
1170 return cmdutil.copy(ui, repo, pats, opts)
1171 finally:
1171 finally:
1172 wlock.release()
1172 wlock.release()
1173
1173
1174 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1174 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1175 def debugancestor(ui, repo, *args):
1175 def debugancestor(ui, repo, *args):
1176 """find the ancestor revision of two revisions in a given index"""
1176 """find the ancestor revision of two revisions in a given index"""
1177 if len(args) == 3:
1177 if len(args) == 3:
1178 index, rev1, rev2 = args
1178 index, rev1, rev2 = args
1179 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1179 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1180 lookup = r.lookup
1180 lookup = r.lookup
1181 elif len(args) == 2:
1181 elif len(args) == 2:
1182 if not repo:
1182 if not repo:
1183 raise util.Abort(_("there is no Mercurial repository here "
1183 raise util.Abort(_("there is no Mercurial repository here "
1184 "(.hg not found)"))
1184 "(.hg not found)"))
1185 rev1, rev2 = args
1185 rev1, rev2 = args
1186 r = repo.changelog
1186 r = repo.changelog
1187 lookup = repo.lookup
1187 lookup = repo.lookup
1188 else:
1188 else:
1189 raise util.Abort(_('either two or three arguments required'))
1189 raise util.Abort(_('either two or three arguments required'))
1190 a = r.ancestor(lookup(rev1), lookup(rev2))
1190 a = r.ancestor(lookup(rev1), lookup(rev2))
1191 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1191 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1192
1192
1193 @command('debugbuilddag',
1193 @command('debugbuilddag',
1194 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1194 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1195 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1195 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1196 ('n', 'new-file', None, _('add new file at each rev'))],
1196 ('n', 'new-file', None, _('add new file at each rev'))],
1197 _('[OPTION]... [TEXT]'))
1197 _('[OPTION]... [TEXT]'))
1198 def debugbuilddag(ui, repo, text=None,
1198 def debugbuilddag(ui, repo, text=None,
1199 mergeable_file=False,
1199 mergeable_file=False,
1200 overwritten_file=False,
1200 overwritten_file=False,
1201 new_file=False):
1201 new_file=False):
1202 """builds a repo with a given DAG from scratch in the current empty repo
1202 """builds a repo with a given DAG from scratch in the current empty repo
1203
1203
1204 The description of the DAG is read from stdin if not given on the
1204 The description of the DAG is read from stdin if not given on the
1205 command line.
1205 command line.
1206
1206
1207 Elements:
1207 Elements:
1208
1208
1209 - "+n" is a linear run of n nodes based on the current default parent
1209 - "+n" is a linear run of n nodes based on the current default parent
1210 - "." is a single node based on the current default parent
1210 - "." is a single node based on the current default parent
1211 - "$" resets the default parent to null (implied at the start);
1211 - "$" resets the default parent to null (implied at the start);
1212 otherwise the default parent is always the last node created
1212 otherwise the default parent is always the last node created
1213 - "<p" sets the default parent to the backref p
1213 - "<p" sets the default parent to the backref p
1214 - "*p" is a fork at parent p, which is a backref
1214 - "*p" is a fork at parent p, which is a backref
1215 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1215 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1216 - "/p2" is a merge of the preceding node and p2
1216 - "/p2" is a merge of the preceding node and p2
1217 - ":tag" defines a local tag for the preceding node
1217 - ":tag" defines a local tag for the preceding node
1218 - "@branch" sets the named branch for subsequent nodes
1218 - "@branch" sets the named branch for subsequent nodes
1219 - "#...\\n" is a comment up to the end of the line
1219 - "#...\\n" is a comment up to the end of the line
1220
1220
1221 Whitespace between the above elements is ignored.
1221 Whitespace between the above elements is ignored.
1222
1222
1223 A backref is either
1223 A backref is either
1224
1224
1225 - a number n, which references the node curr-n, where curr is the current
1225 - a number n, which references the node curr-n, where curr is the current
1226 node, or
1226 node, or
1227 - the name of a local tag you placed earlier using ":tag", or
1227 - the name of a local tag you placed earlier using ":tag", or
1228 - empty to denote the default parent.
1228 - empty to denote the default parent.
1229
1229
1230 All string valued-elements are either strictly alphanumeric, or must
1230 All string valued-elements are either strictly alphanumeric, or must
1231 be enclosed in double quotes ("..."), with "\\" as escape character.
1231 be enclosed in double quotes ("..."), with "\\" as escape character.
1232 """
1232 """
1233
1233
1234 if text is None:
1234 if text is None:
1235 ui.status(_("reading DAG from stdin\n"))
1235 ui.status(_("reading DAG from stdin\n"))
1236 text = ui.fin.read()
1236 text = ui.fin.read()
1237
1237
1238 cl = repo.changelog
1238 cl = repo.changelog
1239 if len(cl) > 0:
1239 if len(cl) > 0:
1240 raise util.Abort(_('repository is not empty'))
1240 raise util.Abort(_('repository is not empty'))
1241
1241
1242 # determine number of revs in DAG
1242 # determine number of revs in DAG
1243 total = 0
1243 total = 0
1244 for type, data in dagparser.parsedag(text):
1244 for type, data in dagparser.parsedag(text):
1245 if type == 'n':
1245 if type == 'n':
1246 total += 1
1246 total += 1
1247
1247
1248 if mergeable_file:
1248 if mergeable_file:
1249 linesperrev = 2
1249 linesperrev = 2
1250 # make a file with k lines per rev
1250 # make a file with k lines per rev
1251 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1251 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1252 initialmergedlines.append("")
1252 initialmergedlines.append("")
1253
1253
1254 tags = []
1254 tags = []
1255
1255
1256 tr = repo.transaction("builddag")
1256 tr = repo.transaction("builddag")
1257 try:
1257 try:
1258
1258
1259 at = -1
1259 at = -1
1260 atbranch = 'default'
1260 atbranch = 'default'
1261 nodeids = []
1261 nodeids = []
1262 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1262 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1263 for type, data in dagparser.parsedag(text):
1263 for type, data in dagparser.parsedag(text):
1264 if type == 'n':
1264 if type == 'n':
1265 ui.note('node %s\n' % str(data))
1265 ui.note('node %s\n' % str(data))
1266 id, ps = data
1266 id, ps = data
1267
1267
1268 files = []
1268 files = []
1269 fctxs = {}
1269 fctxs = {}
1270
1270
1271 p2 = None
1271 p2 = None
1272 if mergeable_file:
1272 if mergeable_file:
1273 fn = "mf"
1273 fn = "mf"
1274 p1 = repo[ps[0]]
1274 p1 = repo[ps[0]]
1275 if len(ps) > 1:
1275 if len(ps) > 1:
1276 p2 = repo[ps[1]]
1276 p2 = repo[ps[1]]
1277 pa = p1.ancestor(p2)
1277 pa = p1.ancestor(p2)
1278 base, local, other = [x[fn].data() for x in pa, p1, p2]
1278 base, local, other = [x[fn].data() for x in pa, p1, p2]
1279 m3 = simplemerge.Merge3Text(base, local, other)
1279 m3 = simplemerge.Merge3Text(base, local, other)
1280 ml = [l.strip() for l in m3.merge_lines()]
1280 ml = [l.strip() for l in m3.merge_lines()]
1281 ml.append("")
1281 ml.append("")
1282 elif at > 0:
1282 elif at > 0:
1283 ml = p1[fn].data().split("\n")
1283 ml = p1[fn].data().split("\n")
1284 else:
1284 else:
1285 ml = initialmergedlines
1285 ml = initialmergedlines
1286 ml[id * linesperrev] += " r%i" % id
1286 ml[id * linesperrev] += " r%i" % id
1287 mergedtext = "\n".join(ml)
1287 mergedtext = "\n".join(ml)
1288 files.append(fn)
1288 files.append(fn)
1289 fctxs[fn] = context.memfilectx(fn, mergedtext)
1289 fctxs[fn] = context.memfilectx(fn, mergedtext)
1290
1290
1291 if overwritten_file:
1291 if overwritten_file:
1292 fn = "of"
1292 fn = "of"
1293 files.append(fn)
1293 files.append(fn)
1294 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1294 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1295
1295
1296 if new_file:
1296 if new_file:
1297 fn = "nf%i" % id
1297 fn = "nf%i" % id
1298 files.append(fn)
1298 files.append(fn)
1299 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1299 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1300 if len(ps) > 1:
1300 if len(ps) > 1:
1301 if not p2:
1301 if not p2:
1302 p2 = repo[ps[1]]
1302 p2 = repo[ps[1]]
1303 for fn in p2:
1303 for fn in p2:
1304 if fn.startswith("nf"):
1304 if fn.startswith("nf"):
1305 files.append(fn)
1305 files.append(fn)
1306 fctxs[fn] = p2[fn]
1306 fctxs[fn] = p2[fn]
1307
1307
1308 def fctxfn(repo, cx, path):
1308 def fctxfn(repo, cx, path):
1309 return fctxs.get(path)
1309 return fctxs.get(path)
1310
1310
1311 if len(ps) == 0 or ps[0] < 0:
1311 if len(ps) == 0 or ps[0] < 0:
1312 pars = [None, None]
1312 pars = [None, None]
1313 elif len(ps) == 1:
1313 elif len(ps) == 1:
1314 pars = [nodeids[ps[0]], None]
1314 pars = [nodeids[ps[0]], None]
1315 else:
1315 else:
1316 pars = [nodeids[p] for p in ps]
1316 pars = [nodeids[p] for p in ps]
1317 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1317 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1318 date=(id, 0),
1318 date=(id, 0),
1319 user="debugbuilddag",
1319 user="debugbuilddag",
1320 extra={'branch': atbranch})
1320 extra={'branch': atbranch})
1321 nodeid = repo.commitctx(cx)
1321 nodeid = repo.commitctx(cx)
1322 nodeids.append(nodeid)
1322 nodeids.append(nodeid)
1323 at = id
1323 at = id
1324 elif type == 'l':
1324 elif type == 'l':
1325 id, name = data
1325 id, name = data
1326 ui.note('tag %s\n' % name)
1326 ui.note('tag %s\n' % name)
1327 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1327 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1328 elif type == 'a':
1328 elif type == 'a':
1329 ui.note('branch %s\n' % data)
1329 ui.note('branch %s\n' % data)
1330 atbranch = data
1330 atbranch = data
1331 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1331 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1332 tr.close()
1332 tr.close()
1333 finally:
1333 finally:
1334 ui.progress(_('building'), None)
1334 ui.progress(_('building'), None)
1335 tr.release()
1335 tr.release()
1336
1336
1337 if tags:
1337 if tags:
1338 repo.opener.write("localtags", "".join(tags))
1338 repo.opener.write("localtags", "".join(tags))
1339
1339
1340 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1340 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1341 def debugbundle(ui, bundlepath, all=None, **opts):
1341 def debugbundle(ui, bundlepath, all=None, **opts):
1342 """lists the contents of a bundle"""
1342 """lists the contents of a bundle"""
1343 f = url.open(ui, bundlepath)
1343 f = url.open(ui, bundlepath)
1344 try:
1344 try:
1345 gen = changegroup.readbundle(f, bundlepath)
1345 gen = changegroup.readbundle(f, bundlepath)
1346 if all:
1346 if all:
1347 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1347 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1348
1348
1349 def showchunks(named):
1349 def showchunks(named):
1350 ui.write("\n%s\n" % named)
1350 ui.write("\n%s\n" % named)
1351 chain = None
1351 chain = None
1352 while True:
1352 while True:
1353 chunkdata = gen.deltachunk(chain)
1353 chunkdata = gen.deltachunk(chain)
1354 if not chunkdata:
1354 if not chunkdata:
1355 break
1355 break
1356 node = chunkdata['node']
1356 node = chunkdata['node']
1357 p1 = chunkdata['p1']
1357 p1 = chunkdata['p1']
1358 p2 = chunkdata['p2']
1358 p2 = chunkdata['p2']
1359 cs = chunkdata['cs']
1359 cs = chunkdata['cs']
1360 deltabase = chunkdata['deltabase']
1360 deltabase = chunkdata['deltabase']
1361 delta = chunkdata['delta']
1361 delta = chunkdata['delta']
1362 ui.write("%s %s %s %s %s %s\n" %
1362 ui.write("%s %s %s %s %s %s\n" %
1363 (hex(node), hex(p1), hex(p2),
1363 (hex(node), hex(p1), hex(p2),
1364 hex(cs), hex(deltabase), len(delta)))
1364 hex(cs), hex(deltabase), len(delta)))
1365 chain = node
1365 chain = node
1366
1366
1367 chunkdata = gen.changelogheader()
1367 chunkdata = gen.changelogheader()
1368 showchunks("changelog")
1368 showchunks("changelog")
1369 chunkdata = gen.manifestheader()
1369 chunkdata = gen.manifestheader()
1370 showchunks("manifest")
1370 showchunks("manifest")
1371 while True:
1371 while True:
1372 chunkdata = gen.filelogheader()
1372 chunkdata = gen.filelogheader()
1373 if not chunkdata:
1373 if not chunkdata:
1374 break
1374 break
1375 fname = chunkdata['filename']
1375 fname = chunkdata['filename']
1376 showchunks(fname)
1376 showchunks(fname)
1377 else:
1377 else:
1378 chunkdata = gen.changelogheader()
1378 chunkdata = gen.changelogheader()
1379 chain = None
1379 chain = None
1380 while True:
1380 while True:
1381 chunkdata = gen.deltachunk(chain)
1381 chunkdata = gen.deltachunk(chain)
1382 if not chunkdata:
1382 if not chunkdata:
1383 break
1383 break
1384 node = chunkdata['node']
1384 node = chunkdata['node']
1385 ui.write("%s\n" % hex(node))
1385 ui.write("%s\n" % hex(node))
1386 chain = node
1386 chain = node
1387 finally:
1387 finally:
1388 f.close()
1388 f.close()
1389
1389
1390 @command('debugcheckstate', [], '')
1390 @command('debugcheckstate', [], '')
1391 def debugcheckstate(ui, repo):
1391 def debugcheckstate(ui, repo):
1392 """validate the correctness of the current dirstate"""
1392 """validate the correctness of the current dirstate"""
1393 parent1, parent2 = repo.dirstate.parents()
1393 parent1, parent2 = repo.dirstate.parents()
1394 m1 = repo[parent1].manifest()
1394 m1 = repo[parent1].manifest()
1395 m2 = repo[parent2].manifest()
1395 m2 = repo[parent2].manifest()
1396 errors = 0
1396 errors = 0
1397 for f in repo.dirstate:
1397 for f in repo.dirstate:
1398 state = repo.dirstate[f]
1398 state = repo.dirstate[f]
1399 if state in "nr" and f not in m1:
1399 if state in "nr" and f not in m1:
1400 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1400 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1401 errors += 1
1401 errors += 1
1402 if state in "a" and f in m1:
1402 if state in "a" and f in m1:
1403 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1403 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1404 errors += 1
1404 errors += 1
1405 if state in "m" and f not in m1 and f not in m2:
1405 if state in "m" and f not in m1 and f not in m2:
1406 ui.warn(_("%s in state %s, but not in either manifest\n") %
1406 ui.warn(_("%s in state %s, but not in either manifest\n") %
1407 (f, state))
1407 (f, state))
1408 errors += 1
1408 errors += 1
1409 for f in m1:
1409 for f in m1:
1410 state = repo.dirstate[f]
1410 state = repo.dirstate[f]
1411 if state not in "nrm":
1411 if state not in "nrm":
1412 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1412 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1413 errors += 1
1413 errors += 1
1414 if errors:
1414 if errors:
1415 error = _(".hg/dirstate inconsistent with current parent's manifest")
1415 error = _(".hg/dirstate inconsistent with current parent's manifest")
1416 raise util.Abort(error)
1416 raise util.Abort(error)
1417
1417
1418 @command('debugcommands', [], _('[COMMAND]'))
1418 @command('debugcommands', [], _('[COMMAND]'))
1419 def debugcommands(ui, cmd='', *args):
1419 def debugcommands(ui, cmd='', *args):
1420 """list all available commands and options"""
1420 """list all available commands and options"""
1421 for cmd, vals in sorted(table.iteritems()):
1421 for cmd, vals in sorted(table.iteritems()):
1422 cmd = cmd.split('|')[0].strip('^')
1422 cmd = cmd.split('|')[0].strip('^')
1423 opts = ', '.join([i[1] for i in vals[1]])
1423 opts = ', '.join([i[1] for i in vals[1]])
1424 ui.write('%s: %s\n' % (cmd, opts))
1424 ui.write('%s: %s\n' % (cmd, opts))
1425
1425
1426 @command('debugcomplete',
1426 @command('debugcomplete',
1427 [('o', 'options', None, _('show the command options'))],
1427 [('o', 'options', None, _('show the command options'))],
1428 _('[-o] CMD'))
1428 _('[-o] CMD'))
1429 def debugcomplete(ui, cmd='', **opts):
1429 def debugcomplete(ui, cmd='', **opts):
1430 """returns the completion list associated with the given command"""
1430 """returns the completion list associated with the given command"""
1431
1431
1432 if opts.get('options'):
1432 if opts.get('options'):
1433 options = []
1433 options = []
1434 otables = [globalopts]
1434 otables = [globalopts]
1435 if cmd:
1435 if cmd:
1436 aliases, entry = cmdutil.findcmd(cmd, table, False)
1436 aliases, entry = cmdutil.findcmd(cmd, table, False)
1437 otables.append(entry[1])
1437 otables.append(entry[1])
1438 for t in otables:
1438 for t in otables:
1439 for o in t:
1439 for o in t:
1440 if "(DEPRECATED)" in o[3]:
1440 if "(DEPRECATED)" in o[3]:
1441 continue
1441 continue
1442 if o[0]:
1442 if o[0]:
1443 options.append('-%s' % o[0])
1443 options.append('-%s' % o[0])
1444 options.append('--%s' % o[1])
1444 options.append('--%s' % o[1])
1445 ui.write("%s\n" % "\n".join(options))
1445 ui.write("%s\n" % "\n".join(options))
1446 return
1446 return
1447
1447
1448 cmdlist = cmdutil.findpossible(cmd, table)
1448 cmdlist = cmdutil.findpossible(cmd, table)
1449 if ui.verbose:
1449 if ui.verbose:
1450 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1450 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1451 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1451 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1452
1452
1453 @command('debugdag',
1453 @command('debugdag',
1454 [('t', 'tags', None, _('use tags as labels')),
1454 [('t', 'tags', None, _('use tags as labels')),
1455 ('b', 'branches', None, _('annotate with branch names')),
1455 ('b', 'branches', None, _('annotate with branch names')),
1456 ('', 'dots', None, _('use dots for runs')),
1456 ('', 'dots', None, _('use dots for runs')),
1457 ('s', 'spaces', None, _('separate elements by spaces'))],
1457 ('s', 'spaces', None, _('separate elements by spaces'))],
1458 _('[OPTION]... [FILE [REV]...]'))
1458 _('[OPTION]... [FILE [REV]...]'))
1459 def debugdag(ui, repo, file_=None, *revs, **opts):
1459 def debugdag(ui, repo, file_=None, *revs, **opts):
1460 """format the changelog or an index DAG as a concise textual description
1460 """format the changelog or an index DAG as a concise textual description
1461
1461
1462 If you pass a revlog index, the revlog's DAG is emitted. If you list
1462 If you pass a revlog index, the revlog's DAG is emitted. If you list
1463 revision numbers, they get labelled in the output as rN.
1463 revision numbers, they get labelled in the output as rN.
1464
1464
1465 Otherwise, the changelog DAG of the current repo is emitted.
1465 Otherwise, the changelog DAG of the current repo is emitted.
1466 """
1466 """
1467 spaces = opts.get('spaces')
1467 spaces = opts.get('spaces')
1468 dots = opts.get('dots')
1468 dots = opts.get('dots')
1469 if file_:
1469 if file_:
1470 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1470 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1471 revs = set((int(r) for r in revs))
1471 revs = set((int(r) for r in revs))
1472 def events():
1472 def events():
1473 for r in rlog:
1473 for r in rlog:
1474 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1474 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1475 if r in revs:
1475 if r in revs:
1476 yield 'l', (r, "r%i" % r)
1476 yield 'l', (r, "r%i" % r)
1477 elif repo:
1477 elif repo:
1478 cl = repo.changelog
1478 cl = repo.changelog
1479 tags = opts.get('tags')
1479 tags = opts.get('tags')
1480 branches = opts.get('branches')
1480 branches = opts.get('branches')
1481 if tags:
1481 if tags:
1482 labels = {}
1482 labels = {}
1483 for l, n in repo.tags().items():
1483 for l, n in repo.tags().items():
1484 labels.setdefault(cl.rev(n), []).append(l)
1484 labels.setdefault(cl.rev(n), []).append(l)
1485 def events():
1485 def events():
1486 b = "default"
1486 b = "default"
1487 for r in cl:
1487 for r in cl:
1488 if branches:
1488 if branches:
1489 newb = cl.read(cl.node(r))[5]['branch']
1489 newb = cl.read(cl.node(r))[5]['branch']
1490 if newb != b:
1490 if newb != b:
1491 yield 'a', newb
1491 yield 'a', newb
1492 b = newb
1492 b = newb
1493 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1493 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1494 if tags:
1494 if tags:
1495 ls = labels.get(r)
1495 ls = labels.get(r)
1496 if ls:
1496 if ls:
1497 for l in ls:
1497 for l in ls:
1498 yield 'l', (r, l)
1498 yield 'l', (r, l)
1499 else:
1499 else:
1500 raise util.Abort(_('need repo for changelog dag'))
1500 raise util.Abort(_('need repo for changelog dag'))
1501
1501
1502 for line in dagparser.dagtextlines(events(),
1502 for line in dagparser.dagtextlines(events(),
1503 addspaces=spaces,
1503 addspaces=spaces,
1504 wraplabels=True,
1504 wraplabels=True,
1505 wrapannotations=True,
1505 wrapannotations=True,
1506 wrapnonlinear=dots,
1506 wrapnonlinear=dots,
1507 usedots=dots,
1507 usedots=dots,
1508 maxlinewidth=70):
1508 maxlinewidth=70):
1509 ui.write(line)
1509 ui.write(line)
1510 ui.write("\n")
1510 ui.write("\n")
1511
1511
1512 @command('debugdata',
1512 @command('debugdata',
1513 [('c', 'changelog', False, _('open changelog')),
1513 [('c', 'changelog', False, _('open changelog')),
1514 ('m', 'manifest', False, _('open manifest'))],
1514 ('m', 'manifest', False, _('open manifest'))],
1515 _('-c|-m|FILE REV'))
1515 _('-c|-m|FILE REV'))
1516 def debugdata(ui, repo, file_, rev = None, **opts):
1516 def debugdata(ui, repo, file_, rev = None, **opts):
1517 """dump the contents of a data file revision"""
1517 """dump the contents of a data file revision"""
1518 if opts.get('changelog') or opts.get('manifest'):
1518 if opts.get('changelog') or opts.get('manifest'):
1519 file_, rev = None, file_
1519 file_, rev = None, file_
1520 elif rev is None:
1520 elif rev is None:
1521 raise error.CommandError('debugdata', _('invalid arguments'))
1521 raise error.CommandError('debugdata', _('invalid arguments'))
1522 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1522 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1523 try:
1523 try:
1524 ui.write(r.revision(r.lookup(rev)))
1524 ui.write(r.revision(r.lookup(rev)))
1525 except KeyError:
1525 except KeyError:
1526 raise util.Abort(_('invalid revision identifier %s') % rev)
1526 raise util.Abort(_('invalid revision identifier %s') % rev)
1527
1527
1528 @command('debugdate',
1528 @command('debugdate',
1529 [('e', 'extended', None, _('try extended date formats'))],
1529 [('e', 'extended', None, _('try extended date formats'))],
1530 _('[-e] DATE [RANGE]'))
1530 _('[-e] DATE [RANGE]'))
1531 def debugdate(ui, date, range=None, **opts):
1531 def debugdate(ui, date, range=None, **opts):
1532 """parse and display a date"""
1532 """parse and display a date"""
1533 if opts["extended"]:
1533 if opts["extended"]:
1534 d = util.parsedate(date, util.extendeddateformats)
1534 d = util.parsedate(date, util.extendeddateformats)
1535 else:
1535 else:
1536 d = util.parsedate(date)
1536 d = util.parsedate(date)
1537 ui.write("internal: %s %s\n" % d)
1537 ui.write("internal: %s %s\n" % d)
1538 ui.write("standard: %s\n" % util.datestr(d))
1538 ui.write("standard: %s\n" % util.datestr(d))
1539 if range:
1539 if range:
1540 m = util.matchdate(range)
1540 m = util.matchdate(range)
1541 ui.write("match: %s\n" % m(d[0]))
1541 ui.write("match: %s\n" % m(d[0]))
1542
1542
1543 @command('debugdiscovery',
1543 @command('debugdiscovery',
1544 [('', 'old', None, _('use old-style discovery')),
1544 [('', 'old', None, _('use old-style discovery')),
1545 ('', 'nonheads', None,
1545 ('', 'nonheads', None,
1546 _('use old-style discovery with non-heads included')),
1546 _('use old-style discovery with non-heads included')),
1547 ] + remoteopts,
1547 ] + remoteopts,
1548 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1548 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1549 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1549 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1550 """runs the changeset discovery protocol in isolation"""
1550 """runs the changeset discovery protocol in isolation"""
1551 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1551 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1552 remote = hg.peer(repo, opts, remoteurl)
1552 remote = hg.peer(repo, opts, remoteurl)
1553 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1553 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1554
1554
1555 # make sure tests are repeatable
1555 # make sure tests are repeatable
1556 random.seed(12323)
1556 random.seed(12323)
1557
1557
1558 def doit(localheads, remoteheads):
1558 def doit(localheads, remoteheads):
1559 if opts.get('old'):
1559 if opts.get('old'):
1560 if localheads:
1560 if localheads:
1561 raise util.Abort('cannot use localheads with old style discovery')
1561 raise util.Abort('cannot use localheads with old style discovery')
1562 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1562 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1563 force=True)
1563 force=True)
1564 common = set(common)
1564 common = set(common)
1565 if not opts.get('nonheads'):
1565 if not opts.get('nonheads'):
1566 ui.write("unpruned common: %s\n" % " ".join([short(n)
1566 ui.write("unpruned common: %s\n" % " ".join([short(n)
1567 for n in common]))
1567 for n in common]))
1568 dag = dagutil.revlogdag(repo.changelog)
1568 dag = dagutil.revlogdag(repo.changelog)
1569 all = dag.ancestorset(dag.internalizeall(common))
1569 all = dag.ancestorset(dag.internalizeall(common))
1570 common = dag.externalizeall(dag.headsetofconnecteds(all))
1570 common = dag.externalizeall(dag.headsetofconnecteds(all))
1571 else:
1571 else:
1572 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1572 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1573 common = set(common)
1573 common = set(common)
1574 rheads = set(hds)
1574 rheads = set(hds)
1575 lheads = set(repo.heads())
1575 lheads = set(repo.heads())
1576 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1576 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1577 if lheads <= common:
1577 if lheads <= common:
1578 ui.write("local is subset\n")
1578 ui.write("local is subset\n")
1579 elif rheads <= common:
1579 elif rheads <= common:
1580 ui.write("remote is subset\n")
1580 ui.write("remote is subset\n")
1581
1581
1582 serverlogs = opts.get('serverlog')
1582 serverlogs = opts.get('serverlog')
1583 if serverlogs:
1583 if serverlogs:
1584 for filename in serverlogs:
1584 for filename in serverlogs:
1585 logfile = open(filename, 'r')
1585 logfile = open(filename, 'r')
1586 try:
1586 try:
1587 line = logfile.readline()
1587 line = logfile.readline()
1588 while line:
1588 while line:
1589 parts = line.strip().split(';')
1589 parts = line.strip().split(';')
1590 op = parts[1]
1590 op = parts[1]
1591 if op == 'cg':
1591 if op == 'cg':
1592 pass
1592 pass
1593 elif op == 'cgss':
1593 elif op == 'cgss':
1594 doit(parts[2].split(' '), parts[3].split(' '))
1594 doit(parts[2].split(' '), parts[3].split(' '))
1595 elif op == 'unb':
1595 elif op == 'unb':
1596 doit(parts[3].split(' '), parts[2].split(' '))
1596 doit(parts[3].split(' '), parts[2].split(' '))
1597 line = logfile.readline()
1597 line = logfile.readline()
1598 finally:
1598 finally:
1599 logfile.close()
1599 logfile.close()
1600
1600
1601 else:
1601 else:
1602 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1602 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1603 opts.get('remote_head'))
1603 opts.get('remote_head'))
1604 localrevs = opts.get('local_head')
1604 localrevs = opts.get('local_head')
1605 doit(localrevs, remoterevs)
1605 doit(localrevs, remoterevs)
1606
1606
1607 @command('debugfileset', [], ('REVSPEC'))
1607 @command('debugfileset', [], ('REVSPEC'))
1608 def debugfileset(ui, repo, expr):
1608 def debugfileset(ui, repo, expr):
1609 '''parse and apply a fileset specification'''
1609 '''parse and apply a fileset specification'''
1610 if ui.verbose:
1610 if ui.verbose:
1611 tree = fileset.parse(expr)[0]
1611 tree = fileset.parse(expr)[0]
1612 ui.note(tree, "\n")
1612 ui.note(tree, "\n")
1613
1613
1614 for f in fileset.getfileset(repo[None], expr):
1614 for f in fileset.getfileset(repo[None], expr):
1615 ui.write("%s\n" % f)
1615 ui.write("%s\n" % f)
1616
1616
1617 @command('debugfsinfo', [], _('[PATH]'))
1617 @command('debugfsinfo', [], _('[PATH]'))
1618 def debugfsinfo(ui, path = "."):
1618 def debugfsinfo(ui, path = "."):
1619 """show information detected about current filesystem"""
1619 """show information detected about current filesystem"""
1620 util.writefile('.debugfsinfo', '')
1620 util.writefile('.debugfsinfo', '')
1621 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1621 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1622 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1622 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1623 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1623 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1624 and 'yes' or 'no'))
1624 and 'yes' or 'no'))
1625 os.unlink('.debugfsinfo')
1625 os.unlink('.debugfsinfo')
1626
1626
1627 @command('debuggetbundle',
1627 @command('debuggetbundle',
1628 [('H', 'head', [], _('id of head node'), _('ID')),
1628 [('H', 'head', [], _('id of head node'), _('ID')),
1629 ('C', 'common', [], _('id of common node'), _('ID')),
1629 ('C', 'common', [], _('id of common node'), _('ID')),
1630 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1630 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1631 _('REPO FILE [-H|-C ID]...'))
1631 _('REPO FILE [-H|-C ID]...'))
1632 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1632 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1633 """retrieves a bundle from a repo
1633 """retrieves a bundle from a repo
1634
1634
1635 Every ID must be a full-length hex node id string. Saves the bundle to the
1635 Every ID must be a full-length hex node id string. Saves the bundle to the
1636 given file.
1636 given file.
1637 """
1637 """
1638 repo = hg.peer(ui, opts, repopath)
1638 repo = hg.peer(ui, opts, repopath)
1639 if not repo.capable('getbundle'):
1639 if not repo.capable('getbundle'):
1640 raise util.Abort("getbundle() not supported by target repository")
1640 raise util.Abort("getbundle() not supported by target repository")
1641 args = {}
1641 args = {}
1642 if common:
1642 if common:
1643 args['common'] = [bin(s) for s in common]
1643 args['common'] = [bin(s) for s in common]
1644 if head:
1644 if head:
1645 args['heads'] = [bin(s) for s in head]
1645 args['heads'] = [bin(s) for s in head]
1646 bundle = repo.getbundle('debug', **args)
1646 bundle = repo.getbundle('debug', **args)
1647
1647
1648 bundletype = opts.get('type', 'bzip2').lower()
1648 bundletype = opts.get('type', 'bzip2').lower()
1649 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1649 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1650 bundletype = btypes.get(bundletype)
1650 bundletype = btypes.get(bundletype)
1651 if bundletype not in changegroup.bundletypes:
1651 if bundletype not in changegroup.bundletypes:
1652 raise util.Abort(_('unknown bundle type specified with --type'))
1652 raise util.Abort(_('unknown bundle type specified with --type'))
1653 changegroup.writebundle(bundle, bundlepath, bundletype)
1653 changegroup.writebundle(bundle, bundlepath, bundletype)
1654
1654
1655 @command('debugignore', [], '')
1655 @command('debugignore', [], '')
1656 def debugignore(ui, repo, *values, **opts):
1656 def debugignore(ui, repo, *values, **opts):
1657 """display the combined ignore pattern"""
1657 """display the combined ignore pattern"""
1658 ignore = repo.dirstate._ignore
1658 ignore = repo.dirstate._ignore
1659 if hasattr(ignore, 'includepat'):
1659 if hasattr(ignore, 'includepat'):
1660 ui.write("%s\n" % ignore.includepat)
1660 ui.write("%s\n" % ignore.includepat)
1661 else:
1661 else:
1662 raise util.Abort(_("no ignore patterns found"))
1662 raise util.Abort(_("no ignore patterns found"))
1663
1663
1664 @command('debugindex',
1664 @command('debugindex',
1665 [('c', 'changelog', False, _('open changelog')),
1665 [('c', 'changelog', False, _('open changelog')),
1666 ('m', 'manifest', False, _('open manifest')),
1666 ('m', 'manifest', False, _('open manifest')),
1667 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1667 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1668 _('[-f FORMAT] -c|-m|FILE'))
1668 _('[-f FORMAT] -c|-m|FILE'))
1669 def debugindex(ui, repo, file_ = None, **opts):
1669 def debugindex(ui, repo, file_ = None, **opts):
1670 """dump the contents of an index file"""
1670 """dump the contents of an index file"""
1671 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1671 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1672 format = opts.get('format', 0)
1672 format = opts.get('format', 0)
1673 if format not in (0, 1):
1673 if format not in (0, 1):
1674 raise util.Abort(_("unknown format %d") % format)
1674 raise util.Abort(_("unknown format %d") % format)
1675
1675
1676 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1676 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1677 if generaldelta:
1677 if generaldelta:
1678 basehdr = ' delta'
1678 basehdr = ' delta'
1679 else:
1679 else:
1680 basehdr = ' base'
1680 basehdr = ' base'
1681
1681
1682 if format == 0:
1682 if format == 0:
1683 ui.write(" rev offset length " + basehdr + " linkrev"
1683 ui.write(" rev offset length " + basehdr + " linkrev"
1684 " nodeid p1 p2\n")
1684 " nodeid p1 p2\n")
1685 elif format == 1:
1685 elif format == 1:
1686 ui.write(" rev flag offset length"
1686 ui.write(" rev flag offset length"
1687 " size " + basehdr + " link p1 p2 nodeid\n")
1687 " size " + basehdr + " link p1 p2 nodeid\n")
1688
1688
1689 for i in r:
1689 for i in r:
1690 node = r.node(i)
1690 node = r.node(i)
1691 if generaldelta:
1691 if generaldelta:
1692 base = r.deltaparent(i)
1692 base = r.deltaparent(i)
1693 else:
1693 else:
1694 base = r.chainbase(i)
1694 base = r.chainbase(i)
1695 if format == 0:
1695 if format == 0:
1696 try:
1696 try:
1697 pp = r.parents(node)
1697 pp = r.parents(node)
1698 except:
1698 except:
1699 pp = [nullid, nullid]
1699 pp = [nullid, nullid]
1700 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1700 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1701 i, r.start(i), r.length(i), base, r.linkrev(i),
1701 i, r.start(i), r.length(i), base, r.linkrev(i),
1702 short(node), short(pp[0]), short(pp[1])))
1702 short(node), short(pp[0]), short(pp[1])))
1703 elif format == 1:
1703 elif format == 1:
1704 pr = r.parentrevs(i)
1704 pr = r.parentrevs(i)
1705 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1705 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1706 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1706 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1707 base, r.linkrev(i), pr[0], pr[1], short(node)))
1707 base, r.linkrev(i), pr[0], pr[1], short(node)))
1708
1708
1709 @command('debugindexdot', [], _('FILE'))
1709 @command('debugindexdot', [], _('FILE'))
1710 def debugindexdot(ui, repo, file_):
1710 def debugindexdot(ui, repo, file_):
1711 """dump an index DAG as a graphviz dot file"""
1711 """dump an index DAG as a graphviz dot file"""
1712 r = None
1712 r = None
1713 if repo:
1713 if repo:
1714 filelog = repo.file(file_)
1714 filelog = repo.file(file_)
1715 if len(filelog):
1715 if len(filelog):
1716 r = filelog
1716 r = filelog
1717 if not r:
1717 if not r:
1718 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1718 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1719 ui.write("digraph G {\n")
1719 ui.write("digraph G {\n")
1720 for i in r:
1720 for i in r:
1721 node = r.node(i)
1721 node = r.node(i)
1722 pp = r.parents(node)
1722 pp = r.parents(node)
1723 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1723 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1724 if pp[1] != nullid:
1724 if pp[1] != nullid:
1725 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1725 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1726 ui.write("}\n")
1726 ui.write("}\n")
1727
1727
1728 @command('debuginstall', [], '')
1728 @command('debuginstall', [], '')
1729 def debuginstall(ui):
1729 def debuginstall(ui):
1730 '''test Mercurial installation
1730 '''test Mercurial installation
1731
1731
1732 Returns 0 on success.
1732 Returns 0 on success.
1733 '''
1733 '''
1734
1734
1735 def writetemp(contents):
1735 def writetemp(contents):
1736 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1736 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1737 f = os.fdopen(fd, "wb")
1737 f = os.fdopen(fd, "wb")
1738 f.write(contents)
1738 f.write(contents)
1739 f.close()
1739 f.close()
1740 return name
1740 return name
1741
1741
1742 problems = 0
1742 problems = 0
1743
1743
1744 # encoding
1744 # encoding
1745 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1745 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1746 try:
1746 try:
1747 encoding.fromlocal("test")
1747 encoding.fromlocal("test")
1748 except util.Abort, inst:
1748 except util.Abort, inst:
1749 ui.write(" %s\n" % inst)
1749 ui.write(" %s\n" % inst)
1750 ui.write(_(" (check that your locale is properly set)\n"))
1750 ui.write(_(" (check that your locale is properly set)\n"))
1751 problems += 1
1751 problems += 1
1752
1752
1753 # compiled modules
1753 # compiled modules
1754 ui.status(_("Checking installed modules (%s)...\n")
1754 ui.status(_("Checking installed modules (%s)...\n")
1755 % os.path.dirname(__file__))
1755 % os.path.dirname(__file__))
1756 try:
1756 try:
1757 import bdiff, mpatch, base85, osutil
1757 import bdiff, mpatch, base85, osutil
1758 except Exception, inst:
1758 except Exception, inst:
1759 ui.write(" %s\n" % inst)
1759 ui.write(" %s\n" % inst)
1760 ui.write(_(" One or more extensions could not be found"))
1760 ui.write(_(" One or more extensions could not be found"))
1761 ui.write(_(" (check that you compiled the extensions)\n"))
1761 ui.write(_(" (check that you compiled the extensions)\n"))
1762 problems += 1
1762 problems += 1
1763
1763
1764 # templates
1764 # templates
1765 ui.status(_("Checking templates...\n"))
1765 ui.status(_("Checking templates...\n"))
1766 try:
1766 try:
1767 import templater
1767 import templater
1768 templater.templater(templater.templatepath("map-cmdline.default"))
1768 templater.templater(templater.templatepath("map-cmdline.default"))
1769 except Exception, inst:
1769 except Exception, inst:
1770 ui.write(" %s\n" % inst)
1770 ui.write(" %s\n" % inst)
1771 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1771 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1772 problems += 1
1772 problems += 1
1773
1773
1774 # editor
1774 # editor
1775 ui.status(_("Checking commit editor...\n"))
1775 ui.status(_("Checking commit editor...\n"))
1776 editor = ui.geteditor()
1776 editor = ui.geteditor()
1777 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1777 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1778 if not cmdpath:
1778 if not cmdpath:
1779 if editor == 'vi':
1779 if editor == 'vi':
1780 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1780 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1781 ui.write(_(" (specify a commit editor in your configuration"
1781 ui.write(_(" (specify a commit editor in your configuration"
1782 " file)\n"))
1782 " file)\n"))
1783 else:
1783 else:
1784 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1784 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1785 ui.write(_(" (specify a commit editor in your configuration"
1785 ui.write(_(" (specify a commit editor in your configuration"
1786 " file)\n"))
1786 " file)\n"))
1787 problems += 1
1787 problems += 1
1788
1788
1789 # check username
1789 # check username
1790 ui.status(_("Checking username...\n"))
1790 ui.status(_("Checking username...\n"))
1791 try:
1791 try:
1792 ui.username()
1792 ui.username()
1793 except util.Abort, e:
1793 except util.Abort, e:
1794 ui.write(" %s\n" % e)
1794 ui.write(" %s\n" % e)
1795 ui.write(_(" (specify a username in your configuration file)\n"))
1795 ui.write(_(" (specify a username in your configuration file)\n"))
1796 problems += 1
1796 problems += 1
1797
1797
1798 if not problems:
1798 if not problems:
1799 ui.status(_("No problems detected\n"))
1799 ui.status(_("No problems detected\n"))
1800 else:
1800 else:
1801 ui.write(_("%s problems detected,"
1801 ui.write(_("%s problems detected,"
1802 " please check your install!\n") % problems)
1802 " please check your install!\n") % problems)
1803
1803
1804 return problems
1804 return problems
1805
1805
1806 @command('debugknown', [], _('REPO ID...'))
1806 @command('debugknown', [], _('REPO ID...'))
1807 def debugknown(ui, repopath, *ids, **opts):
1807 def debugknown(ui, repopath, *ids, **opts):
1808 """test whether node ids are known to a repo
1808 """test whether node ids are known to a repo
1809
1809
1810 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1810 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1811 indicating unknown/known.
1811 indicating unknown/known.
1812 """
1812 """
1813 repo = hg.peer(ui, opts, repopath)
1813 repo = hg.peer(ui, opts, repopath)
1814 if not repo.capable('known'):
1814 if not repo.capable('known'):
1815 raise util.Abort("known() not supported by target repository")
1815 raise util.Abort("known() not supported by target repository")
1816 flags = repo.known([bin(s) for s in ids])
1816 flags = repo.known([bin(s) for s in ids])
1817 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1817 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1818
1818
1819 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1819 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1820 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1820 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1821 '''access the pushkey key/value protocol
1821 '''access the pushkey key/value protocol
1822
1822
1823 With two args, list the keys in the given namespace.
1823 With two args, list the keys in the given namespace.
1824
1824
1825 With five args, set a key to new if it currently is set to old.
1825 With five args, set a key to new if it currently is set to old.
1826 Reports success or failure.
1826 Reports success or failure.
1827 '''
1827 '''
1828
1828
1829 target = hg.peer(ui, {}, repopath)
1829 target = hg.peer(ui, {}, repopath)
1830 if keyinfo:
1830 if keyinfo:
1831 key, old, new = keyinfo
1831 key, old, new = keyinfo
1832 r = target.pushkey(namespace, key, old, new)
1832 r = target.pushkey(namespace, key, old, new)
1833 ui.status(str(r) + '\n')
1833 ui.status(str(r) + '\n')
1834 return not r
1834 return not r
1835 else:
1835 else:
1836 for k, v in target.listkeys(namespace).iteritems():
1836 for k, v in target.listkeys(namespace).iteritems():
1837 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1837 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1838 v.encode('string-escape')))
1838 v.encode('string-escape')))
1839
1839
1840 @command('debugrebuildstate',
1840 @command('debugrebuildstate',
1841 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1841 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1842 _('[-r REV] [REV]'))
1842 _('[-r REV] [REV]'))
1843 def debugrebuildstate(ui, repo, rev="tip"):
1843 def debugrebuildstate(ui, repo, rev="tip"):
1844 """rebuild the dirstate as it would look like for the given revision"""
1844 """rebuild the dirstate as it would look like for the given revision"""
1845 ctx = scmutil.revsingle(repo, rev)
1845 ctx = scmutil.revsingle(repo, rev)
1846 wlock = repo.wlock()
1846 wlock = repo.wlock()
1847 try:
1847 try:
1848 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1848 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1849 finally:
1849 finally:
1850 wlock.release()
1850 wlock.release()
1851
1851
1852 @command('debugrename',
1852 @command('debugrename',
1853 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1853 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1854 _('[-r REV] FILE'))
1854 _('[-r REV] FILE'))
1855 def debugrename(ui, repo, file1, *pats, **opts):
1855 def debugrename(ui, repo, file1, *pats, **opts):
1856 """dump rename information"""
1856 """dump rename information"""
1857
1857
1858 ctx = scmutil.revsingle(repo, opts.get('rev'))
1858 ctx = scmutil.revsingle(repo, opts.get('rev'))
1859 m = scmutil.match(ctx, (file1,) + pats, opts)
1859 m = scmutil.match(ctx, (file1,) + pats, opts)
1860 for abs in ctx.walk(m):
1860 for abs in ctx.walk(m):
1861 fctx = ctx[abs]
1861 fctx = ctx[abs]
1862 o = fctx.filelog().renamed(fctx.filenode())
1862 o = fctx.filelog().renamed(fctx.filenode())
1863 rel = m.rel(abs)
1863 rel = m.rel(abs)
1864 if o:
1864 if o:
1865 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1865 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1866 else:
1866 else:
1867 ui.write(_("%s not renamed\n") % rel)
1867 ui.write(_("%s not renamed\n") % rel)
1868
1868
1869 @command('debugrevlog',
1869 @command('debugrevlog',
1870 [('c', 'changelog', False, _('open changelog')),
1870 [('c', 'changelog', False, _('open changelog')),
1871 ('m', 'manifest', False, _('open manifest')),
1871 ('m', 'manifest', False, _('open manifest')),
1872 ('d', 'dump', False, _('dump index data'))],
1872 ('d', 'dump', False, _('dump index data'))],
1873 _('-c|-m|FILE'))
1873 _('-c|-m|FILE'))
1874 def debugrevlog(ui, repo, file_ = None, **opts):
1874 def debugrevlog(ui, repo, file_ = None, **opts):
1875 """show data and statistics about a revlog"""
1875 """show data and statistics about a revlog"""
1876 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1876 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1877
1877
1878 if opts.get("dump"):
1878 if opts.get("dump"):
1879 numrevs = len(r)
1879 numrevs = len(r)
1880 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1880 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1881 " rawsize totalsize compression heads\n")
1881 " rawsize totalsize compression heads\n")
1882 ts = 0
1882 ts = 0
1883 heads = set()
1883 heads = set()
1884 for rev in xrange(numrevs):
1884 for rev in xrange(numrevs):
1885 dbase = r.deltaparent(rev)
1885 dbase = r.deltaparent(rev)
1886 if dbase == -1:
1886 if dbase == -1:
1887 dbase = rev
1887 dbase = rev
1888 cbase = r.chainbase(rev)
1888 cbase = r.chainbase(rev)
1889 p1, p2 = r.parentrevs(rev)
1889 p1, p2 = r.parentrevs(rev)
1890 rs = r.rawsize(rev)
1890 rs = r.rawsize(rev)
1891 ts = ts + rs
1891 ts = ts + rs
1892 heads -= set(r.parentrevs(rev))
1892 heads -= set(r.parentrevs(rev))
1893 heads.add(rev)
1893 heads.add(rev)
1894 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1894 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1895 (rev, p1, p2, r.start(rev), r.end(rev),
1895 (rev, p1, p2, r.start(rev), r.end(rev),
1896 r.start(dbase), r.start(cbase),
1896 r.start(dbase), r.start(cbase),
1897 r.start(p1), r.start(p2),
1897 r.start(p1), r.start(p2),
1898 rs, ts, ts / r.end(rev), len(heads)))
1898 rs, ts, ts / r.end(rev), len(heads)))
1899 return 0
1899 return 0
1900
1900
1901 v = r.version
1901 v = r.version
1902 format = v & 0xFFFF
1902 format = v & 0xFFFF
1903 flags = []
1903 flags = []
1904 gdelta = False
1904 gdelta = False
1905 if v & revlog.REVLOGNGINLINEDATA:
1905 if v & revlog.REVLOGNGINLINEDATA:
1906 flags.append('inline')
1906 flags.append('inline')
1907 if v & revlog.REVLOGGENERALDELTA:
1907 if v & revlog.REVLOGGENERALDELTA:
1908 gdelta = True
1908 gdelta = True
1909 flags.append('generaldelta')
1909 flags.append('generaldelta')
1910 if not flags:
1910 if not flags:
1911 flags = ['(none)']
1911 flags = ['(none)']
1912
1912
1913 nummerges = 0
1913 nummerges = 0
1914 numfull = 0
1914 numfull = 0
1915 numprev = 0
1915 numprev = 0
1916 nump1 = 0
1916 nump1 = 0
1917 nump2 = 0
1917 nump2 = 0
1918 numother = 0
1918 numother = 0
1919 nump1prev = 0
1919 nump1prev = 0
1920 nump2prev = 0
1920 nump2prev = 0
1921 chainlengths = []
1921 chainlengths = []
1922
1922
1923 datasize = [None, 0, 0L]
1923 datasize = [None, 0, 0L]
1924 fullsize = [None, 0, 0L]
1924 fullsize = [None, 0, 0L]
1925 deltasize = [None, 0, 0L]
1925 deltasize = [None, 0, 0L]
1926
1926
1927 def addsize(size, l):
1927 def addsize(size, l):
1928 if l[0] is None or size < l[0]:
1928 if l[0] is None or size < l[0]:
1929 l[0] = size
1929 l[0] = size
1930 if size > l[1]:
1930 if size > l[1]:
1931 l[1] = size
1931 l[1] = size
1932 l[2] += size
1932 l[2] += size
1933
1933
1934 numrevs = len(r)
1934 numrevs = len(r)
1935 for rev in xrange(numrevs):
1935 for rev in xrange(numrevs):
1936 p1, p2 = r.parentrevs(rev)
1936 p1, p2 = r.parentrevs(rev)
1937 delta = r.deltaparent(rev)
1937 delta = r.deltaparent(rev)
1938 if format > 0:
1938 if format > 0:
1939 addsize(r.rawsize(rev), datasize)
1939 addsize(r.rawsize(rev), datasize)
1940 if p2 != nullrev:
1940 if p2 != nullrev:
1941 nummerges += 1
1941 nummerges += 1
1942 size = r.length(rev)
1942 size = r.length(rev)
1943 if delta == nullrev:
1943 if delta == nullrev:
1944 chainlengths.append(0)
1944 chainlengths.append(0)
1945 numfull += 1
1945 numfull += 1
1946 addsize(size, fullsize)
1946 addsize(size, fullsize)
1947 else:
1947 else:
1948 chainlengths.append(chainlengths[delta] + 1)
1948 chainlengths.append(chainlengths[delta] + 1)
1949 addsize(size, deltasize)
1949 addsize(size, deltasize)
1950 if delta == rev - 1:
1950 if delta == rev - 1:
1951 numprev += 1
1951 numprev += 1
1952 if delta == p1:
1952 if delta == p1:
1953 nump1prev += 1
1953 nump1prev += 1
1954 elif delta == p2:
1954 elif delta == p2:
1955 nump2prev += 1
1955 nump2prev += 1
1956 elif delta == p1:
1956 elif delta == p1:
1957 nump1 += 1
1957 nump1 += 1
1958 elif delta == p2:
1958 elif delta == p2:
1959 nump2 += 1
1959 nump2 += 1
1960 elif delta != nullrev:
1960 elif delta != nullrev:
1961 numother += 1
1961 numother += 1
1962
1962
1963 numdeltas = numrevs - numfull
1963 numdeltas = numrevs - numfull
1964 numoprev = numprev - nump1prev - nump2prev
1964 numoprev = numprev - nump1prev - nump2prev
1965 totalrawsize = datasize[2]
1965 totalrawsize = datasize[2]
1966 datasize[2] /= numrevs
1966 datasize[2] /= numrevs
1967 fulltotal = fullsize[2]
1967 fulltotal = fullsize[2]
1968 fullsize[2] /= numfull
1968 fullsize[2] /= numfull
1969 deltatotal = deltasize[2]
1969 deltatotal = deltasize[2]
1970 deltasize[2] /= numrevs - numfull
1970 deltasize[2] /= numrevs - numfull
1971 totalsize = fulltotal + deltatotal
1971 totalsize = fulltotal + deltatotal
1972 avgchainlen = sum(chainlengths) / numrevs
1972 avgchainlen = sum(chainlengths) / numrevs
1973 compratio = totalrawsize / totalsize
1973 compratio = totalrawsize / totalsize
1974
1974
1975 basedfmtstr = '%%%dd\n'
1975 basedfmtstr = '%%%dd\n'
1976 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1976 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1977
1977
1978 def dfmtstr(max):
1978 def dfmtstr(max):
1979 return basedfmtstr % len(str(max))
1979 return basedfmtstr % len(str(max))
1980 def pcfmtstr(max, padding=0):
1980 def pcfmtstr(max, padding=0):
1981 return basepcfmtstr % (len(str(max)), ' ' * padding)
1981 return basepcfmtstr % (len(str(max)), ' ' * padding)
1982
1982
1983 def pcfmt(value, total):
1983 def pcfmt(value, total):
1984 return (value, 100 * float(value) / total)
1984 return (value, 100 * float(value) / total)
1985
1985
1986 ui.write('format : %d\n' % format)
1986 ui.write('format : %d\n' % format)
1987 ui.write('flags : %s\n' % ', '.join(flags))
1987 ui.write('flags : %s\n' % ', '.join(flags))
1988
1988
1989 ui.write('\n')
1989 ui.write('\n')
1990 fmt = pcfmtstr(totalsize)
1990 fmt = pcfmtstr(totalsize)
1991 fmt2 = dfmtstr(totalsize)
1991 fmt2 = dfmtstr(totalsize)
1992 ui.write('revisions : ' + fmt2 % numrevs)
1992 ui.write('revisions : ' + fmt2 % numrevs)
1993 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
1993 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
1994 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
1994 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
1995 ui.write('revisions : ' + fmt2 % numrevs)
1995 ui.write('revisions : ' + fmt2 % numrevs)
1996 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
1996 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
1997 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
1997 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
1998 ui.write('revision size : ' + fmt2 % totalsize)
1998 ui.write('revision size : ' + fmt2 % totalsize)
1999 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
1999 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2000 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2000 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2001
2001
2002 ui.write('\n')
2002 ui.write('\n')
2003 fmt = dfmtstr(max(avgchainlen, compratio))
2003 fmt = dfmtstr(max(avgchainlen, compratio))
2004 ui.write('avg chain length : ' + fmt % avgchainlen)
2004 ui.write('avg chain length : ' + fmt % avgchainlen)
2005 ui.write('compression ratio : ' + fmt % compratio)
2005 ui.write('compression ratio : ' + fmt % compratio)
2006
2006
2007 if format > 0:
2007 if format > 0:
2008 ui.write('\n')
2008 ui.write('\n')
2009 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2009 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2010 % tuple(datasize))
2010 % tuple(datasize))
2011 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2011 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2012 % tuple(fullsize))
2012 % tuple(fullsize))
2013 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2013 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2014 % tuple(deltasize))
2014 % tuple(deltasize))
2015
2015
2016 if numdeltas > 0:
2016 if numdeltas > 0:
2017 ui.write('\n')
2017 ui.write('\n')
2018 fmt = pcfmtstr(numdeltas)
2018 fmt = pcfmtstr(numdeltas)
2019 fmt2 = pcfmtstr(numdeltas, 4)
2019 fmt2 = pcfmtstr(numdeltas, 4)
2020 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2020 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2021 if numprev > 0:
2021 if numprev > 0:
2022 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2022 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2023 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2023 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2024 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2024 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2025 if gdelta:
2025 if gdelta:
2026 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2026 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2027 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2027 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2028 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2028 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2029
2029
2030 @command('debugrevspec', [], ('REVSPEC'))
2030 @command('debugrevspec', [], ('REVSPEC'))
2031 def debugrevspec(ui, repo, expr):
2031 def debugrevspec(ui, repo, expr):
2032 '''parse and apply a revision specification'''
2032 '''parse and apply a revision specification'''
2033 if ui.verbose:
2033 if ui.verbose:
2034 tree = revset.parse(expr)[0]
2034 tree = revset.parse(expr)[0]
2035 ui.note(tree, "\n")
2035 ui.note(tree, "\n")
2036 newtree = revset.findaliases(ui, tree)
2036 newtree = revset.findaliases(ui, tree)
2037 if newtree != tree:
2037 if newtree != tree:
2038 ui.note(newtree, "\n")
2038 ui.note(newtree, "\n")
2039 func = revset.match(ui, expr)
2039 func = revset.match(ui, expr)
2040 for c in func(repo, range(len(repo))):
2040 for c in func(repo, range(len(repo))):
2041 ui.write("%s\n" % c)
2041 ui.write("%s\n" % c)
2042
2042
2043 @command('debugsetparents', [], _('REV1 [REV2]'))
2043 @command('debugsetparents', [], _('REV1 [REV2]'))
2044 def debugsetparents(ui, repo, rev1, rev2=None):
2044 def debugsetparents(ui, repo, rev1, rev2=None):
2045 """manually set the parents of the current working directory
2045 """manually set the parents of the current working directory
2046
2046
2047 This is useful for writing repository conversion tools, but should
2047 This is useful for writing repository conversion tools, but should
2048 be used with care.
2048 be used with care.
2049
2049
2050 Returns 0 on success.
2050 Returns 0 on success.
2051 """
2051 """
2052
2052
2053 r1 = scmutil.revsingle(repo, rev1).node()
2053 r1 = scmutil.revsingle(repo, rev1).node()
2054 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2054 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2055
2055
2056 wlock = repo.wlock()
2056 wlock = repo.wlock()
2057 try:
2057 try:
2058 repo.dirstate.setparents(r1, r2)
2058 repo.dirstate.setparents(r1, r2)
2059 finally:
2059 finally:
2060 wlock.release()
2060 wlock.release()
2061
2061
2062 @command('debugstate',
2062 @command('debugstate',
2063 [('', 'nodates', None, _('do not display the saved mtime')),
2063 [('', 'nodates', None, _('do not display the saved mtime')),
2064 ('', 'datesort', None, _('sort by saved mtime'))],
2064 ('', 'datesort', None, _('sort by saved mtime'))],
2065 _('[OPTION]...'))
2065 _('[OPTION]...'))
2066 def debugstate(ui, repo, nodates=None, datesort=None):
2066 def debugstate(ui, repo, nodates=None, datesort=None):
2067 """show the contents of the current dirstate"""
2067 """show the contents of the current dirstate"""
2068 timestr = ""
2068 timestr = ""
2069 showdate = not nodates
2069 showdate = not nodates
2070 if datesort:
2070 if datesort:
2071 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2071 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2072 else:
2072 else:
2073 keyfunc = None # sort by filename
2073 keyfunc = None # sort by filename
2074 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2074 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2075 if showdate:
2075 if showdate:
2076 if ent[3] == -1:
2076 if ent[3] == -1:
2077 # Pad or slice to locale representation
2077 # Pad or slice to locale representation
2078 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2078 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2079 time.localtime(0)))
2079 time.localtime(0)))
2080 timestr = 'unset'
2080 timestr = 'unset'
2081 timestr = (timestr[:locale_len] +
2081 timestr = (timestr[:locale_len] +
2082 ' ' * (locale_len - len(timestr)))
2082 ' ' * (locale_len - len(timestr)))
2083 else:
2083 else:
2084 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2084 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2085 time.localtime(ent[3]))
2085 time.localtime(ent[3]))
2086 if ent[1] & 020000:
2086 if ent[1] & 020000:
2087 mode = 'lnk'
2087 mode = 'lnk'
2088 else:
2088 else:
2089 mode = '%3o' % (ent[1] & 0777)
2089 mode = '%3o' % (ent[1] & 0777)
2090 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2090 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2091 for f in repo.dirstate.copies():
2091 for f in repo.dirstate.copies():
2092 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2092 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2093
2093
2094 @command('debugsub',
2094 @command('debugsub',
2095 [('r', 'rev', '',
2095 [('r', 'rev', '',
2096 _('revision to check'), _('REV'))],
2096 _('revision to check'), _('REV'))],
2097 _('[-r REV] [REV]'))
2097 _('[-r REV] [REV]'))
2098 def debugsub(ui, repo, rev=None):
2098 def debugsub(ui, repo, rev=None):
2099 ctx = scmutil.revsingle(repo, rev, None)
2099 ctx = scmutil.revsingle(repo, rev, None)
2100 for k, v in sorted(ctx.substate.items()):
2100 for k, v in sorted(ctx.substate.items()):
2101 ui.write('path %s\n' % k)
2101 ui.write('path %s\n' % k)
2102 ui.write(' source %s\n' % v[0])
2102 ui.write(' source %s\n' % v[0])
2103 ui.write(' revision %s\n' % v[1])
2103 ui.write(' revision %s\n' % v[1])
2104
2104
2105 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2105 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2106 def debugwalk(ui, repo, *pats, **opts):
2106 def debugwalk(ui, repo, *pats, **opts):
2107 """show how files match on given patterns"""
2107 """show how files match on given patterns"""
2108 m = scmutil.match(repo[None], pats, opts)
2108 m = scmutil.match(repo[None], pats, opts)
2109 items = list(repo.walk(m))
2109 items = list(repo.walk(m))
2110 if not items:
2110 if not items:
2111 return
2111 return
2112 fmt = 'f %%-%ds %%-%ds %%s' % (
2112 fmt = 'f %%-%ds %%-%ds %%s' % (
2113 max([len(abs) for abs in items]),
2113 max([len(abs) for abs in items]),
2114 max([len(m.rel(abs)) for abs in items]))
2114 max([len(m.rel(abs)) for abs in items]))
2115 for abs in items:
2115 for abs in items:
2116 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2116 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2117 ui.write("%s\n" % line.rstrip())
2117 ui.write("%s\n" % line.rstrip())
2118
2118
2119 @command('debugwireargs',
2119 @command('debugwireargs',
2120 [('', 'three', '', 'three'),
2120 [('', 'three', '', 'three'),
2121 ('', 'four', '', 'four'),
2121 ('', 'four', '', 'four'),
2122 ('', 'five', '', 'five'),
2122 ('', 'five', '', 'five'),
2123 ] + remoteopts,
2123 ] + remoteopts,
2124 _('REPO [OPTIONS]... [ONE [TWO]]'))
2124 _('REPO [OPTIONS]... [ONE [TWO]]'))
2125 def debugwireargs(ui, repopath, *vals, **opts):
2125 def debugwireargs(ui, repopath, *vals, **opts):
2126 repo = hg.peer(ui, opts, repopath)
2126 repo = hg.peer(ui, opts, repopath)
2127 for opt in remoteopts:
2127 for opt in remoteopts:
2128 del opts[opt[1]]
2128 del opts[opt[1]]
2129 args = {}
2129 args = {}
2130 for k, v in opts.iteritems():
2130 for k, v in opts.iteritems():
2131 if v:
2131 if v:
2132 args[k] = v
2132 args[k] = v
2133 # run twice to check that we don't mess up the stream for the next command
2133 # run twice to check that we don't mess up the stream for the next command
2134 res1 = repo.debugwireargs(*vals, **args)
2134 res1 = repo.debugwireargs(*vals, **args)
2135 res2 = repo.debugwireargs(*vals, **args)
2135 res2 = repo.debugwireargs(*vals, **args)
2136 ui.write("%s\n" % res1)
2136 ui.write("%s\n" % res1)
2137 if res1 != res2:
2137 if res1 != res2:
2138 ui.warn("%s\n" % res2)
2138 ui.warn("%s\n" % res2)
2139
2139
2140 @command('^diff',
2140 @command('^diff',
2141 [('r', 'rev', [], _('revision'), _('REV')),
2141 [('r', 'rev', [], _('revision'), _('REV')),
2142 ('c', 'change', '', _('change made by revision'), _('REV'))
2142 ('c', 'change', '', _('change made by revision'), _('REV'))
2143 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2143 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2144 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2144 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2145 def diff(ui, repo, *pats, **opts):
2145 def diff(ui, repo, *pats, **opts):
2146 """diff repository (or selected files)
2146 """diff repository (or selected files)
2147
2147
2148 Show differences between revisions for the specified files.
2148 Show differences between revisions for the specified files.
2149
2149
2150 Differences between files are shown using the unified diff format.
2150 Differences between files are shown using the unified diff format.
2151
2151
2152 .. note::
2152 .. note::
2153 diff may generate unexpected results for merges, as it will
2153 diff may generate unexpected results for merges, as it will
2154 default to comparing against the working directory's first
2154 default to comparing against the working directory's first
2155 parent changeset if no revisions are specified.
2155 parent changeset if no revisions are specified.
2156
2156
2157 When two revision arguments are given, then changes are shown
2157 When two revision arguments are given, then changes are shown
2158 between those revisions. If only one revision is specified then
2158 between those revisions. If only one revision is specified then
2159 that revision is compared to the working directory, and, when no
2159 that revision is compared to the working directory, and, when no
2160 revisions are specified, the working directory files are compared
2160 revisions are specified, the working directory files are compared
2161 to its parent.
2161 to its parent.
2162
2162
2163 Alternatively you can specify -c/--change with a revision to see
2163 Alternatively you can specify -c/--change with a revision to see
2164 the changes in that changeset relative to its first parent.
2164 the changes in that changeset relative to its first parent.
2165
2165
2166 Without the -a/--text option, diff will avoid generating diffs of
2166 Without the -a/--text option, diff will avoid generating diffs of
2167 files it detects as binary. With -a, diff will generate a diff
2167 files it detects as binary. With -a, diff will generate a diff
2168 anyway, probably with undesirable results.
2168 anyway, probably with undesirable results.
2169
2169
2170 Use the -g/--git option to generate diffs in the git extended diff
2170 Use the -g/--git option to generate diffs in the git extended diff
2171 format. For more information, read :hg:`help diffs`.
2171 format. For more information, read :hg:`help diffs`.
2172
2172
2173 Returns 0 on success.
2173 Returns 0 on success.
2174 """
2174 """
2175
2175
2176 revs = opts.get('rev')
2176 revs = opts.get('rev')
2177 change = opts.get('change')
2177 change = opts.get('change')
2178 stat = opts.get('stat')
2178 stat = opts.get('stat')
2179 reverse = opts.get('reverse')
2179 reverse = opts.get('reverse')
2180
2180
2181 if revs and change:
2181 if revs and change:
2182 msg = _('cannot specify --rev and --change at the same time')
2182 msg = _('cannot specify --rev and --change at the same time')
2183 raise util.Abort(msg)
2183 raise util.Abort(msg)
2184 elif change:
2184 elif change:
2185 node2 = scmutil.revsingle(repo, change, None).node()
2185 node2 = scmutil.revsingle(repo, change, None).node()
2186 node1 = repo[node2].p1().node()
2186 node1 = repo[node2].p1().node()
2187 else:
2187 else:
2188 node1, node2 = scmutil.revpair(repo, revs)
2188 node1, node2 = scmutil.revpair(repo, revs)
2189
2189
2190 if reverse:
2190 if reverse:
2191 node1, node2 = node2, node1
2191 node1, node2 = node2, node1
2192
2192
2193 diffopts = patch.diffopts(ui, opts)
2193 diffopts = patch.diffopts(ui, opts)
2194 m = scmutil.match(repo[node2], pats, opts)
2194 m = scmutil.match(repo[node2], pats, opts)
2195 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2195 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2196 listsubrepos=opts.get('subrepos'))
2196 listsubrepos=opts.get('subrepos'))
2197
2197
2198 @command('^export',
2198 @command('^export',
2199 [('o', 'output', '',
2199 [('o', 'output', '',
2200 _('print output to file with formatted name'), _('FORMAT')),
2200 _('print output to file with formatted name'), _('FORMAT')),
2201 ('', 'switch-parent', None, _('diff against the second parent')),
2201 ('', 'switch-parent', None, _('diff against the second parent')),
2202 ('r', 'rev', [], _('revisions to export'), _('REV')),
2202 ('r', 'rev', [], _('revisions to export'), _('REV')),
2203 ] + diffopts,
2203 ] + diffopts,
2204 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2204 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2205 def export(ui, repo, *changesets, **opts):
2205 def export(ui, repo, *changesets, **opts):
2206 """dump the header and diffs for one or more changesets
2206 """dump the header and diffs for one or more changesets
2207
2207
2208 Print the changeset header and diffs for one or more revisions.
2208 Print the changeset header and diffs for one or more revisions.
2209
2209
2210 The information shown in the changeset header is: author, date,
2210 The information shown in the changeset header is: author, date,
2211 branch name (if non-default), changeset hash, parent(s) and commit
2211 branch name (if non-default), changeset hash, parent(s) and commit
2212 comment.
2212 comment.
2213
2213
2214 .. note::
2214 .. note::
2215 export may generate unexpected diff output for merge
2215 export may generate unexpected diff output for merge
2216 changesets, as it will compare the merge changeset against its
2216 changesets, as it will compare the merge changeset against its
2217 first parent only.
2217 first parent only.
2218
2218
2219 Output may be to a file, in which case the name of the file is
2219 Output may be to a file, in which case the name of the file is
2220 given using a format string. The formatting rules are as follows:
2220 given using a format string. The formatting rules are as follows:
2221
2221
2222 :``%%``: literal "%" character
2222 :``%%``: literal "%" character
2223 :``%H``: changeset hash (40 hexadecimal digits)
2223 :``%H``: changeset hash (40 hexadecimal digits)
2224 :``%N``: number of patches being generated
2224 :``%N``: number of patches being generated
2225 :``%R``: changeset revision number
2225 :``%R``: changeset revision number
2226 :``%b``: basename of the exporting repository
2226 :``%b``: basename of the exporting repository
2227 :``%h``: short-form changeset hash (12 hexadecimal digits)
2227 :``%h``: short-form changeset hash (12 hexadecimal digits)
2228 :``%n``: zero-padded sequence number, starting at 1
2228 :``%n``: zero-padded sequence number, starting at 1
2229 :``%r``: zero-padded changeset revision number
2229 :``%r``: zero-padded changeset revision number
2230
2230
2231 Without the -a/--text option, export will avoid generating diffs
2231 Without the -a/--text option, export will avoid generating diffs
2232 of files it detects as binary. With -a, export will generate a
2232 of files it detects as binary. With -a, export will generate a
2233 diff anyway, probably with undesirable results.
2233 diff anyway, probably with undesirable results.
2234
2234
2235 Use the -g/--git option to generate diffs in the git extended diff
2235 Use the -g/--git option to generate diffs in the git extended diff
2236 format. See :hg:`help diffs` for more information.
2236 format. See :hg:`help diffs` for more information.
2237
2237
2238 With the --switch-parent option, the diff will be against the
2238 With the --switch-parent option, the diff will be against the
2239 second parent. It can be useful to review a merge.
2239 second parent. It can be useful to review a merge.
2240
2240
2241 Returns 0 on success.
2241 Returns 0 on success.
2242 """
2242 """
2243 changesets += tuple(opts.get('rev', []))
2243 changesets += tuple(opts.get('rev', []))
2244 if not changesets:
2244 if not changesets:
2245 raise util.Abort(_("export requires at least one changeset"))
2245 raise util.Abort(_("export requires at least one changeset"))
2246 revs = scmutil.revrange(repo, changesets)
2246 revs = scmutil.revrange(repo, changesets)
2247 if len(revs) > 1:
2247 if len(revs) > 1:
2248 ui.note(_('exporting patches:\n'))
2248 ui.note(_('exporting patches:\n'))
2249 else:
2249 else:
2250 ui.note(_('exporting patch:\n'))
2250 ui.note(_('exporting patch:\n'))
2251 cmdutil.export(repo, revs, template=opts.get('output'),
2251 cmdutil.export(repo, revs, template=opts.get('output'),
2252 switch_parent=opts.get('switch_parent'),
2252 switch_parent=opts.get('switch_parent'),
2253 opts=patch.diffopts(ui, opts))
2253 opts=patch.diffopts(ui, opts))
2254
2254
2255 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2255 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2256 def forget(ui, repo, *pats, **opts):
2256 def forget(ui, repo, *pats, **opts):
2257 """forget the specified files on the next commit
2257 """forget the specified files on the next commit
2258
2258
2259 Mark the specified files so they will no longer be tracked
2259 Mark the specified files so they will no longer be tracked
2260 after the next commit.
2260 after the next commit.
2261
2261
2262 This only removes files from the current branch, not from the
2262 This only removes files from the current branch, not from the
2263 entire project history, and it does not delete them from the
2263 entire project history, and it does not delete them from the
2264 working directory.
2264 working directory.
2265
2265
2266 To undo a forget before the next commit, see :hg:`add`.
2266 To undo a forget before the next commit, see :hg:`add`.
2267
2267
2268 Returns 0 on success.
2268 Returns 0 on success.
2269 """
2269 """
2270
2270
2271 if not pats:
2271 if not pats:
2272 raise util.Abort(_('no files specified'))
2272 raise util.Abort(_('no files specified'))
2273
2273
2274 m = scmutil.match(repo[None], pats, opts)
2274 m = scmutil.match(repo[None], pats, opts)
2275 s = repo.status(match=m, clean=True)
2275 s = repo.status(match=m, clean=True)
2276 forget = sorted(s[0] + s[1] + s[3] + s[6])
2276 forget = sorted(s[0] + s[1] + s[3] + s[6])
2277 errs = 0
2277 errs = 0
2278
2278
2279 for f in m.files():
2279 for f in m.files():
2280 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2280 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2281 if os.path.exists(m.rel(f)):
2281 if os.path.exists(m.rel(f)):
2282 ui.warn(_('not removing %s: file is already untracked\n')
2282 ui.warn(_('not removing %s: file is already untracked\n')
2283 % m.rel(f))
2283 % m.rel(f))
2284 errs = 1
2284 errs = 1
2285
2285
2286 for f in forget:
2286 for f in forget:
2287 if ui.verbose or not m.exact(f):
2287 if ui.verbose or not m.exact(f):
2288 ui.status(_('removing %s\n') % m.rel(f))
2288 ui.status(_('removing %s\n') % m.rel(f))
2289
2289
2290 repo[None].forget(forget)
2290 repo[None].forget(forget)
2291 return errs
2291 return errs
2292
2292
2293 @command('grep',
2293 @command('grep',
2294 [('0', 'print0', None, _('end fields with NUL')),
2294 [('0', 'print0', None, _('end fields with NUL')),
2295 ('', 'all', None, _('print all revisions that match')),
2295 ('', 'all', None, _('print all revisions that match')),
2296 ('a', 'text', None, _('treat all files as text')),
2296 ('a', 'text', None, _('treat all files as text')),
2297 ('f', 'follow', None,
2297 ('f', 'follow', None,
2298 _('follow changeset history,'
2298 _('follow changeset history,'
2299 ' or file history across copies and renames')),
2299 ' or file history across copies and renames')),
2300 ('i', 'ignore-case', None, _('ignore case when matching')),
2300 ('i', 'ignore-case', None, _('ignore case when matching')),
2301 ('l', 'files-with-matches', None,
2301 ('l', 'files-with-matches', None,
2302 _('print only filenames and revisions that match')),
2302 _('print only filenames and revisions that match')),
2303 ('n', 'line-number', None, _('print matching line numbers')),
2303 ('n', 'line-number', None, _('print matching line numbers')),
2304 ('r', 'rev', [],
2304 ('r', 'rev', [],
2305 _('only search files changed within revision range'), _('REV')),
2305 _('only search files changed within revision range'), _('REV')),
2306 ('u', 'user', None, _('list the author (long with -v)')),
2306 ('u', 'user', None, _('list the author (long with -v)')),
2307 ('d', 'date', None, _('list the date (short with -q)')),
2307 ('d', 'date', None, _('list the date (short with -q)')),
2308 ] + walkopts,
2308 ] + walkopts,
2309 _('[OPTION]... PATTERN [FILE]...'))
2309 _('[OPTION]... PATTERN [FILE]...'))
2310 def grep(ui, repo, pattern, *pats, **opts):
2310 def grep(ui, repo, pattern, *pats, **opts):
2311 """search for a pattern in specified files and revisions
2311 """search for a pattern in specified files and revisions
2312
2312
2313 Search revisions of files for a regular expression.
2313 Search revisions of files for a regular expression.
2314
2314
2315 This command behaves differently than Unix grep. It only accepts
2315 This command behaves differently than Unix grep. It only accepts
2316 Python/Perl regexps. It searches repository history, not the
2316 Python/Perl regexps. It searches repository history, not the
2317 working directory. It always prints the revision number in which a
2317 working directory. It always prints the revision number in which a
2318 match appears.
2318 match appears.
2319
2319
2320 By default, grep only prints output for the first revision of a
2320 By default, grep only prints output for the first revision of a
2321 file in which it finds a match. To get it to print every revision
2321 file in which it finds a match. To get it to print every revision
2322 that contains a change in match status ("-" for a match that
2322 that contains a change in match status ("-" for a match that
2323 becomes a non-match, or "+" for a non-match that becomes a match),
2323 becomes a non-match, or "+" for a non-match that becomes a match),
2324 use the --all flag.
2324 use the --all flag.
2325
2325
2326 Returns 0 if a match is found, 1 otherwise.
2326 Returns 0 if a match is found, 1 otherwise.
2327 """
2327 """
2328 reflags = 0
2328 reflags = 0
2329 if opts.get('ignore_case'):
2329 if opts.get('ignore_case'):
2330 reflags |= re.I
2330 reflags |= re.I
2331 try:
2331 try:
2332 regexp = re.compile(pattern, reflags)
2332 regexp = re.compile(pattern, reflags)
2333 except re.error, inst:
2333 except re.error, inst:
2334 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2334 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2335 return 1
2335 return 1
2336 sep, eol = ':', '\n'
2336 sep, eol = ':', '\n'
2337 if opts.get('print0'):
2337 if opts.get('print0'):
2338 sep = eol = '\0'
2338 sep = eol = '\0'
2339
2339
2340 getfile = util.lrucachefunc(repo.file)
2340 getfile = util.lrucachefunc(repo.file)
2341
2341
2342 def matchlines(body):
2342 def matchlines(body):
2343 begin = 0
2343 begin = 0
2344 linenum = 0
2344 linenum = 0
2345 while True:
2345 while True:
2346 match = regexp.search(body, begin)
2346 match = regexp.search(body, begin)
2347 if not match:
2347 if not match:
2348 break
2348 break
2349 mstart, mend = match.span()
2349 mstart, mend = match.span()
2350 linenum += body.count('\n', begin, mstart) + 1
2350 linenum += body.count('\n', begin, mstart) + 1
2351 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2351 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2352 begin = body.find('\n', mend) + 1 or len(body)
2352 begin = body.find('\n', mend) + 1 or len(body)
2353 lend = begin - 1
2353 lend = begin - 1
2354 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2354 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2355
2355
2356 class linestate(object):
2356 class linestate(object):
2357 def __init__(self, line, linenum, colstart, colend):
2357 def __init__(self, line, linenum, colstart, colend):
2358 self.line = line
2358 self.line = line
2359 self.linenum = linenum
2359 self.linenum = linenum
2360 self.colstart = colstart
2360 self.colstart = colstart
2361 self.colend = colend
2361 self.colend = colend
2362
2362
2363 def __hash__(self):
2363 def __hash__(self):
2364 return hash((self.linenum, self.line))
2364 return hash((self.linenum, self.line))
2365
2365
2366 def __eq__(self, other):
2366 def __eq__(self, other):
2367 return self.line == other.line
2367 return self.line == other.line
2368
2368
2369 matches = {}
2369 matches = {}
2370 copies = {}
2370 copies = {}
2371 def grepbody(fn, rev, body):
2371 def grepbody(fn, rev, body):
2372 matches[rev].setdefault(fn, [])
2372 matches[rev].setdefault(fn, [])
2373 m = matches[rev][fn]
2373 m = matches[rev][fn]
2374 for lnum, cstart, cend, line in matchlines(body):
2374 for lnum, cstart, cend, line in matchlines(body):
2375 s = linestate(line, lnum, cstart, cend)
2375 s = linestate(line, lnum, cstart, cend)
2376 m.append(s)
2376 m.append(s)
2377
2377
2378 def difflinestates(a, b):
2378 def difflinestates(a, b):
2379 sm = difflib.SequenceMatcher(None, a, b)
2379 sm = difflib.SequenceMatcher(None, a, b)
2380 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2380 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2381 if tag == 'insert':
2381 if tag == 'insert':
2382 for i in xrange(blo, bhi):
2382 for i in xrange(blo, bhi):
2383 yield ('+', b[i])
2383 yield ('+', b[i])
2384 elif tag == 'delete':
2384 elif tag == 'delete':
2385 for i in xrange(alo, ahi):
2385 for i in xrange(alo, ahi):
2386 yield ('-', a[i])
2386 yield ('-', a[i])
2387 elif tag == 'replace':
2387 elif tag == 'replace':
2388 for i in xrange(alo, ahi):
2388 for i in xrange(alo, ahi):
2389 yield ('-', a[i])
2389 yield ('-', a[i])
2390 for i in xrange(blo, bhi):
2390 for i in xrange(blo, bhi):
2391 yield ('+', b[i])
2391 yield ('+', b[i])
2392
2392
2393 def display(fn, ctx, pstates, states):
2393 def display(fn, ctx, pstates, states):
2394 rev = ctx.rev()
2394 rev = ctx.rev()
2395 datefunc = ui.quiet and util.shortdate or util.datestr
2395 datefunc = ui.quiet and util.shortdate or util.datestr
2396 found = False
2396 found = False
2397 filerevmatches = {}
2397 filerevmatches = {}
2398 def binary():
2398 def binary():
2399 flog = getfile(fn)
2399 flog = getfile(fn)
2400 return util.binary(flog.read(ctx.filenode(fn)))
2400 return util.binary(flog.read(ctx.filenode(fn)))
2401
2401
2402 if opts.get('all'):
2402 if opts.get('all'):
2403 iter = difflinestates(pstates, states)
2403 iter = difflinestates(pstates, states)
2404 else:
2404 else:
2405 iter = [('', l) for l in states]
2405 iter = [('', l) for l in states]
2406 for change, l in iter:
2406 for change, l in iter:
2407 cols = [fn, str(rev)]
2407 cols = [fn, str(rev)]
2408 before, match, after = None, None, None
2408 before, match, after = None, None, None
2409 if opts.get('line_number'):
2409 if opts.get('line_number'):
2410 cols.append(str(l.linenum))
2410 cols.append(str(l.linenum))
2411 if opts.get('all'):
2411 if opts.get('all'):
2412 cols.append(change)
2412 cols.append(change)
2413 if opts.get('user'):
2413 if opts.get('user'):
2414 cols.append(ui.shortuser(ctx.user()))
2414 cols.append(ui.shortuser(ctx.user()))
2415 if opts.get('date'):
2415 if opts.get('date'):
2416 cols.append(datefunc(ctx.date()))
2416 cols.append(datefunc(ctx.date()))
2417 if opts.get('files_with_matches'):
2417 if opts.get('files_with_matches'):
2418 c = (fn, rev)
2418 c = (fn, rev)
2419 if c in filerevmatches:
2419 if c in filerevmatches:
2420 continue
2420 continue
2421 filerevmatches[c] = 1
2421 filerevmatches[c] = 1
2422 else:
2422 else:
2423 before = l.line[:l.colstart]
2423 before = l.line[:l.colstart]
2424 match = l.line[l.colstart:l.colend]
2424 match = l.line[l.colstart:l.colend]
2425 after = l.line[l.colend:]
2425 after = l.line[l.colend:]
2426 ui.write(sep.join(cols))
2426 ui.write(sep.join(cols))
2427 if before is not None:
2427 if before is not None:
2428 if not opts.get('text') and binary():
2428 if not opts.get('text') and binary():
2429 ui.write(sep + " Binary file matches")
2429 ui.write(sep + " Binary file matches")
2430 else:
2430 else:
2431 ui.write(sep + before)
2431 ui.write(sep + before)
2432 ui.write(match, label='grep.match')
2432 ui.write(match, label='grep.match')
2433 ui.write(after)
2433 ui.write(after)
2434 ui.write(eol)
2434 ui.write(eol)
2435 found = True
2435 found = True
2436 return found
2436 return found
2437
2437
2438 skip = {}
2438 skip = {}
2439 revfiles = {}
2439 revfiles = {}
2440 matchfn = scmutil.match(repo[None], pats, opts)
2440 matchfn = scmutil.match(repo[None], pats, opts)
2441 found = False
2441 found = False
2442 follow = opts.get('follow')
2442 follow = opts.get('follow')
2443
2443
2444 def prep(ctx, fns):
2444 def prep(ctx, fns):
2445 rev = ctx.rev()
2445 rev = ctx.rev()
2446 pctx = ctx.p1()
2446 pctx = ctx.p1()
2447 parent = pctx.rev()
2447 parent = pctx.rev()
2448 matches.setdefault(rev, {})
2448 matches.setdefault(rev, {})
2449 matches.setdefault(parent, {})
2449 matches.setdefault(parent, {})
2450 files = revfiles.setdefault(rev, [])
2450 files = revfiles.setdefault(rev, [])
2451 for fn in fns:
2451 for fn in fns:
2452 flog = getfile(fn)
2452 flog = getfile(fn)
2453 try:
2453 try:
2454 fnode = ctx.filenode(fn)
2454 fnode = ctx.filenode(fn)
2455 except error.LookupError:
2455 except error.LookupError:
2456 continue
2456 continue
2457
2457
2458 copied = flog.renamed(fnode)
2458 copied = flog.renamed(fnode)
2459 copy = follow and copied and copied[0]
2459 copy = follow and copied and copied[0]
2460 if copy:
2460 if copy:
2461 copies.setdefault(rev, {})[fn] = copy
2461 copies.setdefault(rev, {})[fn] = copy
2462 if fn in skip:
2462 if fn in skip:
2463 if copy:
2463 if copy:
2464 skip[copy] = True
2464 skip[copy] = True
2465 continue
2465 continue
2466 files.append(fn)
2466 files.append(fn)
2467
2467
2468 if fn not in matches[rev]:
2468 if fn not in matches[rev]:
2469 grepbody(fn, rev, flog.read(fnode))
2469 grepbody(fn, rev, flog.read(fnode))
2470
2470
2471 pfn = copy or fn
2471 pfn = copy or fn
2472 if pfn not in matches[parent]:
2472 if pfn not in matches[parent]:
2473 try:
2473 try:
2474 fnode = pctx.filenode(pfn)
2474 fnode = pctx.filenode(pfn)
2475 grepbody(pfn, parent, flog.read(fnode))
2475 grepbody(pfn, parent, flog.read(fnode))
2476 except error.LookupError:
2476 except error.LookupError:
2477 pass
2477 pass
2478
2478
2479 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2479 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2480 rev = ctx.rev()
2480 rev = ctx.rev()
2481 parent = ctx.p1().rev()
2481 parent = ctx.p1().rev()
2482 for fn in sorted(revfiles.get(rev, [])):
2482 for fn in sorted(revfiles.get(rev, [])):
2483 states = matches[rev][fn]
2483 states = matches[rev][fn]
2484 copy = copies.get(rev, {}).get(fn)
2484 copy = copies.get(rev, {}).get(fn)
2485 if fn in skip:
2485 if fn in skip:
2486 if copy:
2486 if copy:
2487 skip[copy] = True
2487 skip[copy] = True
2488 continue
2488 continue
2489 pstates = matches.get(parent, {}).get(copy or fn, [])
2489 pstates = matches.get(parent, {}).get(copy or fn, [])
2490 if pstates or states:
2490 if pstates or states:
2491 r = display(fn, ctx, pstates, states)
2491 r = display(fn, ctx, pstates, states)
2492 found = found or r
2492 found = found or r
2493 if r and not opts.get('all'):
2493 if r and not opts.get('all'):
2494 skip[fn] = True
2494 skip[fn] = True
2495 if copy:
2495 if copy:
2496 skip[copy] = True
2496 skip[copy] = True
2497 del matches[rev]
2497 del matches[rev]
2498 del revfiles[rev]
2498 del revfiles[rev]
2499
2499
2500 return not found
2500 return not found
2501
2501
2502 @command('heads',
2502 @command('heads',
2503 [('r', 'rev', '',
2503 [('r', 'rev', '',
2504 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2504 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2505 ('t', 'topo', False, _('show topological heads only')),
2505 ('t', 'topo', False, _('show topological heads only')),
2506 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2506 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2507 ('c', 'closed', False, _('show normal and closed branch heads')),
2507 ('c', 'closed', False, _('show normal and closed branch heads')),
2508 ] + templateopts,
2508 ] + templateopts,
2509 _('[-ac] [-r STARTREV] [REV]...'))
2509 _('[-ac] [-r STARTREV] [REV]...'))
2510 def heads(ui, repo, *branchrevs, **opts):
2510 def heads(ui, repo, *branchrevs, **opts):
2511 """show current repository heads or show branch heads
2511 """show current repository heads or show branch heads
2512
2512
2513 With no arguments, show all repository branch heads.
2513 With no arguments, show all repository branch heads.
2514
2514
2515 Repository "heads" are changesets with no child changesets. They are
2515 Repository "heads" are changesets with no child changesets. They are
2516 where development generally takes place and are the usual targets
2516 where development generally takes place and are the usual targets
2517 for update and merge operations. Branch heads are changesets that have
2517 for update and merge operations. Branch heads are changesets that have
2518 no child changeset on the same branch.
2518 no child changeset on the same branch.
2519
2519
2520 If one or more REVs are given, only branch heads on the branches
2520 If one or more REVs are given, only branch heads on the branches
2521 associated with the specified changesets are shown.
2521 associated with the specified changesets are shown.
2522
2522
2523 If -c/--closed is specified, also show branch heads marked closed
2523 If -c/--closed is specified, also show branch heads marked closed
2524 (see :hg:`commit --close-branch`).
2524 (see :hg:`commit --close-branch`).
2525
2525
2526 If STARTREV is specified, only those heads that are descendants of
2526 If STARTREV is specified, only those heads that are descendants of
2527 STARTREV will be displayed.
2527 STARTREV will be displayed.
2528
2528
2529 If -t/--topo is specified, named branch mechanics will be ignored and only
2529 If -t/--topo is specified, named branch mechanics will be ignored and only
2530 changesets without children will be shown.
2530 changesets without children will be shown.
2531
2531
2532 Returns 0 if matching heads are found, 1 if not.
2532 Returns 0 if matching heads are found, 1 if not.
2533 """
2533 """
2534
2534
2535 start = None
2535 start = None
2536 if 'rev' in opts:
2536 if 'rev' in opts:
2537 start = scmutil.revsingle(repo, opts['rev'], None).node()
2537 start = scmutil.revsingle(repo, opts['rev'], None).node()
2538
2538
2539 if opts.get('topo'):
2539 if opts.get('topo'):
2540 heads = [repo[h] for h in repo.heads(start)]
2540 heads = [repo[h] for h in repo.heads(start)]
2541 else:
2541 else:
2542 heads = []
2542 heads = []
2543 for branch in repo.branchmap():
2543 for branch in repo.branchmap():
2544 heads += repo.branchheads(branch, start, opts.get('closed'))
2544 heads += repo.branchheads(branch, start, opts.get('closed'))
2545 heads = [repo[h] for h in heads]
2545 heads = [repo[h] for h in heads]
2546
2546
2547 if branchrevs:
2547 if branchrevs:
2548 branches = set(repo[br].branch() for br in branchrevs)
2548 branches = set(repo[br].branch() for br in branchrevs)
2549 heads = [h for h in heads if h.branch() in branches]
2549 heads = [h for h in heads if h.branch() in branches]
2550
2550
2551 if opts.get('active') and branchrevs:
2551 if opts.get('active') and branchrevs:
2552 dagheads = repo.heads(start)
2552 dagheads = repo.heads(start)
2553 heads = [h for h in heads if h.node() in dagheads]
2553 heads = [h for h in heads if h.node() in dagheads]
2554
2554
2555 if branchrevs:
2555 if branchrevs:
2556 haveheads = set(h.branch() for h in heads)
2556 haveheads = set(h.branch() for h in heads)
2557 if branches - haveheads:
2557 if branches - haveheads:
2558 headless = ', '.join(b for b in branches - haveheads)
2558 headless = ', '.join(b for b in branches - haveheads)
2559 msg = _('no open branch heads found on branches %s')
2559 msg = _('no open branch heads found on branches %s')
2560 if opts.get('rev'):
2560 if opts.get('rev'):
2561 msg += _(' (started at %s)' % opts['rev'])
2561 msg += _(' (started at %s)' % opts['rev'])
2562 ui.warn((msg + '\n') % headless)
2562 ui.warn((msg + '\n') % headless)
2563
2563
2564 if not heads:
2564 if not heads:
2565 return 1
2565 return 1
2566
2566
2567 heads = sorted(heads, key=lambda x: -x.rev())
2567 heads = sorted(heads, key=lambda x: -x.rev())
2568 displayer = cmdutil.show_changeset(ui, repo, opts)
2568 displayer = cmdutil.show_changeset(ui, repo, opts)
2569 for ctx in heads:
2569 for ctx in heads:
2570 displayer.show(ctx)
2570 displayer.show(ctx)
2571 displayer.close()
2571 displayer.close()
2572
2572
2573 @command('help',
2573 @command('help',
2574 [('e', 'extension', None, _('show only help for extensions')),
2574 [('e', 'extension', None, _('show only help for extensions')),
2575 ('c', 'command', None, _('show only help for commands'))],
2575 ('c', 'command', None, _('show only help for commands'))],
2576 _('[-ec] [TOPIC]'))
2576 _('[-ec] [TOPIC]'))
2577 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True, **opts):
2577 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True, **opts):
2578 """show help for a given topic or a help overview
2578 """show help for a given topic or a help overview
2579
2579
2580 With no arguments, print a list of commands with short help messages.
2580 With no arguments, print a list of commands with short help messages.
2581
2581
2582 Given a topic, extension, or command name, print help for that
2582 Given a topic, extension, or command name, print help for that
2583 topic.
2583 topic.
2584
2584
2585 Returns 0 if successful.
2585 Returns 0 if successful.
2586 """
2586 """
2587 option_lists = []
2587 option_lists = []
2588 textwidth = min(ui.termwidth(), 80) - 2
2588 textwidth = min(ui.termwidth(), 80) - 2
2589
2589
2590 def addglobalopts(aliases):
2590 def addglobalopts(aliases):
2591 if ui.verbose:
2591 if ui.verbose:
2592 option_lists.append((_("global options:"), globalopts))
2592 option_lists.append((_("global options:"), globalopts))
2593 if name == 'shortlist':
2593 if name == 'shortlist':
2594 option_lists.append((_('use "hg help" for the full list '
2594 option_lists.append((_('use "hg help" for the full list '
2595 'of commands'), ()))
2595 'of commands'), ()))
2596 else:
2596 else:
2597 if name == 'shortlist':
2597 if name == 'shortlist':
2598 msg = _('use "hg help" for the full list of commands '
2598 msg = _('use "hg help" for the full list of commands '
2599 'or "hg -v" for details')
2599 'or "hg -v" for details')
2600 elif name and not full:
2600 elif name and not full:
2601 msg = _('use "hg help %s" to show the full help text' % name)
2601 msg = _('use "hg help %s" to show the full help text' % name)
2602 elif aliases:
2602 elif aliases:
2603 msg = _('use "hg -v help%s" to show builtin aliases and '
2603 msg = _('use "hg -v help%s" to show builtin aliases and '
2604 'global options') % (name and " " + name or "")
2604 'global options') % (name and " " + name or "")
2605 else:
2605 else:
2606 msg = _('use "hg -v help %s" to show global options') % name
2606 msg = _('use "hg -v help %s" to show global options') % name
2607 option_lists.append((msg, ()))
2607 option_lists.append((msg, ()))
2608
2608
2609 def helpcmd(name):
2609 def helpcmd(name):
2610 if with_version:
2610 if with_version:
2611 version_(ui)
2611 version_(ui)
2612 ui.write('\n')
2612 ui.write('\n')
2613
2613
2614 try:
2614 try:
2615 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2615 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2616 except error.AmbiguousCommand, inst:
2616 except error.AmbiguousCommand, inst:
2617 # py3k fix: except vars can't be used outside the scope of the
2617 # py3k fix: except vars can't be used outside the scope of the
2618 # except block, nor can be used inside a lambda. python issue4617
2618 # except block, nor can be used inside a lambda. python issue4617
2619 prefix = inst.args[0]
2619 prefix = inst.args[0]
2620 select = lambda c: c.lstrip('^').startswith(prefix)
2620 select = lambda c: c.lstrip('^').startswith(prefix)
2621 helplist(_('list of commands:\n\n'), select)
2621 helplist(_('list of commands:\n\n'), select)
2622 return
2622 return
2623
2623
2624 # check if it's an invalid alias and display its error if it is
2624 # check if it's an invalid alias and display its error if it is
2625 if getattr(entry[0], 'badalias', False):
2625 if getattr(entry[0], 'badalias', False):
2626 if not unknowncmd:
2626 if not unknowncmd:
2627 entry[0](ui)
2627 entry[0](ui)
2628 return
2628 return
2629
2629
2630 # synopsis
2630 # synopsis
2631 if len(entry) > 2:
2631 if len(entry) > 2:
2632 if entry[2].startswith('hg'):
2632 if entry[2].startswith('hg'):
2633 ui.write("%s\n" % entry[2])
2633 ui.write("%s\n" % entry[2])
2634 else:
2634 else:
2635 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2635 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2636 else:
2636 else:
2637 ui.write('hg %s\n' % aliases[0])
2637 ui.write('hg %s\n' % aliases[0])
2638
2638
2639 # aliases
2639 # aliases
2640 if full and not ui.quiet and len(aliases) > 1:
2640 if full and not ui.quiet and len(aliases) > 1:
2641 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2641 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2642
2642
2643 # description
2643 # description
2644 doc = gettext(entry[0].__doc__)
2644 doc = gettext(entry[0].__doc__)
2645 if not doc:
2645 if not doc:
2646 doc = _("(no help text available)")
2646 doc = _("(no help text available)")
2647 if hasattr(entry[0], 'definition'): # aliased command
2647 if hasattr(entry[0], 'definition'): # aliased command
2648 if entry[0].definition.startswith('!'): # shell alias
2648 if entry[0].definition.startswith('!'): # shell alias
2649 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2649 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2650 else:
2650 else:
2651 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2651 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2652 if ui.quiet or not full:
2652 if ui.quiet or not full:
2653 doc = doc.splitlines()[0]
2653 doc = doc.splitlines()[0]
2654 keep = ui.verbose and ['verbose'] or []
2654 keep = ui.verbose and ['verbose'] or []
2655 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2655 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2656 ui.write("\n%s\n" % formatted)
2656 ui.write("\n%s\n" % formatted)
2657 if pruned:
2657 if pruned:
2658 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2658 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2659
2659
2660 if not ui.quiet:
2660 if not ui.quiet:
2661 # options
2661 # options
2662 if entry[1]:
2662 if entry[1]:
2663 option_lists.append((_("options:\n"), entry[1]))
2663 option_lists.append((_("options:\n"), entry[1]))
2664
2664
2665 addglobalopts(False)
2665 addglobalopts(False)
2666
2666
2667 # check if this command shadows a non-trivial (multi-line)
2667 # check if this command shadows a non-trivial (multi-line)
2668 # extension help text
2668 # extension help text
2669 try:
2669 try:
2670 mod = extensions.find(name)
2670 mod = extensions.find(name)
2671 doc = gettext(mod.__doc__) or ''
2671 doc = gettext(mod.__doc__) or ''
2672 if '\n' in doc.strip():
2672 if '\n' in doc.strip():
2673 msg = _('use "hg help -e %s" to show help for '
2673 msg = _('use "hg help -e %s" to show help for '
2674 'the %s extension') % (name, name)
2674 'the %s extension') % (name, name)
2675 ui.write('\n%s\n' % msg)
2675 ui.write('\n%s\n' % msg)
2676 except KeyError:
2676 except KeyError:
2677 pass
2677 pass
2678
2678
2679 def helplist(header, select=None):
2679 def helplist(header, select=None):
2680 h = {}
2680 h = {}
2681 cmds = {}
2681 cmds = {}
2682 for c, e in table.iteritems():
2682 for c, e in table.iteritems():
2683 f = c.split("|", 1)[0]
2683 f = c.split("|", 1)[0]
2684 if select and not select(f):
2684 if select and not select(f):
2685 continue
2685 continue
2686 if (not select and name != 'shortlist' and
2686 if (not select and name != 'shortlist' and
2687 e[0].__module__ != __name__):
2687 e[0].__module__ != __name__):
2688 continue
2688 continue
2689 if name == "shortlist" and not f.startswith("^"):
2689 if name == "shortlist" and not f.startswith("^"):
2690 continue
2690 continue
2691 f = f.lstrip("^")
2691 f = f.lstrip("^")
2692 if not ui.debugflag and f.startswith("debug"):
2692 if not ui.debugflag and f.startswith("debug"):
2693 continue
2693 continue
2694 doc = e[0].__doc__
2694 doc = e[0].__doc__
2695 if doc and 'DEPRECATED' in doc and not ui.verbose:
2695 if doc and 'DEPRECATED' in doc and not ui.verbose:
2696 continue
2696 continue
2697 doc = gettext(doc)
2697 doc = gettext(doc)
2698 if not doc:
2698 if not doc:
2699 doc = _("(no help text available)")
2699 doc = _("(no help text available)")
2700 h[f] = doc.splitlines()[0].rstrip()
2700 h[f] = doc.splitlines()[0].rstrip()
2701 cmds[f] = c.lstrip("^")
2701 cmds[f] = c.lstrip("^")
2702
2702
2703 if not h:
2703 if not h:
2704 ui.status(_('no commands defined\n'))
2704 ui.status(_('no commands defined\n'))
2705 return
2705 return
2706
2706
2707 ui.status(header)
2707 ui.status(header)
2708 fns = sorted(h)
2708 fns = sorted(h)
2709 m = max(map(len, fns))
2709 m = max(map(len, fns))
2710 for f in fns:
2710 for f in fns:
2711 if ui.verbose:
2711 if ui.verbose:
2712 commands = cmds[f].replace("|",", ")
2712 commands = cmds[f].replace("|",", ")
2713 ui.write(" %s:\n %s\n"%(commands, h[f]))
2713 ui.write(" %s:\n %s\n"%(commands, h[f]))
2714 else:
2714 else:
2715 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2715 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2716 initindent=' %-*s ' % (m, f),
2716 initindent=' %-*s ' % (m, f),
2717 hangindent=' ' * (m + 4))))
2717 hangindent=' ' * (m + 4))))
2718
2718
2719 if not ui.quiet:
2719 if not ui.quiet:
2720 addglobalopts(True)
2720 addglobalopts(True)
2721
2721
2722 def helptopic(name):
2722 def helptopic(name):
2723 for names, header, doc in help.helptable:
2723 for names, header, doc in help.helptable:
2724 if name in names:
2724 if name in names:
2725 break
2725 break
2726 else:
2726 else:
2727 raise error.UnknownCommand(name)
2727 raise error.UnknownCommand(name)
2728
2728
2729 # description
2729 # description
2730 if not doc:
2730 if not doc:
2731 doc = _("(no help text available)")
2731 doc = _("(no help text available)")
2732 if hasattr(doc, '__call__'):
2732 if hasattr(doc, '__call__'):
2733 doc = doc()
2733 doc = doc()
2734
2734
2735 ui.write("%s\n\n" % header)
2735 ui.write("%s\n\n" % header)
2736 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2736 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2737 try:
2737 try:
2738 cmdutil.findcmd(name, table)
2738 cmdutil.findcmd(name, table)
2739 ui.write(_('\nuse "hg help -c %s" to see help for '
2739 ui.write(_('\nuse "hg help -c %s" to see help for '
2740 'the %s command\n') % (name, name))
2740 'the %s command\n') % (name, name))
2741 except error.UnknownCommand:
2741 except error.UnknownCommand:
2742 pass
2742 pass
2743
2743
2744 def helpext(name):
2744 def helpext(name):
2745 try:
2745 try:
2746 mod = extensions.find(name)
2746 mod = extensions.find(name)
2747 doc = gettext(mod.__doc__) or _('no help text available')
2747 doc = gettext(mod.__doc__) or _('no help text available')
2748 except KeyError:
2748 except KeyError:
2749 mod = None
2749 mod = None
2750 doc = extensions.disabledext(name)
2750 doc = extensions.disabledext(name)
2751 if not doc:
2751 if not doc:
2752 raise error.UnknownCommand(name)
2752 raise error.UnknownCommand(name)
2753
2753
2754 if '\n' not in doc:
2754 if '\n' not in doc:
2755 head, tail = doc, ""
2755 head, tail = doc, ""
2756 else:
2756 else:
2757 head, tail = doc.split('\n', 1)
2757 head, tail = doc.split('\n', 1)
2758 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2758 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2759 if tail:
2759 if tail:
2760 ui.write(minirst.format(tail, textwidth))
2760 ui.write(minirst.format(tail, textwidth))
2761 ui.status('\n\n')
2761 ui.status('\n\n')
2762
2762
2763 if mod:
2763 if mod:
2764 try:
2764 try:
2765 ct = mod.cmdtable
2765 ct = mod.cmdtable
2766 except AttributeError:
2766 except AttributeError:
2767 ct = {}
2767 ct = {}
2768 modcmds = set([c.split('|', 1)[0] for c in ct])
2768 modcmds = set([c.split('|', 1)[0] for c in ct])
2769 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2769 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2770 else:
2770 else:
2771 ui.write(_('use "hg help extensions" for information on enabling '
2771 ui.write(_('use "hg help extensions" for information on enabling '
2772 'extensions\n'))
2772 'extensions\n'))
2773
2773
2774 def helpextcmd(name):
2774 def helpextcmd(name):
2775 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2775 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2776 doc = gettext(mod.__doc__).splitlines()[0]
2776 doc = gettext(mod.__doc__).splitlines()[0]
2777
2777
2778 msg = help.listexts(_("'%s' is provided by the following "
2778 msg = help.listexts(_("'%s' is provided by the following "
2779 "extension:") % cmd, {ext: doc}, indent=4)
2779 "extension:") % cmd, {ext: doc}, indent=4)
2780 ui.write(minirst.format(msg, textwidth))
2780 ui.write(minirst.format(msg, textwidth))
2781 ui.write('\n\n')
2781 ui.write('\n\n')
2782 ui.write(_('use "hg help extensions" for information on enabling '
2782 ui.write(_('use "hg help extensions" for information on enabling '
2783 'extensions\n'))
2783 'extensions\n'))
2784
2784
2785 if name and name != 'shortlist':
2785 if name and name != 'shortlist':
2786 i = None
2786 i = None
2787 if unknowncmd:
2787 if unknowncmd:
2788 queries = (helpextcmd,)
2788 queries = (helpextcmd,)
2789 elif opts.get('extension'):
2789 elif opts.get('extension'):
2790 queries = (helpext,)
2790 queries = (helpext,)
2791 elif opts.get('command'):
2791 elif opts.get('command'):
2792 queries = (helpcmd,)
2792 queries = (helpcmd,)
2793 else:
2793 else:
2794 queries = (helptopic, helpcmd, helpext, helpextcmd)
2794 queries = (helptopic, helpcmd, helpext, helpextcmd)
2795 for f in queries:
2795 for f in queries:
2796 try:
2796 try:
2797 f(name)
2797 f(name)
2798 i = None
2798 i = None
2799 break
2799 break
2800 except error.UnknownCommand, inst:
2800 except error.UnknownCommand, inst:
2801 i = inst
2801 i = inst
2802 if i:
2802 if i:
2803 raise i
2803 raise i
2804
2804
2805 else:
2805 else:
2806 # program name
2806 # program name
2807 if ui.verbose or with_version:
2807 if ui.verbose or with_version:
2808 version_(ui)
2808 version_(ui)
2809 else:
2809 else:
2810 ui.status(_("Mercurial Distributed SCM\n"))
2810 ui.status(_("Mercurial Distributed SCM\n"))
2811 ui.status('\n')
2811 ui.status('\n')
2812
2812
2813 # list of commands
2813 # list of commands
2814 if name == "shortlist":
2814 if name == "shortlist":
2815 header = _('basic commands:\n\n')
2815 header = _('basic commands:\n\n')
2816 else:
2816 else:
2817 header = _('list of commands:\n\n')
2817 header = _('list of commands:\n\n')
2818
2818
2819 helplist(header)
2819 helplist(header)
2820 if name != 'shortlist':
2820 if name != 'shortlist':
2821 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2821 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2822 if text:
2822 if text:
2823 ui.write("\n%s\n" % minirst.format(text, textwidth))
2823 ui.write("\n%s\n" % minirst.format(text, textwidth))
2824
2824
2825 # list all option lists
2825 # list all option lists
2826 opt_output = []
2826 opt_output = []
2827 multioccur = False
2827 multioccur = False
2828 for title, options in option_lists:
2828 for title, options in option_lists:
2829 opt_output.append(("\n%s" % title, None))
2829 opt_output.append(("\n%s" % title, None))
2830 for option in options:
2830 for option in options:
2831 if len(option) == 5:
2831 if len(option) == 5:
2832 shortopt, longopt, default, desc, optlabel = option
2832 shortopt, longopt, default, desc, optlabel = option
2833 else:
2833 else:
2834 shortopt, longopt, default, desc = option
2834 shortopt, longopt, default, desc = option
2835 optlabel = _("VALUE") # default label
2835 optlabel = _("VALUE") # default label
2836
2836
2837 if _("DEPRECATED") in desc and not ui.verbose:
2837 if _("DEPRECATED") in desc and not ui.verbose:
2838 continue
2838 continue
2839 if isinstance(default, list):
2839 if isinstance(default, list):
2840 numqualifier = " %s [+]" % optlabel
2840 numqualifier = " %s [+]" % optlabel
2841 multioccur = True
2841 multioccur = True
2842 elif (default is not None) and not isinstance(default, bool):
2842 elif (default is not None) and not isinstance(default, bool):
2843 numqualifier = " %s" % optlabel
2843 numqualifier = " %s" % optlabel
2844 else:
2844 else:
2845 numqualifier = ""
2845 numqualifier = ""
2846 opt_output.append(("%2s%s" %
2846 opt_output.append(("%2s%s" %
2847 (shortopt and "-%s" % shortopt,
2847 (shortopt and "-%s" % shortopt,
2848 longopt and " --%s%s" %
2848 longopt and " --%s%s" %
2849 (longopt, numqualifier)),
2849 (longopt, numqualifier)),
2850 "%s%s" % (desc,
2850 "%s%s" % (desc,
2851 default
2851 default
2852 and _(" (default: %s)") % default
2852 and _(" (default: %s)") % default
2853 or "")))
2853 or "")))
2854 if multioccur:
2854 if multioccur:
2855 msg = _("\n[+] marked option can be specified multiple times")
2855 msg = _("\n[+] marked option can be specified multiple times")
2856 if ui.verbose and name != 'shortlist':
2856 if ui.verbose and name != 'shortlist':
2857 opt_output.append((msg, None))
2857 opt_output.append((msg, None))
2858 else:
2858 else:
2859 opt_output.insert(-1, (msg, None))
2859 opt_output.insert(-1, (msg, None))
2860
2860
2861 if not name:
2861 if not name:
2862 ui.write(_("\nadditional help topics:\n\n"))
2862 ui.write(_("\nadditional help topics:\n\n"))
2863 topics = []
2863 topics = []
2864 for names, header, doc in help.helptable:
2864 for names, header, doc in help.helptable:
2865 topics.append((sorted(names, key=len, reverse=True)[0], header))
2865 topics.append((sorted(names, key=len, reverse=True)[0], header))
2866 topics_len = max([len(s[0]) for s in topics])
2866 topics_len = max([len(s[0]) for s in topics])
2867 for t, desc in topics:
2867 for t, desc in topics:
2868 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2868 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2869
2869
2870 if opt_output:
2870 if opt_output:
2871 colwidth = encoding.colwidth
2871 colwidth = encoding.colwidth
2872 # normalize: (opt or message, desc or None, width of opt)
2872 # normalize: (opt or message, desc or None, width of opt)
2873 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2873 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2874 for opt, desc in opt_output]
2874 for opt, desc in opt_output]
2875 hanging = max([e[2] for e in entries])
2875 hanging = max([e[2] for e in entries])
2876 for opt, desc, width in entries:
2876 for opt, desc, width in entries:
2877 if desc:
2877 if desc:
2878 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2878 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2879 hangindent = ' ' * (hanging + 3)
2879 hangindent = ' ' * (hanging + 3)
2880 ui.write('%s\n' % (util.wrap(desc, textwidth,
2880 ui.write('%s\n' % (util.wrap(desc, textwidth,
2881 initindent=initindent,
2881 initindent=initindent,
2882 hangindent=hangindent)))
2882 hangindent=hangindent)))
2883 else:
2883 else:
2884 ui.write("%s\n" % opt)
2884 ui.write("%s\n" % opt)
2885
2885
2886 @command('identify|id',
2886 @command('identify|id',
2887 [('r', 'rev', '',
2887 [('r', 'rev', '',
2888 _('identify the specified revision'), _('REV')),
2888 _('identify the specified revision'), _('REV')),
2889 ('n', 'num', None, _('show local revision number')),
2889 ('n', 'num', None, _('show local revision number')),
2890 ('i', 'id', None, _('show global revision id')),
2890 ('i', 'id', None, _('show global revision id')),
2891 ('b', 'branch', None, _('show branch')),
2891 ('b', 'branch', None, _('show branch')),
2892 ('t', 'tags', None, _('show tags')),
2892 ('t', 'tags', None, _('show tags')),
2893 ('B', 'bookmarks', None, _('show bookmarks'))],
2893 ('B', 'bookmarks', None, _('show bookmarks'))],
2894 _('[-nibtB] [-r REV] [SOURCE]'))
2894 _('[-nibtB] [-r REV] [SOURCE]'))
2895 def identify(ui, repo, source=None, rev=None,
2895 def identify(ui, repo, source=None, rev=None,
2896 num=None, id=None, branch=None, tags=None, bookmarks=None):
2896 num=None, id=None, branch=None, tags=None, bookmarks=None):
2897 """identify the working copy or specified revision
2897 """identify the working copy or specified revision
2898
2898
2899 Print a summary identifying the repository state at REV using one or
2899 Print a summary identifying the repository state at REV using one or
2900 two parent hash identifiers, followed by a "+" if the working
2900 two parent hash identifiers, followed by a "+" if the working
2901 directory has uncommitted changes, the branch name (if not default),
2901 directory has uncommitted changes, the branch name (if not default),
2902 a list of tags, and a list of bookmarks.
2902 a list of tags, and a list of bookmarks.
2903
2903
2904 When REV is not given, print a summary of the current state of the
2904 When REV is not given, print a summary of the current state of the
2905 repository.
2905 repository.
2906
2906
2907 Specifying a path to a repository root or Mercurial bundle will
2907 Specifying a path to a repository root or Mercurial bundle will
2908 cause lookup to operate on that repository/bundle.
2908 cause lookup to operate on that repository/bundle.
2909
2909
2910 Returns 0 if successful.
2910 Returns 0 if successful.
2911 """
2911 """
2912
2912
2913 if not repo and not source:
2913 if not repo and not source:
2914 raise util.Abort(_("there is no Mercurial repository here "
2914 raise util.Abort(_("there is no Mercurial repository here "
2915 "(.hg not found)"))
2915 "(.hg not found)"))
2916
2916
2917 hexfunc = ui.debugflag and hex or short
2917 hexfunc = ui.debugflag and hex or short
2918 default = not (num or id or branch or tags or bookmarks)
2918 default = not (num or id or branch or tags or bookmarks)
2919 output = []
2919 output = []
2920 revs = []
2920 revs = []
2921
2921
2922 if source:
2922 if source:
2923 source, branches = hg.parseurl(ui.expandpath(source))
2923 source, branches = hg.parseurl(ui.expandpath(source))
2924 repo = hg.peer(ui, {}, source)
2924 repo = hg.peer(ui, {}, source)
2925 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2925 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2926
2926
2927 if not repo.local():
2927 if not repo.local():
2928 if num or branch or tags:
2928 if num or branch or tags:
2929 raise util.Abort(
2929 raise util.Abort(
2930 _("can't query remote revision number, branch, or tags"))
2930 _("can't query remote revision number, branch, or tags"))
2931 if not rev and revs:
2931 if not rev and revs:
2932 rev = revs[0]
2932 rev = revs[0]
2933 if not rev:
2933 if not rev:
2934 rev = "tip"
2934 rev = "tip"
2935
2935
2936 remoterev = repo.lookup(rev)
2936 remoterev = repo.lookup(rev)
2937 if default or id:
2937 if default or id:
2938 output = [hexfunc(remoterev)]
2938 output = [hexfunc(remoterev)]
2939
2939
2940 def getbms():
2940 def getbms():
2941 bms = []
2941 bms = []
2942
2942
2943 if 'bookmarks' in repo.listkeys('namespaces'):
2943 if 'bookmarks' in repo.listkeys('namespaces'):
2944 hexremoterev = hex(remoterev)
2944 hexremoterev = hex(remoterev)
2945 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2945 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2946 if bmr == hexremoterev]
2946 if bmr == hexremoterev]
2947
2947
2948 return bms
2948 return bms
2949
2949
2950 if bookmarks:
2950 if bookmarks:
2951 output.extend(getbms())
2951 output.extend(getbms())
2952 elif default and not ui.quiet:
2952 elif default and not ui.quiet:
2953 # multiple bookmarks for a single parent separated by '/'
2953 # multiple bookmarks for a single parent separated by '/'
2954 bm = '/'.join(getbms())
2954 bm = '/'.join(getbms())
2955 if bm:
2955 if bm:
2956 output.append(bm)
2956 output.append(bm)
2957 else:
2957 else:
2958 if not rev:
2958 if not rev:
2959 ctx = repo[None]
2959 ctx = repo[None]
2960 parents = ctx.parents()
2960 parents = ctx.parents()
2961 changed = ""
2961 changed = ""
2962 if default or id or num:
2962 if default or id or num:
2963 changed = util.any(repo.status()) and "+" or ""
2963 changed = util.any(repo.status()) and "+" or ""
2964 if default or id:
2964 if default or id:
2965 output = ["%s%s" %
2965 output = ["%s%s" %
2966 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2966 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2967 if num:
2967 if num:
2968 output.append("%s%s" %
2968 output.append("%s%s" %
2969 ('+'.join([str(p.rev()) for p in parents]), changed))
2969 ('+'.join([str(p.rev()) for p in parents]), changed))
2970 else:
2970 else:
2971 ctx = scmutil.revsingle(repo, rev)
2971 ctx = scmutil.revsingle(repo, rev)
2972 if default or id:
2972 if default or id:
2973 output = [hexfunc(ctx.node())]
2973 output = [hexfunc(ctx.node())]
2974 if num:
2974 if num:
2975 output.append(str(ctx.rev()))
2975 output.append(str(ctx.rev()))
2976
2976
2977 if default and not ui.quiet:
2977 if default and not ui.quiet:
2978 b = ctx.branch()
2978 b = ctx.branch()
2979 if b != 'default':
2979 if b != 'default':
2980 output.append("(%s)" % b)
2980 output.append("(%s)" % b)
2981
2981
2982 # multiple tags for a single parent separated by '/'
2982 # multiple tags for a single parent separated by '/'
2983 t = '/'.join(ctx.tags())
2983 t = '/'.join(ctx.tags())
2984 if t:
2984 if t:
2985 output.append(t)
2985 output.append(t)
2986
2986
2987 # multiple bookmarks for a single parent separated by '/'
2987 # multiple bookmarks for a single parent separated by '/'
2988 bm = '/'.join(ctx.bookmarks())
2988 bm = '/'.join(ctx.bookmarks())
2989 if bm:
2989 if bm:
2990 output.append(bm)
2990 output.append(bm)
2991 else:
2991 else:
2992 if branch:
2992 if branch:
2993 output.append(ctx.branch())
2993 output.append(ctx.branch())
2994
2994
2995 if tags:
2995 if tags:
2996 output.extend(ctx.tags())
2996 output.extend(ctx.tags())
2997
2997
2998 if bookmarks:
2998 if bookmarks:
2999 output.extend(ctx.bookmarks())
2999 output.extend(ctx.bookmarks())
3000
3000
3001 ui.write("%s\n" % ' '.join(output))
3001 ui.write("%s\n" % ' '.join(output))
3002
3002
3003 @command('import|patch',
3003 @command('import|patch',
3004 [('p', 'strip', 1,
3004 [('p', 'strip', 1,
3005 _('directory strip option for patch. This has the same '
3005 _('directory strip option for patch. This has the same '
3006 'meaning as the corresponding patch option'), _('NUM')),
3006 'meaning as the corresponding patch option'), _('NUM')),
3007 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3007 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3008 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3008 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3009 ('', 'no-commit', None,
3009 ('', 'no-commit', None,
3010 _("don't commit, just update the working directory")),
3010 _("don't commit, just update the working directory")),
3011 ('', 'bypass', None,
3011 ('', 'bypass', None,
3012 _("apply patch without touching the working directory")),
3012 _("apply patch without touching the working directory")),
3013 ('', 'exact', None,
3013 ('', 'exact', None,
3014 _('apply patch to the nodes from which it was generated')),
3014 _('apply patch to the nodes from which it was generated')),
3015 ('', 'import-branch', None,
3015 ('', 'import-branch', None,
3016 _('use any branch information in patch (implied by --exact)'))] +
3016 _('use any branch information in patch (implied by --exact)'))] +
3017 commitopts + commitopts2 + similarityopts,
3017 commitopts + commitopts2 + similarityopts,
3018 _('[OPTION]... PATCH...'))
3018 _('[OPTION]... PATCH...'))
3019 def import_(ui, repo, patch1, *patches, **opts):
3019 def import_(ui, repo, patch1, *patches, **opts):
3020 """import an ordered set of patches
3020 """import an ordered set of patches
3021
3021
3022 Import a list of patches and commit them individually (unless
3022 Import a list of patches and commit them individually (unless
3023 --no-commit is specified).
3023 --no-commit is specified).
3024
3024
3025 If there are outstanding changes in the working directory, import
3025 If there are outstanding changes in the working directory, import
3026 will abort unless given the -f/--force flag.
3026 will abort unless given the -f/--force flag.
3027
3027
3028 You can import a patch straight from a mail message. Even patches
3028 You can import a patch straight from a mail message. Even patches
3029 as attachments work (to use the body part, it must have type
3029 as attachments work (to use the body part, it must have type
3030 text/plain or text/x-patch). From and Subject headers of email
3030 text/plain or text/x-patch). From and Subject headers of email
3031 message are used as default committer and commit message. All
3031 message are used as default committer and commit message. All
3032 text/plain body parts before first diff are added to commit
3032 text/plain body parts before first diff are added to commit
3033 message.
3033 message.
3034
3034
3035 If the imported patch was generated by :hg:`export`, user and
3035 If the imported patch was generated by :hg:`export`, user and
3036 description from patch override values from message headers and
3036 description from patch override values from message headers and
3037 body. Values given on command line with -m/--message and -u/--user
3037 body. Values given on command line with -m/--message and -u/--user
3038 override these.
3038 override these.
3039
3039
3040 If --exact is specified, import will set the working directory to
3040 If --exact is specified, import will set the working directory to
3041 the parent of each patch before applying it, and will abort if the
3041 the parent of each patch before applying it, and will abort if the
3042 resulting changeset has a different ID than the one recorded in
3042 resulting changeset has a different ID than the one recorded in
3043 the patch. This may happen due to character set problems or other
3043 the patch. This may happen due to character set problems or other
3044 deficiencies in the text patch format.
3044 deficiencies in the text patch format.
3045
3045
3046 Use --bypass to apply and commit patches directly to the
3046 Use --bypass to apply and commit patches directly to the
3047 repository, not touching the working directory. Without --exact,
3047 repository, not touching the working directory. Without --exact,
3048 patches will be applied on top of the working directory parent
3048 patches will be applied on top of the working directory parent
3049 revision.
3049 revision.
3050
3050
3051 With -s/--similarity, hg will attempt to discover renames and
3051 With -s/--similarity, hg will attempt to discover renames and
3052 copies in the patch in the same way as 'addremove'.
3052 copies in the patch in the same way as 'addremove'.
3053
3053
3054 To read a patch from standard input, use "-" as the patch name. If
3054 To read a patch from standard input, use "-" as the patch name. If
3055 a URL is specified, the patch will be downloaded from it.
3055 a URL is specified, the patch will be downloaded from it.
3056 See :hg:`help dates` for a list of formats valid for -d/--date.
3056 See :hg:`help dates` for a list of formats valid for -d/--date.
3057
3057
3058 Returns 0 on success.
3058 Returns 0 on success.
3059 """
3059 """
3060 patches = (patch1,) + patches
3060 patches = (patch1,) + patches
3061
3061
3062 date = opts.get('date')
3062 date = opts.get('date')
3063 if date:
3063 if date:
3064 opts['date'] = util.parsedate(date)
3064 opts['date'] = util.parsedate(date)
3065
3065
3066 update = not opts.get('bypass')
3066 update = not opts.get('bypass')
3067 if not update and opts.get('no_commit'):
3067 if not update and opts.get('no_commit'):
3068 raise util.Abort(_('cannot use --no-commit with --bypass'))
3068 raise util.Abort(_('cannot use --no-commit with --bypass'))
3069 try:
3069 try:
3070 sim = float(opts.get('similarity') or 0)
3070 sim = float(opts.get('similarity') or 0)
3071 except ValueError:
3071 except ValueError:
3072 raise util.Abort(_('similarity must be a number'))
3072 raise util.Abort(_('similarity must be a number'))
3073 if sim < 0 or sim > 100:
3073 if sim < 0 or sim > 100:
3074 raise util.Abort(_('similarity must be between 0 and 100'))
3074 raise util.Abort(_('similarity must be between 0 and 100'))
3075 if sim and not update:
3075 if sim and not update:
3076 raise util.Abort(_('cannot use --similarity with --bypass'))
3076 raise util.Abort(_('cannot use --similarity with --bypass'))
3077
3077
3078 if (opts.get('exact') or not opts.get('force')) and update:
3078 if (opts.get('exact') or not opts.get('force')) and update:
3079 cmdutil.bailifchanged(repo)
3079 cmdutil.bailifchanged(repo)
3080
3080
3081 d = opts["base"]
3081 d = opts["base"]
3082 strip = opts["strip"]
3082 strip = opts["strip"]
3083 wlock = lock = None
3083 wlock = lock = None
3084 msgs = []
3084 msgs = []
3085
3085
3086 def checkexact(repo, n, nodeid):
3086 def checkexact(repo, n, nodeid):
3087 if opts.get('exact') and hex(n) != nodeid:
3087 if opts.get('exact') and hex(n) != nodeid:
3088 repo.rollback()
3088 repo.rollback()
3089 raise util.Abort(_('patch is damaged or loses information'))
3089 raise util.Abort(_('patch is damaged or loses information'))
3090
3090
3091 def tryone(ui, hunk, parents):
3091 def tryone(ui, hunk, parents):
3092 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3092 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3093 patch.extract(ui, hunk)
3093 patch.extract(ui, hunk)
3094
3094
3095 if not tmpname:
3095 if not tmpname:
3096 return None
3096 return None
3097 commitid = _('to working directory')
3097 commitid = _('to working directory')
3098
3098
3099 try:
3099 try:
3100 cmdline_message = cmdutil.logmessage(ui, opts)
3100 cmdline_message = cmdutil.logmessage(ui, opts)
3101 if cmdline_message:
3101 if cmdline_message:
3102 # pickup the cmdline msg
3102 # pickup the cmdline msg
3103 message = cmdline_message
3103 message = cmdline_message
3104 elif message:
3104 elif message:
3105 # pickup the patch msg
3105 # pickup the patch msg
3106 message = message.strip()
3106 message = message.strip()
3107 else:
3107 else:
3108 # launch the editor
3108 # launch the editor
3109 message = None
3109 message = None
3110 ui.debug('message:\n%s\n' % message)
3110 ui.debug('message:\n%s\n' % message)
3111
3111
3112 if len(parents) == 1:
3112 if len(parents) == 1:
3113 parents.append(repo[nullid])
3113 parents.append(repo[nullid])
3114 if opts.get('exact'):
3114 if opts.get('exact'):
3115 if not nodeid or not p1:
3115 if not nodeid or not p1:
3116 raise util.Abort(_('not a Mercurial patch'))
3116 raise util.Abort(_('not a Mercurial patch'))
3117 p1 = repo[p1]
3117 p1 = repo[p1]
3118 p2 = repo[p2 or nullid]
3118 p2 = repo[p2 or nullid]
3119 elif p2:
3119 elif p2:
3120 try:
3120 try:
3121 p1 = repo[p1]
3121 p1 = repo[p1]
3122 p2 = repo[p2]
3122 p2 = repo[p2]
3123 except error.RepoError:
3123 except error.RepoError:
3124 p1, p2 = parents
3124 p1, p2 = parents
3125 else:
3125 else:
3126 p1, p2 = parents
3126 p1, p2 = parents
3127
3127
3128 n = None
3128 n = None
3129 if update:
3129 if update:
3130 if opts.get('exact') and p1 != parents[0]:
3130 if opts.get('exact') and p1 != parents[0]:
3131 hg.clean(repo, p1.node())
3131 hg.clean(repo, p1.node())
3132 if p1 != parents[0] and p2 != parents[1]:
3132 if p1 != parents[0] and p2 != parents[1]:
3133 repo.dirstate.setparents(p1.node(), p2.node())
3133 repo.dirstate.setparents(p1.node(), p2.node())
3134
3134
3135 if opts.get('exact') or opts.get('import_branch'):
3135 if opts.get('exact') or opts.get('import_branch'):
3136 repo.dirstate.setbranch(branch or 'default')
3136 repo.dirstate.setbranch(branch or 'default')
3137
3137
3138 files = set()
3138 files = set()
3139 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3139 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3140 eolmode=None, similarity=sim / 100.0)
3140 eolmode=None, similarity=sim / 100.0)
3141 files = list(files)
3141 files = list(files)
3142 if opts.get('no_commit'):
3142 if opts.get('no_commit'):
3143 if message:
3143 if message:
3144 msgs.append(message)
3144 msgs.append(message)
3145 else:
3145 else:
3146 if opts.get('exact'):
3146 if opts.get('exact'):
3147 m = None
3147 m = None
3148 else:
3148 else:
3149 m = scmutil.matchfiles(repo, files or [])
3149 m = scmutil.matchfiles(repo, files or [])
3150 n = repo.commit(message, opts.get('user') or user,
3150 n = repo.commit(message, opts.get('user') or user,
3151 opts.get('date') or date, match=m,
3151 opts.get('date') or date, match=m,
3152 editor=cmdutil.commiteditor)
3152 editor=cmdutil.commiteditor)
3153 checkexact(repo, n, nodeid)
3153 checkexact(repo, n, nodeid)
3154 # Force a dirstate write so that the next transaction
3154 # Force a dirstate write so that the next transaction
3155 # backups an up-to-date file.
3155 # backups an up-to-date file.
3156 repo.dirstate.write()
3156 repo.dirstate.write()
3157 else:
3157 else:
3158 if opts.get('exact') or opts.get('import_branch'):
3158 if opts.get('exact') or opts.get('import_branch'):
3159 branch = branch or 'default'
3159 branch = branch or 'default'
3160 else:
3160 else:
3161 branch = p1.branch()
3161 branch = p1.branch()
3162 store = patch.filestore()
3162 store = patch.filestore()
3163 try:
3163 try:
3164 files = set()
3164 files = set()
3165 try:
3165 try:
3166 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3166 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3167 files, eolmode=None)
3167 files, eolmode=None)
3168 except patch.PatchError, e:
3168 except patch.PatchError, e:
3169 raise util.Abort(str(e))
3169 raise util.Abort(str(e))
3170 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3170 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3171 message,
3171 message,
3172 opts.get('user') or user,
3172 opts.get('user') or user,
3173 opts.get('date') or date,
3173 opts.get('date') or date,
3174 branch, files, store,
3174 branch, files, store,
3175 editor=cmdutil.commiteditor)
3175 editor=cmdutil.commiteditor)
3176 repo.savecommitmessage(memctx.description())
3176 repo.savecommitmessage(memctx.description())
3177 n = memctx.commit()
3177 n = memctx.commit()
3178 checkexact(repo, n, nodeid)
3178 checkexact(repo, n, nodeid)
3179 finally:
3179 finally:
3180 store.close()
3180 store.close()
3181 if n:
3181 if n:
3182 commitid = short(n)
3182 commitid = short(n)
3183 return commitid
3183 return commitid
3184 finally:
3184 finally:
3185 os.unlink(tmpname)
3185 os.unlink(tmpname)
3186
3186
3187 try:
3187 try:
3188 wlock = repo.wlock()
3188 wlock = repo.wlock()
3189 lock = repo.lock()
3189 lock = repo.lock()
3190 parents = repo.parents()
3190 parents = repo.parents()
3191 lastcommit = None
3191 lastcommit = None
3192 for p in patches:
3192 for p in patches:
3193 pf = os.path.join(d, p)
3193 pf = os.path.join(d, p)
3194
3194
3195 if pf == '-':
3195 if pf == '-':
3196 ui.status(_("applying patch from stdin\n"))
3196 ui.status(_("applying patch from stdin\n"))
3197 pf = ui.fin
3197 pf = ui.fin
3198 else:
3198 else:
3199 ui.status(_("applying %s\n") % p)
3199 ui.status(_("applying %s\n") % p)
3200 pf = url.open(ui, pf)
3200 pf = url.open(ui, pf)
3201
3201
3202 haspatch = False
3202 haspatch = False
3203 for hunk in patch.split(pf):
3203 for hunk in patch.split(pf):
3204 commitid = tryone(ui, hunk, parents)
3204 commitid = tryone(ui, hunk, parents)
3205 if commitid:
3205 if commitid:
3206 haspatch = True
3206 haspatch = True
3207 if lastcommit:
3207 if lastcommit:
3208 ui.status(_('applied %s\n') % lastcommit)
3208 ui.status(_('applied %s\n') % lastcommit)
3209 lastcommit = commitid
3209 lastcommit = commitid
3210 if update or opts.get('exact'):
3210 if update or opts.get('exact'):
3211 parents = repo.parents()
3211 parents = repo.parents()
3212 else:
3212 else:
3213 parents = [repo[commitid]]
3213 parents = [repo[commitid]]
3214
3214
3215 if not haspatch:
3215 if not haspatch:
3216 raise util.Abort(_('no diffs found'))
3216 raise util.Abort(_('no diffs found'))
3217
3217
3218 if msgs:
3218 if msgs:
3219 repo.savecommitmessage('\n* * *\n'.join(msgs))
3219 repo.savecommitmessage('\n* * *\n'.join(msgs))
3220 finally:
3220 finally:
3221 release(lock, wlock)
3221 release(lock, wlock)
3222
3222
3223 @command('incoming|in',
3223 @command('incoming|in',
3224 [('f', 'force', None,
3224 [('f', 'force', None,
3225 _('run even if remote repository is unrelated')),
3225 _('run even if remote repository is unrelated')),
3226 ('n', 'newest-first', None, _('show newest record first')),
3226 ('n', 'newest-first', None, _('show newest record first')),
3227 ('', 'bundle', '',
3227 ('', 'bundle', '',
3228 _('file to store the bundles into'), _('FILE')),
3228 _('file to store the bundles into'), _('FILE')),
3229 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3229 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3230 ('B', 'bookmarks', False, _("compare bookmarks")),
3230 ('B', 'bookmarks', False, _("compare bookmarks")),
3231 ('b', 'branch', [],
3231 ('b', 'branch', [],
3232 _('a specific branch you would like to pull'), _('BRANCH')),
3232 _('a specific branch you would like to pull'), _('BRANCH')),
3233 ] + logopts + remoteopts + subrepoopts,
3233 ] + logopts + remoteopts + subrepoopts,
3234 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3234 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3235 def incoming(ui, repo, source="default", **opts):
3235 def incoming(ui, repo, source="default", **opts):
3236 """show new changesets found in source
3236 """show new changesets found in source
3237
3237
3238 Show new changesets found in the specified path/URL or the default
3238 Show new changesets found in the specified path/URL or the default
3239 pull location. These are the changesets that would have been pulled
3239 pull location. These are the changesets that would have been pulled
3240 if a pull at the time you issued this command.
3240 if a pull at the time you issued this command.
3241
3241
3242 For remote repository, using --bundle avoids downloading the
3242 For remote repository, using --bundle avoids downloading the
3243 changesets twice if the incoming is followed by a pull.
3243 changesets twice if the incoming is followed by a pull.
3244
3244
3245 See pull for valid source format details.
3245 See pull for valid source format details.
3246
3246
3247 Returns 0 if there are incoming changes, 1 otherwise.
3247 Returns 0 if there are incoming changes, 1 otherwise.
3248 """
3248 """
3249 if opts.get('bundle') and opts.get('subrepos'):
3249 if opts.get('bundle') and opts.get('subrepos'):
3250 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3250 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3251
3251
3252 if opts.get('bookmarks'):
3252 if opts.get('bookmarks'):
3253 source, branches = hg.parseurl(ui.expandpath(source),
3253 source, branches = hg.parseurl(ui.expandpath(source),
3254 opts.get('branch'))
3254 opts.get('branch'))
3255 other = hg.peer(repo, opts, source)
3255 other = hg.peer(repo, opts, source)
3256 if 'bookmarks' not in other.listkeys('namespaces'):
3256 if 'bookmarks' not in other.listkeys('namespaces'):
3257 ui.warn(_("remote doesn't support bookmarks\n"))
3257 ui.warn(_("remote doesn't support bookmarks\n"))
3258 return 0
3258 return 0
3259 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3259 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3260 return bookmarks.diff(ui, repo, other)
3260 return bookmarks.diff(ui, repo, other)
3261
3261
3262 repo._subtoppath = ui.expandpath(source)
3262 repo._subtoppath = ui.expandpath(source)
3263 try:
3263 try:
3264 return hg.incoming(ui, repo, source, opts)
3264 return hg.incoming(ui, repo, source, opts)
3265 finally:
3265 finally:
3266 del repo._subtoppath
3266 del repo._subtoppath
3267
3267
3268
3268
3269 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3269 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3270 def init(ui, dest=".", **opts):
3270 def init(ui, dest=".", **opts):
3271 """create a new repository in the given directory
3271 """create a new repository in the given directory
3272
3272
3273 Initialize a new repository in the given directory. If the given
3273 Initialize a new repository in the given directory. If the given
3274 directory does not exist, it will be created.
3274 directory does not exist, it will be created.
3275
3275
3276 If no directory is given, the current directory is used.
3276 If no directory is given, the current directory is used.
3277
3277
3278 It is possible to specify an ``ssh://`` URL as the destination.
3278 It is possible to specify an ``ssh://`` URL as the destination.
3279 See :hg:`help urls` for more information.
3279 See :hg:`help urls` for more information.
3280
3280
3281 Returns 0 on success.
3281 Returns 0 on success.
3282 """
3282 """
3283 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3283 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3284
3284
3285 @command('locate',
3285 @command('locate',
3286 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3286 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3287 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3287 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3288 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3288 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3289 ] + walkopts,
3289 ] + walkopts,
3290 _('[OPTION]... [PATTERN]...'))
3290 _('[OPTION]... [PATTERN]...'))
3291 def locate(ui, repo, *pats, **opts):
3291 def locate(ui, repo, *pats, **opts):
3292 """locate files matching specific patterns
3292 """locate files matching specific patterns
3293
3293
3294 Print files under Mercurial control in the working directory whose
3294 Print files under Mercurial control in the working directory whose
3295 names match the given patterns.
3295 names match the given patterns.
3296
3296
3297 By default, this command searches all directories in the working
3297 By default, this command searches all directories in the working
3298 directory. To search just the current directory and its
3298 directory. To search just the current directory and its
3299 subdirectories, use "--include .".
3299 subdirectories, use "--include .".
3300
3300
3301 If no patterns are given to match, this command prints the names
3301 If no patterns are given to match, this command prints the names
3302 of all files under Mercurial control in the working directory.
3302 of all files under Mercurial control in the working directory.
3303
3303
3304 If you want to feed the output of this command into the "xargs"
3304 If you want to feed the output of this command into the "xargs"
3305 command, use the -0 option to both this command and "xargs". This
3305 command, use the -0 option to both this command and "xargs". This
3306 will avoid the problem of "xargs" treating single filenames that
3306 will avoid the problem of "xargs" treating single filenames that
3307 contain whitespace as multiple filenames.
3307 contain whitespace as multiple filenames.
3308
3308
3309 Returns 0 if a match is found, 1 otherwise.
3309 Returns 0 if a match is found, 1 otherwise.
3310 """
3310 """
3311 end = opts.get('print0') and '\0' or '\n'
3311 end = opts.get('print0') and '\0' or '\n'
3312 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3312 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3313
3313
3314 ret = 1
3314 ret = 1
3315 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3315 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3316 m.bad = lambda x, y: False
3316 m.bad = lambda x, y: False
3317 for abs in repo[rev].walk(m):
3317 for abs in repo[rev].walk(m):
3318 if not rev and abs not in repo.dirstate:
3318 if not rev and abs not in repo.dirstate:
3319 continue
3319 continue
3320 if opts.get('fullpath'):
3320 if opts.get('fullpath'):
3321 ui.write(repo.wjoin(abs), end)
3321 ui.write(repo.wjoin(abs), end)
3322 else:
3322 else:
3323 ui.write(((pats and m.rel(abs)) or abs), end)
3323 ui.write(((pats and m.rel(abs)) or abs), end)
3324 ret = 0
3324 ret = 0
3325
3325
3326 return ret
3326 return ret
3327
3327
3328 @command('^log|history',
3328 @command('^log|history',
3329 [('f', 'follow', None,
3329 [('f', 'follow', None,
3330 _('follow changeset history, or file history across copies and renames')),
3330 _('follow changeset history, or file history across copies and renames')),
3331 ('', 'follow-first', None,
3331 ('', 'follow-first', None,
3332 _('only follow the first parent of merge changesets')),
3332 _('only follow the first parent of merge changesets')),
3333 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3333 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3334 ('C', 'copies', None, _('show copied files')),
3334 ('C', 'copies', None, _('show copied files')),
3335 ('k', 'keyword', [],
3335 ('k', 'keyword', [],
3336 _('do case-insensitive search for a given text'), _('TEXT')),
3336 _('do case-insensitive search for a given text'), _('TEXT')),
3337 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3337 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3338 ('', 'removed', None, _('include revisions where files were removed')),
3338 ('', 'removed', None, _('include revisions where files were removed')),
3339 ('m', 'only-merges', None, _('show only merges')),
3339 ('m', 'only-merges', None, _('show only merges')),
3340 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3340 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3341 ('', 'only-branch', [],
3341 ('', 'only-branch', [],
3342 _('show only changesets within the given named branch (DEPRECATED)'),
3342 _('show only changesets within the given named branch (DEPRECATED)'),
3343 _('BRANCH')),
3343 _('BRANCH')),
3344 ('b', 'branch', [],
3344 ('b', 'branch', [],
3345 _('show changesets within the given named branch'), _('BRANCH')),
3345 _('show changesets within the given named branch'), _('BRANCH')),
3346 ('P', 'prune', [],
3346 ('P', 'prune', [],
3347 _('do not display revision or any of its ancestors'), _('REV')),
3347 _('do not display revision or any of its ancestors'), _('REV')),
3348 ('h', 'hidden', False, _('show hidden changesets')),
3348 ('h', 'hidden', False, _('show hidden changesets')),
3349 ] + logopts + walkopts,
3349 ] + logopts + walkopts,
3350 _('[OPTION]... [FILE]'))
3350 _('[OPTION]... [FILE]'))
3351 def log(ui, repo, *pats, **opts):
3351 def log(ui, repo, *pats, **opts):
3352 """show revision history of entire repository or files
3352 """show revision history of entire repository or files
3353
3353
3354 Print the revision history of the specified files or the entire
3354 Print the revision history of the specified files or the entire
3355 project.
3355 project.
3356
3356
3357 File history is shown without following rename or copy history of
3357 File history is shown without following rename or copy history of
3358 files. Use -f/--follow with a filename to follow history across
3358 files. Use -f/--follow with a filename to follow history across
3359 renames and copies. --follow without a filename will only show
3359 renames and copies. --follow without a filename will only show
3360 ancestors or descendants of the starting revision. --follow-first
3360 ancestors or descendants of the starting revision. --follow-first
3361 only follows the first parent of merge revisions.
3361 only follows the first parent of merge revisions.
3362
3362
3363 If no revision range is specified, the default is ``tip:0`` unless
3363 If no revision range is specified, the default is ``tip:0`` unless
3364 --follow is set, in which case the working directory parent is
3364 --follow is set, in which case the working directory parent is
3365 used as the starting revision. You can specify a revision set for
3365 used as the starting revision. You can specify a revision set for
3366 log, see :hg:`help revsets` for more information.
3366 log, see :hg:`help revsets` for more information.
3367
3367
3368 See :hg:`help dates` for a list of formats valid for -d/--date.
3368 See :hg:`help dates` for a list of formats valid for -d/--date.
3369
3369
3370 By default this command prints revision number and changeset id,
3370 By default this command prints revision number and changeset id,
3371 tags, non-trivial parents, user, date and time, and a summary for
3371 tags, non-trivial parents, user, date and time, and a summary for
3372 each commit. When the -v/--verbose switch is used, the list of
3372 each commit. When the -v/--verbose switch is used, the list of
3373 changed files and full commit message are shown.
3373 changed files and full commit message are shown.
3374
3374
3375 .. note::
3375 .. note::
3376 log -p/--patch may generate unexpected diff output for merge
3376 log -p/--patch may generate unexpected diff output for merge
3377 changesets, as it will only compare the merge changeset against
3377 changesets, as it will only compare the merge changeset against
3378 its first parent. Also, only files different from BOTH parents
3378 its first parent. Also, only files different from BOTH parents
3379 will appear in files:.
3379 will appear in files:.
3380
3380
3381 Returns 0 on success.
3381 Returns 0 on success.
3382 """
3382 """
3383
3383
3384 matchfn = scmutil.match(repo[None], pats, opts)
3384 matchfn = scmutil.match(repo[None], pats, opts)
3385 limit = cmdutil.loglimit(opts)
3385 limit = cmdutil.loglimit(opts)
3386 count = 0
3386 count = 0
3387
3387
3388 endrev = None
3388 endrev = None
3389 if opts.get('copies') and opts.get('rev'):
3389 if opts.get('copies') and opts.get('rev'):
3390 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3390 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3391
3391
3392 df = False
3392 df = False
3393 if opts["date"]:
3393 if opts["date"]:
3394 df = util.matchdate(opts["date"])
3394 df = util.matchdate(opts["date"])
3395
3395
3396 branches = opts.get('branch', []) + opts.get('only_branch', [])
3396 branches = opts.get('branch', []) + opts.get('only_branch', [])
3397 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3397 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3398
3398
3399 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3399 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3400 def prep(ctx, fns):
3400 def prep(ctx, fns):
3401 rev = ctx.rev()
3401 rev = ctx.rev()
3402 parents = [p for p in repo.changelog.parentrevs(rev)
3402 parents = [p for p in repo.changelog.parentrevs(rev)
3403 if p != nullrev]
3403 if p != nullrev]
3404 if opts.get('no_merges') and len(parents) == 2:
3404 if opts.get('no_merges') and len(parents) == 2:
3405 return
3405 return
3406 if opts.get('only_merges') and len(parents) != 2:
3406 if opts.get('only_merges') and len(parents) != 2:
3407 return
3407 return
3408 if opts.get('branch') and ctx.branch() not in opts['branch']:
3408 if opts.get('branch') and ctx.branch() not in opts['branch']:
3409 return
3409 return
3410 if not opts.get('hidden') and ctx.hidden():
3410 if not opts.get('hidden') and ctx.hidden():
3411 return
3411 return
3412 if df and not df(ctx.date()[0]):
3412 if df and not df(ctx.date()[0]):
3413 return
3413 return
3414 if opts['user'] and not [k for k in opts['user']
3414 if opts['user'] and not [k for k in opts['user']
3415 if k.lower() in ctx.user().lower()]:
3415 if k.lower() in ctx.user().lower()]:
3416 return
3416 return
3417 if opts.get('keyword'):
3417 if opts.get('keyword'):
3418 for k in [kw.lower() for kw in opts['keyword']]:
3418 for k in [kw.lower() for kw in opts['keyword']]:
3419 if (k in ctx.user().lower() or
3419 if (k in ctx.user().lower() or
3420 k in ctx.description().lower() or
3420 k in ctx.description().lower() or
3421 k in " ".join(ctx.files()).lower()):
3421 k in " ".join(ctx.files()).lower()):
3422 break
3422 break
3423 else:
3423 else:
3424 return
3424 return
3425
3425
3426 copies = None
3426 copies = None
3427 if opts.get('copies') and rev:
3427 if opts.get('copies') and rev:
3428 copies = []
3428 copies = []
3429 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3429 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3430 for fn in ctx.files():
3430 for fn in ctx.files():
3431 rename = getrenamed(fn, rev)
3431 rename = getrenamed(fn, rev)
3432 if rename:
3432 if rename:
3433 copies.append((fn, rename[0]))
3433 copies.append((fn, rename[0]))
3434
3434
3435 revmatchfn = None
3435 revmatchfn = None
3436 if opts.get('patch') or opts.get('stat'):
3436 if opts.get('patch') or opts.get('stat'):
3437 if opts.get('follow') or opts.get('follow_first'):
3437 if opts.get('follow') or opts.get('follow_first'):
3438 # note: this might be wrong when following through merges
3438 # note: this might be wrong when following through merges
3439 revmatchfn = scmutil.match(repo[None], fns, default='path')
3439 revmatchfn = scmutil.match(repo[None], fns, default='path')
3440 else:
3440 else:
3441 revmatchfn = matchfn
3441 revmatchfn = matchfn
3442
3442
3443 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3443 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3444
3444
3445 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3445 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3446 if count == limit:
3446 if count == limit:
3447 break
3447 break
3448 if displayer.flush(ctx.rev()):
3448 if displayer.flush(ctx.rev()):
3449 count += 1
3449 count += 1
3450 displayer.close()
3450 displayer.close()
3451
3451
3452 @command('manifest',
3452 @command('manifest',
3453 [('r', 'rev', '', _('revision to display'), _('REV')),
3453 [('r', 'rev', '', _('revision to display'), _('REV')),
3454 ('', 'all', False, _("list files from all revisions"))],
3454 ('', 'all', False, _("list files from all revisions"))],
3455 _('[-r REV]'))
3455 _('[-r REV]'))
3456 def manifest(ui, repo, node=None, rev=None, **opts):
3456 def manifest(ui, repo, node=None, rev=None, **opts):
3457 """output the current or given revision of the project manifest
3457 """output the current or given revision of the project manifest
3458
3458
3459 Print a list of version controlled files for the given revision.
3459 Print a list of version controlled files for the given revision.
3460 If no revision is given, the first parent of the working directory
3460 If no revision is given, the first parent of the working directory
3461 is used, or the null revision if no revision is checked out.
3461 is used, or the null revision if no revision is checked out.
3462
3462
3463 With -v, print file permissions, symlink and executable bits.
3463 With -v, print file permissions, symlink and executable bits.
3464 With --debug, print file revision hashes.
3464 With --debug, print file revision hashes.
3465
3465
3466 If option --all is specified, the list of all files from all revisions
3466 If option --all is specified, the list of all files from all revisions
3467 is printed. This includes deleted and renamed files.
3467 is printed. This includes deleted and renamed files.
3468
3468
3469 Returns 0 on success.
3469 Returns 0 on success.
3470 """
3470 """
3471 if opts.get('all'):
3471 if opts.get('all'):
3472 if rev or node:
3472 if rev or node:
3473 raise util.Abort(_("can't specify a revision with --all"))
3473 raise util.Abort(_("can't specify a revision with --all"))
3474
3474
3475 res = []
3475 res = []
3476 prefix = "data/"
3476 prefix = "data/"
3477 suffix = ".i"
3477 suffix = ".i"
3478 plen = len(prefix)
3478 plen = len(prefix)
3479 slen = len(suffix)
3479 slen = len(suffix)
3480 lock = repo.lock()
3480 lock = repo.lock()
3481 try:
3481 try:
3482 for fn, b, size in repo.store.datafiles():
3482 for fn, b, size in repo.store.datafiles():
3483 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3483 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3484 res.append(fn[plen:-slen])
3484 res.append(fn[plen:-slen])
3485 finally:
3485 finally:
3486 lock.release()
3486 lock.release()
3487 for f in sorted(res):
3487 for f in sorted(res):
3488 ui.write("%s\n" % f)
3488 ui.write("%s\n" % f)
3489 return
3489 return
3490
3490
3491 if rev and node:
3491 if rev and node:
3492 raise util.Abort(_("please specify just one revision"))
3492 raise util.Abort(_("please specify just one revision"))
3493
3493
3494 if not node:
3494 if not node:
3495 node = rev
3495 node = rev
3496
3496
3497 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3497 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3498 ctx = scmutil.revsingle(repo, node)
3498 ctx = scmutil.revsingle(repo, node)
3499 for f in ctx:
3499 for f in ctx:
3500 if ui.debugflag:
3500 if ui.debugflag:
3501 ui.write("%40s " % hex(ctx.manifest()[f]))
3501 ui.write("%40s " % hex(ctx.manifest()[f]))
3502 if ui.verbose:
3502 if ui.verbose:
3503 ui.write(decor[ctx.flags(f)])
3503 ui.write(decor[ctx.flags(f)])
3504 ui.write("%s\n" % f)
3504 ui.write("%s\n" % f)
3505
3505
3506 @command('^merge',
3506 @command('^merge',
3507 [('f', 'force', None, _('force a merge with outstanding changes')),
3507 [('f', 'force', None, _('force a merge with outstanding changes')),
3508 ('t', 'tool', '', _('specify merge tool')),
3508 ('t', 'tool', '', _('specify merge tool')),
3509 ('r', 'rev', '', _('revision to merge'), _('REV')),
3509 ('r', 'rev', '', _('revision to merge'), _('REV')),
3510 ('P', 'preview', None,
3510 ('P', 'preview', None,
3511 _('review revisions to merge (no merge is performed)'))],
3511 _('review revisions to merge (no merge is performed)'))],
3512 _('[-P] [-f] [[-r] REV]'))
3512 _('[-P] [-f] [[-r] REV]'))
3513 def merge(ui, repo, node=None, **opts):
3513 def merge(ui, repo, node=None, **opts):
3514 """merge working directory with another revision
3514 """merge working directory with another revision
3515
3515
3516 The current working directory is updated with all changes made in
3516 The current working directory is updated with all changes made in
3517 the requested revision since the last common predecessor revision.
3517 the requested revision since the last common predecessor revision.
3518
3518
3519 Files that changed between either parent are marked as changed for
3519 Files that changed between either parent are marked as changed for
3520 the next commit and a commit must be performed before any further
3520 the next commit and a commit must be performed before any further
3521 updates to the repository are allowed. The next commit will have
3521 updates to the repository are allowed. The next commit will have
3522 two parents.
3522 two parents.
3523
3523
3524 ``--tool`` can be used to specify the merge tool used for file
3524 ``--tool`` can be used to specify the merge tool used for file
3525 merges. It overrides the HGMERGE environment variable and your
3525 merges. It overrides the HGMERGE environment variable and your
3526 configuration files. See :hg:`help merge-tools` for options.
3526 configuration files. See :hg:`help merge-tools` for options.
3527
3527
3528 If no revision is specified, the working directory's parent is a
3528 If no revision is specified, the working directory's parent is a
3529 head revision, and the current branch contains exactly one other
3529 head revision, and the current branch contains exactly one other
3530 head, the other head is merged with by default. Otherwise, an
3530 head, the other head is merged with by default. Otherwise, an
3531 explicit revision with which to merge with must be provided.
3531 explicit revision with which to merge with must be provided.
3532
3532
3533 :hg:`resolve` must be used to resolve unresolved files.
3533 :hg:`resolve` must be used to resolve unresolved files.
3534
3534
3535 To undo an uncommitted merge, use :hg:`update --clean .` which
3535 To undo an uncommitted merge, use :hg:`update --clean .` which
3536 will check out a clean copy of the original merge parent, losing
3536 will check out a clean copy of the original merge parent, losing
3537 all changes.
3537 all changes.
3538
3538
3539 Returns 0 on success, 1 if there are unresolved files.
3539 Returns 0 on success, 1 if there are unresolved files.
3540 """
3540 """
3541
3541
3542 if opts.get('rev') and node:
3542 if opts.get('rev') and node:
3543 raise util.Abort(_("please specify just one revision"))
3543 raise util.Abort(_("please specify just one revision"))
3544 if not node:
3544 if not node:
3545 node = opts.get('rev')
3545 node = opts.get('rev')
3546
3546
3547 if not node:
3547 if not node:
3548 branch = repo[None].branch()
3548 branch = repo[None].branch()
3549 bheads = repo.branchheads(branch)
3549 bheads = repo.branchheads(branch)
3550 if len(bheads) > 2:
3550 if len(bheads) > 2:
3551 raise util.Abort(_("branch '%s' has %d heads - "
3551 raise util.Abort(_("branch '%s' has %d heads - "
3552 "please merge with an explicit rev")
3552 "please merge with an explicit rev")
3553 % (branch, len(bheads)),
3553 % (branch, len(bheads)),
3554 hint=_("run 'hg heads .' to see heads"))
3554 hint=_("run 'hg heads .' to see heads"))
3555
3555
3556 parent = repo.dirstate.p1()
3556 parent = repo.dirstate.p1()
3557 if len(bheads) == 1:
3557 if len(bheads) == 1:
3558 if len(repo.heads()) > 1:
3558 if len(repo.heads()) > 1:
3559 raise util.Abort(_("branch '%s' has one head - "
3559 raise util.Abort(_("branch '%s' has one head - "
3560 "please merge with an explicit rev")
3560 "please merge with an explicit rev")
3561 % branch,
3561 % branch,
3562 hint=_("run 'hg heads' to see all heads"))
3562 hint=_("run 'hg heads' to see all heads"))
3563 msg = _('there is nothing to merge')
3563 msg = _('there is nothing to merge')
3564 if parent != repo.lookup(repo[None].branch()):
3564 if parent != repo.lookup(repo[None].branch()):
3565 msg = _('%s - use "hg update" instead') % msg
3565 msg = _('%s - use "hg update" instead') % msg
3566 raise util.Abort(msg)
3566 raise util.Abort(msg)
3567
3567
3568 if parent not in bheads:
3568 if parent not in bheads:
3569 raise util.Abort(_('working directory not at a head revision'),
3569 raise util.Abort(_('working directory not at a head revision'),
3570 hint=_("use 'hg update' or merge with an "
3570 hint=_("use 'hg update' or merge with an "
3571 "explicit revision"))
3571 "explicit revision"))
3572 node = parent == bheads[0] and bheads[-1] or bheads[0]
3572 node = parent == bheads[0] and bheads[-1] or bheads[0]
3573 else:
3573 else:
3574 node = scmutil.revsingle(repo, node).node()
3574 node = scmutil.revsingle(repo, node).node()
3575
3575
3576 if opts.get('preview'):
3576 if opts.get('preview'):
3577 # find nodes that are ancestors of p2 but not of p1
3577 # find nodes that are ancestors of p2 but not of p1
3578 p1 = repo.lookup('.')
3578 p1 = repo.lookup('.')
3579 p2 = repo.lookup(node)
3579 p2 = repo.lookup(node)
3580 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3580 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3581
3581
3582 displayer = cmdutil.show_changeset(ui, repo, opts)
3582 displayer = cmdutil.show_changeset(ui, repo, opts)
3583 for node in nodes:
3583 for node in nodes:
3584 displayer.show(repo[node])
3584 displayer.show(repo[node])
3585 displayer.close()
3585 displayer.close()
3586 return 0
3586 return 0
3587
3587
3588 try:
3588 try:
3589 # ui.forcemerge is an internal variable, do not document
3589 # ui.forcemerge is an internal variable, do not document
3590 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3590 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3591 return hg.merge(repo, node, force=opts.get('force'))
3591 return hg.merge(repo, node, force=opts.get('force'))
3592 finally:
3592 finally:
3593 ui.setconfig('ui', 'forcemerge', '')
3593 ui.setconfig('ui', 'forcemerge', '')
3594
3594
3595 @command('outgoing|out',
3595 @command('outgoing|out',
3596 [('f', 'force', None, _('run even when the destination is unrelated')),
3596 [('f', 'force', None, _('run even when the destination is unrelated')),
3597 ('r', 'rev', [],
3597 ('r', 'rev', [],
3598 _('a changeset intended to be included in the destination'), _('REV')),
3598 _('a changeset intended to be included in the destination'), _('REV')),
3599 ('n', 'newest-first', None, _('show newest record first')),
3599 ('n', 'newest-first', None, _('show newest record first')),
3600 ('B', 'bookmarks', False, _('compare bookmarks')),
3600 ('B', 'bookmarks', False, _('compare bookmarks')),
3601 ('b', 'branch', [], _('a specific branch you would like to push'),
3601 ('b', 'branch', [], _('a specific branch you would like to push'),
3602 _('BRANCH')),
3602 _('BRANCH')),
3603 ] + logopts + remoteopts + subrepoopts,
3603 ] + logopts + remoteopts + subrepoopts,
3604 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3604 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3605 def outgoing(ui, repo, dest=None, **opts):
3605 def outgoing(ui, repo, dest=None, **opts):
3606 """show changesets not found in the destination
3606 """show changesets not found in the destination
3607
3607
3608 Show changesets not found in the specified destination repository
3608 Show changesets not found in the specified destination repository
3609 or the default push location. These are the changesets that would
3609 or the default push location. These are the changesets that would
3610 be pushed if a push was requested.
3610 be pushed if a push was requested.
3611
3611
3612 See pull for details of valid destination formats.
3612 See pull for details of valid destination formats.
3613
3613
3614 Returns 0 if there are outgoing changes, 1 otherwise.
3614 Returns 0 if there are outgoing changes, 1 otherwise.
3615 """
3615 """
3616
3616
3617 if opts.get('bookmarks'):
3617 if opts.get('bookmarks'):
3618 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3618 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3619 dest, branches = hg.parseurl(dest, opts.get('branch'))
3619 dest, branches = hg.parseurl(dest, opts.get('branch'))
3620 other = hg.peer(repo, opts, dest)
3620 other = hg.peer(repo, opts, dest)
3621 if 'bookmarks' not in other.listkeys('namespaces'):
3621 if 'bookmarks' not in other.listkeys('namespaces'):
3622 ui.warn(_("remote doesn't support bookmarks\n"))
3622 ui.warn(_("remote doesn't support bookmarks\n"))
3623 return 0
3623 return 0
3624 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3624 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3625 return bookmarks.diff(ui, other, repo)
3625 return bookmarks.diff(ui, other, repo)
3626
3626
3627 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3627 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3628 try:
3628 try:
3629 return hg.outgoing(ui, repo, dest, opts)
3629 return hg.outgoing(ui, repo, dest, opts)
3630 finally:
3630 finally:
3631 del repo._subtoppath
3631 del repo._subtoppath
3632
3632
3633 @command('parents',
3633 @command('parents',
3634 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3634 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3635 ] + templateopts,
3635 ] + templateopts,
3636 _('[-r REV] [FILE]'))
3636 _('[-r REV] [FILE]'))
3637 def parents(ui, repo, file_=None, **opts):
3637 def parents(ui, repo, file_=None, **opts):
3638 """show the parents of the working directory or revision
3638 """show the parents of the working directory or revision
3639
3639
3640 Print the working directory's parent revisions. If a revision is
3640 Print the working directory's parent revisions. If a revision is
3641 given via -r/--rev, the parent of that revision will be printed.
3641 given via -r/--rev, the parent of that revision will be printed.
3642 If a file argument is given, the revision in which the file was
3642 If a file argument is given, the revision in which the file was
3643 last changed (before the working directory revision or the
3643 last changed (before the working directory revision or the
3644 argument to --rev if given) is printed.
3644 argument to --rev if given) is printed.
3645
3645
3646 Returns 0 on success.
3646 Returns 0 on success.
3647 """
3647 """
3648
3648
3649 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3649 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3650
3650
3651 if file_:
3651 if file_:
3652 m = scmutil.match(ctx, (file_,), opts)
3652 m = scmutil.match(ctx, (file_,), opts)
3653 if m.anypats() or len(m.files()) != 1:
3653 if m.anypats() or len(m.files()) != 1:
3654 raise util.Abort(_('can only specify an explicit filename'))
3654 raise util.Abort(_('can only specify an explicit filename'))
3655 file_ = m.files()[0]
3655 file_ = m.files()[0]
3656 filenodes = []
3656 filenodes = []
3657 for cp in ctx.parents():
3657 for cp in ctx.parents():
3658 if not cp:
3658 if not cp:
3659 continue
3659 continue
3660 try:
3660 try:
3661 filenodes.append(cp.filenode(file_))
3661 filenodes.append(cp.filenode(file_))
3662 except error.LookupError:
3662 except error.LookupError:
3663 pass
3663 pass
3664 if not filenodes:
3664 if not filenodes:
3665 raise util.Abort(_("'%s' not found in manifest!") % file_)
3665 raise util.Abort(_("'%s' not found in manifest!") % file_)
3666 fl = repo.file(file_)
3666 fl = repo.file(file_)
3667 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3667 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3668 else:
3668 else:
3669 p = [cp.node() for cp in ctx.parents()]
3669 p = [cp.node() for cp in ctx.parents()]
3670
3670
3671 displayer = cmdutil.show_changeset(ui, repo, opts)
3671 displayer = cmdutil.show_changeset(ui, repo, opts)
3672 for n in p:
3672 for n in p:
3673 if n != nullid:
3673 if n != nullid:
3674 displayer.show(repo[n])
3674 displayer.show(repo[n])
3675 displayer.close()
3675 displayer.close()
3676
3676
3677 @command('paths', [], _('[NAME]'))
3677 @command('paths', [], _('[NAME]'))
3678 def paths(ui, repo, search=None):
3678 def paths(ui, repo, search=None):
3679 """show aliases for remote repositories
3679 """show aliases for remote repositories
3680
3680
3681 Show definition of symbolic path name NAME. If no name is given,
3681 Show definition of symbolic path name NAME. If no name is given,
3682 show definition of all available names.
3682 show definition of all available names.
3683
3683
3684 Option -q/--quiet suppresses all output when searching for NAME
3684 Option -q/--quiet suppresses all output when searching for NAME
3685 and shows only the path names when listing all definitions.
3685 and shows only the path names when listing all definitions.
3686
3686
3687 Path names are defined in the [paths] section of your
3687 Path names are defined in the [paths] section of your
3688 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3688 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3689 repository, ``.hg/hgrc`` is used, too.
3689 repository, ``.hg/hgrc`` is used, too.
3690
3690
3691 The path names ``default`` and ``default-push`` have a special
3691 The path names ``default`` and ``default-push`` have a special
3692 meaning. When performing a push or pull operation, they are used
3692 meaning. When performing a push or pull operation, they are used
3693 as fallbacks if no location is specified on the command-line.
3693 as fallbacks if no location is specified on the command-line.
3694 When ``default-push`` is set, it will be used for push and
3694 When ``default-push`` is set, it will be used for push and
3695 ``default`` will be used for pull; otherwise ``default`` is used
3695 ``default`` will be used for pull; otherwise ``default`` is used
3696 as the fallback for both. When cloning a repository, the clone
3696 as the fallback for both. When cloning a repository, the clone
3697 source is written as ``default`` in ``.hg/hgrc``. Note that
3697 source is written as ``default`` in ``.hg/hgrc``. Note that
3698 ``default`` and ``default-push`` apply to all inbound (e.g.
3698 ``default`` and ``default-push`` apply to all inbound (e.g.
3699 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3699 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3700 :hg:`bundle`) operations.
3700 :hg:`bundle`) operations.
3701
3701
3702 See :hg:`help urls` for more information.
3702 See :hg:`help urls` for more information.
3703
3703
3704 Returns 0 on success.
3704 Returns 0 on success.
3705 """
3705 """
3706 if search:
3706 if search:
3707 for name, path in ui.configitems("paths"):
3707 for name, path in ui.configitems("paths"):
3708 if name == search:
3708 if name == search:
3709 ui.status("%s\n" % util.hidepassword(path))
3709 ui.status("%s\n" % util.hidepassword(path))
3710 return
3710 return
3711 if not ui.quiet:
3711 if not ui.quiet:
3712 ui.warn(_("not found!\n"))
3712 ui.warn(_("not found!\n"))
3713 return 1
3713 return 1
3714 else:
3714 else:
3715 for name, path in ui.configitems("paths"):
3715 for name, path in ui.configitems("paths"):
3716 if ui.quiet:
3716 if ui.quiet:
3717 ui.write("%s\n" % name)
3717 ui.write("%s\n" % name)
3718 else:
3718 else:
3719 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3719 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3720
3720
3721 def postincoming(ui, repo, modheads, optupdate, checkout):
3721 def postincoming(ui, repo, modheads, optupdate, checkout):
3722 if modheads == 0:
3722 if modheads == 0:
3723 return
3723 return
3724 if optupdate:
3724 if optupdate:
3725 try:
3725 try:
3726 return hg.update(repo, checkout)
3726 return hg.update(repo, checkout)
3727 except util.Abort, inst:
3727 except util.Abort, inst:
3728 ui.warn(_("not updating: %s\n" % str(inst)))
3728 ui.warn(_("not updating: %s\n" % str(inst)))
3729 return 0
3729 return 0
3730 if modheads > 1:
3730 if modheads > 1:
3731 currentbranchheads = len(repo.branchheads())
3731 currentbranchheads = len(repo.branchheads())
3732 if currentbranchheads == modheads:
3732 if currentbranchheads == modheads:
3733 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3733 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3734 elif currentbranchheads > 1:
3734 elif currentbranchheads > 1:
3735 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3735 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3736 else:
3736 else:
3737 ui.status(_("(run 'hg heads' to see heads)\n"))
3737 ui.status(_("(run 'hg heads' to see heads)\n"))
3738 else:
3738 else:
3739 ui.status(_("(run 'hg update' to get a working copy)\n"))
3739 ui.status(_("(run 'hg update' to get a working copy)\n"))
3740
3740
3741 @command('^pull',
3741 @command('^pull',
3742 [('u', 'update', None,
3742 [('u', 'update', None,
3743 _('update to new branch head if changesets were pulled')),
3743 _('update to new branch head if changesets were pulled')),
3744 ('f', 'force', None, _('run even when remote repository is unrelated')),
3744 ('f', 'force', None, _('run even when remote repository is unrelated')),
3745 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3745 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3746 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3746 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3747 ('b', 'branch', [], _('a specific branch you would like to pull'),
3747 ('b', 'branch', [], _('a specific branch you would like to pull'),
3748 _('BRANCH')),
3748 _('BRANCH')),
3749 ] + remoteopts,
3749 ] + remoteopts,
3750 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3750 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3751 def pull(ui, repo, source="default", **opts):
3751 def pull(ui, repo, source="default", **opts):
3752 """pull changes from the specified source
3752 """pull changes from the specified source
3753
3753
3754 Pull changes from a remote repository to a local one.
3754 Pull changes from a remote repository to a local one.
3755
3755
3756 This finds all changes from the repository at the specified path
3756 This finds all changes from the repository at the specified path
3757 or URL and adds them to a local repository (the current one unless
3757 or URL and adds them to a local repository (the current one unless
3758 -R is specified). By default, this does not update the copy of the
3758 -R is specified). By default, this does not update the copy of the
3759 project in the working directory.
3759 project in the working directory.
3760
3760
3761 Use :hg:`incoming` if you want to see what would have been added
3761 Use :hg:`incoming` if you want to see what would have been added
3762 by a pull at the time you issued this command. If you then decide
3762 by a pull at the time you issued this command. If you then decide
3763 to add those changes to the repository, you should use :hg:`pull
3763 to add those changes to the repository, you should use :hg:`pull
3764 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3764 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3765
3765
3766 If SOURCE is omitted, the 'default' path will be used.
3766 If SOURCE is omitted, the 'default' path will be used.
3767 See :hg:`help urls` for more information.
3767 See :hg:`help urls` for more information.
3768
3768
3769 Returns 0 on success, 1 if an update had unresolved files.
3769 Returns 0 on success, 1 if an update had unresolved files.
3770 """
3770 """
3771 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3771 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3772 other = hg.peer(repo, opts, source)
3772 other = hg.peer(repo, opts, source)
3773 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3773 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3774 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3774 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3775
3775
3776 if opts.get('bookmark'):
3776 if opts.get('bookmark'):
3777 if not revs:
3777 if not revs:
3778 revs = []
3778 revs = []
3779 rb = other.listkeys('bookmarks')
3779 rb = other.listkeys('bookmarks')
3780 for b in opts['bookmark']:
3780 for b in opts['bookmark']:
3781 if b not in rb:
3781 if b not in rb:
3782 raise util.Abort(_('remote bookmark %s not found!') % b)
3782 raise util.Abort(_('remote bookmark %s not found!') % b)
3783 revs.append(rb[b])
3783 revs.append(rb[b])
3784
3784
3785 if revs:
3785 if revs:
3786 try:
3786 try:
3787 revs = [other.lookup(rev) for rev in revs]
3787 revs = [other.lookup(rev) for rev in revs]
3788 except error.CapabilityError:
3788 except error.CapabilityError:
3789 err = _("other repository doesn't support revision lookup, "
3789 err = _("other repository doesn't support revision lookup, "
3790 "so a rev cannot be specified.")
3790 "so a rev cannot be specified.")
3791 raise util.Abort(err)
3791 raise util.Abort(err)
3792
3792
3793 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3793 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3794 bookmarks.updatefromremote(ui, repo, other)
3794 bookmarks.updatefromremote(ui, repo, other)
3795 if checkout:
3795 if checkout:
3796 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3796 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3797 repo._subtoppath = source
3797 repo._subtoppath = source
3798 try:
3798 try:
3799 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3799 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3800
3800
3801 finally:
3801 finally:
3802 del repo._subtoppath
3802 del repo._subtoppath
3803
3803
3804 # update specified bookmarks
3804 # update specified bookmarks
3805 if opts.get('bookmark'):
3805 if opts.get('bookmark'):
3806 for b in opts['bookmark']:
3806 for b in opts['bookmark']:
3807 # explicit pull overrides local bookmark if any
3807 # explicit pull overrides local bookmark if any
3808 ui.status(_("importing bookmark %s\n") % b)
3808 ui.status(_("importing bookmark %s\n") % b)
3809 repo._bookmarks[b] = repo[rb[b]].node()
3809 repo._bookmarks[b] = repo[rb[b]].node()
3810 bookmarks.write(repo)
3810 bookmarks.write(repo)
3811
3811
3812 return ret
3812 return ret
3813
3813
3814 @command('^push',
3814 @command('^push',
3815 [('f', 'force', None, _('force push')),
3815 [('f', 'force', None, _('force push')),
3816 ('r', 'rev', [],
3816 ('r', 'rev', [],
3817 _('a changeset intended to be included in the destination'),
3817 _('a changeset intended to be included in the destination'),
3818 _('REV')),
3818 _('REV')),
3819 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3819 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3820 ('b', 'branch', [],
3820 ('b', 'branch', [],
3821 _('a specific branch you would like to push'), _('BRANCH')),
3821 _('a specific branch you would like to push'), _('BRANCH')),
3822 ('', 'new-branch', False, _('allow pushing a new branch')),
3822 ('', 'new-branch', False, _('allow pushing a new branch')),
3823 ] + remoteopts,
3823 ] + remoteopts,
3824 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3824 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3825 def push(ui, repo, dest=None, **opts):
3825 def push(ui, repo, dest=None, **opts):
3826 """push changes to the specified destination
3826 """push changes to the specified destination
3827
3827
3828 Push changesets from the local repository to the specified
3828 Push changesets from the local repository to the specified
3829 destination.
3829 destination.
3830
3830
3831 This operation is symmetrical to pull: it is identical to a pull
3831 This operation is symmetrical to pull: it is identical to a pull
3832 in the destination repository from the current one.
3832 in the destination repository from the current one.
3833
3833
3834 By default, push will not allow creation of new heads at the
3834 By default, push will not allow creation of new heads at the
3835 destination, since multiple heads would make it unclear which head
3835 destination, since multiple heads would make it unclear which head
3836 to use. In this situation, it is recommended to pull and merge
3836 to use. In this situation, it is recommended to pull and merge
3837 before pushing.
3837 before pushing.
3838
3838
3839 Use --new-branch if you want to allow push to create a new named
3839 Use --new-branch if you want to allow push to create a new named
3840 branch that is not present at the destination. This allows you to
3840 branch that is not present at the destination. This allows you to
3841 only create a new branch without forcing other changes.
3841 only create a new branch without forcing other changes.
3842
3842
3843 Use -f/--force to override the default behavior and push all
3843 Use -f/--force to override the default behavior and push all
3844 changesets on all branches.
3844 changesets on all branches.
3845
3845
3846 If -r/--rev is used, the specified revision and all its ancestors
3846 If -r/--rev is used, the specified revision and all its ancestors
3847 will be pushed to the remote repository.
3847 will be pushed to the remote repository.
3848
3848
3849 Please see :hg:`help urls` for important details about ``ssh://``
3849 Please see :hg:`help urls` for important details about ``ssh://``
3850 URLs. If DESTINATION is omitted, a default path will be used.
3850 URLs. If DESTINATION is omitted, a default path will be used.
3851
3851
3852 Returns 0 if push was successful, 1 if nothing to push.
3852 Returns 0 if push was successful, 1 if nothing to push.
3853 """
3853 """
3854
3854
3855 if opts.get('bookmark'):
3855 if opts.get('bookmark'):
3856 for b in opts['bookmark']:
3856 for b in opts['bookmark']:
3857 # translate -B options to -r so changesets get pushed
3857 # translate -B options to -r so changesets get pushed
3858 if b in repo._bookmarks:
3858 if b in repo._bookmarks:
3859 opts.setdefault('rev', []).append(b)
3859 opts.setdefault('rev', []).append(b)
3860 else:
3860 else:
3861 # if we try to push a deleted bookmark, translate it to null
3861 # if we try to push a deleted bookmark, translate it to null
3862 # this lets simultaneous -r, -b options continue working
3862 # this lets simultaneous -r, -b options continue working
3863 opts.setdefault('rev', []).append("null")
3863 opts.setdefault('rev', []).append("null")
3864
3864
3865 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3865 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3866 dest, branches = hg.parseurl(dest, opts.get('branch'))
3866 dest, branches = hg.parseurl(dest, opts.get('branch'))
3867 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3867 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3868 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3868 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3869 other = hg.peer(repo, opts, dest)
3869 other = hg.peer(repo, opts, dest)
3870 if revs:
3870 if revs:
3871 revs = [repo.lookup(rev) for rev in revs]
3871 revs = [repo.lookup(rev) for rev in revs]
3872
3872
3873 repo._subtoppath = dest
3873 repo._subtoppath = dest
3874 try:
3874 try:
3875 # push subrepos depth-first for coherent ordering
3875 # push subrepos depth-first for coherent ordering
3876 c = repo['']
3876 c = repo['']
3877 subs = c.substate # only repos that are committed
3877 subs = c.substate # only repos that are committed
3878 for s in sorted(subs):
3878 for s in sorted(subs):
3879 if not c.sub(s).push(opts.get('force')):
3879 if not c.sub(s).push(opts.get('force')):
3880 return False
3880 return False
3881 finally:
3881 finally:
3882 del repo._subtoppath
3882 del repo._subtoppath
3883 result = repo.push(other, opts.get('force'), revs=revs,
3883 result = repo.push(other, opts.get('force'), revs=revs,
3884 newbranch=opts.get('new_branch'))
3884 newbranch=opts.get('new_branch'))
3885
3885
3886 result = (result == 0)
3886 result = (result == 0)
3887
3887
3888 if opts.get('bookmark'):
3888 if opts.get('bookmark'):
3889 rb = other.listkeys('bookmarks')
3889 rb = other.listkeys('bookmarks')
3890 for b in opts['bookmark']:
3890 for b in opts['bookmark']:
3891 # explicit push overrides remote bookmark if any
3891 # explicit push overrides remote bookmark if any
3892 if b in repo._bookmarks:
3892 if b in repo._bookmarks:
3893 ui.status(_("exporting bookmark %s\n") % b)
3893 ui.status(_("exporting bookmark %s\n") % b)
3894 new = repo[b].hex()
3894 new = repo[b].hex()
3895 elif b in rb:
3895 elif b in rb:
3896 ui.status(_("deleting remote bookmark %s\n") % b)
3896 ui.status(_("deleting remote bookmark %s\n") % b)
3897 new = '' # delete
3897 new = '' # delete
3898 else:
3898 else:
3899 ui.warn(_('bookmark %s does not exist on the local '
3899 ui.warn(_('bookmark %s does not exist on the local '
3900 'or remote repository!\n') % b)
3900 'or remote repository!\n') % b)
3901 return 2
3901 return 2
3902 old = rb.get(b, '')
3902 old = rb.get(b, '')
3903 r = other.pushkey('bookmarks', b, old, new)
3903 r = other.pushkey('bookmarks', b, old, new)
3904 if not r:
3904 if not r:
3905 ui.warn(_('updating bookmark %s failed!\n') % b)
3905 ui.warn(_('updating bookmark %s failed!\n') % b)
3906 if not result:
3906 if not result:
3907 result = 2
3907 result = 2
3908
3908
3909 return result
3909 return result
3910
3910
3911 @command('recover', [])
3911 @command('recover', [])
3912 def recover(ui, repo):
3912 def recover(ui, repo):
3913 """roll back an interrupted transaction
3913 """roll back an interrupted transaction
3914
3914
3915 Recover from an interrupted commit or pull.
3915 Recover from an interrupted commit or pull.
3916
3916
3917 This command tries to fix the repository status after an
3917 This command tries to fix the repository status after an
3918 interrupted operation. It should only be necessary when Mercurial
3918 interrupted operation. It should only be necessary when Mercurial
3919 suggests it.
3919 suggests it.
3920
3920
3921 Returns 0 if successful, 1 if nothing to recover or verify fails.
3921 Returns 0 if successful, 1 if nothing to recover or verify fails.
3922 """
3922 """
3923 if repo.recover():
3923 if repo.recover():
3924 return hg.verify(repo)
3924 return hg.verify(repo)
3925 return 1
3925 return 1
3926
3926
3927 @command('^remove|rm',
3927 @command('^remove|rm',
3928 [('A', 'after', None, _('record delete for missing files')),
3928 [('A', 'after', None, _('record delete for missing files')),
3929 ('f', 'force', None,
3929 ('f', 'force', None,
3930 _('remove (and delete) file even if added or modified')),
3930 _('remove (and delete) file even if added or modified')),
3931 ] + walkopts,
3931 ] + walkopts,
3932 _('[OPTION]... FILE...'))
3932 _('[OPTION]... FILE...'))
3933 def remove(ui, repo, *pats, **opts):
3933 def remove(ui, repo, *pats, **opts):
3934 """remove the specified files on the next commit
3934 """remove the specified files on the next commit
3935
3935
3936 Schedule the indicated files for removal from the repository.
3936 Schedule the indicated files for removal from the repository.
3937
3937
3938 This only removes files from the current branch, not from the
3938 This only removes files from the current branch, not from the
3939 entire project history. -A/--after can be used to remove only
3939 entire project history. -A/--after can be used to remove only
3940 files that have already been deleted, -f/--force can be used to
3940 files that have already been deleted, -f/--force can be used to
3941 force deletion, and -Af can be used to remove files from the next
3941 force deletion, and -Af can be used to remove files from the next
3942 revision without deleting them from the working directory.
3942 revision without deleting them from the working directory.
3943
3943
3944 The following table details the behavior of remove for different
3944 The following table details the behavior of remove for different
3945 file states (columns) and option combinations (rows). The file
3945 file states (columns) and option combinations (rows). The file
3946 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3946 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3947 reported by :hg:`status`). The actions are Warn, Remove (from
3947 reported by :hg:`status`). The actions are Warn, Remove (from
3948 branch) and Delete (from disk)::
3948 branch) and Delete (from disk)::
3949
3949
3950 A C M !
3950 A C M !
3951 none W RD W R
3951 none W RD W R
3952 -f R RD RD R
3952 -f R RD RD R
3953 -A W W W R
3953 -A W W W R
3954 -Af R R R R
3954 -Af R R R R
3955
3955
3956 Note that remove never deletes files in Added [A] state from the
3956 Note that remove never deletes files in Added [A] state from the
3957 working directory, not even if option --force is specified.
3957 working directory, not even if option --force is specified.
3958
3958
3959 This command schedules the files to be removed at the next commit.
3959 This command schedules the files to be removed at the next commit.
3960 To undo a remove before that, see :hg:`revert`.
3960 To undo a remove before that, see :hg:`revert`.
3961
3961
3962 Returns 0 on success, 1 if any warnings encountered.
3962 Returns 0 on success, 1 if any warnings encountered.
3963 """
3963 """
3964
3964
3965 ret = 0
3965 ret = 0
3966 after, force = opts.get('after'), opts.get('force')
3966 after, force = opts.get('after'), opts.get('force')
3967 if not pats and not after:
3967 if not pats and not after:
3968 raise util.Abort(_('no files specified'))
3968 raise util.Abort(_('no files specified'))
3969
3969
3970 m = scmutil.match(repo[None], pats, opts)
3970 m = scmutil.match(repo[None], pats, opts)
3971 s = repo.status(match=m, clean=True)
3971 s = repo.status(match=m, clean=True)
3972 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3972 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3973
3973
3974 for f in m.files():
3974 for f in m.files():
3975 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3975 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3976 if os.path.exists(m.rel(f)):
3976 if os.path.exists(m.rel(f)):
3977 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3977 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3978 ret = 1
3978 ret = 1
3979
3979
3980 if force:
3980 if force:
3981 list = modified + deleted + clean + added
3981 list = modified + deleted + clean + added
3982 elif after:
3982 elif after:
3983 list = deleted
3983 list = deleted
3984 for f in modified + added + clean:
3984 for f in modified + added + clean:
3985 ui.warn(_('not removing %s: file still exists (use -f'
3985 ui.warn(_('not removing %s: file still exists (use -f'
3986 ' to force removal)\n') % m.rel(f))
3986 ' to force removal)\n') % m.rel(f))
3987 ret = 1
3987 ret = 1
3988 else:
3988 else:
3989 list = deleted + clean
3989 list = deleted + clean
3990 for f in modified:
3990 for f in modified:
3991 ui.warn(_('not removing %s: file is modified (use -f'
3991 ui.warn(_('not removing %s: file is modified (use -f'
3992 ' to force removal)\n') % m.rel(f))
3992 ' to force removal)\n') % m.rel(f))
3993 ret = 1
3993 ret = 1
3994 for f in added:
3994 for f in added:
3995 ui.warn(_('not removing %s: file has been marked for add (use -f'
3995 ui.warn(_('not removing %s: file has been marked for add (use -f'
3996 ' to force removal)\n') % m.rel(f))
3996 ' to force removal)\n') % m.rel(f))
3997 ret = 1
3997 ret = 1
3998
3998
3999 for f in sorted(list):
3999 for f in sorted(list):
4000 if ui.verbose or not m.exact(f):
4000 if ui.verbose or not m.exact(f):
4001 ui.status(_('removing %s\n') % m.rel(f))
4001 ui.status(_('removing %s\n') % m.rel(f))
4002
4002
4003 wlock = repo.wlock()
4003 wlock = repo.wlock()
4004 try:
4004 try:
4005 if not after:
4005 if not after:
4006 for f in list:
4006 for f in list:
4007 if f in added:
4007 if f in added:
4008 continue # we never unlink added files on remove
4008 continue # we never unlink added files on remove
4009 try:
4009 try:
4010 util.unlinkpath(repo.wjoin(f))
4010 util.unlinkpath(repo.wjoin(f))
4011 except OSError, inst:
4011 except OSError, inst:
4012 if inst.errno != errno.ENOENT:
4012 if inst.errno != errno.ENOENT:
4013 raise
4013 raise
4014 repo[None].forget(list)
4014 repo[None].forget(list)
4015 finally:
4015 finally:
4016 wlock.release()
4016 wlock.release()
4017
4017
4018 return ret
4018 return ret
4019
4019
4020 @command('rename|move|mv',
4020 @command('rename|move|mv',
4021 [('A', 'after', None, _('record a rename that has already occurred')),
4021 [('A', 'after', None, _('record a rename that has already occurred')),
4022 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4022 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4023 ] + walkopts + dryrunopts,
4023 ] + walkopts + dryrunopts,
4024 _('[OPTION]... SOURCE... DEST'))
4024 _('[OPTION]... SOURCE... DEST'))
4025 def rename(ui, repo, *pats, **opts):
4025 def rename(ui, repo, *pats, **opts):
4026 """rename files; equivalent of copy + remove
4026 """rename files; equivalent of copy + remove
4027
4027
4028 Mark dest as copies of sources; mark sources for deletion. If dest
4028 Mark dest as copies of sources; mark sources for deletion. If dest
4029 is a directory, copies are put in that directory. If dest is a
4029 is a directory, copies are put in that directory. If dest is a
4030 file, there can only be one source.
4030 file, there can only be one source.
4031
4031
4032 By default, this command copies the contents of files as they
4032 By default, this command copies the contents of files as they
4033 exist in the working directory. If invoked with -A/--after, the
4033 exist in the working directory. If invoked with -A/--after, the
4034 operation is recorded, but no copying is performed.
4034 operation is recorded, but no copying is performed.
4035
4035
4036 This command takes effect at the next commit. To undo a rename
4036 This command takes effect at the next commit. To undo a rename
4037 before that, see :hg:`revert`.
4037 before that, see :hg:`revert`.
4038
4038
4039 Returns 0 on success, 1 if errors are encountered.
4039 Returns 0 on success, 1 if errors are encountered.
4040 """
4040 """
4041 wlock = repo.wlock(False)
4041 wlock = repo.wlock(False)
4042 try:
4042 try:
4043 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4043 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4044 finally:
4044 finally:
4045 wlock.release()
4045 wlock.release()
4046
4046
4047 @command('resolve',
4047 @command('resolve',
4048 [('a', 'all', None, _('select all unresolved files')),
4048 [('a', 'all', None, _('select all unresolved files')),
4049 ('l', 'list', None, _('list state of files needing merge')),
4049 ('l', 'list', None, _('list state of files needing merge')),
4050 ('m', 'mark', None, _('mark files as resolved')),
4050 ('m', 'mark', None, _('mark files as resolved')),
4051 ('u', 'unmark', None, _('mark files as unresolved')),
4051 ('u', 'unmark', None, _('mark files as unresolved')),
4052 ('t', 'tool', '', _('specify merge tool')),
4052 ('t', 'tool', '', _('specify merge tool')),
4053 ('n', 'no-status', None, _('hide status prefix'))]
4053 ('n', 'no-status', None, _('hide status prefix'))]
4054 + walkopts,
4054 + walkopts,
4055 _('[OPTION]... [FILE]...'))
4055 _('[OPTION]... [FILE]...'))
4056 def resolve(ui, repo, *pats, **opts):
4056 def resolve(ui, repo, *pats, **opts):
4057 """redo merges or set/view the merge status of files
4057 """redo merges or set/view the merge status of files
4058
4058
4059 Merges with unresolved conflicts are often the result of
4059 Merges with unresolved conflicts are often the result of
4060 non-interactive merging using the ``internal:merge`` configuration
4060 non-interactive merging using the ``internal:merge`` configuration
4061 setting, or a command-line merge tool like ``diff3``. The resolve
4061 setting, or a command-line merge tool like ``diff3``. The resolve
4062 command is used to manage the files involved in a merge, after
4062 command is used to manage the files involved in a merge, after
4063 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4063 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4064 working directory must have two parents).
4064 working directory must have two parents).
4065
4065
4066 The resolve command can be used in the following ways:
4066 The resolve command can be used in the following ways:
4067
4067
4068 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4068 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4069 files, discarding any previous merge attempts. Re-merging is not
4069 files, discarding any previous merge attempts. Re-merging is not
4070 performed for files already marked as resolved. Use ``--all/-a``
4070 performed for files already marked as resolved. Use ``--all/-a``
4071 to selects all unresolved files. ``--tool`` can be used to specify
4071 to selects all unresolved files. ``--tool`` can be used to specify
4072 the merge tool used for the given files. It overrides the HGMERGE
4072 the merge tool used for the given files. It overrides the HGMERGE
4073 environment variable and your configuration files.
4073 environment variable and your configuration files.
4074
4074
4075 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4075 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4076 (e.g. after having manually fixed-up the files). The default is
4076 (e.g. after having manually fixed-up the files). The default is
4077 to mark all unresolved files.
4077 to mark all unresolved files.
4078
4078
4079 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4079 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4080 default is to mark all resolved files.
4080 default is to mark all resolved files.
4081
4081
4082 - :hg:`resolve -l`: list files which had or still have conflicts.
4082 - :hg:`resolve -l`: list files which had or still have conflicts.
4083 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4083 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4084
4084
4085 Note that Mercurial will not let you commit files with unresolved
4085 Note that Mercurial will not let you commit files with unresolved
4086 merge conflicts. You must use :hg:`resolve -m ...` before you can
4086 merge conflicts. You must use :hg:`resolve -m ...` before you can
4087 commit after a conflicting merge.
4087 commit after a conflicting merge.
4088
4088
4089 Returns 0 on success, 1 if any files fail a resolve attempt.
4089 Returns 0 on success, 1 if any files fail a resolve attempt.
4090 """
4090 """
4091
4091
4092 all, mark, unmark, show, nostatus = \
4092 all, mark, unmark, show, nostatus = \
4093 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4093 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4094
4094
4095 if (show and (mark or unmark)) or (mark and unmark):
4095 if (show and (mark or unmark)) or (mark and unmark):
4096 raise util.Abort(_("too many options specified"))
4096 raise util.Abort(_("too many options specified"))
4097 if pats and all:
4097 if pats and all:
4098 raise util.Abort(_("can't specify --all and patterns"))
4098 raise util.Abort(_("can't specify --all and patterns"))
4099 if not (all or pats or show or mark or unmark):
4099 if not (all or pats or show or mark or unmark):
4100 raise util.Abort(_('no files or directories specified; '
4100 raise util.Abort(_('no files or directories specified; '
4101 'use --all to remerge all files'))
4101 'use --all to remerge all files'))
4102
4102
4103 ms = mergemod.mergestate(repo)
4103 ms = mergemod.mergestate(repo)
4104 m = scmutil.match(repo[None], pats, opts)
4104 m = scmutil.match(repo[None], pats, opts)
4105 ret = 0
4105 ret = 0
4106
4106
4107 for f in ms:
4107 for f in ms:
4108 if m(f):
4108 if m(f):
4109 if show:
4109 if show:
4110 if nostatus:
4110 if nostatus:
4111 ui.write("%s\n" % f)
4111 ui.write("%s\n" % f)
4112 else:
4112 else:
4113 ui.write("%s %s\n" % (ms[f].upper(), f),
4113 ui.write("%s %s\n" % (ms[f].upper(), f),
4114 label='resolve.' +
4114 label='resolve.' +
4115 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4115 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4116 elif mark:
4116 elif mark:
4117 ms.mark(f, "r")
4117 ms.mark(f, "r")
4118 elif unmark:
4118 elif unmark:
4119 ms.mark(f, "u")
4119 ms.mark(f, "u")
4120 else:
4120 else:
4121 wctx = repo[None]
4121 wctx = repo[None]
4122 mctx = wctx.parents()[-1]
4122 mctx = wctx.parents()[-1]
4123
4123
4124 # backup pre-resolve (merge uses .orig for its own purposes)
4124 # backup pre-resolve (merge uses .orig for its own purposes)
4125 a = repo.wjoin(f)
4125 a = repo.wjoin(f)
4126 util.copyfile(a, a + ".resolve")
4126 util.copyfile(a, a + ".resolve")
4127
4127
4128 try:
4128 try:
4129 # resolve file
4129 # resolve file
4130 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4130 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4131 if ms.resolve(f, wctx, mctx):
4131 if ms.resolve(f, wctx, mctx):
4132 ret = 1
4132 ret = 1
4133 finally:
4133 finally:
4134 ui.setconfig('ui', 'forcemerge', '')
4134 ui.setconfig('ui', 'forcemerge', '')
4135
4135
4136 # replace filemerge's .orig file with our resolve file
4136 # replace filemerge's .orig file with our resolve file
4137 util.rename(a + ".resolve", a + ".orig")
4137 util.rename(a + ".resolve", a + ".orig")
4138
4138
4139 ms.commit()
4139 ms.commit()
4140 return ret
4140 return ret
4141
4141
4142 @command('revert',
4142 @command('revert',
4143 [('a', 'all', None, _('revert all changes when no arguments given')),
4143 [('a', 'all', None, _('revert all changes when no arguments given')),
4144 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4144 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4145 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4145 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4146 ('', 'no-backup', None, _('do not save backup copies of files')),
4146 ('', 'no-backup', None, _('do not save backup copies of files')),
4147 ] + walkopts + dryrunopts,
4147 ] + walkopts + dryrunopts,
4148 _('[OPTION]... [-r REV] [NAME]...'))
4148 _('[OPTION]... [-r REV] [NAME]...'))
4149 def revert(ui, repo, *pats, **opts):
4149 def revert(ui, repo, *pats, **opts):
4150 """restore files to their checkout state
4150 """restore files to their checkout state
4151
4151
4152 .. note::
4152 .. note::
4153 To check out earlier revisions, you should use :hg:`update REV`.
4153 To check out earlier revisions, you should use :hg:`update REV`.
4154 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4154 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4155
4155
4156 With no revision specified, revert the specified files or directories
4156 With no revision specified, revert the specified files or directories
4157 to the state they had in the first parent of the working directory.
4157 to the state they had in the first parent of the working directory.
4158 This restores the contents of files to an unmodified
4158 This restores the contents of files to an unmodified
4159 state and unschedules adds, removes, copies, and renames.
4159 state and unschedules adds, removes, copies, and renames.
4160
4160
4161 Using the -r/--rev or -d/--date options, revert the given files or
4161 Using the -r/--rev or -d/--date options, revert the given files or
4162 directories to their states as of a specific revision. Because
4162 directories to their states as of a specific revision. Because
4163 revert does not change the working directory parents, this will
4163 revert does not change the working directory parents, this will
4164 cause these files to appear modified. This can be helpful to "back
4164 cause these files to appear modified. This can be helpful to "back
4165 out" some or all of an earlier change. See :hg:`backout` for a
4165 out" some or all of an earlier change. See :hg:`backout` for a
4166 related method.
4166 related method.
4167
4167
4168 Modified files are saved with a .orig suffix before reverting.
4168 Modified files are saved with a .orig suffix before reverting.
4169 To disable these backups, use --no-backup.
4169 To disable these backups, use --no-backup.
4170
4170
4171 See :hg:`help dates` for a list of formats valid for -d/--date.
4171 See :hg:`help dates` for a list of formats valid for -d/--date.
4172
4172
4173 Returns 0 on success.
4173 Returns 0 on success.
4174 """
4174 """
4175
4175
4176 if opts.get("date"):
4176 if opts.get("date"):
4177 if opts.get("rev"):
4177 if opts.get("rev"):
4178 raise util.Abort(_("you can't specify a revision and a date"))
4178 raise util.Abort(_("you can't specify a revision and a date"))
4179 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4179 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4180
4180
4181 parent, p2 = repo.dirstate.parents()
4181 parent, p2 = repo.dirstate.parents()
4182
4182
4183 if not pats and not opts.get('all'):
4183 if not pats and not opts.get('all'):
4184 raise util.Abort(_('no files or directories specified'),
4184 raise util.Abort(_('no files or directories specified'),
4185 hint=_('use --all to revert all files'))
4185 hint=_('use --all to revert all files'))
4186
4186
4187 ctx = scmutil.revsingle(repo, opts.get('rev'))
4187 ctx = scmutil.revsingle(repo, opts.get('rev'))
4188 node = ctx.node()
4188 node = ctx.node()
4189 mf = ctx.manifest()
4189 mf = ctx.manifest()
4190 if node == parent:
4190 if node == parent:
4191 pmf = mf
4191 pmf = mf
4192 else:
4192 else:
4193 pmf = None
4193 pmf = None
4194
4194
4195 # need all matching names in dirstate and manifest of target rev,
4195 # need all matching names in dirstate and manifest of target rev,
4196 # so have to walk both. do not print errors if files exist in one
4196 # so have to walk both. do not print errors if files exist in one
4197 # but not other.
4197 # but not other.
4198
4198
4199 names = {}
4199 names = {}
4200
4200
4201 wlock = repo.wlock()
4201 wlock = repo.wlock()
4202 try:
4202 try:
4203 # walk dirstate.
4203 # walk dirstate.
4204
4204
4205 m = scmutil.match(repo[None], pats, opts)
4205 m = scmutil.match(repo[None], pats, opts)
4206 m.bad = lambda x, y: False
4206 m.bad = lambda x, y: False
4207 for abs in repo.walk(m):
4207 for abs in repo.walk(m):
4208 names[abs] = m.rel(abs), m.exact(abs)
4208 names[abs] = m.rel(abs), m.exact(abs)
4209
4209
4210 # walk target manifest.
4210 # walk target manifest.
4211
4211
4212 def badfn(path, msg):
4212 def badfn(path, msg):
4213 if path in names:
4213 if path in names:
4214 return
4214 return
4215 path_ = path + '/'
4215 path_ = path + '/'
4216 for f in names:
4216 for f in names:
4217 if f.startswith(path_):
4217 if f.startswith(path_):
4218 return
4218 return
4219 ui.warn("%s: %s\n" % (m.rel(path), msg))
4219 ui.warn("%s: %s\n" % (m.rel(path), msg))
4220
4220
4221 m = scmutil.match(repo[node], pats, opts)
4221 m = scmutil.match(repo[node], pats, opts)
4222 m.bad = badfn
4222 m.bad = badfn
4223 for abs in repo[node].walk(m):
4223 for abs in repo[node].walk(m):
4224 if abs not in names:
4224 if abs not in names:
4225 names[abs] = m.rel(abs), m.exact(abs)
4225 names[abs] = m.rel(abs), m.exact(abs)
4226
4226
4227 m = scmutil.matchfiles(repo, names)
4227 m = scmutil.matchfiles(repo, names)
4228 changes = repo.status(match=m)[:4]
4228 changes = repo.status(match=m)[:4]
4229 modified, added, removed, deleted = map(set, changes)
4229 modified, added, removed, deleted = map(set, changes)
4230
4230
4231 # if f is a rename, also revert the source
4231 # if f is a rename, also revert the source
4232 cwd = repo.getcwd()
4232 cwd = repo.getcwd()
4233 for f in added:
4233 for f in added:
4234 src = repo.dirstate.copied(f)
4234 src = repo.dirstate.copied(f)
4235 if src and src not in names and repo.dirstate[src] == 'r':
4235 if src and src not in names and repo.dirstate[src] == 'r':
4236 removed.add(src)
4236 removed.add(src)
4237 names[src] = (repo.pathto(src, cwd), True)
4237 names[src] = (repo.pathto(src, cwd), True)
4238
4238
4239 def removeforget(abs):
4239 def removeforget(abs):
4240 if repo.dirstate[abs] == 'a':
4240 if repo.dirstate[abs] == 'a':
4241 return _('forgetting %s\n')
4241 return _('forgetting %s\n')
4242 return _('removing %s\n')
4242 return _('removing %s\n')
4243
4243
4244 revert = ([], _('reverting %s\n'))
4244 revert = ([], _('reverting %s\n'))
4245 add = ([], _('adding %s\n'))
4245 add = ([], _('adding %s\n'))
4246 remove = ([], removeforget)
4246 remove = ([], removeforget)
4247 undelete = ([], _('undeleting %s\n'))
4247 undelete = ([], _('undeleting %s\n'))
4248
4248
4249 disptable = (
4249 disptable = (
4250 # dispatch table:
4250 # dispatch table:
4251 # file state
4251 # file state
4252 # action if in target manifest
4252 # action if in target manifest
4253 # action if not in target manifest
4253 # action if not in target manifest
4254 # make backup if in target manifest
4254 # make backup if in target manifest
4255 # make backup if not in target manifest
4255 # make backup if not in target manifest
4256 (modified, revert, remove, True, True),
4256 (modified, revert, remove, True, True),
4257 (added, revert, remove, True, False),
4257 (added, revert, remove, True, False),
4258 (removed, undelete, None, False, False),
4258 (removed, undelete, None, False, False),
4259 (deleted, revert, remove, False, False),
4259 (deleted, revert, remove, False, False),
4260 )
4260 )
4261
4261
4262 for abs, (rel, exact) in sorted(names.items()):
4262 for abs, (rel, exact) in sorted(names.items()):
4263 mfentry = mf.get(abs)
4263 mfentry = mf.get(abs)
4264 target = repo.wjoin(abs)
4264 target = repo.wjoin(abs)
4265 def handle(xlist, dobackup):
4265 def handle(xlist, dobackup):
4266 xlist[0].append(abs)
4266 xlist[0].append(abs)
4267 if (dobackup and not opts.get('no_backup') and
4267 if (dobackup and not opts.get('no_backup') and
4268 os.path.lexists(target)):
4268 os.path.lexists(target)):
4269 bakname = "%s.orig" % rel
4269 bakname = "%s.orig" % rel
4270 ui.note(_('saving current version of %s as %s\n') %
4270 ui.note(_('saving current version of %s as %s\n') %
4271 (rel, bakname))
4271 (rel, bakname))
4272 if not opts.get('dry_run'):
4272 if not opts.get('dry_run'):
4273 util.rename(target, bakname)
4273 util.rename(target, bakname)
4274 if ui.verbose or not exact:
4274 if ui.verbose or not exact:
4275 msg = xlist[1]
4275 msg = xlist[1]
4276 if not isinstance(msg, basestring):
4276 if not isinstance(msg, basestring):
4277 msg = msg(abs)
4277 msg = msg(abs)
4278 ui.status(msg % rel)
4278 ui.status(msg % rel)
4279 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4279 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4280 if abs not in table:
4280 if abs not in table:
4281 continue
4281 continue
4282 # file has changed in dirstate
4282 # file has changed in dirstate
4283 if mfentry:
4283 if mfentry:
4284 handle(hitlist, backuphit)
4284 handle(hitlist, backuphit)
4285 elif misslist is not None:
4285 elif misslist is not None:
4286 handle(misslist, backupmiss)
4286 handle(misslist, backupmiss)
4287 break
4287 break
4288 else:
4288 else:
4289 if abs not in repo.dirstate:
4289 if abs not in repo.dirstate:
4290 if mfentry:
4290 if mfentry:
4291 handle(add, True)
4291 handle(add, True)
4292 elif exact:
4292 elif exact:
4293 ui.warn(_('file not managed: %s\n') % rel)
4293 ui.warn(_('file not managed: %s\n') % rel)
4294 continue
4294 continue
4295 # file has not changed in dirstate
4295 # file has not changed in dirstate
4296 if node == parent:
4296 if node == parent:
4297 if exact:
4297 if exact:
4298 ui.warn(_('no changes needed to %s\n') % rel)
4298 ui.warn(_('no changes needed to %s\n') % rel)
4299 continue
4299 continue
4300 if pmf is None:
4300 if pmf is None:
4301 # only need parent manifest in this unlikely case,
4301 # only need parent manifest in this unlikely case,
4302 # so do not read by default
4302 # so do not read by default
4303 pmf = repo[parent].manifest()
4303 pmf = repo[parent].manifest()
4304 if abs in pmf:
4304 if abs in pmf:
4305 if mfentry:
4305 if mfentry:
4306 # if version of file is same in parent and target
4306 # if version of file is same in parent and target
4307 # manifests, do nothing
4307 # manifests, do nothing
4308 if (pmf[abs] != mfentry or
4308 if (pmf[abs] != mfentry or
4309 pmf.flags(abs) != mf.flags(abs)):
4309 pmf.flags(abs) != mf.flags(abs)):
4310 handle(revert, False)
4310 handle(revert, False)
4311 else:
4311 else:
4312 handle(remove, False)
4312 handle(remove, False)
4313
4313
4314 if not opts.get('dry_run'):
4314 if not opts.get('dry_run'):
4315 def checkout(f):
4315 def checkout(f):
4316 fc = ctx[f]
4316 fc = ctx[f]
4317 repo.wwrite(f, fc.data(), fc.flags())
4317 repo.wwrite(f, fc.data(), fc.flags())
4318
4318
4319 audit_path = scmutil.pathauditor(repo.root)
4319 audit_path = scmutil.pathauditor(repo.root)
4320 for f in remove[0]:
4320 for f in remove[0]:
4321 if repo.dirstate[f] == 'a':
4321 if repo.dirstate[f] == 'a':
4322 repo.dirstate.drop(f)
4322 repo.dirstate.drop(f)
4323 continue
4323 continue
4324 audit_path(f)
4324 audit_path(f)
4325 try:
4325 try:
4326 util.unlinkpath(repo.wjoin(f))
4326 util.unlinkpath(repo.wjoin(f))
4327 except OSError:
4327 except OSError:
4328 pass
4328 pass
4329 repo.dirstate.remove(f)
4329 repo.dirstate.remove(f)
4330
4330
4331 normal = None
4331 normal = None
4332 if node == parent:
4332 if node == parent:
4333 # We're reverting to our parent. If possible, we'd like status
4333 # We're reverting to our parent. If possible, we'd like status
4334 # to report the file as clean. We have to use normallookup for
4334 # to report the file as clean. We have to use normallookup for
4335 # merges to avoid losing information about merged/dirty files.
4335 # merges to avoid losing information about merged/dirty files.
4336 if p2 != nullid:
4336 if p2 != nullid:
4337 normal = repo.dirstate.normallookup
4337 normal = repo.dirstate.normallookup
4338 else:
4338 else:
4339 normal = repo.dirstate.normal
4339 normal = repo.dirstate.normal
4340 for f in revert[0]:
4340 for f in revert[0]:
4341 checkout(f)
4341 checkout(f)
4342 if normal:
4342 if normal:
4343 normal(f)
4343 normal(f)
4344
4344
4345 for f in add[0]:
4345 for f in add[0]:
4346 checkout(f)
4346 checkout(f)
4347 repo.dirstate.add(f)
4347 repo.dirstate.add(f)
4348
4348
4349 normal = repo.dirstate.normallookup
4349 normal = repo.dirstate.normallookup
4350 if node == parent and p2 == nullid:
4350 if node == parent and p2 == nullid:
4351 normal = repo.dirstate.normal
4351 normal = repo.dirstate.normal
4352 for f in undelete[0]:
4352 for f in undelete[0]:
4353 checkout(f)
4353 checkout(f)
4354 normal(f)
4354 normal(f)
4355
4355
4356 finally:
4356 finally:
4357 wlock.release()
4357 wlock.release()
4358
4358
4359 @command('rollback', dryrunopts)
4359 @command('rollback', dryrunopts)
4360 def rollback(ui, repo, **opts):
4360 def rollback(ui, repo, **opts):
4361 """roll back the last transaction (dangerous)
4361 """roll back the last transaction (dangerous)
4362
4362
4363 This command should be used with care. There is only one level of
4363 This command should be used with care. There is only one level of
4364 rollback, and there is no way to undo a rollback. It will also
4364 rollback, and there is no way to undo a rollback. It will also
4365 restore the dirstate at the time of the last transaction, losing
4365 restore the dirstate at the time of the last transaction, losing
4366 any dirstate changes since that time. This command does not alter
4366 any dirstate changes since that time. This command does not alter
4367 the working directory.
4367 the working directory.
4368
4368
4369 Transactions are used to encapsulate the effects of all commands
4369 Transactions are used to encapsulate the effects of all commands
4370 that create new changesets or propagate existing changesets into a
4370 that create new changesets or propagate existing changesets into a
4371 repository. For example, the following commands are transactional,
4371 repository. For example, the following commands are transactional,
4372 and their effects can be rolled back:
4372 and their effects can be rolled back:
4373
4373
4374 - commit
4374 - commit
4375 - import
4375 - import
4376 - pull
4376 - pull
4377 - push (with this repository as the destination)
4377 - push (with this repository as the destination)
4378 - unbundle
4378 - unbundle
4379
4379
4380 This command is not intended for use on public repositories. Once
4380 This command is not intended for use on public repositories. Once
4381 changes are visible for pull by other users, rolling a transaction
4381 changes are visible for pull by other users, rolling a transaction
4382 back locally is ineffective (someone else may already have pulled
4382 back locally is ineffective (someone else may already have pulled
4383 the changes). Furthermore, a race is possible with readers of the
4383 the changes). Furthermore, a race is possible with readers of the
4384 repository; for example an in-progress pull from the repository
4384 repository; for example an in-progress pull from the repository
4385 may fail if a rollback is performed.
4385 may fail if a rollback is performed.
4386
4386
4387 Returns 0 on success, 1 if no rollback data is available.
4387 Returns 0 on success, 1 if no rollback data is available.
4388 """
4388 """
4389 return repo.rollback(opts.get('dry_run'))
4389 return repo.rollback(opts.get('dry_run'))
4390
4390
4391 @command('root', [])
4391 @command('root', [])
4392 def root(ui, repo):
4392 def root(ui, repo):
4393 """print the root (top) of the current working directory
4393 """print the root (top) of the current working directory
4394
4394
4395 Print the root directory of the current repository.
4395 Print the root directory of the current repository.
4396
4396
4397 Returns 0 on success.
4397 Returns 0 on success.
4398 """
4398 """
4399 ui.write(repo.root + "\n")
4399 ui.write(repo.root + "\n")
4400
4400
4401 @command('^serve',
4401 @command('^serve',
4402 [('A', 'accesslog', '', _('name of access log file to write to'),
4402 [('A', 'accesslog', '', _('name of access log file to write to'),
4403 _('FILE')),
4403 _('FILE')),
4404 ('d', 'daemon', None, _('run server in background')),
4404 ('d', 'daemon', None, _('run server in background')),
4405 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4405 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4406 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4406 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4407 # use string type, then we can check if something was passed
4407 # use string type, then we can check if something was passed
4408 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4408 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4409 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4409 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4410 _('ADDR')),
4410 _('ADDR')),
4411 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4411 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4412 _('PREFIX')),
4412 _('PREFIX')),
4413 ('n', 'name', '',
4413 ('n', 'name', '',
4414 _('name to show in web pages (default: working directory)'), _('NAME')),
4414 _('name to show in web pages (default: working directory)'), _('NAME')),
4415 ('', 'web-conf', '',
4415 ('', 'web-conf', '',
4416 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4416 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4417 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4417 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4418 _('FILE')),
4418 _('FILE')),
4419 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4419 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4420 ('', 'stdio', None, _('for remote clients')),
4420 ('', 'stdio', None, _('for remote clients')),
4421 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4421 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4422 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4422 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4423 ('', 'style', '', _('template style to use'), _('STYLE')),
4423 ('', 'style', '', _('template style to use'), _('STYLE')),
4424 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4424 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4425 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4425 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4426 _('[OPTION]...'))
4426 _('[OPTION]...'))
4427 def serve(ui, repo, **opts):
4427 def serve(ui, repo, **opts):
4428 """start stand-alone webserver
4428 """start stand-alone webserver
4429
4429
4430 Start a local HTTP repository browser and pull server. You can use
4430 Start a local HTTP repository browser and pull server. You can use
4431 this for ad-hoc sharing and browsing of repositories. It is
4431 this for ad-hoc sharing and browsing of repositories. It is
4432 recommended to use a real web server to serve a repository for
4432 recommended to use a real web server to serve a repository for
4433 longer periods of time.
4433 longer periods of time.
4434
4434
4435 Please note that the server does not implement access control.
4435 Please note that the server does not implement access control.
4436 This means that, by default, anybody can read from the server and
4436 This means that, by default, anybody can read from the server and
4437 nobody can write to it by default. Set the ``web.allow_push``
4437 nobody can write to it by default. Set the ``web.allow_push``
4438 option to ``*`` to allow everybody to push to the server. You
4438 option to ``*`` to allow everybody to push to the server. You
4439 should use a real web server if you need to authenticate users.
4439 should use a real web server if you need to authenticate users.
4440
4440
4441 By default, the server logs accesses to stdout and errors to
4441 By default, the server logs accesses to stdout and errors to
4442 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4442 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4443 files.
4443 files.
4444
4444
4445 To have the server choose a free port number to listen on, specify
4445 To have the server choose a free port number to listen on, specify
4446 a port number of 0; in this case, the server will print the port
4446 a port number of 0; in this case, the server will print the port
4447 number it uses.
4447 number it uses.
4448
4448
4449 Returns 0 on success.
4449 Returns 0 on success.
4450 """
4450 """
4451
4451
4452 if opts["stdio"] and opts["cmdserver"]:
4452 if opts["stdio"] and opts["cmdserver"]:
4453 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4453 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4454
4454
4455 def checkrepo():
4455 def checkrepo():
4456 if repo is None:
4456 if repo is None:
4457 raise error.RepoError(_("There is no Mercurial repository here"
4457 raise error.RepoError(_("There is no Mercurial repository here"
4458 " (.hg not found)"))
4458 " (.hg not found)"))
4459
4459
4460 if opts["stdio"]:
4460 if opts["stdio"]:
4461 checkrepo()
4461 checkrepo()
4462 s = sshserver.sshserver(ui, repo)
4462 s = sshserver.sshserver(ui, repo)
4463 s.serve_forever()
4463 s.serve_forever()
4464
4464
4465 if opts["cmdserver"]:
4465 if opts["cmdserver"]:
4466 checkrepo()
4466 checkrepo()
4467 s = commandserver.server(ui, repo, opts["cmdserver"])
4467 s = commandserver.server(ui, repo, opts["cmdserver"])
4468 return s.serve()
4468 return s.serve()
4469
4469
4470 # this way we can check if something was given in the command-line
4470 # this way we can check if something was given in the command-line
4471 if opts.get('port'):
4471 if opts.get('port'):
4472 opts['port'] = util.getport(opts.get('port'))
4472 opts['port'] = util.getport(opts.get('port'))
4473
4473
4474 baseui = repo and repo.baseui or ui
4474 baseui = repo and repo.baseui or ui
4475 optlist = ("name templates style address port prefix ipv6"
4475 optlist = ("name templates style address port prefix ipv6"
4476 " accesslog errorlog certificate encoding")
4476 " accesslog errorlog certificate encoding")
4477 for o in optlist.split():
4477 for o in optlist.split():
4478 val = opts.get(o, '')
4478 val = opts.get(o, '')
4479 if val in (None, ''): # should check against default options instead
4479 if val in (None, ''): # should check against default options instead
4480 continue
4480 continue
4481 baseui.setconfig("web", o, val)
4481 baseui.setconfig("web", o, val)
4482 if repo and repo.ui != baseui:
4482 if repo and repo.ui != baseui:
4483 repo.ui.setconfig("web", o, val)
4483 repo.ui.setconfig("web", o, val)
4484
4484
4485 o = opts.get('web_conf') or opts.get('webdir_conf')
4485 o = opts.get('web_conf') or opts.get('webdir_conf')
4486 if not o:
4486 if not o:
4487 if not repo:
4487 if not repo:
4488 raise error.RepoError(_("There is no Mercurial repository"
4488 raise error.RepoError(_("There is no Mercurial repository"
4489 " here (.hg not found)"))
4489 " here (.hg not found)"))
4490 o = repo.root
4490 o = repo.root
4491
4491
4492 app = hgweb.hgweb(o, baseui=ui)
4492 app = hgweb.hgweb(o, baseui=ui)
4493
4493
4494 class service(object):
4494 class service(object):
4495 def init(self):
4495 def init(self):
4496 util.setsignalhandler()
4496 util.setsignalhandler()
4497 self.httpd = hgweb.server.create_server(ui, app)
4497 self.httpd = hgweb.server.create_server(ui, app)
4498
4498
4499 if opts['port'] and not ui.verbose:
4499 if opts['port'] and not ui.verbose:
4500 return
4500 return
4501
4501
4502 if self.httpd.prefix:
4502 if self.httpd.prefix:
4503 prefix = self.httpd.prefix.strip('/') + '/'
4503 prefix = self.httpd.prefix.strip('/') + '/'
4504 else:
4504 else:
4505 prefix = ''
4505 prefix = ''
4506
4506
4507 port = ':%d' % self.httpd.port
4507 port = ':%d' % self.httpd.port
4508 if port == ':80':
4508 if port == ':80':
4509 port = ''
4509 port = ''
4510
4510
4511 bindaddr = self.httpd.addr
4511 bindaddr = self.httpd.addr
4512 if bindaddr == '0.0.0.0':
4512 if bindaddr == '0.0.0.0':
4513 bindaddr = '*'
4513 bindaddr = '*'
4514 elif ':' in bindaddr: # IPv6
4514 elif ':' in bindaddr: # IPv6
4515 bindaddr = '[%s]' % bindaddr
4515 bindaddr = '[%s]' % bindaddr
4516
4516
4517 fqaddr = self.httpd.fqaddr
4517 fqaddr = self.httpd.fqaddr
4518 if ':' in fqaddr:
4518 if ':' in fqaddr:
4519 fqaddr = '[%s]' % fqaddr
4519 fqaddr = '[%s]' % fqaddr
4520 if opts['port']:
4520 if opts['port']:
4521 write = ui.status
4521 write = ui.status
4522 else:
4522 else:
4523 write = ui.write
4523 write = ui.write
4524 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4524 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4525 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4525 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4526
4526
4527 def run(self):
4527 def run(self):
4528 self.httpd.serve_forever()
4528 self.httpd.serve_forever()
4529
4529
4530 service = service()
4530 service = service()
4531
4531
4532 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4532 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4533
4533
4534 @command('showconfig|debugconfig',
4534 @command('showconfig|debugconfig',
4535 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4535 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4536 _('[-u] [NAME]...'))
4536 _('[-u] [NAME]...'))
4537 def showconfig(ui, repo, *values, **opts):
4537 def showconfig(ui, repo, *values, **opts):
4538 """show combined config settings from all hgrc files
4538 """show combined config settings from all hgrc files
4539
4539
4540 With no arguments, print names and values of all config items.
4540 With no arguments, print names and values of all config items.
4541
4541
4542 With one argument of the form section.name, print just the value
4542 With one argument of the form section.name, print just the value
4543 of that config item.
4543 of that config item.
4544
4544
4545 With multiple arguments, print names and values of all config
4545 With multiple arguments, print names and values of all config
4546 items with matching section names.
4546 items with matching section names.
4547
4547
4548 With --debug, the source (filename and line number) is printed
4548 With --debug, the source (filename and line number) is printed
4549 for each config item.
4549 for each config item.
4550
4550
4551 Returns 0 on success.
4551 Returns 0 on success.
4552 """
4552 """
4553
4553
4554 for f in scmutil.rcpath():
4554 for f in scmutil.rcpath():
4555 ui.debug(_('read config from: %s\n') % f)
4555 ui.debug('read config from: %s\n' % f)
4556 untrusted = bool(opts.get('untrusted'))
4556 untrusted = bool(opts.get('untrusted'))
4557 if values:
4557 if values:
4558 sections = [v for v in values if '.' not in v]
4558 sections = [v for v in values if '.' not in v]
4559 items = [v for v in values if '.' in v]
4559 items = [v for v in values if '.' in v]
4560 if len(items) > 1 or items and sections:
4560 if len(items) > 1 or items and sections:
4561 raise util.Abort(_('only one config item permitted'))
4561 raise util.Abort(_('only one config item permitted'))
4562 for section, name, value in ui.walkconfig(untrusted=untrusted):
4562 for section, name, value in ui.walkconfig(untrusted=untrusted):
4563 value = str(value).replace('\n', '\\n')
4563 value = str(value).replace('\n', '\\n')
4564 sectname = section + '.' + name
4564 sectname = section + '.' + name
4565 if values:
4565 if values:
4566 for v in values:
4566 for v in values:
4567 if v == section:
4567 if v == section:
4568 ui.debug('%s: ' %
4568 ui.debug('%s: ' %
4569 ui.configsource(section, name, untrusted))
4569 ui.configsource(section, name, untrusted))
4570 ui.write('%s=%s\n' % (sectname, value))
4570 ui.write('%s=%s\n' % (sectname, value))
4571 elif v == sectname:
4571 elif v == sectname:
4572 ui.debug('%s: ' %
4572 ui.debug('%s: ' %
4573 ui.configsource(section, name, untrusted))
4573 ui.configsource(section, name, untrusted))
4574 ui.write(value, '\n')
4574 ui.write(value, '\n')
4575 else:
4575 else:
4576 ui.debug('%s: ' %
4576 ui.debug('%s: ' %
4577 ui.configsource(section, name, untrusted))
4577 ui.configsource(section, name, untrusted))
4578 ui.write('%s=%s\n' % (sectname, value))
4578 ui.write('%s=%s\n' % (sectname, value))
4579
4579
4580 @command('^status|st',
4580 @command('^status|st',
4581 [('A', 'all', None, _('show status of all files')),
4581 [('A', 'all', None, _('show status of all files')),
4582 ('m', 'modified', None, _('show only modified files')),
4582 ('m', 'modified', None, _('show only modified files')),
4583 ('a', 'added', None, _('show only added files')),
4583 ('a', 'added', None, _('show only added files')),
4584 ('r', 'removed', None, _('show only removed files')),
4584 ('r', 'removed', None, _('show only removed files')),
4585 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4585 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4586 ('c', 'clean', None, _('show only files without changes')),
4586 ('c', 'clean', None, _('show only files without changes')),
4587 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4587 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4588 ('i', 'ignored', None, _('show only ignored files')),
4588 ('i', 'ignored', None, _('show only ignored files')),
4589 ('n', 'no-status', None, _('hide status prefix')),
4589 ('n', 'no-status', None, _('hide status prefix')),
4590 ('C', 'copies', None, _('show source of copied files')),
4590 ('C', 'copies', None, _('show source of copied files')),
4591 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4591 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4592 ('', 'rev', [], _('show difference from revision'), _('REV')),
4592 ('', 'rev', [], _('show difference from revision'), _('REV')),
4593 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4593 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4594 ] + walkopts + subrepoopts,
4594 ] + walkopts + subrepoopts,
4595 _('[OPTION]... [FILE]...'))
4595 _('[OPTION]... [FILE]...'))
4596 def status(ui, repo, *pats, **opts):
4596 def status(ui, repo, *pats, **opts):
4597 """show changed files in the working directory
4597 """show changed files in the working directory
4598
4598
4599 Show status of files in the repository. If names are given, only
4599 Show status of files in the repository. If names are given, only
4600 files that match are shown. Files that are clean or ignored or
4600 files that match are shown. Files that are clean or ignored or
4601 the source of a copy/move operation, are not listed unless
4601 the source of a copy/move operation, are not listed unless
4602 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4602 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4603 Unless options described with "show only ..." are given, the
4603 Unless options described with "show only ..." are given, the
4604 options -mardu are used.
4604 options -mardu are used.
4605
4605
4606 Option -q/--quiet hides untracked (unknown and ignored) files
4606 Option -q/--quiet hides untracked (unknown and ignored) files
4607 unless explicitly requested with -u/--unknown or -i/--ignored.
4607 unless explicitly requested with -u/--unknown or -i/--ignored.
4608
4608
4609 .. note::
4609 .. note::
4610 status may appear to disagree with diff if permissions have
4610 status may appear to disagree with diff if permissions have
4611 changed or a merge has occurred. The standard diff format does
4611 changed or a merge has occurred. The standard diff format does
4612 not report permission changes and diff only reports changes
4612 not report permission changes and diff only reports changes
4613 relative to one merge parent.
4613 relative to one merge parent.
4614
4614
4615 If one revision is given, it is used as the base revision.
4615 If one revision is given, it is used as the base revision.
4616 If two revisions are given, the differences between them are
4616 If two revisions are given, the differences between them are
4617 shown. The --change option can also be used as a shortcut to list
4617 shown. The --change option can also be used as a shortcut to list
4618 the changed files of a revision from its first parent.
4618 the changed files of a revision from its first parent.
4619
4619
4620 The codes used to show the status of files are::
4620 The codes used to show the status of files are::
4621
4621
4622 M = modified
4622 M = modified
4623 A = added
4623 A = added
4624 R = removed
4624 R = removed
4625 C = clean
4625 C = clean
4626 ! = missing (deleted by non-hg command, but still tracked)
4626 ! = missing (deleted by non-hg command, but still tracked)
4627 ? = not tracked
4627 ? = not tracked
4628 I = ignored
4628 I = ignored
4629 = origin of the previous file listed as A (added)
4629 = origin of the previous file listed as A (added)
4630
4630
4631 Returns 0 on success.
4631 Returns 0 on success.
4632 """
4632 """
4633
4633
4634 revs = opts.get('rev')
4634 revs = opts.get('rev')
4635 change = opts.get('change')
4635 change = opts.get('change')
4636
4636
4637 if revs and change:
4637 if revs and change:
4638 msg = _('cannot specify --rev and --change at the same time')
4638 msg = _('cannot specify --rev and --change at the same time')
4639 raise util.Abort(msg)
4639 raise util.Abort(msg)
4640 elif change:
4640 elif change:
4641 node2 = repo.lookup(change)
4641 node2 = repo.lookup(change)
4642 node1 = repo[node2].p1().node()
4642 node1 = repo[node2].p1().node()
4643 else:
4643 else:
4644 node1, node2 = scmutil.revpair(repo, revs)
4644 node1, node2 = scmutil.revpair(repo, revs)
4645
4645
4646 cwd = (pats and repo.getcwd()) or ''
4646 cwd = (pats and repo.getcwd()) or ''
4647 end = opts.get('print0') and '\0' or '\n'
4647 end = opts.get('print0') and '\0' or '\n'
4648 copy = {}
4648 copy = {}
4649 states = 'modified added removed deleted unknown ignored clean'.split()
4649 states = 'modified added removed deleted unknown ignored clean'.split()
4650 show = [k for k in states if opts.get(k)]
4650 show = [k for k in states if opts.get(k)]
4651 if opts.get('all'):
4651 if opts.get('all'):
4652 show += ui.quiet and (states[:4] + ['clean']) or states
4652 show += ui.quiet and (states[:4] + ['clean']) or states
4653 if not show:
4653 if not show:
4654 show = ui.quiet and states[:4] or states[:5]
4654 show = ui.quiet and states[:4] or states[:5]
4655
4655
4656 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
4656 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
4657 'ignored' in show, 'clean' in show, 'unknown' in show,
4657 'ignored' in show, 'clean' in show, 'unknown' in show,
4658 opts.get('subrepos'))
4658 opts.get('subrepos'))
4659 changestates = zip(states, 'MAR!?IC', stat)
4659 changestates = zip(states, 'MAR!?IC', stat)
4660
4660
4661 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4661 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4662 ctxn = repo[nullid]
4662 ctxn = repo[nullid]
4663 ctx1 = repo[node1]
4663 ctx1 = repo[node1]
4664 ctx2 = repo[node2]
4664 ctx2 = repo[node2]
4665 added = stat[1]
4665 added = stat[1]
4666 if node2 is None:
4666 if node2 is None:
4667 added = stat[0] + stat[1] # merged?
4667 added = stat[0] + stat[1] # merged?
4668
4668
4669 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4669 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4670 if k in added:
4670 if k in added:
4671 copy[k] = v
4671 copy[k] = v
4672 elif v in added:
4672 elif v in added:
4673 copy[v] = k
4673 copy[v] = k
4674
4674
4675 for state, char, files in changestates:
4675 for state, char, files in changestates:
4676 if state in show:
4676 if state in show:
4677 format = "%s %%s%s" % (char, end)
4677 format = "%s %%s%s" % (char, end)
4678 if opts.get('no_status'):
4678 if opts.get('no_status'):
4679 format = "%%s%s" % end
4679 format = "%%s%s" % end
4680
4680
4681 for f in files:
4681 for f in files:
4682 ui.write(format % repo.pathto(f, cwd),
4682 ui.write(format % repo.pathto(f, cwd),
4683 label='status.' + state)
4683 label='status.' + state)
4684 if f in copy:
4684 if f in copy:
4685 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4685 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4686 label='status.copied')
4686 label='status.copied')
4687
4687
4688 @command('^summary|sum',
4688 @command('^summary|sum',
4689 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4689 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4690 def summary(ui, repo, **opts):
4690 def summary(ui, repo, **opts):
4691 """summarize working directory state
4691 """summarize working directory state
4692
4692
4693 This generates a brief summary of the working directory state,
4693 This generates a brief summary of the working directory state,
4694 including parents, branch, commit status, and available updates.
4694 including parents, branch, commit status, and available updates.
4695
4695
4696 With the --remote option, this will check the default paths for
4696 With the --remote option, this will check the default paths for
4697 incoming and outgoing changes. This can be time-consuming.
4697 incoming and outgoing changes. This can be time-consuming.
4698
4698
4699 Returns 0 on success.
4699 Returns 0 on success.
4700 """
4700 """
4701
4701
4702 ctx = repo[None]
4702 ctx = repo[None]
4703 parents = ctx.parents()
4703 parents = ctx.parents()
4704 pnode = parents[0].node()
4704 pnode = parents[0].node()
4705
4705
4706 for p in parents:
4706 for p in parents:
4707 # label with log.changeset (instead of log.parent) since this
4707 # label with log.changeset (instead of log.parent) since this
4708 # shows a working directory parent *changeset*:
4708 # shows a working directory parent *changeset*:
4709 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4709 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4710 label='log.changeset')
4710 label='log.changeset')
4711 ui.write(' '.join(p.tags()), label='log.tag')
4711 ui.write(' '.join(p.tags()), label='log.tag')
4712 if p.bookmarks():
4712 if p.bookmarks():
4713 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
4713 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
4714 if p.rev() == -1:
4714 if p.rev() == -1:
4715 if not len(repo):
4715 if not len(repo):
4716 ui.write(_(' (empty repository)'))
4716 ui.write(_(' (empty repository)'))
4717 else:
4717 else:
4718 ui.write(_(' (no revision checked out)'))
4718 ui.write(_(' (no revision checked out)'))
4719 ui.write('\n')
4719 ui.write('\n')
4720 if p.description():
4720 if p.description():
4721 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4721 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4722 label='log.summary')
4722 label='log.summary')
4723
4723
4724 branch = ctx.branch()
4724 branch = ctx.branch()
4725 bheads = repo.branchheads(branch)
4725 bheads = repo.branchheads(branch)
4726 m = _('branch: %s\n') % branch
4726 m = _('branch: %s\n') % branch
4727 if branch != 'default':
4727 if branch != 'default':
4728 ui.write(m, label='log.branch')
4728 ui.write(m, label='log.branch')
4729 else:
4729 else:
4730 ui.status(m, label='log.branch')
4730 ui.status(m, label='log.branch')
4731
4731
4732 st = list(repo.status(unknown=True))[:6]
4732 st = list(repo.status(unknown=True))[:6]
4733
4733
4734 c = repo.dirstate.copies()
4734 c = repo.dirstate.copies()
4735 copied, renamed = [], []
4735 copied, renamed = [], []
4736 for d, s in c.iteritems():
4736 for d, s in c.iteritems():
4737 if s in st[2]:
4737 if s in st[2]:
4738 st[2].remove(s)
4738 st[2].remove(s)
4739 renamed.append(d)
4739 renamed.append(d)
4740 else:
4740 else:
4741 copied.append(d)
4741 copied.append(d)
4742 if d in st[1]:
4742 if d in st[1]:
4743 st[1].remove(d)
4743 st[1].remove(d)
4744 st.insert(3, renamed)
4744 st.insert(3, renamed)
4745 st.insert(4, copied)
4745 st.insert(4, copied)
4746
4746
4747 ms = mergemod.mergestate(repo)
4747 ms = mergemod.mergestate(repo)
4748 st.append([f for f in ms if ms[f] == 'u'])
4748 st.append([f for f in ms if ms[f] == 'u'])
4749
4749
4750 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4750 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4751 st.append(subs)
4751 st.append(subs)
4752
4752
4753 labels = [ui.label(_('%d modified'), 'status.modified'),
4753 labels = [ui.label(_('%d modified'), 'status.modified'),
4754 ui.label(_('%d added'), 'status.added'),
4754 ui.label(_('%d added'), 'status.added'),
4755 ui.label(_('%d removed'), 'status.removed'),
4755 ui.label(_('%d removed'), 'status.removed'),
4756 ui.label(_('%d renamed'), 'status.copied'),
4756 ui.label(_('%d renamed'), 'status.copied'),
4757 ui.label(_('%d copied'), 'status.copied'),
4757 ui.label(_('%d copied'), 'status.copied'),
4758 ui.label(_('%d deleted'), 'status.deleted'),
4758 ui.label(_('%d deleted'), 'status.deleted'),
4759 ui.label(_('%d unknown'), 'status.unknown'),
4759 ui.label(_('%d unknown'), 'status.unknown'),
4760 ui.label(_('%d ignored'), 'status.ignored'),
4760 ui.label(_('%d ignored'), 'status.ignored'),
4761 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4761 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4762 ui.label(_('%d subrepos'), 'status.modified')]
4762 ui.label(_('%d subrepos'), 'status.modified')]
4763 t = []
4763 t = []
4764 for s, l in zip(st, labels):
4764 for s, l in zip(st, labels):
4765 if s:
4765 if s:
4766 t.append(l % len(s))
4766 t.append(l % len(s))
4767
4767
4768 t = ', '.join(t)
4768 t = ', '.join(t)
4769 cleanworkdir = False
4769 cleanworkdir = False
4770
4770
4771 if len(parents) > 1:
4771 if len(parents) > 1:
4772 t += _(' (merge)')
4772 t += _(' (merge)')
4773 elif branch != parents[0].branch():
4773 elif branch != parents[0].branch():
4774 t += _(' (new branch)')
4774 t += _(' (new branch)')
4775 elif (parents[0].extra().get('close') and
4775 elif (parents[0].extra().get('close') and
4776 pnode in repo.branchheads(branch, closed=True)):
4776 pnode in repo.branchheads(branch, closed=True)):
4777 t += _(' (head closed)')
4777 t += _(' (head closed)')
4778 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4778 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4779 t += _(' (clean)')
4779 t += _(' (clean)')
4780 cleanworkdir = True
4780 cleanworkdir = True
4781 elif pnode not in bheads:
4781 elif pnode not in bheads:
4782 t += _(' (new branch head)')
4782 t += _(' (new branch head)')
4783
4783
4784 if cleanworkdir:
4784 if cleanworkdir:
4785 ui.status(_('commit: %s\n') % t.strip())
4785 ui.status(_('commit: %s\n') % t.strip())
4786 else:
4786 else:
4787 ui.write(_('commit: %s\n') % t.strip())
4787 ui.write(_('commit: %s\n') % t.strip())
4788
4788
4789 # all ancestors of branch heads - all ancestors of parent = new csets
4789 # all ancestors of branch heads - all ancestors of parent = new csets
4790 new = [0] * len(repo)
4790 new = [0] * len(repo)
4791 cl = repo.changelog
4791 cl = repo.changelog
4792 for a in [cl.rev(n) for n in bheads]:
4792 for a in [cl.rev(n) for n in bheads]:
4793 new[a] = 1
4793 new[a] = 1
4794 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
4794 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
4795 new[a] = 1
4795 new[a] = 1
4796 for a in [p.rev() for p in parents]:
4796 for a in [p.rev() for p in parents]:
4797 if a >= 0:
4797 if a >= 0:
4798 new[a] = 0
4798 new[a] = 0
4799 for a in cl.ancestors(*[p.rev() for p in parents]):
4799 for a in cl.ancestors(*[p.rev() for p in parents]):
4800 new[a] = 0
4800 new[a] = 0
4801 new = sum(new)
4801 new = sum(new)
4802
4802
4803 if new == 0:
4803 if new == 0:
4804 ui.status(_('update: (current)\n'))
4804 ui.status(_('update: (current)\n'))
4805 elif pnode not in bheads:
4805 elif pnode not in bheads:
4806 ui.write(_('update: %d new changesets (update)\n') % new)
4806 ui.write(_('update: %d new changesets (update)\n') % new)
4807 else:
4807 else:
4808 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4808 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4809 (new, len(bheads)))
4809 (new, len(bheads)))
4810
4810
4811 if opts.get('remote'):
4811 if opts.get('remote'):
4812 t = []
4812 t = []
4813 source, branches = hg.parseurl(ui.expandpath('default'))
4813 source, branches = hg.parseurl(ui.expandpath('default'))
4814 other = hg.peer(repo, {}, source)
4814 other = hg.peer(repo, {}, source)
4815 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4815 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4816 ui.debug('comparing with %s\n' % util.hidepassword(source))
4816 ui.debug('comparing with %s\n' % util.hidepassword(source))
4817 repo.ui.pushbuffer()
4817 repo.ui.pushbuffer()
4818 commoninc = discovery.findcommonincoming(repo, other)
4818 commoninc = discovery.findcommonincoming(repo, other)
4819 _common, incoming, _rheads = commoninc
4819 _common, incoming, _rheads = commoninc
4820 repo.ui.popbuffer()
4820 repo.ui.popbuffer()
4821 if incoming:
4821 if incoming:
4822 t.append(_('1 or more incoming'))
4822 t.append(_('1 or more incoming'))
4823
4823
4824 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4824 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4825 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4825 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4826 if source != dest:
4826 if source != dest:
4827 other = hg.peer(repo, {}, dest)
4827 other = hg.peer(repo, {}, dest)
4828 commoninc = None
4828 commoninc = None
4829 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4829 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4830 repo.ui.pushbuffer()
4830 repo.ui.pushbuffer()
4831 common, outheads = discovery.findcommonoutgoing(repo, other,
4831 common, outheads = discovery.findcommonoutgoing(repo, other,
4832 commoninc=commoninc)
4832 commoninc=commoninc)
4833 repo.ui.popbuffer()
4833 repo.ui.popbuffer()
4834 o = repo.changelog.findmissing(common=common, heads=outheads)
4834 o = repo.changelog.findmissing(common=common, heads=outheads)
4835 if o:
4835 if o:
4836 t.append(_('%d outgoing') % len(o))
4836 t.append(_('%d outgoing') % len(o))
4837 if 'bookmarks' in other.listkeys('namespaces'):
4837 if 'bookmarks' in other.listkeys('namespaces'):
4838 lmarks = repo.listkeys('bookmarks')
4838 lmarks = repo.listkeys('bookmarks')
4839 rmarks = other.listkeys('bookmarks')
4839 rmarks = other.listkeys('bookmarks')
4840 diff = set(rmarks) - set(lmarks)
4840 diff = set(rmarks) - set(lmarks)
4841 if len(diff) > 0:
4841 if len(diff) > 0:
4842 t.append(_('%d incoming bookmarks') % len(diff))
4842 t.append(_('%d incoming bookmarks') % len(diff))
4843 diff = set(lmarks) - set(rmarks)
4843 diff = set(lmarks) - set(rmarks)
4844 if len(diff) > 0:
4844 if len(diff) > 0:
4845 t.append(_('%d outgoing bookmarks') % len(diff))
4845 t.append(_('%d outgoing bookmarks') % len(diff))
4846
4846
4847 if t:
4847 if t:
4848 ui.write(_('remote: %s\n') % (', '.join(t)))
4848 ui.write(_('remote: %s\n') % (', '.join(t)))
4849 else:
4849 else:
4850 ui.status(_('remote: (synced)\n'))
4850 ui.status(_('remote: (synced)\n'))
4851
4851
4852 @command('tag',
4852 @command('tag',
4853 [('f', 'force', None, _('force tag')),
4853 [('f', 'force', None, _('force tag')),
4854 ('l', 'local', None, _('make the tag local')),
4854 ('l', 'local', None, _('make the tag local')),
4855 ('r', 'rev', '', _('revision to tag'), _('REV')),
4855 ('r', 'rev', '', _('revision to tag'), _('REV')),
4856 ('', 'remove', None, _('remove a tag')),
4856 ('', 'remove', None, _('remove a tag')),
4857 # -l/--local is already there, commitopts cannot be used
4857 # -l/--local is already there, commitopts cannot be used
4858 ('e', 'edit', None, _('edit commit message')),
4858 ('e', 'edit', None, _('edit commit message')),
4859 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
4859 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
4860 ] + commitopts2,
4860 ] + commitopts2,
4861 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
4861 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
4862 def tag(ui, repo, name1, *names, **opts):
4862 def tag(ui, repo, name1, *names, **opts):
4863 """add one or more tags for the current or given revision
4863 """add one or more tags for the current or given revision
4864
4864
4865 Name a particular revision using <name>.
4865 Name a particular revision using <name>.
4866
4866
4867 Tags are used to name particular revisions of the repository and are
4867 Tags are used to name particular revisions of the repository and are
4868 very useful to compare different revisions, to go back to significant
4868 very useful to compare different revisions, to go back to significant
4869 earlier versions or to mark branch points as releases, etc. Changing
4869 earlier versions or to mark branch points as releases, etc. Changing
4870 an existing tag is normally disallowed; use -f/--force to override.
4870 an existing tag is normally disallowed; use -f/--force to override.
4871
4871
4872 If no revision is given, the parent of the working directory is
4872 If no revision is given, the parent of the working directory is
4873 used, or tip if no revision is checked out.
4873 used, or tip if no revision is checked out.
4874
4874
4875 To facilitate version control, distribution, and merging of tags,
4875 To facilitate version control, distribution, and merging of tags,
4876 they are stored as a file named ".hgtags" which is managed similarly
4876 they are stored as a file named ".hgtags" which is managed similarly
4877 to other project files and can be hand-edited if necessary. This
4877 to other project files and can be hand-edited if necessary. This
4878 also means that tagging creates a new commit. The file
4878 also means that tagging creates a new commit. The file
4879 ".hg/localtags" is used for local tags (not shared among
4879 ".hg/localtags" is used for local tags (not shared among
4880 repositories).
4880 repositories).
4881
4881
4882 Tag commits are usually made at the head of a branch. If the parent
4882 Tag commits are usually made at the head of a branch. If the parent
4883 of the working directory is not a branch head, :hg:`tag` aborts; use
4883 of the working directory is not a branch head, :hg:`tag` aborts; use
4884 -f/--force to force the tag commit to be based on a non-head
4884 -f/--force to force the tag commit to be based on a non-head
4885 changeset.
4885 changeset.
4886
4886
4887 See :hg:`help dates` for a list of formats valid for -d/--date.
4887 See :hg:`help dates` for a list of formats valid for -d/--date.
4888
4888
4889 Since tag names have priority over branch names during revision
4889 Since tag names have priority over branch names during revision
4890 lookup, using an existing branch name as a tag name is discouraged.
4890 lookup, using an existing branch name as a tag name is discouraged.
4891
4891
4892 Returns 0 on success.
4892 Returns 0 on success.
4893 """
4893 """
4894
4894
4895 rev_ = "."
4895 rev_ = "."
4896 names = [t.strip() for t in (name1,) + names]
4896 names = [t.strip() for t in (name1,) + names]
4897 if len(names) != len(set(names)):
4897 if len(names) != len(set(names)):
4898 raise util.Abort(_('tag names must be unique'))
4898 raise util.Abort(_('tag names must be unique'))
4899 for n in names:
4899 for n in names:
4900 if n in ['tip', '.', 'null']:
4900 if n in ['tip', '.', 'null']:
4901 raise util.Abort(_("the name '%s' is reserved") % n)
4901 raise util.Abort(_("the name '%s' is reserved") % n)
4902 if not n:
4902 if not n:
4903 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4903 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4904 if opts.get('rev') and opts.get('remove'):
4904 if opts.get('rev') and opts.get('remove'):
4905 raise util.Abort(_("--rev and --remove are incompatible"))
4905 raise util.Abort(_("--rev and --remove are incompatible"))
4906 if opts.get('rev'):
4906 if opts.get('rev'):
4907 rev_ = opts['rev']
4907 rev_ = opts['rev']
4908 message = opts.get('message')
4908 message = opts.get('message')
4909 if opts.get('remove'):
4909 if opts.get('remove'):
4910 expectedtype = opts.get('local') and 'local' or 'global'
4910 expectedtype = opts.get('local') and 'local' or 'global'
4911 for n in names:
4911 for n in names:
4912 if not repo.tagtype(n):
4912 if not repo.tagtype(n):
4913 raise util.Abort(_("tag '%s' does not exist") % n)
4913 raise util.Abort(_("tag '%s' does not exist") % n)
4914 if repo.tagtype(n) != expectedtype:
4914 if repo.tagtype(n) != expectedtype:
4915 if expectedtype == 'global':
4915 if expectedtype == 'global':
4916 raise util.Abort(_("tag '%s' is not a global tag") % n)
4916 raise util.Abort(_("tag '%s' is not a global tag") % n)
4917 else:
4917 else:
4918 raise util.Abort(_("tag '%s' is not a local tag") % n)
4918 raise util.Abort(_("tag '%s' is not a local tag") % n)
4919 rev_ = nullid
4919 rev_ = nullid
4920 if not message:
4920 if not message:
4921 # we don't translate commit messages
4921 # we don't translate commit messages
4922 message = 'Removed tag %s' % ', '.join(names)
4922 message = 'Removed tag %s' % ', '.join(names)
4923 elif not opts.get('force'):
4923 elif not opts.get('force'):
4924 for n in names:
4924 for n in names:
4925 if n in repo.tags():
4925 if n in repo.tags():
4926 raise util.Abort(_("tag '%s' already exists "
4926 raise util.Abort(_("tag '%s' already exists "
4927 "(use -f to force)") % n)
4927 "(use -f to force)") % n)
4928 if not opts.get('local'):
4928 if not opts.get('local'):
4929 p1, p2 = repo.dirstate.parents()
4929 p1, p2 = repo.dirstate.parents()
4930 if p2 != nullid:
4930 if p2 != nullid:
4931 raise util.Abort(_('uncommitted merge'))
4931 raise util.Abort(_('uncommitted merge'))
4932 bheads = repo.branchheads()
4932 bheads = repo.branchheads()
4933 if not opts.get('force') and bheads and p1 not in bheads:
4933 if not opts.get('force') and bheads and p1 not in bheads:
4934 raise util.Abort(_('not at a branch head (use -f to force)'))
4934 raise util.Abort(_('not at a branch head (use -f to force)'))
4935 r = scmutil.revsingle(repo, rev_).node()
4935 r = scmutil.revsingle(repo, rev_).node()
4936
4936
4937 if not message:
4937 if not message:
4938 # we don't translate commit messages
4938 # we don't translate commit messages
4939 message = ('Added tag %s for changeset %s' %
4939 message = ('Added tag %s for changeset %s' %
4940 (', '.join(names), short(r)))
4940 (', '.join(names), short(r)))
4941
4941
4942 date = opts.get('date')
4942 date = opts.get('date')
4943 if date:
4943 if date:
4944 date = util.parsedate(date)
4944 date = util.parsedate(date)
4945
4945
4946 if opts.get('edit'):
4946 if opts.get('edit'):
4947 message = ui.edit(message, ui.username())
4947 message = ui.edit(message, ui.username())
4948
4948
4949 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4949 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4950
4950
4951 @command('tags', [], '')
4951 @command('tags', [], '')
4952 def tags(ui, repo):
4952 def tags(ui, repo):
4953 """list repository tags
4953 """list repository tags
4954
4954
4955 This lists both regular and local tags. When the -v/--verbose
4955 This lists both regular and local tags. When the -v/--verbose
4956 switch is used, a third column "local" is printed for local tags.
4956 switch is used, a third column "local" is printed for local tags.
4957
4957
4958 Returns 0 on success.
4958 Returns 0 on success.
4959 """
4959 """
4960
4960
4961 hexfunc = ui.debugflag and hex or short
4961 hexfunc = ui.debugflag and hex or short
4962 tagtype = ""
4962 tagtype = ""
4963
4963
4964 for t, n in reversed(repo.tagslist()):
4964 for t, n in reversed(repo.tagslist()):
4965 if ui.quiet:
4965 if ui.quiet:
4966 ui.write("%s\n" % t)
4966 ui.write("%s\n" % t)
4967 continue
4967 continue
4968
4968
4969 hn = hexfunc(n)
4969 hn = hexfunc(n)
4970 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4970 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4971 spaces = " " * (30 - encoding.colwidth(t))
4971 spaces = " " * (30 - encoding.colwidth(t))
4972
4972
4973 if ui.verbose:
4973 if ui.verbose:
4974 if repo.tagtype(t) == 'local':
4974 if repo.tagtype(t) == 'local':
4975 tagtype = " local"
4975 tagtype = " local"
4976 else:
4976 else:
4977 tagtype = ""
4977 tagtype = ""
4978 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4978 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4979
4979
4980 @command('tip',
4980 @command('tip',
4981 [('p', 'patch', None, _('show patch')),
4981 [('p', 'patch', None, _('show patch')),
4982 ('g', 'git', None, _('use git extended diff format')),
4982 ('g', 'git', None, _('use git extended diff format')),
4983 ] + templateopts,
4983 ] + templateopts,
4984 _('[-p] [-g]'))
4984 _('[-p] [-g]'))
4985 def tip(ui, repo, **opts):
4985 def tip(ui, repo, **opts):
4986 """show the tip revision
4986 """show the tip revision
4987
4987
4988 The tip revision (usually just called the tip) is the changeset
4988 The tip revision (usually just called the tip) is the changeset
4989 most recently added to the repository (and therefore the most
4989 most recently added to the repository (and therefore the most
4990 recently changed head).
4990 recently changed head).
4991
4991
4992 If you have just made a commit, that commit will be the tip. If
4992 If you have just made a commit, that commit will be the tip. If
4993 you have just pulled changes from another repository, the tip of
4993 you have just pulled changes from another repository, the tip of
4994 that repository becomes the current tip. The "tip" tag is special
4994 that repository becomes the current tip. The "tip" tag is special
4995 and cannot be renamed or assigned to a different changeset.
4995 and cannot be renamed or assigned to a different changeset.
4996
4996
4997 Returns 0 on success.
4997 Returns 0 on success.
4998 """
4998 """
4999 displayer = cmdutil.show_changeset(ui, repo, opts)
4999 displayer = cmdutil.show_changeset(ui, repo, opts)
5000 displayer.show(repo[len(repo) - 1])
5000 displayer.show(repo[len(repo) - 1])
5001 displayer.close()
5001 displayer.close()
5002
5002
5003 @command('unbundle',
5003 @command('unbundle',
5004 [('u', 'update', None,
5004 [('u', 'update', None,
5005 _('update to new branch head if changesets were unbundled'))],
5005 _('update to new branch head if changesets were unbundled'))],
5006 _('[-u] FILE...'))
5006 _('[-u] FILE...'))
5007 def unbundle(ui, repo, fname1, *fnames, **opts):
5007 def unbundle(ui, repo, fname1, *fnames, **opts):
5008 """apply one or more changegroup files
5008 """apply one or more changegroup files
5009
5009
5010 Apply one or more compressed changegroup files generated by the
5010 Apply one or more compressed changegroup files generated by the
5011 bundle command.
5011 bundle command.
5012
5012
5013 Returns 0 on success, 1 if an update has unresolved files.
5013 Returns 0 on success, 1 if an update has unresolved files.
5014 """
5014 """
5015 fnames = (fname1,) + fnames
5015 fnames = (fname1,) + fnames
5016
5016
5017 lock = repo.lock()
5017 lock = repo.lock()
5018 wc = repo['.']
5018 wc = repo['.']
5019 try:
5019 try:
5020 for fname in fnames:
5020 for fname in fnames:
5021 f = url.open(ui, fname)
5021 f = url.open(ui, fname)
5022 gen = changegroup.readbundle(f, fname)
5022 gen = changegroup.readbundle(f, fname)
5023 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5023 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5024 lock=lock)
5024 lock=lock)
5025 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5025 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5026 finally:
5026 finally:
5027 lock.release()
5027 lock.release()
5028 return postincoming(ui, repo, modheads, opts.get('update'), None)
5028 return postincoming(ui, repo, modheads, opts.get('update'), None)
5029
5029
5030 @command('^update|up|checkout|co',
5030 @command('^update|up|checkout|co',
5031 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5031 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5032 ('c', 'check', None,
5032 ('c', 'check', None,
5033 _('update across branches if no uncommitted changes')),
5033 _('update across branches if no uncommitted changes')),
5034 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5034 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5035 ('r', 'rev', '', _('revision'), _('REV'))],
5035 ('r', 'rev', '', _('revision'), _('REV'))],
5036 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5036 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5037 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5037 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5038 """update working directory (or switch revisions)
5038 """update working directory (or switch revisions)
5039
5039
5040 Update the repository's working directory to the specified
5040 Update the repository's working directory to the specified
5041 changeset. If no changeset is specified, update to the tip of the
5041 changeset. If no changeset is specified, update to the tip of the
5042 current named branch.
5042 current named branch.
5043
5043
5044 If the changeset is not a descendant of the working directory's
5044 If the changeset is not a descendant of the working directory's
5045 parent, the update is aborted. With the -c/--check option, the
5045 parent, the update is aborted. With the -c/--check option, the
5046 working directory is checked for uncommitted changes; if none are
5046 working directory is checked for uncommitted changes; if none are
5047 found, the working directory is updated to the specified
5047 found, the working directory is updated to the specified
5048 changeset.
5048 changeset.
5049
5049
5050 The following rules apply when the working directory contains
5050 The following rules apply when the working directory contains
5051 uncommitted changes:
5051 uncommitted changes:
5052
5052
5053 1. If neither -c/--check nor -C/--clean is specified, and if
5053 1. If neither -c/--check nor -C/--clean is specified, and if
5054 the requested changeset is an ancestor or descendant of
5054 the requested changeset is an ancestor or descendant of
5055 the working directory's parent, the uncommitted changes
5055 the working directory's parent, the uncommitted changes
5056 are merged into the requested changeset and the merged
5056 are merged into the requested changeset and the merged
5057 result is left uncommitted. If the requested changeset is
5057 result is left uncommitted. If the requested changeset is
5058 not an ancestor or descendant (that is, it is on another
5058 not an ancestor or descendant (that is, it is on another
5059 branch), the update is aborted and the uncommitted changes
5059 branch), the update is aborted and the uncommitted changes
5060 are preserved.
5060 are preserved.
5061
5061
5062 2. With the -c/--check option, the update is aborted and the
5062 2. With the -c/--check option, the update is aborted and the
5063 uncommitted changes are preserved.
5063 uncommitted changes are preserved.
5064
5064
5065 3. With the -C/--clean option, uncommitted changes are discarded and
5065 3. With the -C/--clean option, uncommitted changes are discarded and
5066 the working directory is updated to the requested changeset.
5066 the working directory is updated to the requested changeset.
5067
5067
5068 Use null as the changeset to remove the working directory (like
5068 Use null as the changeset to remove the working directory (like
5069 :hg:`clone -U`).
5069 :hg:`clone -U`).
5070
5070
5071 If you want to update just one file to an older changeset, use
5071 If you want to update just one file to an older changeset, use
5072 :hg:`revert`.
5072 :hg:`revert`.
5073
5073
5074 See :hg:`help dates` for a list of formats valid for -d/--date.
5074 See :hg:`help dates` for a list of formats valid for -d/--date.
5075
5075
5076 Returns 0 on success, 1 if there are unresolved files.
5076 Returns 0 on success, 1 if there are unresolved files.
5077 """
5077 """
5078 if rev and node:
5078 if rev and node:
5079 raise util.Abort(_("please specify just one revision"))
5079 raise util.Abort(_("please specify just one revision"))
5080
5080
5081 if rev is None or rev == '':
5081 if rev is None or rev == '':
5082 rev = node
5082 rev = node
5083
5083
5084 # if we defined a bookmark, we have to remember the original bookmark name
5084 # if we defined a bookmark, we have to remember the original bookmark name
5085 brev = rev
5085 brev = rev
5086 rev = scmutil.revsingle(repo, rev, rev).rev()
5086 rev = scmutil.revsingle(repo, rev, rev).rev()
5087
5087
5088 if check and clean:
5088 if check and clean:
5089 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5089 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5090
5090
5091 if check:
5091 if check:
5092 # we could use dirty() but we can ignore merge and branch trivia
5092 # we could use dirty() but we can ignore merge and branch trivia
5093 c = repo[None]
5093 c = repo[None]
5094 if c.modified() or c.added() or c.removed():
5094 if c.modified() or c.added() or c.removed():
5095 raise util.Abort(_("uncommitted local changes"))
5095 raise util.Abort(_("uncommitted local changes"))
5096
5096
5097 if date:
5097 if date:
5098 if rev is not None:
5098 if rev is not None:
5099 raise util.Abort(_("you can't specify a revision and a date"))
5099 raise util.Abort(_("you can't specify a revision and a date"))
5100 rev = cmdutil.finddate(ui, repo, date)
5100 rev = cmdutil.finddate(ui, repo, date)
5101
5101
5102 if clean or check:
5102 if clean or check:
5103 ret = hg.clean(repo, rev)
5103 ret = hg.clean(repo, rev)
5104 else:
5104 else:
5105 ret = hg.update(repo, rev)
5105 ret = hg.update(repo, rev)
5106
5106
5107 if brev in repo._bookmarks:
5107 if brev in repo._bookmarks:
5108 bookmarks.setcurrent(repo, brev)
5108 bookmarks.setcurrent(repo, brev)
5109
5109
5110 return ret
5110 return ret
5111
5111
5112 @command('verify', [])
5112 @command('verify', [])
5113 def verify(ui, repo):
5113 def verify(ui, repo):
5114 """verify the integrity of the repository
5114 """verify the integrity of the repository
5115
5115
5116 Verify the integrity of the current repository.
5116 Verify the integrity of the current repository.
5117
5117
5118 This will perform an extensive check of the repository's
5118 This will perform an extensive check of the repository's
5119 integrity, validating the hashes and checksums of each entry in
5119 integrity, validating the hashes and checksums of each entry in
5120 the changelog, manifest, and tracked files, as well as the
5120 the changelog, manifest, and tracked files, as well as the
5121 integrity of their crosslinks and indices.
5121 integrity of their crosslinks and indices.
5122
5122
5123 Returns 0 on success, 1 if errors are encountered.
5123 Returns 0 on success, 1 if errors are encountered.
5124 """
5124 """
5125 return hg.verify(repo)
5125 return hg.verify(repo)
5126
5126
5127 @command('version', [])
5127 @command('version', [])
5128 def version_(ui):
5128 def version_(ui):
5129 """output version and copyright information"""
5129 """output version and copyright information"""
5130 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5130 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5131 % util.version())
5131 % util.version())
5132 ui.status(_(
5132 ui.status(_(
5133 "(see http://mercurial.selenic.com for more information)\n"
5133 "(see http://mercurial.selenic.com for more information)\n"
5134 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5134 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5135 "This is free software; see the source for copying conditions. "
5135 "This is free software; see the source for copying conditions. "
5136 "There is NO\nwarranty; "
5136 "There is NO\nwarranty; "
5137 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5137 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5138 ))
5138 ))
5139
5139
5140 norepo = ("clone init version help debugcommands debugcomplete"
5140 norepo = ("clone init version help debugcommands debugcomplete"
5141 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5141 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5142 " debugknown debuggetbundle debugbundle")
5142 " debugknown debuggetbundle debugbundle")
5143 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5143 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5144 " debugdata debugindex debugindexdot debugrevlog")
5144 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,709 +1,709 b''
1 # dispatch.py - command dispatching for mercurial
1 # dispatch.py - command dispatching for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
10 import util, commands, hg, fancyopts, extensions, hook, error
10 import util, commands, hg, fancyopts, extensions, hook, error
11 import cmdutil, encoding
11 import cmdutil, encoding
12 import ui as uimod
12 import ui as uimod
13
13
14 class request(object):
14 class request(object):
15 def __init__(self, args, ui=None, repo=None, fin=None, fout=None, ferr=None):
15 def __init__(self, args, ui=None, repo=None, fin=None, fout=None, ferr=None):
16 self.args = args
16 self.args = args
17 self.ui = ui
17 self.ui = ui
18 self.repo = repo
18 self.repo = repo
19
19
20 # input/output/error streams
20 # input/output/error streams
21 self.fin = fin
21 self.fin = fin
22 self.fout = fout
22 self.fout = fout
23 self.ferr = ferr
23 self.ferr = ferr
24
24
25 def run():
25 def run():
26 "run the command in sys.argv"
26 "run the command in sys.argv"
27 sys.exit(dispatch(request(sys.argv[1:])))
27 sys.exit(dispatch(request(sys.argv[1:])))
28
28
29 def dispatch(req):
29 def dispatch(req):
30 "run the command specified in req.args"
30 "run the command specified in req.args"
31 if req.ferr:
31 if req.ferr:
32 ferr = req.ferr
32 ferr = req.ferr
33 elif req.ui:
33 elif req.ui:
34 ferr = req.ui.ferr
34 ferr = req.ui.ferr
35 else:
35 else:
36 ferr = sys.stderr
36 ferr = sys.stderr
37
37
38 try:
38 try:
39 if not req.ui:
39 if not req.ui:
40 req.ui = uimod.ui()
40 req.ui = uimod.ui()
41 if '--traceback' in req.args:
41 if '--traceback' in req.args:
42 req.ui.setconfig('ui', 'traceback', 'on')
42 req.ui.setconfig('ui', 'traceback', 'on')
43
43
44 # set ui streams from the request
44 # set ui streams from the request
45 if req.fin:
45 if req.fin:
46 req.ui.fin = req.fin
46 req.ui.fin = req.fin
47 if req.fout:
47 if req.fout:
48 req.ui.fout = req.fout
48 req.ui.fout = req.fout
49 if req.ferr:
49 if req.ferr:
50 req.ui.ferr = req.ferr
50 req.ui.ferr = req.ferr
51 except util.Abort, inst:
51 except util.Abort, inst:
52 ferr.write(_("abort: %s\n") % inst)
52 ferr.write(_("abort: %s\n") % inst)
53 if inst.hint:
53 if inst.hint:
54 ferr.write(_("(%s)\n") % inst.hint)
54 ferr.write(_("(%s)\n") % inst.hint)
55 return -1
55 return -1
56 except error.ParseError, inst:
56 except error.ParseError, inst:
57 if len(inst.args) > 1:
57 if len(inst.args) > 1:
58 ferr.write(_("hg: parse error at %s: %s\n") %
58 ferr.write(_("hg: parse error at %s: %s\n") %
59 (inst.args[1], inst.args[0]))
59 (inst.args[1], inst.args[0]))
60 else:
60 else:
61 ferr.write(_("hg: parse error: %s\n") % inst.args[0])
61 ferr.write(_("hg: parse error: %s\n") % inst.args[0])
62 return -1
62 return -1
63
63
64 return _runcatch(req)
64 return _runcatch(req)
65
65
66 def _runcatch(req):
66 def _runcatch(req):
67 def catchterm(*args):
67 def catchterm(*args):
68 raise error.SignalInterrupt
68 raise error.SignalInterrupt
69
69
70 ui = req.ui
70 ui = req.ui
71 try:
71 try:
72 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
72 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
73 num = getattr(signal, name, None)
73 num = getattr(signal, name, None)
74 if num:
74 if num:
75 signal.signal(num, catchterm)
75 signal.signal(num, catchterm)
76 except ValueError:
76 except ValueError:
77 pass # happens if called in a thread
77 pass # happens if called in a thread
78
78
79 try:
79 try:
80 try:
80 try:
81 # enter the debugger before command execution
81 # enter the debugger before command execution
82 if '--debugger' in req.args:
82 if '--debugger' in req.args:
83 ui.warn(_("entering debugger - "
83 ui.warn(_("entering debugger - "
84 "type c to continue starting hg or h for help\n"))
84 "type c to continue starting hg or h for help\n"))
85 pdb.set_trace()
85 pdb.set_trace()
86 try:
86 try:
87 return _dispatch(req)
87 return _dispatch(req)
88 finally:
88 finally:
89 ui.flush()
89 ui.flush()
90 except:
90 except:
91 # enter the debugger when we hit an exception
91 # enter the debugger when we hit an exception
92 if '--debugger' in req.args:
92 if '--debugger' in req.args:
93 traceback.print_exc()
93 traceback.print_exc()
94 pdb.post_mortem(sys.exc_info()[2])
94 pdb.post_mortem(sys.exc_info()[2])
95 ui.traceback()
95 ui.traceback()
96 raise
96 raise
97
97
98 # Global exception handling, alphabetically
98 # Global exception handling, alphabetically
99 # Mercurial-specific first, followed by built-in and library exceptions
99 # Mercurial-specific first, followed by built-in and library exceptions
100 except error.AmbiguousCommand, inst:
100 except error.AmbiguousCommand, inst:
101 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
101 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
102 (inst.args[0], " ".join(inst.args[1])))
102 (inst.args[0], " ".join(inst.args[1])))
103 except error.ParseError, inst:
103 except error.ParseError, inst:
104 if len(inst.args) > 1:
104 if len(inst.args) > 1:
105 ui.warn(_("hg: parse error at %s: %s\n") %
105 ui.warn(_("hg: parse error at %s: %s\n") %
106 (inst.args[1], inst.args[0]))
106 (inst.args[1], inst.args[0]))
107 else:
107 else:
108 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
108 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
109 return -1
109 return -1
110 except error.LockHeld, inst:
110 except error.LockHeld, inst:
111 if inst.errno == errno.ETIMEDOUT:
111 if inst.errno == errno.ETIMEDOUT:
112 reason = _('timed out waiting for lock held by %s') % inst.locker
112 reason = _('timed out waiting for lock held by %s') % inst.locker
113 else:
113 else:
114 reason = _('lock held by %s') % inst.locker
114 reason = _('lock held by %s') % inst.locker
115 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
115 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
116 except error.LockUnavailable, inst:
116 except error.LockUnavailable, inst:
117 ui.warn(_("abort: could not lock %s: %s\n") %
117 ui.warn(_("abort: could not lock %s: %s\n") %
118 (inst.desc or inst.filename, inst.strerror))
118 (inst.desc or inst.filename, inst.strerror))
119 except error.CommandError, inst:
119 except error.CommandError, inst:
120 if inst.args[0]:
120 if inst.args[0]:
121 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
121 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
122 commands.help_(ui, inst.args[0], full=False, command=True)
122 commands.help_(ui, inst.args[0], full=False, command=True)
123 else:
123 else:
124 ui.warn(_("hg: %s\n") % inst.args[1])
124 ui.warn(_("hg: %s\n") % inst.args[1])
125 commands.help_(ui, 'shortlist')
125 commands.help_(ui, 'shortlist')
126 except error.RepoError, inst:
126 except error.RepoError, inst:
127 ui.warn(_("abort: %s!\n") % inst)
127 ui.warn(_("abort: %s!\n") % inst)
128 except error.ResponseError, inst:
128 except error.ResponseError, inst:
129 ui.warn(_("abort: %s") % inst.args[0])
129 ui.warn(_("abort: %s") % inst.args[0])
130 if not isinstance(inst.args[1], basestring):
130 if not isinstance(inst.args[1], basestring):
131 ui.warn(" %r\n" % (inst.args[1],))
131 ui.warn(" %r\n" % (inst.args[1],))
132 elif not inst.args[1]:
132 elif not inst.args[1]:
133 ui.warn(_(" empty string\n"))
133 ui.warn(_(" empty string\n"))
134 else:
134 else:
135 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
135 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
136 except error.RevlogError, inst:
136 except error.RevlogError, inst:
137 ui.warn(_("abort: %s!\n") % inst)
137 ui.warn(_("abort: %s!\n") % inst)
138 except error.SignalInterrupt:
138 except error.SignalInterrupt:
139 ui.warn(_("killed!\n"))
139 ui.warn(_("killed!\n"))
140 except error.UnknownCommand, inst:
140 except error.UnknownCommand, inst:
141 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
141 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
142 try:
142 try:
143 # check if the command is in a disabled extension
143 # check if the command is in a disabled extension
144 # (but don't check for extensions themselves)
144 # (but don't check for extensions themselves)
145 commands.help_(ui, inst.args[0], unknowncmd=True)
145 commands.help_(ui, inst.args[0], unknowncmd=True)
146 except error.UnknownCommand:
146 except error.UnknownCommand:
147 commands.help_(ui, 'shortlist')
147 commands.help_(ui, 'shortlist')
148 except util.Abort, inst:
148 except util.Abort, inst:
149 ui.warn(_("abort: %s\n") % inst)
149 ui.warn(_("abort: %s\n") % inst)
150 if inst.hint:
150 if inst.hint:
151 ui.warn(_("(%s)\n") % inst.hint)
151 ui.warn(_("(%s)\n") % inst.hint)
152 except ImportError, inst:
152 except ImportError, inst:
153 ui.warn(_("abort: %s!\n") % inst)
153 ui.warn(_("abort: %s!\n") % inst)
154 m = str(inst).split()[-1]
154 m = str(inst).split()[-1]
155 if m in "mpatch bdiff".split():
155 if m in "mpatch bdiff".split():
156 ui.warn(_("(did you forget to compile extensions?)\n"))
156 ui.warn(_("(did you forget to compile extensions?)\n"))
157 elif m in "zlib".split():
157 elif m in "zlib".split():
158 ui.warn(_("(is your Python install correct?)\n"))
158 ui.warn(_("(is your Python install correct?)\n"))
159 except IOError, inst:
159 except IOError, inst:
160 if hasattr(inst, "code"):
160 if hasattr(inst, "code"):
161 ui.warn(_("abort: %s\n") % inst)
161 ui.warn(_("abort: %s\n") % inst)
162 elif hasattr(inst, "reason"):
162 elif hasattr(inst, "reason"):
163 try: # usually it is in the form (errno, strerror)
163 try: # usually it is in the form (errno, strerror)
164 reason = inst.reason.args[1]
164 reason = inst.reason.args[1]
165 except (AttributeError, IndexError):
165 except (AttributeError, IndexError):
166 # it might be anything, for example a string
166 # it might be anything, for example a string
167 reason = inst.reason
167 reason = inst.reason
168 ui.warn(_("abort: error: %s\n") % reason)
168 ui.warn(_("abort: error: %s\n") % reason)
169 elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
169 elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
170 if ui.debugflag:
170 if ui.debugflag:
171 ui.warn(_("broken pipe\n"))
171 ui.warn(_("broken pipe\n"))
172 elif getattr(inst, "strerror", None):
172 elif getattr(inst, "strerror", None):
173 if getattr(inst, "filename", None):
173 if getattr(inst, "filename", None):
174 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
174 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
175 else:
175 else:
176 ui.warn(_("abort: %s\n") % inst.strerror)
176 ui.warn(_("abort: %s\n") % inst.strerror)
177 else:
177 else:
178 raise
178 raise
179 except OSError, inst:
179 except OSError, inst:
180 if getattr(inst, "filename", None):
180 if getattr(inst, "filename", None):
181 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
181 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
182 else:
182 else:
183 ui.warn(_("abort: %s\n") % inst.strerror)
183 ui.warn(_("abort: %s\n") % inst.strerror)
184 except KeyboardInterrupt:
184 except KeyboardInterrupt:
185 try:
185 try:
186 ui.warn(_("interrupted!\n"))
186 ui.warn(_("interrupted!\n"))
187 except IOError, inst:
187 except IOError, inst:
188 if inst.errno == errno.EPIPE:
188 if inst.errno == errno.EPIPE:
189 if ui.debugflag:
189 if ui.debugflag:
190 ui.warn(_("\nbroken pipe\n"))
190 ui.warn(_("\nbroken pipe\n"))
191 else:
191 else:
192 raise
192 raise
193 except MemoryError:
193 except MemoryError:
194 ui.warn(_("abort: out of memory\n"))
194 ui.warn(_("abort: out of memory\n"))
195 except SystemExit, inst:
195 except SystemExit, inst:
196 # Commands shouldn't sys.exit directly, but give a return code.
196 # Commands shouldn't sys.exit directly, but give a return code.
197 # Just in case catch this and and pass exit code to caller.
197 # Just in case catch this and and pass exit code to caller.
198 return inst.code
198 return inst.code
199 except socket.error, inst:
199 except socket.error, inst:
200 ui.warn(_("abort: %s\n") % inst.args[-1])
200 ui.warn(_("abort: %s\n") % inst.args[-1])
201 except:
201 except:
202 ui.warn(_("** unknown exception encountered,"
202 ui.warn(_("** unknown exception encountered,"
203 " please report by visiting\n"))
203 " please report by visiting\n"))
204 ui.warn(_("** http://mercurial.selenic.com/wiki/BugTracker\n"))
204 ui.warn(_("** http://mercurial.selenic.com/wiki/BugTracker\n"))
205 ui.warn(_("** Python %s\n") % sys.version.replace('\n', ''))
205 ui.warn(_("** Python %s\n") % sys.version.replace('\n', ''))
206 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
206 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
207 % util.version())
207 % util.version())
208 ui.warn(_("** Extensions loaded: %s\n")
208 ui.warn(_("** Extensions loaded: %s\n")
209 % ", ".join([x[0] for x in extensions.extensions()]))
209 % ", ".join([x[0] for x in extensions.extensions()]))
210 raise
210 raise
211
211
212 return -1
212 return -1
213
213
214 def aliasargs(fn, givenargs):
214 def aliasargs(fn, givenargs):
215 args = getattr(fn, 'args', [])
215 args = getattr(fn, 'args', [])
216 if args and givenargs:
216 if args and givenargs:
217 cmd = ' '.join(map(util.shellquote, args))
217 cmd = ' '.join(map(util.shellquote, args))
218
218
219 nums = []
219 nums = []
220 def replacer(m):
220 def replacer(m):
221 num = int(m.group(1)) - 1
221 num = int(m.group(1)) - 1
222 nums.append(num)
222 nums.append(num)
223 return givenargs[num]
223 return givenargs[num]
224 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
224 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
225 givenargs = [x for i, x in enumerate(givenargs)
225 givenargs = [x for i, x in enumerate(givenargs)
226 if i not in nums]
226 if i not in nums]
227 args = shlex.split(cmd)
227 args = shlex.split(cmd)
228 return args + givenargs
228 return args + givenargs
229
229
230 class cmdalias(object):
230 class cmdalias(object):
231 def __init__(self, name, definition, cmdtable):
231 def __init__(self, name, definition, cmdtable):
232 self.name = self.cmd = name
232 self.name = self.cmd = name
233 self.cmdname = ''
233 self.cmdname = ''
234 self.definition = definition
234 self.definition = definition
235 self.args = []
235 self.args = []
236 self.opts = []
236 self.opts = []
237 self.help = ''
237 self.help = ''
238 self.norepo = True
238 self.norepo = True
239 self.badalias = False
239 self.badalias = False
240
240
241 try:
241 try:
242 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
242 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
243 for alias, e in cmdtable.iteritems():
243 for alias, e in cmdtable.iteritems():
244 if e is entry:
244 if e is entry:
245 self.cmd = alias
245 self.cmd = alias
246 break
246 break
247 self.shadows = True
247 self.shadows = True
248 except error.UnknownCommand:
248 except error.UnknownCommand:
249 self.shadows = False
249 self.shadows = False
250
250
251 if not self.definition:
251 if not self.definition:
252 def fn(ui, *args):
252 def fn(ui, *args):
253 ui.warn(_("no definition for alias '%s'\n") % self.name)
253 ui.warn(_("no definition for alias '%s'\n") % self.name)
254 return 1
254 return 1
255 self.fn = fn
255 self.fn = fn
256 self.badalias = True
256 self.badalias = True
257
257
258 return
258 return
259
259
260 if self.definition.startswith('!'):
260 if self.definition.startswith('!'):
261 self.shell = True
261 self.shell = True
262 def fn(ui, *args):
262 def fn(ui, *args):
263 env = {'HG_ARGS': ' '.join((self.name,) + args)}
263 env = {'HG_ARGS': ' '.join((self.name,) + args)}
264 def _checkvar(m):
264 def _checkvar(m):
265 if m.groups()[0] == '$':
265 if m.groups()[0] == '$':
266 return m.group()
266 return m.group()
267 elif int(m.groups()[0]) <= len(args):
267 elif int(m.groups()[0]) <= len(args):
268 return m.group()
268 return m.group()
269 else:
269 else:
270 ui.debug(_("No argument found for substitution "
270 ui.debug("No argument found for substitution "
271 "of %i variable in alias '%s' definition.")
271 "of %i variable in alias '%s' definition."
272 % (int(m.groups()[0]), self.name))
272 % (int(m.groups()[0]), self.name))
273 return ''
273 return ''
274 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
274 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
275 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
275 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
276 replace['0'] = self.name
276 replace['0'] = self.name
277 replace['@'] = ' '.join(args)
277 replace['@'] = ' '.join(args)
278 cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True)
278 cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True)
279 return util.system(cmd, environ=env, out=ui.fout)
279 return util.system(cmd, environ=env, out=ui.fout)
280 self.fn = fn
280 self.fn = fn
281 return
281 return
282
282
283 args = shlex.split(self.definition)
283 args = shlex.split(self.definition)
284 self.cmdname = cmd = args.pop(0)
284 self.cmdname = cmd = args.pop(0)
285 args = map(util.expandpath, args)
285 args = map(util.expandpath, args)
286
286
287 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
287 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
288 if _earlygetopt([invalidarg], args):
288 if _earlygetopt([invalidarg], args):
289 def fn(ui, *args):
289 def fn(ui, *args):
290 ui.warn(_("error in definition for alias '%s': %s may only "
290 ui.warn(_("error in definition for alias '%s': %s may only "
291 "be given on the command line\n")
291 "be given on the command line\n")
292 % (self.name, invalidarg))
292 % (self.name, invalidarg))
293 return 1
293 return 1
294
294
295 self.fn = fn
295 self.fn = fn
296 self.badalias = True
296 self.badalias = True
297 return
297 return
298
298
299 try:
299 try:
300 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
300 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
301 if len(tableentry) > 2:
301 if len(tableentry) > 2:
302 self.fn, self.opts, self.help = tableentry
302 self.fn, self.opts, self.help = tableentry
303 else:
303 else:
304 self.fn, self.opts = tableentry
304 self.fn, self.opts = tableentry
305
305
306 self.args = aliasargs(self.fn, args)
306 self.args = aliasargs(self.fn, args)
307 if cmd not in commands.norepo.split(' '):
307 if cmd not in commands.norepo.split(' '):
308 self.norepo = False
308 self.norepo = False
309 if self.help.startswith("hg " + cmd):
309 if self.help.startswith("hg " + cmd):
310 # drop prefix in old-style help lines so hg shows the alias
310 # drop prefix in old-style help lines so hg shows the alias
311 self.help = self.help[4 + len(cmd):]
311 self.help = self.help[4 + len(cmd):]
312 self.__doc__ = self.fn.__doc__
312 self.__doc__ = self.fn.__doc__
313
313
314 except error.UnknownCommand:
314 except error.UnknownCommand:
315 def fn(ui, *args):
315 def fn(ui, *args):
316 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
316 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
317 % (self.name, cmd))
317 % (self.name, cmd))
318 try:
318 try:
319 # check if the command is in a disabled extension
319 # check if the command is in a disabled extension
320 commands.help_(ui, cmd, unknowncmd=True)
320 commands.help_(ui, cmd, unknowncmd=True)
321 except error.UnknownCommand:
321 except error.UnknownCommand:
322 pass
322 pass
323 return 1
323 return 1
324 self.fn = fn
324 self.fn = fn
325 self.badalias = True
325 self.badalias = True
326 except error.AmbiguousCommand:
326 except error.AmbiguousCommand:
327 def fn(ui, *args):
327 def fn(ui, *args):
328 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
328 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
329 % (self.name, cmd))
329 % (self.name, cmd))
330 return 1
330 return 1
331 self.fn = fn
331 self.fn = fn
332 self.badalias = True
332 self.badalias = True
333
333
334 def __call__(self, ui, *args, **opts):
334 def __call__(self, ui, *args, **opts):
335 if self.shadows:
335 if self.shadows:
336 ui.debug("alias '%s' shadows command '%s'\n" %
336 ui.debug("alias '%s' shadows command '%s'\n" %
337 (self.name, self.cmdname))
337 (self.name, self.cmdname))
338
338
339 if hasattr(self, 'shell'):
339 if hasattr(self, 'shell'):
340 return self.fn(ui, *args, **opts)
340 return self.fn(ui, *args, **opts)
341 else:
341 else:
342 try:
342 try:
343 util.checksignature(self.fn)(ui, *args, **opts)
343 util.checksignature(self.fn)(ui, *args, **opts)
344 except error.SignatureError:
344 except error.SignatureError:
345 args = ' '.join([self.cmdname] + self.args)
345 args = ' '.join([self.cmdname] + self.args)
346 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
346 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
347 raise
347 raise
348
348
349 def addaliases(ui, cmdtable):
349 def addaliases(ui, cmdtable):
350 # aliases are processed after extensions have been loaded, so they
350 # aliases are processed after extensions have been loaded, so they
351 # may use extension commands. Aliases can also use other alias definitions,
351 # may use extension commands. Aliases can also use other alias definitions,
352 # but only if they have been defined prior to the current definition.
352 # but only if they have been defined prior to the current definition.
353 for alias, definition in ui.configitems('alias'):
353 for alias, definition in ui.configitems('alias'):
354 aliasdef = cmdalias(alias, definition, cmdtable)
354 aliasdef = cmdalias(alias, definition, cmdtable)
355 cmdtable[aliasdef.cmd] = (aliasdef, aliasdef.opts, aliasdef.help)
355 cmdtable[aliasdef.cmd] = (aliasdef, aliasdef.opts, aliasdef.help)
356 if aliasdef.norepo:
356 if aliasdef.norepo:
357 commands.norepo += ' %s' % alias
357 commands.norepo += ' %s' % alias
358
358
359 def _parse(ui, args):
359 def _parse(ui, args):
360 options = {}
360 options = {}
361 cmdoptions = {}
361 cmdoptions = {}
362
362
363 try:
363 try:
364 args = fancyopts.fancyopts(args, commands.globalopts, options)
364 args = fancyopts.fancyopts(args, commands.globalopts, options)
365 except fancyopts.getopt.GetoptError, inst:
365 except fancyopts.getopt.GetoptError, inst:
366 raise error.CommandError(None, inst)
366 raise error.CommandError(None, inst)
367
367
368 if args:
368 if args:
369 cmd, args = args[0], args[1:]
369 cmd, args = args[0], args[1:]
370 aliases, entry = cmdutil.findcmd(cmd, commands.table,
370 aliases, entry = cmdutil.findcmd(cmd, commands.table,
371 ui.config("ui", "strict"))
371 ui.config("ui", "strict"))
372 cmd = aliases[0]
372 cmd = aliases[0]
373 args = aliasargs(entry[0], args)
373 args = aliasargs(entry[0], args)
374 defaults = ui.config("defaults", cmd)
374 defaults = ui.config("defaults", cmd)
375 if defaults:
375 if defaults:
376 args = map(util.expandpath, shlex.split(defaults)) + args
376 args = map(util.expandpath, shlex.split(defaults)) + args
377 c = list(entry[1])
377 c = list(entry[1])
378 else:
378 else:
379 cmd = None
379 cmd = None
380 c = []
380 c = []
381
381
382 # combine global options into local
382 # combine global options into local
383 for o in commands.globalopts:
383 for o in commands.globalopts:
384 c.append((o[0], o[1], options[o[1]], o[3]))
384 c.append((o[0], o[1], options[o[1]], o[3]))
385
385
386 try:
386 try:
387 args = fancyopts.fancyopts(args, c, cmdoptions, True)
387 args = fancyopts.fancyopts(args, c, cmdoptions, True)
388 except fancyopts.getopt.GetoptError, inst:
388 except fancyopts.getopt.GetoptError, inst:
389 raise error.CommandError(cmd, inst)
389 raise error.CommandError(cmd, inst)
390
390
391 # separate global options back out
391 # separate global options back out
392 for o in commands.globalopts:
392 for o in commands.globalopts:
393 n = o[1]
393 n = o[1]
394 options[n] = cmdoptions[n]
394 options[n] = cmdoptions[n]
395 del cmdoptions[n]
395 del cmdoptions[n]
396
396
397 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
397 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
398
398
399 def _parseconfig(ui, config):
399 def _parseconfig(ui, config):
400 """parse the --config options from the command line"""
400 """parse the --config options from the command line"""
401 for cfg in config:
401 for cfg in config:
402 try:
402 try:
403 name, value = cfg.split('=', 1)
403 name, value = cfg.split('=', 1)
404 section, name = name.split('.', 1)
404 section, name = name.split('.', 1)
405 if not section or not name:
405 if not section or not name:
406 raise IndexError
406 raise IndexError
407 ui.setconfig(section, name, value)
407 ui.setconfig(section, name, value)
408 except (IndexError, ValueError):
408 except (IndexError, ValueError):
409 raise util.Abort(_('malformed --config option: %r '
409 raise util.Abort(_('malformed --config option: %r '
410 '(use --config section.name=value)') % cfg)
410 '(use --config section.name=value)') % cfg)
411
411
412 def _earlygetopt(aliases, args):
412 def _earlygetopt(aliases, args):
413 """Return list of values for an option (or aliases).
413 """Return list of values for an option (or aliases).
414
414
415 The values are listed in the order they appear in args.
415 The values are listed in the order they appear in args.
416 The options and values are removed from args.
416 The options and values are removed from args.
417 """
417 """
418 try:
418 try:
419 argcount = args.index("--")
419 argcount = args.index("--")
420 except ValueError:
420 except ValueError:
421 argcount = len(args)
421 argcount = len(args)
422 shortopts = [opt for opt in aliases if len(opt) == 2]
422 shortopts = [opt for opt in aliases if len(opt) == 2]
423 values = []
423 values = []
424 pos = 0
424 pos = 0
425 while pos < argcount:
425 while pos < argcount:
426 if args[pos] in aliases:
426 if args[pos] in aliases:
427 if pos + 1 >= argcount:
427 if pos + 1 >= argcount:
428 # ignore and let getopt report an error if there is no value
428 # ignore and let getopt report an error if there is no value
429 break
429 break
430 del args[pos]
430 del args[pos]
431 values.append(args.pop(pos))
431 values.append(args.pop(pos))
432 argcount -= 2
432 argcount -= 2
433 elif args[pos][:2] in shortopts:
433 elif args[pos][:2] in shortopts:
434 # short option can have no following space, e.g. hg log -Rfoo
434 # short option can have no following space, e.g. hg log -Rfoo
435 values.append(args.pop(pos)[2:])
435 values.append(args.pop(pos)[2:])
436 argcount -= 1
436 argcount -= 1
437 else:
437 else:
438 pos += 1
438 pos += 1
439 return values
439 return values
440
440
441 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
441 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
442 # run pre-hook, and abort if it fails
442 # run pre-hook, and abort if it fails
443 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
443 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
444 pats=cmdpats, opts=cmdoptions)
444 pats=cmdpats, opts=cmdoptions)
445 if ret:
445 if ret:
446 return ret
446 return ret
447 ret = _runcommand(ui, options, cmd, d)
447 ret = _runcommand(ui, options, cmd, d)
448 # run post-hook, passing command result
448 # run post-hook, passing command result
449 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
449 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
450 result=ret, pats=cmdpats, opts=cmdoptions)
450 result=ret, pats=cmdpats, opts=cmdoptions)
451 return ret
451 return ret
452
452
453 def _getlocal(ui, rpath):
453 def _getlocal(ui, rpath):
454 """Return (path, local ui object) for the given target path.
454 """Return (path, local ui object) for the given target path.
455
455
456 Takes paths in [cwd]/.hg/hgrc into account."
456 Takes paths in [cwd]/.hg/hgrc into account."
457 """
457 """
458 try:
458 try:
459 wd = os.getcwd()
459 wd = os.getcwd()
460 except OSError, e:
460 except OSError, e:
461 raise util.Abort(_("error getting current working directory: %s") %
461 raise util.Abort(_("error getting current working directory: %s") %
462 e.strerror)
462 e.strerror)
463 path = cmdutil.findrepo(wd) or ""
463 path = cmdutil.findrepo(wd) or ""
464 if not path:
464 if not path:
465 lui = ui
465 lui = ui
466 else:
466 else:
467 lui = ui.copy()
467 lui = ui.copy()
468 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
468 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
469
469
470 if rpath:
470 if rpath:
471 path = lui.expandpath(rpath[-1])
471 path = lui.expandpath(rpath[-1])
472 lui = ui.copy()
472 lui = ui.copy()
473 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
473 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
474
474
475 return path, lui
475 return path, lui
476
476
477 def _checkshellalias(ui, args):
477 def _checkshellalias(ui, args):
478 cwd = os.getcwd()
478 cwd = os.getcwd()
479 norepo = commands.norepo
479 norepo = commands.norepo
480 options = {}
480 options = {}
481
481
482 try:
482 try:
483 args = fancyopts.fancyopts(args, commands.globalopts, options)
483 args = fancyopts.fancyopts(args, commands.globalopts, options)
484 except fancyopts.getopt.GetoptError:
484 except fancyopts.getopt.GetoptError:
485 return
485 return
486
486
487 if not args:
487 if not args:
488 return
488 return
489
489
490 _parseconfig(ui, options['config'])
490 _parseconfig(ui, options['config'])
491 if options['cwd']:
491 if options['cwd']:
492 os.chdir(options['cwd'])
492 os.chdir(options['cwd'])
493
493
494 path, lui = _getlocal(ui, [options['repository']])
494 path, lui = _getlocal(ui, [options['repository']])
495
495
496 cmdtable = commands.table.copy()
496 cmdtable = commands.table.copy()
497 addaliases(lui, cmdtable)
497 addaliases(lui, cmdtable)
498
498
499 cmd = args[0]
499 cmd = args[0]
500 try:
500 try:
501 aliases, entry = cmdutil.findcmd(cmd, cmdtable, lui.config("ui", "strict"))
501 aliases, entry = cmdutil.findcmd(cmd, cmdtable, lui.config("ui", "strict"))
502 except (error.AmbiguousCommand, error.UnknownCommand):
502 except (error.AmbiguousCommand, error.UnknownCommand):
503 commands.norepo = norepo
503 commands.norepo = norepo
504 os.chdir(cwd)
504 os.chdir(cwd)
505 return
505 return
506
506
507 cmd = aliases[0]
507 cmd = aliases[0]
508 fn = entry[0]
508 fn = entry[0]
509
509
510 if cmd and hasattr(fn, 'shell'):
510 if cmd and hasattr(fn, 'shell'):
511 d = lambda: fn(ui, *args[1:])
511 d = lambda: fn(ui, *args[1:])
512 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, [], {})
512 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, [], {})
513
513
514 commands.norepo = norepo
514 commands.norepo = norepo
515 os.chdir(cwd)
515 os.chdir(cwd)
516
516
517 _loaded = set()
517 _loaded = set()
518 def _dispatch(req):
518 def _dispatch(req):
519 args = req.args
519 args = req.args
520 ui = req.ui
520 ui = req.ui
521
521
522 shellaliasfn = _checkshellalias(ui, args)
522 shellaliasfn = _checkshellalias(ui, args)
523 if shellaliasfn:
523 if shellaliasfn:
524 return shellaliasfn()
524 return shellaliasfn()
525
525
526 # read --config before doing anything else
526 # read --config before doing anything else
527 # (e.g. to change trust settings for reading .hg/hgrc)
527 # (e.g. to change trust settings for reading .hg/hgrc)
528 _parseconfig(ui, _earlygetopt(['--config'], args))
528 _parseconfig(ui, _earlygetopt(['--config'], args))
529
529
530 # check for cwd
530 # check for cwd
531 cwd = _earlygetopt(['--cwd'], args)
531 cwd = _earlygetopt(['--cwd'], args)
532 if cwd:
532 if cwd:
533 os.chdir(cwd[-1])
533 os.chdir(cwd[-1])
534
534
535 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
535 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
536 path, lui = _getlocal(ui, rpath)
536 path, lui = _getlocal(ui, rpath)
537
537
538 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
538 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
539 # reposetup. Programs like TortoiseHg will call _dispatch several
539 # reposetup. Programs like TortoiseHg will call _dispatch several
540 # times so we keep track of configured extensions in _loaded.
540 # times so we keep track of configured extensions in _loaded.
541 extensions.loadall(lui)
541 extensions.loadall(lui)
542 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
542 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
543 # Propagate any changes to lui.__class__ by extensions
543 # Propagate any changes to lui.__class__ by extensions
544 ui.__class__ = lui.__class__
544 ui.__class__ = lui.__class__
545
545
546 # (uisetup and extsetup are handled in extensions.loadall)
546 # (uisetup and extsetup are handled in extensions.loadall)
547
547
548 for name, module in exts:
548 for name, module in exts:
549 cmdtable = getattr(module, 'cmdtable', {})
549 cmdtable = getattr(module, 'cmdtable', {})
550 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
550 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
551 if overrides:
551 if overrides:
552 ui.warn(_("extension '%s' overrides commands: %s\n")
552 ui.warn(_("extension '%s' overrides commands: %s\n")
553 % (name, " ".join(overrides)))
553 % (name, " ".join(overrides)))
554 commands.table.update(cmdtable)
554 commands.table.update(cmdtable)
555 _loaded.add(name)
555 _loaded.add(name)
556
556
557 # (reposetup is handled in hg.repository)
557 # (reposetup is handled in hg.repository)
558
558
559 addaliases(lui, commands.table)
559 addaliases(lui, commands.table)
560
560
561 # check for fallback encoding
561 # check for fallback encoding
562 fallback = lui.config('ui', 'fallbackencoding')
562 fallback = lui.config('ui', 'fallbackencoding')
563 if fallback:
563 if fallback:
564 encoding.fallbackencoding = fallback
564 encoding.fallbackencoding = fallback
565
565
566 fullargs = args
566 fullargs = args
567 cmd, func, args, options, cmdoptions = _parse(lui, args)
567 cmd, func, args, options, cmdoptions = _parse(lui, args)
568
568
569 if options["config"]:
569 if options["config"]:
570 raise util.Abort(_("option --config may not be abbreviated!"))
570 raise util.Abort(_("option --config may not be abbreviated!"))
571 if options["cwd"]:
571 if options["cwd"]:
572 raise util.Abort(_("option --cwd may not be abbreviated!"))
572 raise util.Abort(_("option --cwd may not be abbreviated!"))
573 if options["repository"]:
573 if options["repository"]:
574 raise util.Abort(_(
574 raise util.Abort(_(
575 "Option -R has to be separated from other options (e.g. not -qR) "
575 "Option -R has to be separated from other options (e.g. not -qR) "
576 "and --repository may only be abbreviated as --repo!"))
576 "and --repository may only be abbreviated as --repo!"))
577
577
578 if options["encoding"]:
578 if options["encoding"]:
579 encoding.encoding = options["encoding"]
579 encoding.encoding = options["encoding"]
580 if options["encodingmode"]:
580 if options["encodingmode"]:
581 encoding.encodingmode = options["encodingmode"]
581 encoding.encodingmode = options["encodingmode"]
582 if options["time"]:
582 if options["time"]:
583 def get_times():
583 def get_times():
584 t = os.times()
584 t = os.times()
585 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
585 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
586 t = (t[0], t[1], t[2], t[3], time.clock())
586 t = (t[0], t[1], t[2], t[3], time.clock())
587 return t
587 return t
588 s = get_times()
588 s = get_times()
589 def print_time():
589 def print_time():
590 t = get_times()
590 t = get_times()
591 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
591 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
592 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
592 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
593 atexit.register(print_time)
593 atexit.register(print_time)
594
594
595 if options['verbose'] or options['debug'] or options['quiet']:
595 if options['verbose'] or options['debug'] or options['quiet']:
596 for ui_ in (ui, lui):
596 for ui_ in (ui, lui):
597 ui_.setconfig('ui', 'verbose', str(bool(options['verbose'])))
597 ui_.setconfig('ui', 'verbose', str(bool(options['verbose'])))
598 ui_.setconfig('ui', 'debug', str(bool(options['debug'])))
598 ui_.setconfig('ui', 'debug', str(bool(options['debug'])))
599 ui_.setconfig('ui', 'quiet', str(bool(options['quiet'])))
599 ui_.setconfig('ui', 'quiet', str(bool(options['quiet'])))
600 if options['traceback']:
600 if options['traceback']:
601 for ui_ in (ui, lui):
601 for ui_ in (ui, lui):
602 ui_.setconfig('ui', 'traceback', 'on')
602 ui_.setconfig('ui', 'traceback', 'on')
603 if options['noninteractive']:
603 if options['noninteractive']:
604 for ui_ in (ui, lui):
604 for ui_ in (ui, lui):
605 ui_.setconfig('ui', 'interactive', 'off')
605 ui_.setconfig('ui', 'interactive', 'off')
606
606
607 if cmdoptions.get('insecure', False):
607 if cmdoptions.get('insecure', False):
608 for ui_ in (ui, lui):
608 for ui_ in (ui, lui):
609 ui_.setconfig('web', 'cacerts', '')
609 ui_.setconfig('web', 'cacerts', '')
610
610
611 if options['help']:
611 if options['help']:
612 return commands.help_(ui, cmd, options['version'])
612 return commands.help_(ui, cmd, options['version'])
613 elif options['version']:
613 elif options['version']:
614 return commands.version_(ui)
614 return commands.version_(ui)
615 elif not cmd:
615 elif not cmd:
616 return commands.help_(ui, 'shortlist')
616 return commands.help_(ui, 'shortlist')
617
617
618 repo = None
618 repo = None
619 cmdpats = args[:]
619 cmdpats = args[:]
620 if cmd not in commands.norepo.split():
620 if cmd not in commands.norepo.split():
621 # use the repo from the request only if we don't have -R
621 # use the repo from the request only if we don't have -R
622 if not rpath:
622 if not rpath:
623 repo = req.repo
623 repo = req.repo
624
624
625 if not repo:
625 if not repo:
626 try:
626 try:
627 repo = hg.repository(ui, path=path)
627 repo = hg.repository(ui, path=path)
628 ui = repo.ui
628 ui = repo.ui
629 if not repo.local():
629 if not repo.local():
630 raise util.Abort(_("repository '%s' is not local") % path)
630 raise util.Abort(_("repository '%s' is not local") % path)
631 ui.setconfig("bundle", "mainreporoot", repo.root)
631 ui.setconfig("bundle", "mainreporoot", repo.root)
632 except error.RequirementError:
632 except error.RequirementError:
633 raise
633 raise
634 except error.RepoError:
634 except error.RepoError:
635 if cmd not in commands.optionalrepo.split():
635 if cmd not in commands.optionalrepo.split():
636 if args and not path: # try to infer -R from command args
636 if args and not path: # try to infer -R from command args
637 repos = map(cmdutil.findrepo, args)
637 repos = map(cmdutil.findrepo, args)
638 guess = repos[0]
638 guess = repos[0]
639 if guess and repos.count(guess) == len(repos):
639 if guess and repos.count(guess) == len(repos):
640 req.args = ['--repository', guess] + fullargs
640 req.args = ['--repository', guess] + fullargs
641 return _dispatch(req)
641 return _dispatch(req)
642 if not path:
642 if not path:
643 raise error.RepoError(_("no repository found in %r"
643 raise error.RepoError(_("no repository found in %r"
644 " (.hg not found)") % os.getcwd())
644 " (.hg not found)") % os.getcwd())
645 raise
645 raise
646 args.insert(0, repo)
646 args.insert(0, repo)
647 elif rpath:
647 elif rpath:
648 ui.warn(_("warning: --repository ignored\n"))
648 ui.warn(_("warning: --repository ignored\n"))
649
649
650 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
650 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
651 ui.log("command", msg + "\n")
651 ui.log("command", msg + "\n")
652 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
652 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
653 try:
653 try:
654 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
654 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
655 cmdpats, cmdoptions)
655 cmdpats, cmdoptions)
656 finally:
656 finally:
657 if repo:
657 if repo:
658 repo.close()
658 repo.close()
659
659
660 def _runcommand(ui, options, cmd, cmdfunc):
660 def _runcommand(ui, options, cmd, cmdfunc):
661 def checkargs():
661 def checkargs():
662 try:
662 try:
663 return cmdfunc()
663 return cmdfunc()
664 except error.SignatureError:
664 except error.SignatureError:
665 raise error.CommandError(cmd, _("invalid arguments"))
665 raise error.CommandError(cmd, _("invalid arguments"))
666
666
667 if options['profile']:
667 if options['profile']:
668 format = ui.config('profiling', 'format', default='text')
668 format = ui.config('profiling', 'format', default='text')
669
669
670 if not format in ['text', 'kcachegrind']:
670 if not format in ['text', 'kcachegrind']:
671 ui.warn(_("unrecognized profiling format '%s'"
671 ui.warn(_("unrecognized profiling format '%s'"
672 " - Ignored\n") % format)
672 " - Ignored\n") % format)
673 format = 'text'
673 format = 'text'
674
674
675 output = ui.config('profiling', 'output')
675 output = ui.config('profiling', 'output')
676
676
677 if output:
677 if output:
678 path = ui.expandpath(output)
678 path = ui.expandpath(output)
679 ostream = open(path, 'wb')
679 ostream = open(path, 'wb')
680 else:
680 else:
681 ostream = sys.stderr
681 ostream = sys.stderr
682
682
683 try:
683 try:
684 from mercurial import lsprof
684 from mercurial import lsprof
685 except ImportError:
685 except ImportError:
686 raise util.Abort(_(
686 raise util.Abort(_(
687 'lsprof not available - install from '
687 'lsprof not available - install from '
688 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
688 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
689 p = lsprof.Profiler()
689 p = lsprof.Profiler()
690 p.enable(subcalls=True)
690 p.enable(subcalls=True)
691 try:
691 try:
692 return checkargs()
692 return checkargs()
693 finally:
693 finally:
694 p.disable()
694 p.disable()
695
695
696 if format == 'kcachegrind':
696 if format == 'kcachegrind':
697 import lsprofcalltree
697 import lsprofcalltree
698 calltree = lsprofcalltree.KCacheGrind(p)
698 calltree = lsprofcalltree.KCacheGrind(p)
699 calltree.output(ostream)
699 calltree.output(ostream)
700 else:
700 else:
701 # format == 'text'
701 # format == 'text'
702 stats = lsprof.Stats(p.getstats())
702 stats = lsprof.Stats(p.getstats())
703 stats.sort()
703 stats.sort()
704 stats.pprint(top=10, file=ostream, climit=5)
704 stats.pprint(top=10, file=ostream, climit=5)
705
705
706 if output:
706 if output:
707 ostream.close()
707 ostream.close()
708 else:
708 else:
709 return checkargs()
709 return checkargs()
@@ -1,711 +1,711 b''
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import errno, getpass, os, socket, sys, tempfile, traceback
9 import errno, getpass, os, socket, sys, tempfile, traceback
10 import config, scmutil, util, error
10 import config, scmutil, util, error
11
11
12 class ui(object):
12 class ui(object):
13 def __init__(self, src=None):
13 def __init__(self, src=None):
14 self._buffers = []
14 self._buffers = []
15 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
15 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
16 self._reportuntrusted = True
16 self._reportuntrusted = True
17 self._ocfg = config.config() # overlay
17 self._ocfg = config.config() # overlay
18 self._tcfg = config.config() # trusted
18 self._tcfg = config.config() # trusted
19 self._ucfg = config.config() # untrusted
19 self._ucfg = config.config() # untrusted
20 self._trustusers = set()
20 self._trustusers = set()
21 self._trustgroups = set()
21 self._trustgroups = set()
22
22
23 if src:
23 if src:
24 self.fout = src.fout
24 self.fout = src.fout
25 self.ferr = src.ferr
25 self.ferr = src.ferr
26 self.fin = src.fin
26 self.fin = src.fin
27
27
28 self._tcfg = src._tcfg.copy()
28 self._tcfg = src._tcfg.copy()
29 self._ucfg = src._ucfg.copy()
29 self._ucfg = src._ucfg.copy()
30 self._ocfg = src._ocfg.copy()
30 self._ocfg = src._ocfg.copy()
31 self._trustusers = src._trustusers.copy()
31 self._trustusers = src._trustusers.copy()
32 self._trustgroups = src._trustgroups.copy()
32 self._trustgroups = src._trustgroups.copy()
33 self.environ = src.environ
33 self.environ = src.environ
34 self.fixconfig()
34 self.fixconfig()
35 else:
35 else:
36 self.fout = sys.stdout
36 self.fout = sys.stdout
37 self.ferr = sys.stderr
37 self.ferr = sys.stderr
38 self.fin = sys.stdin
38 self.fin = sys.stdin
39
39
40 # shared read-only environment
40 # shared read-only environment
41 self.environ = os.environ
41 self.environ = os.environ
42 # we always trust global config files
42 # we always trust global config files
43 for f in scmutil.rcpath():
43 for f in scmutil.rcpath():
44 self.readconfig(f, trust=True)
44 self.readconfig(f, trust=True)
45
45
46 def copy(self):
46 def copy(self):
47 return self.__class__(self)
47 return self.__class__(self)
48
48
49 def _is_trusted(self, fp, f):
49 def _is_trusted(self, fp, f):
50 st = util.fstat(fp)
50 st = util.fstat(fp)
51 if util.isowner(st):
51 if util.isowner(st):
52 return True
52 return True
53
53
54 tusers, tgroups = self._trustusers, self._trustgroups
54 tusers, tgroups = self._trustusers, self._trustgroups
55 if '*' in tusers or '*' in tgroups:
55 if '*' in tusers or '*' in tgroups:
56 return True
56 return True
57
57
58 user = util.username(st.st_uid)
58 user = util.username(st.st_uid)
59 group = util.groupname(st.st_gid)
59 group = util.groupname(st.st_gid)
60 if user in tusers or group in tgroups or user == util.username():
60 if user in tusers or group in tgroups or user == util.username():
61 return True
61 return True
62
62
63 if self._reportuntrusted:
63 if self._reportuntrusted:
64 self.warn(_('Not trusting file %s from untrusted '
64 self.warn(_('Not trusting file %s from untrusted '
65 'user %s, group %s\n') % (f, user, group))
65 'user %s, group %s\n') % (f, user, group))
66 return False
66 return False
67
67
68 def readconfig(self, filename, root=None, trust=False,
68 def readconfig(self, filename, root=None, trust=False,
69 sections=None, remap=None):
69 sections=None, remap=None):
70 try:
70 try:
71 fp = open(filename)
71 fp = open(filename)
72 except IOError:
72 except IOError:
73 if not sections: # ignore unless we were looking for something
73 if not sections: # ignore unless we were looking for something
74 return
74 return
75 raise
75 raise
76
76
77 cfg = config.config()
77 cfg = config.config()
78 trusted = sections or trust or self._is_trusted(fp, filename)
78 trusted = sections or trust or self._is_trusted(fp, filename)
79
79
80 try:
80 try:
81 cfg.read(filename, fp, sections=sections, remap=remap)
81 cfg.read(filename, fp, sections=sections, remap=remap)
82 except error.ConfigError, inst:
82 except error.ConfigError, inst:
83 if trusted:
83 if trusted:
84 raise
84 raise
85 self.warn(_("Ignored: %s\n") % str(inst))
85 self.warn(_("Ignored: %s\n") % str(inst))
86
86
87 if self.plain():
87 if self.plain():
88 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
88 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
89 'logtemplate', 'style',
89 'logtemplate', 'style',
90 'traceback', 'verbose'):
90 'traceback', 'verbose'):
91 if k in cfg['ui']:
91 if k in cfg['ui']:
92 del cfg['ui'][k]
92 del cfg['ui'][k]
93 for k, v in cfg.items('defaults'):
93 for k, v in cfg.items('defaults'):
94 del cfg['defaults'][k]
94 del cfg['defaults'][k]
95 # Don't remove aliases from the configuration if in the exceptionlist
95 # Don't remove aliases from the configuration if in the exceptionlist
96 if self.plain('alias'):
96 if self.plain('alias'):
97 for k, v in cfg.items('alias'):
97 for k, v in cfg.items('alias'):
98 del cfg['alias'][k]
98 del cfg['alias'][k]
99
99
100 if trusted:
100 if trusted:
101 self._tcfg.update(cfg)
101 self._tcfg.update(cfg)
102 self._tcfg.update(self._ocfg)
102 self._tcfg.update(self._ocfg)
103 self._ucfg.update(cfg)
103 self._ucfg.update(cfg)
104 self._ucfg.update(self._ocfg)
104 self._ucfg.update(self._ocfg)
105
105
106 if root is None:
106 if root is None:
107 root = os.path.expanduser('~')
107 root = os.path.expanduser('~')
108 self.fixconfig(root=root)
108 self.fixconfig(root=root)
109
109
110 def fixconfig(self, root=None, section=None):
110 def fixconfig(self, root=None, section=None):
111 if section in (None, 'paths'):
111 if section in (None, 'paths'):
112 # expand vars and ~
112 # expand vars and ~
113 # translate paths relative to root (or home) into absolute paths
113 # translate paths relative to root (or home) into absolute paths
114 root = root or os.getcwd()
114 root = root or os.getcwd()
115 for c in self._tcfg, self._ucfg, self._ocfg:
115 for c in self._tcfg, self._ucfg, self._ocfg:
116 for n, p in c.items('paths'):
116 for n, p in c.items('paths'):
117 if not p:
117 if not p:
118 continue
118 continue
119 if '%%' in p:
119 if '%%' in p:
120 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
120 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
121 % (n, p, self.configsource('paths', n)))
121 % (n, p, self.configsource('paths', n)))
122 p = p.replace('%%', '%')
122 p = p.replace('%%', '%')
123 p = util.expandpath(p)
123 p = util.expandpath(p)
124 if not util.hasscheme(p) and not os.path.isabs(p):
124 if not util.hasscheme(p) and not os.path.isabs(p):
125 p = os.path.normpath(os.path.join(root, p))
125 p = os.path.normpath(os.path.join(root, p))
126 c.set("paths", n, p)
126 c.set("paths", n, p)
127
127
128 if section in (None, 'ui'):
128 if section in (None, 'ui'):
129 # update ui options
129 # update ui options
130 self.debugflag = self.configbool('ui', 'debug')
130 self.debugflag = self.configbool('ui', 'debug')
131 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
131 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
132 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
132 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
133 if self.verbose and self.quiet:
133 if self.verbose and self.quiet:
134 self.quiet = self.verbose = False
134 self.quiet = self.verbose = False
135 self._reportuntrusted = self.debugflag or self.configbool("ui",
135 self._reportuntrusted = self.debugflag or self.configbool("ui",
136 "report_untrusted", True)
136 "report_untrusted", True)
137 self.tracebackflag = self.configbool('ui', 'traceback', False)
137 self.tracebackflag = self.configbool('ui', 'traceback', False)
138
138
139 if section in (None, 'trusted'):
139 if section in (None, 'trusted'):
140 # update trust information
140 # update trust information
141 self._trustusers.update(self.configlist('trusted', 'users'))
141 self._trustusers.update(self.configlist('trusted', 'users'))
142 self._trustgroups.update(self.configlist('trusted', 'groups'))
142 self._trustgroups.update(self.configlist('trusted', 'groups'))
143
143
144 def setconfig(self, section, name, value, overlay=True):
144 def setconfig(self, section, name, value, overlay=True):
145 if overlay:
145 if overlay:
146 self._ocfg.set(section, name, value)
146 self._ocfg.set(section, name, value)
147 self._tcfg.set(section, name, value)
147 self._tcfg.set(section, name, value)
148 self._ucfg.set(section, name, value)
148 self._ucfg.set(section, name, value)
149 self.fixconfig(section=section)
149 self.fixconfig(section=section)
150
150
151 def _data(self, untrusted):
151 def _data(self, untrusted):
152 return untrusted and self._ucfg or self._tcfg
152 return untrusted and self._ucfg or self._tcfg
153
153
154 def configsource(self, section, name, untrusted=False):
154 def configsource(self, section, name, untrusted=False):
155 return self._data(untrusted).source(section, name) or 'none'
155 return self._data(untrusted).source(section, name) or 'none'
156
156
157 def config(self, section, name, default=None, untrusted=False):
157 def config(self, section, name, default=None, untrusted=False):
158 value = self._data(untrusted).get(section, name, default)
158 value = self._data(untrusted).get(section, name, default)
159 if self.debugflag and not untrusted and self._reportuntrusted:
159 if self.debugflag and not untrusted and self._reportuntrusted:
160 uvalue = self._ucfg.get(section, name)
160 uvalue = self._ucfg.get(section, name)
161 if uvalue is not None and uvalue != value:
161 if uvalue is not None and uvalue != value:
162 self.debug(_("ignoring untrusted configuration option "
162 self.debug("ignoring untrusted configuration option "
163 "%s.%s = %s\n") % (section, name, uvalue))
163 "%s.%s = %s\n" % (section, name, uvalue))
164 return value
164 return value
165
165
166 def configpath(self, section, name, default=None, untrusted=False):
166 def configpath(self, section, name, default=None, untrusted=False):
167 'get a path config item, expanded relative to config file'
167 'get a path config item, expanded relative to config file'
168 v = self.config(section, name, default, untrusted)
168 v = self.config(section, name, default, untrusted)
169 if not os.path.isabs(v) or "://" not in v:
169 if not os.path.isabs(v) or "://" not in v:
170 src = self.configsource(section, name, untrusted)
170 src = self.configsource(section, name, untrusted)
171 if ':' in src:
171 if ':' in src:
172 base = os.path.dirname(src.rsplit(':'))
172 base = os.path.dirname(src.rsplit(':'))
173 v = os.path.join(base, os.path.expanduser(v))
173 v = os.path.join(base, os.path.expanduser(v))
174 return v
174 return v
175
175
176 def configbool(self, section, name, default=False, untrusted=False):
176 def configbool(self, section, name, default=False, untrusted=False):
177 """parse a configuration element as a boolean
177 """parse a configuration element as a boolean
178
178
179 >>> u = ui(); s = 'foo'
179 >>> u = ui(); s = 'foo'
180 >>> u.setconfig(s, 'true', 'yes')
180 >>> u.setconfig(s, 'true', 'yes')
181 >>> u.configbool(s, 'true')
181 >>> u.configbool(s, 'true')
182 True
182 True
183 >>> u.setconfig(s, 'false', 'no')
183 >>> u.setconfig(s, 'false', 'no')
184 >>> u.configbool(s, 'false')
184 >>> u.configbool(s, 'false')
185 False
185 False
186 >>> u.configbool(s, 'unknown')
186 >>> u.configbool(s, 'unknown')
187 False
187 False
188 >>> u.configbool(s, 'unknown', True)
188 >>> u.configbool(s, 'unknown', True)
189 True
189 True
190 >>> u.setconfig(s, 'invalid', 'somevalue')
190 >>> u.setconfig(s, 'invalid', 'somevalue')
191 >>> u.configbool(s, 'invalid')
191 >>> u.configbool(s, 'invalid')
192 Traceback (most recent call last):
192 Traceback (most recent call last):
193 ...
193 ...
194 ConfigError: foo.invalid is not a boolean ('somevalue')
194 ConfigError: foo.invalid is not a boolean ('somevalue')
195 """
195 """
196
196
197 v = self.config(section, name, None, untrusted)
197 v = self.config(section, name, None, untrusted)
198 if v is None:
198 if v is None:
199 return default
199 return default
200 if isinstance(v, bool):
200 if isinstance(v, bool):
201 return v
201 return v
202 b = util.parsebool(v)
202 b = util.parsebool(v)
203 if b is None:
203 if b is None:
204 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
204 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
205 % (section, name, v))
205 % (section, name, v))
206 return b
206 return b
207
207
208 def configint(self, section, name, default=None, untrusted=False):
208 def configint(self, section, name, default=None, untrusted=False):
209 """parse a configuration element as an integer
209 """parse a configuration element as an integer
210
210
211 >>> u = ui(); s = 'foo'
211 >>> u = ui(); s = 'foo'
212 >>> u.setconfig(s, 'int1', '42')
212 >>> u.setconfig(s, 'int1', '42')
213 >>> u.configint(s, 'int1')
213 >>> u.configint(s, 'int1')
214 42
214 42
215 >>> u.setconfig(s, 'int2', '-42')
215 >>> u.setconfig(s, 'int2', '-42')
216 >>> u.configint(s, 'int2')
216 >>> u.configint(s, 'int2')
217 -42
217 -42
218 >>> u.configint(s, 'unknown', 7)
218 >>> u.configint(s, 'unknown', 7)
219 7
219 7
220 >>> u.setconfig(s, 'invalid', 'somevalue')
220 >>> u.setconfig(s, 'invalid', 'somevalue')
221 >>> u.configint(s, 'invalid')
221 >>> u.configint(s, 'invalid')
222 Traceback (most recent call last):
222 Traceback (most recent call last):
223 ...
223 ...
224 ConfigError: foo.invalid is not an integer ('somevalue')
224 ConfigError: foo.invalid is not an integer ('somevalue')
225 """
225 """
226
226
227 v = self.config(section, name, None, untrusted)
227 v = self.config(section, name, None, untrusted)
228 if v is None:
228 if v is None:
229 return default
229 return default
230 try:
230 try:
231 return int(v)
231 return int(v)
232 except ValueError:
232 except ValueError:
233 raise error.ConfigError(_("%s.%s is not an integer ('%s')")
233 raise error.ConfigError(_("%s.%s is not an integer ('%s')")
234 % (section, name, v))
234 % (section, name, v))
235
235
236 def configlist(self, section, name, default=None, untrusted=False):
236 def configlist(self, section, name, default=None, untrusted=False):
237 """parse a configuration element as a list of comma/space separated
237 """parse a configuration element as a list of comma/space separated
238 strings
238 strings
239
239
240 >>> u = ui(); s = 'foo'
240 >>> u = ui(); s = 'foo'
241 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
241 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
242 >>> u.configlist(s, 'list1')
242 >>> u.configlist(s, 'list1')
243 ['this', 'is', 'a small', 'test']
243 ['this', 'is', 'a small', 'test']
244 """
244 """
245
245
246 def _parse_plain(parts, s, offset):
246 def _parse_plain(parts, s, offset):
247 whitespace = False
247 whitespace = False
248 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
248 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
249 whitespace = True
249 whitespace = True
250 offset += 1
250 offset += 1
251 if offset >= len(s):
251 if offset >= len(s):
252 return None, parts, offset
252 return None, parts, offset
253 if whitespace:
253 if whitespace:
254 parts.append('')
254 parts.append('')
255 if s[offset] == '"' and not parts[-1]:
255 if s[offset] == '"' and not parts[-1]:
256 return _parse_quote, parts, offset + 1
256 return _parse_quote, parts, offset + 1
257 elif s[offset] == '"' and parts[-1][-1] == '\\':
257 elif s[offset] == '"' and parts[-1][-1] == '\\':
258 parts[-1] = parts[-1][:-1] + s[offset]
258 parts[-1] = parts[-1][:-1] + s[offset]
259 return _parse_plain, parts, offset + 1
259 return _parse_plain, parts, offset + 1
260 parts[-1] += s[offset]
260 parts[-1] += s[offset]
261 return _parse_plain, parts, offset + 1
261 return _parse_plain, parts, offset + 1
262
262
263 def _parse_quote(parts, s, offset):
263 def _parse_quote(parts, s, offset):
264 if offset < len(s) and s[offset] == '"': # ""
264 if offset < len(s) and s[offset] == '"': # ""
265 parts.append('')
265 parts.append('')
266 offset += 1
266 offset += 1
267 while offset < len(s) and (s[offset].isspace() or
267 while offset < len(s) and (s[offset].isspace() or
268 s[offset] == ','):
268 s[offset] == ','):
269 offset += 1
269 offset += 1
270 return _parse_plain, parts, offset
270 return _parse_plain, parts, offset
271
271
272 while offset < len(s) and s[offset] != '"':
272 while offset < len(s) and s[offset] != '"':
273 if (s[offset] == '\\' and offset + 1 < len(s)
273 if (s[offset] == '\\' and offset + 1 < len(s)
274 and s[offset + 1] == '"'):
274 and s[offset + 1] == '"'):
275 offset += 1
275 offset += 1
276 parts[-1] += '"'
276 parts[-1] += '"'
277 else:
277 else:
278 parts[-1] += s[offset]
278 parts[-1] += s[offset]
279 offset += 1
279 offset += 1
280
280
281 if offset >= len(s):
281 if offset >= len(s):
282 real_parts = _configlist(parts[-1])
282 real_parts = _configlist(parts[-1])
283 if not real_parts:
283 if not real_parts:
284 parts[-1] = '"'
284 parts[-1] = '"'
285 else:
285 else:
286 real_parts[0] = '"' + real_parts[0]
286 real_parts[0] = '"' + real_parts[0]
287 parts = parts[:-1]
287 parts = parts[:-1]
288 parts.extend(real_parts)
288 parts.extend(real_parts)
289 return None, parts, offset
289 return None, parts, offset
290
290
291 offset += 1
291 offset += 1
292 while offset < len(s) and s[offset] in [' ', ',']:
292 while offset < len(s) and s[offset] in [' ', ',']:
293 offset += 1
293 offset += 1
294
294
295 if offset < len(s):
295 if offset < len(s):
296 if offset + 1 == len(s) and s[offset] == '"':
296 if offset + 1 == len(s) and s[offset] == '"':
297 parts[-1] += '"'
297 parts[-1] += '"'
298 offset += 1
298 offset += 1
299 else:
299 else:
300 parts.append('')
300 parts.append('')
301 else:
301 else:
302 return None, parts, offset
302 return None, parts, offset
303
303
304 return _parse_plain, parts, offset
304 return _parse_plain, parts, offset
305
305
306 def _configlist(s):
306 def _configlist(s):
307 s = s.rstrip(' ,')
307 s = s.rstrip(' ,')
308 if not s:
308 if not s:
309 return []
309 return []
310 parser, parts, offset = _parse_plain, [''], 0
310 parser, parts, offset = _parse_plain, [''], 0
311 while parser:
311 while parser:
312 parser, parts, offset = parser(parts, s, offset)
312 parser, parts, offset = parser(parts, s, offset)
313 return parts
313 return parts
314
314
315 result = self.config(section, name, untrusted=untrusted)
315 result = self.config(section, name, untrusted=untrusted)
316 if result is None:
316 if result is None:
317 result = default or []
317 result = default or []
318 if isinstance(result, basestring):
318 if isinstance(result, basestring):
319 result = _configlist(result.lstrip(' ,\n'))
319 result = _configlist(result.lstrip(' ,\n'))
320 if result is None:
320 if result is None:
321 result = default or []
321 result = default or []
322 return result
322 return result
323
323
324 def has_section(self, section, untrusted=False):
324 def has_section(self, section, untrusted=False):
325 '''tell whether section exists in config.'''
325 '''tell whether section exists in config.'''
326 return section in self._data(untrusted)
326 return section in self._data(untrusted)
327
327
328 def configitems(self, section, untrusted=False):
328 def configitems(self, section, untrusted=False):
329 items = self._data(untrusted).items(section)
329 items = self._data(untrusted).items(section)
330 if self.debugflag and not untrusted and self._reportuntrusted:
330 if self.debugflag and not untrusted and self._reportuntrusted:
331 for k, v in self._ucfg.items(section):
331 for k, v in self._ucfg.items(section):
332 if self._tcfg.get(section, k) != v:
332 if self._tcfg.get(section, k) != v:
333 self.debug(_("ignoring untrusted configuration option "
333 self.debug("ignoring untrusted configuration option "
334 "%s.%s = %s\n") % (section, k, v))
334 "%s.%s = %s\n" % (section, k, v))
335 return items
335 return items
336
336
337 def walkconfig(self, untrusted=False):
337 def walkconfig(self, untrusted=False):
338 cfg = self._data(untrusted)
338 cfg = self._data(untrusted)
339 for section in cfg.sections():
339 for section in cfg.sections():
340 for name, value in self.configitems(section, untrusted):
340 for name, value in self.configitems(section, untrusted):
341 yield section, name, value
341 yield section, name, value
342
342
343 def plain(self, feature=None):
343 def plain(self, feature=None):
344 '''is plain mode active?
344 '''is plain mode active?
345
345
346 Plain mode means that all configuration variables which affect
346 Plain mode means that all configuration variables which affect
347 the behavior and output of Mercurial should be
347 the behavior and output of Mercurial should be
348 ignored. Additionally, the output should be stable,
348 ignored. Additionally, the output should be stable,
349 reproducible and suitable for use in scripts or applications.
349 reproducible and suitable for use in scripts or applications.
350
350
351 The only way to trigger plain mode is by setting either the
351 The only way to trigger plain mode is by setting either the
352 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
352 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
353
353
354 The return value can either be
354 The return value can either be
355 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
355 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
356 - True otherwise
356 - True otherwise
357 '''
357 '''
358 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
358 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
359 return False
359 return False
360 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
360 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
361 if feature and exceptions:
361 if feature and exceptions:
362 return feature not in exceptions
362 return feature not in exceptions
363 return True
363 return True
364
364
365 def username(self):
365 def username(self):
366 """Return default username to be used in commits.
366 """Return default username to be used in commits.
367
367
368 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
368 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
369 and stop searching if one of these is set.
369 and stop searching if one of these is set.
370 If not found and ui.askusername is True, ask the user, else use
370 If not found and ui.askusername is True, ask the user, else use
371 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
371 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
372 """
372 """
373 user = os.environ.get("HGUSER")
373 user = os.environ.get("HGUSER")
374 if user is None:
374 if user is None:
375 user = self.config("ui", "username")
375 user = self.config("ui", "username")
376 if user is not None:
376 if user is not None:
377 user = os.path.expandvars(user)
377 user = os.path.expandvars(user)
378 if user is None:
378 if user is None:
379 user = os.environ.get("EMAIL")
379 user = os.environ.get("EMAIL")
380 if user is None and self.configbool("ui", "askusername"):
380 if user is None and self.configbool("ui", "askusername"):
381 user = self.prompt(_("enter a commit username:"), default=None)
381 user = self.prompt(_("enter a commit username:"), default=None)
382 if user is None and not self.interactive():
382 if user is None and not self.interactive():
383 try:
383 try:
384 user = '%s@%s' % (util.getuser(), socket.getfqdn())
384 user = '%s@%s' % (util.getuser(), socket.getfqdn())
385 self.warn(_("No username found, using '%s' instead\n") % user)
385 self.warn(_("No username found, using '%s' instead\n") % user)
386 except KeyError:
386 except KeyError:
387 pass
387 pass
388 if not user:
388 if not user:
389 raise util.Abort(_('no username supplied (see "hg help config")'))
389 raise util.Abort(_('no username supplied (see "hg help config")'))
390 if "\n" in user:
390 if "\n" in user:
391 raise util.Abort(_("username %s contains a newline\n") % repr(user))
391 raise util.Abort(_("username %s contains a newline\n") % repr(user))
392 return user
392 return user
393
393
394 def shortuser(self, user):
394 def shortuser(self, user):
395 """Return a short representation of a user name or email address."""
395 """Return a short representation of a user name or email address."""
396 if not self.verbose:
396 if not self.verbose:
397 user = util.shortuser(user)
397 user = util.shortuser(user)
398 return user
398 return user
399
399
400 def expandpath(self, loc, default=None):
400 def expandpath(self, loc, default=None):
401 """Return repository location relative to cwd or from [paths]"""
401 """Return repository location relative to cwd or from [paths]"""
402 if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
402 if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
403 return loc
403 return loc
404
404
405 path = self.config('paths', loc)
405 path = self.config('paths', loc)
406 if not path and default is not None:
406 if not path and default is not None:
407 path = self.config('paths', default)
407 path = self.config('paths', default)
408 return path or loc
408 return path or loc
409
409
410 def pushbuffer(self):
410 def pushbuffer(self):
411 self._buffers.append([])
411 self._buffers.append([])
412
412
413 def popbuffer(self, labeled=False):
413 def popbuffer(self, labeled=False):
414 '''pop the last buffer and return the buffered output
414 '''pop the last buffer and return the buffered output
415
415
416 If labeled is True, any labels associated with buffered
416 If labeled is True, any labels associated with buffered
417 output will be handled. By default, this has no effect
417 output will be handled. By default, this has no effect
418 on the output returned, but extensions and GUI tools may
418 on the output returned, but extensions and GUI tools may
419 handle this argument and returned styled output. If output
419 handle this argument and returned styled output. If output
420 is being buffered so it can be captured and parsed or
420 is being buffered so it can be captured and parsed or
421 processed, labeled should not be set to True.
421 processed, labeled should not be set to True.
422 '''
422 '''
423 return "".join(self._buffers.pop())
423 return "".join(self._buffers.pop())
424
424
425 def write(self, *args, **opts):
425 def write(self, *args, **opts):
426 '''write args to output
426 '''write args to output
427
427
428 By default, this method simply writes to the buffer or stdout,
428 By default, this method simply writes to the buffer or stdout,
429 but extensions or GUI tools may override this method,
429 but extensions or GUI tools may override this method,
430 write_err(), popbuffer(), and label() to style output from
430 write_err(), popbuffer(), and label() to style output from
431 various parts of hg.
431 various parts of hg.
432
432
433 An optional keyword argument, "label", can be passed in.
433 An optional keyword argument, "label", can be passed in.
434 This should be a string containing label names separated by
434 This should be a string containing label names separated by
435 space. Label names take the form of "topic.type". For example,
435 space. Label names take the form of "topic.type". For example,
436 ui.debug() issues a label of "ui.debug".
436 ui.debug() issues a label of "ui.debug".
437
437
438 When labeling output for a specific command, a label of
438 When labeling output for a specific command, a label of
439 "cmdname.type" is recommended. For example, status issues
439 "cmdname.type" is recommended. For example, status issues
440 a label of "status.modified" for modified files.
440 a label of "status.modified" for modified files.
441 '''
441 '''
442 if self._buffers:
442 if self._buffers:
443 self._buffers[-1].extend([str(a) for a in args])
443 self._buffers[-1].extend([str(a) for a in args])
444 else:
444 else:
445 for a in args:
445 for a in args:
446 self.fout.write(str(a))
446 self.fout.write(str(a))
447
447
448 def write_err(self, *args, **opts):
448 def write_err(self, *args, **opts):
449 try:
449 try:
450 if not getattr(self.fout, 'closed', False):
450 if not getattr(self.fout, 'closed', False):
451 self.fout.flush()
451 self.fout.flush()
452 for a in args:
452 for a in args:
453 self.ferr.write(str(a))
453 self.ferr.write(str(a))
454 # stderr may be buffered under win32 when redirected to files,
454 # stderr may be buffered under win32 when redirected to files,
455 # including stdout.
455 # including stdout.
456 if not getattr(self.ferr, 'closed', False):
456 if not getattr(self.ferr, 'closed', False):
457 self.ferr.flush()
457 self.ferr.flush()
458 except IOError, inst:
458 except IOError, inst:
459 if inst.errno not in (errno.EPIPE, errno.EIO):
459 if inst.errno not in (errno.EPIPE, errno.EIO):
460 raise
460 raise
461
461
462 def flush(self):
462 def flush(self):
463 try: self.fout.flush()
463 try: self.fout.flush()
464 except: pass
464 except: pass
465 try: self.ferr.flush()
465 try: self.ferr.flush()
466 except: pass
466 except: pass
467
467
468 def interactive(self):
468 def interactive(self):
469 '''is interactive input allowed?
469 '''is interactive input allowed?
470
470
471 An interactive session is a session where input can be reasonably read
471 An interactive session is a session where input can be reasonably read
472 from `sys.stdin'. If this function returns false, any attempt to read
472 from `sys.stdin'. If this function returns false, any attempt to read
473 from stdin should fail with an error, unless a sensible default has been
473 from stdin should fail with an error, unless a sensible default has been
474 specified.
474 specified.
475
475
476 Interactiveness is triggered by the value of the `ui.interactive'
476 Interactiveness is triggered by the value of the `ui.interactive'
477 configuration variable or - if it is unset - when `sys.stdin' points
477 configuration variable or - if it is unset - when `sys.stdin' points
478 to a terminal device.
478 to a terminal device.
479
479
480 This function refers to input only; for output, see `ui.formatted()'.
480 This function refers to input only; for output, see `ui.formatted()'.
481 '''
481 '''
482 i = self.configbool("ui", "interactive", None)
482 i = self.configbool("ui", "interactive", None)
483 if i is None:
483 if i is None:
484 # some environments replace stdin without implementing isatty
484 # some environments replace stdin without implementing isatty
485 # usually those are non-interactive
485 # usually those are non-interactive
486 return util.isatty(self.fin)
486 return util.isatty(self.fin)
487
487
488 return i
488 return i
489
489
490 def termwidth(self):
490 def termwidth(self):
491 '''how wide is the terminal in columns?
491 '''how wide is the terminal in columns?
492 '''
492 '''
493 if 'COLUMNS' in os.environ:
493 if 'COLUMNS' in os.environ:
494 try:
494 try:
495 return int(os.environ['COLUMNS'])
495 return int(os.environ['COLUMNS'])
496 except ValueError:
496 except ValueError:
497 pass
497 pass
498 return util.termwidth()
498 return util.termwidth()
499
499
500 def formatted(self):
500 def formatted(self):
501 '''should formatted output be used?
501 '''should formatted output be used?
502
502
503 It is often desirable to format the output to suite the output medium.
503 It is often desirable to format the output to suite the output medium.
504 Examples of this are truncating long lines or colorizing messages.
504 Examples of this are truncating long lines or colorizing messages.
505 However, this is not often not desirable when piping output into other
505 However, this is not often not desirable when piping output into other
506 utilities, e.g. `grep'.
506 utilities, e.g. `grep'.
507
507
508 Formatted output is triggered by the value of the `ui.formatted'
508 Formatted output is triggered by the value of the `ui.formatted'
509 configuration variable or - if it is unset - when `sys.stdout' points
509 configuration variable or - if it is unset - when `sys.stdout' points
510 to a terminal device. Please note that `ui.formatted' should be
510 to a terminal device. Please note that `ui.formatted' should be
511 considered an implementation detail; it is not intended for use outside
511 considered an implementation detail; it is not intended for use outside
512 Mercurial or its extensions.
512 Mercurial or its extensions.
513
513
514 This function refers to output only; for input, see `ui.interactive()'.
514 This function refers to output only; for input, see `ui.interactive()'.
515 This function always returns false when in plain mode, see `ui.plain()'.
515 This function always returns false when in plain mode, see `ui.plain()'.
516 '''
516 '''
517 if self.plain():
517 if self.plain():
518 return False
518 return False
519
519
520 i = self.configbool("ui", "formatted", None)
520 i = self.configbool("ui", "formatted", None)
521 if i is None:
521 if i is None:
522 # some environments replace stdout without implementing isatty
522 # some environments replace stdout without implementing isatty
523 # usually those are non-interactive
523 # usually those are non-interactive
524 return util.isatty(self.fout)
524 return util.isatty(self.fout)
525
525
526 return i
526 return i
527
527
528 def _readline(self, prompt=''):
528 def _readline(self, prompt=''):
529 if util.isatty(self.fin):
529 if util.isatty(self.fin):
530 try:
530 try:
531 # magically add command line editing support, where
531 # magically add command line editing support, where
532 # available
532 # available
533 import readline
533 import readline
534 # force demandimport to really load the module
534 # force demandimport to really load the module
535 readline.read_history_file
535 readline.read_history_file
536 # windows sometimes raises something other than ImportError
536 # windows sometimes raises something other than ImportError
537 except Exception:
537 except Exception:
538 pass
538 pass
539
539
540 # instead of trying to emulate raw_input, swap our in/out
540 # instead of trying to emulate raw_input, swap our in/out
541 # with sys.stdin/out
541 # with sys.stdin/out
542 old = sys.stdout, sys.stdin
542 old = sys.stdout, sys.stdin
543 sys.stdout, sys.stdin = self.fout, self.fin
543 sys.stdout, sys.stdin = self.fout, self.fin
544 line = raw_input(prompt)
544 line = raw_input(prompt)
545 sys.stdout, sys.stdin = old
545 sys.stdout, sys.stdin = old
546
546
547 # When stdin is in binary mode on Windows, it can cause
547 # When stdin is in binary mode on Windows, it can cause
548 # raw_input() to emit an extra trailing carriage return
548 # raw_input() to emit an extra trailing carriage return
549 if os.linesep == '\r\n' and line and line[-1] == '\r':
549 if os.linesep == '\r\n' and line and line[-1] == '\r':
550 line = line[:-1]
550 line = line[:-1]
551 return line
551 return line
552
552
553 def prompt(self, msg, default="y"):
553 def prompt(self, msg, default="y"):
554 """Prompt user with msg, read response.
554 """Prompt user with msg, read response.
555 If ui is not interactive, the default is returned.
555 If ui is not interactive, the default is returned.
556 """
556 """
557 if not self.interactive():
557 if not self.interactive():
558 self.write(msg, ' ', default, "\n")
558 self.write(msg, ' ', default, "\n")
559 return default
559 return default
560 try:
560 try:
561 r = self._readline(self.label(msg, 'ui.prompt') + ' ')
561 r = self._readline(self.label(msg, 'ui.prompt') + ' ')
562 if not r:
562 if not r:
563 return default
563 return default
564 return r
564 return r
565 except EOFError:
565 except EOFError:
566 raise util.Abort(_('response expected'))
566 raise util.Abort(_('response expected'))
567
567
568 def promptchoice(self, msg, choices, default=0):
568 def promptchoice(self, msg, choices, default=0):
569 """Prompt user with msg, read response, and ensure it matches
569 """Prompt user with msg, read response, and ensure it matches
570 one of the provided choices. The index of the choice is returned.
570 one of the provided choices. The index of the choice is returned.
571 choices is a sequence of acceptable responses with the format:
571 choices is a sequence of acceptable responses with the format:
572 ('&None', 'E&xec', 'Sym&link') Responses are case insensitive.
572 ('&None', 'E&xec', 'Sym&link') Responses are case insensitive.
573 If ui is not interactive, the default is returned.
573 If ui is not interactive, the default is returned.
574 """
574 """
575 resps = [s[s.index('&')+1].lower() for s in choices]
575 resps = [s[s.index('&')+1].lower() for s in choices]
576 while True:
576 while True:
577 r = self.prompt(msg, resps[default])
577 r = self.prompt(msg, resps[default])
578 if r.lower() in resps:
578 if r.lower() in resps:
579 return resps.index(r.lower())
579 return resps.index(r.lower())
580 self.write(_("unrecognized response\n"))
580 self.write(_("unrecognized response\n"))
581
581
582 def getpass(self, prompt=None, default=None):
582 def getpass(self, prompt=None, default=None):
583 if not self.interactive():
583 if not self.interactive():
584 return default
584 return default
585 try:
585 try:
586 return getpass.getpass(prompt or _('password: '))
586 return getpass.getpass(prompt or _('password: '))
587 except EOFError:
587 except EOFError:
588 raise util.Abort(_('response expected'))
588 raise util.Abort(_('response expected'))
589 def status(self, *msg, **opts):
589 def status(self, *msg, **opts):
590 '''write status message to output (if ui.quiet is False)
590 '''write status message to output (if ui.quiet is False)
591
591
592 This adds an output label of "ui.status".
592 This adds an output label of "ui.status".
593 '''
593 '''
594 if not self.quiet:
594 if not self.quiet:
595 opts['label'] = opts.get('label', '') + ' ui.status'
595 opts['label'] = opts.get('label', '') + ' ui.status'
596 self.write(*msg, **opts)
596 self.write(*msg, **opts)
597 def warn(self, *msg, **opts):
597 def warn(self, *msg, **opts):
598 '''write warning message to output (stderr)
598 '''write warning message to output (stderr)
599
599
600 This adds an output label of "ui.warning".
600 This adds an output label of "ui.warning".
601 '''
601 '''
602 opts['label'] = opts.get('label', '') + ' ui.warning'
602 opts['label'] = opts.get('label', '') + ' ui.warning'
603 self.write_err(*msg, **opts)
603 self.write_err(*msg, **opts)
604 def note(self, *msg, **opts):
604 def note(self, *msg, **opts):
605 '''write note to output (if ui.verbose is True)
605 '''write note to output (if ui.verbose is True)
606
606
607 This adds an output label of "ui.note".
607 This adds an output label of "ui.note".
608 '''
608 '''
609 if self.verbose:
609 if self.verbose:
610 opts['label'] = opts.get('label', '') + ' ui.note'
610 opts['label'] = opts.get('label', '') + ' ui.note'
611 self.write(*msg, **opts)
611 self.write(*msg, **opts)
612 def debug(self, *msg, **opts):
612 def debug(self, *msg, **opts):
613 '''write debug message to output (if ui.debugflag is True)
613 '''write debug message to output (if ui.debugflag is True)
614
614
615 This adds an output label of "ui.debug".
615 This adds an output label of "ui.debug".
616 '''
616 '''
617 if self.debugflag:
617 if self.debugflag:
618 opts['label'] = opts.get('label', '') + ' ui.debug'
618 opts['label'] = opts.get('label', '') + ' ui.debug'
619 self.write(*msg, **opts)
619 self.write(*msg, **opts)
620 def edit(self, text, user):
620 def edit(self, text, user):
621 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
621 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
622 text=True)
622 text=True)
623 try:
623 try:
624 f = os.fdopen(fd, "w")
624 f = os.fdopen(fd, "w")
625 f.write(text)
625 f.write(text)
626 f.close()
626 f.close()
627
627
628 editor = self.geteditor()
628 editor = self.geteditor()
629
629
630 util.system("%s \"%s\"" % (editor, name),
630 util.system("%s \"%s\"" % (editor, name),
631 environ={'HGUSER': user},
631 environ={'HGUSER': user},
632 onerr=util.Abort, errprefix=_("edit failed"))
632 onerr=util.Abort, errprefix=_("edit failed"))
633
633
634 f = open(name)
634 f = open(name)
635 t = f.read()
635 t = f.read()
636 f.close()
636 f.close()
637 finally:
637 finally:
638 os.unlink(name)
638 os.unlink(name)
639
639
640 return t
640 return t
641
641
642 def traceback(self, exc=None):
642 def traceback(self, exc=None):
643 '''print exception traceback if traceback printing enabled.
643 '''print exception traceback if traceback printing enabled.
644 only to call in exception handler. returns true if traceback
644 only to call in exception handler. returns true if traceback
645 printed.'''
645 printed.'''
646 if self.tracebackflag:
646 if self.tracebackflag:
647 if exc:
647 if exc:
648 traceback.print_exception(exc[0], exc[1], exc[2])
648 traceback.print_exception(exc[0], exc[1], exc[2])
649 else:
649 else:
650 traceback.print_exc()
650 traceback.print_exc()
651 return self.tracebackflag
651 return self.tracebackflag
652
652
653 def geteditor(self):
653 def geteditor(self):
654 '''return editor to use'''
654 '''return editor to use'''
655 return (os.environ.get("HGEDITOR") or
655 return (os.environ.get("HGEDITOR") or
656 self.config("ui", "editor") or
656 self.config("ui", "editor") or
657 os.environ.get("VISUAL") or
657 os.environ.get("VISUAL") or
658 os.environ.get("EDITOR", "vi"))
658 os.environ.get("EDITOR", "vi"))
659
659
660 def progress(self, topic, pos, item="", unit="", total=None):
660 def progress(self, topic, pos, item="", unit="", total=None):
661 '''show a progress message
661 '''show a progress message
662
662
663 With stock hg, this is simply a debug message that is hidden
663 With stock hg, this is simply a debug message that is hidden
664 by default, but with extensions or GUI tools it may be
664 by default, but with extensions or GUI tools it may be
665 visible. 'topic' is the current operation, 'item' is a
665 visible. 'topic' is the current operation, 'item' is a
666 non-numeric marker of the current position (ie the currently
666 non-numeric marker of the current position (ie the currently
667 in-process file), 'pos' is the current numeric position (ie
667 in-process file), 'pos' is the current numeric position (ie
668 revision, bytes, etc.), unit is a corresponding unit label,
668 revision, bytes, etc.), unit is a corresponding unit label,
669 and total is the highest expected pos.
669 and total is the highest expected pos.
670
670
671 Multiple nested topics may be active at a time.
671 Multiple nested topics may be active at a time.
672
672
673 All topics should be marked closed by setting pos to None at
673 All topics should be marked closed by setting pos to None at
674 termination.
674 termination.
675 '''
675 '''
676
676
677 if pos is None or not self.debugflag:
677 if pos is None or not self.debugflag:
678 return
678 return
679
679
680 if unit:
680 if unit:
681 unit = ' ' + unit
681 unit = ' ' + unit
682 if item:
682 if item:
683 item = ' ' + item
683 item = ' ' + item
684
684
685 if total:
685 if total:
686 pct = 100.0 * pos / total
686 pct = 100.0 * pos / total
687 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
687 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
688 % (topic, item, pos, total, unit, pct))
688 % (topic, item, pos, total, unit, pct))
689 else:
689 else:
690 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
690 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
691
691
692 def log(self, service, message):
692 def log(self, service, message):
693 '''hook for logging facility extensions
693 '''hook for logging facility extensions
694
694
695 service should be a readily-identifiable subsystem, which will
695 service should be a readily-identifiable subsystem, which will
696 allow filtering.
696 allow filtering.
697 message should be a newline-terminated string to log.
697 message should be a newline-terminated string to log.
698 '''
698 '''
699 pass
699 pass
700
700
701 def label(self, msg, label):
701 def label(self, msg, label):
702 '''style msg based on supplied label
702 '''style msg based on supplied label
703
703
704 Like ui.write(), this just returns msg unchanged, but extensions
704 Like ui.write(), this just returns msg unchanged, but extensions
705 and GUI tools can override it to allow styling output without
705 and GUI tools can override it to allow styling output without
706 writing it.
706 writing it.
707
707
708 ui.write(s, 'label') is equivalent to
708 ui.write(s, 'label') is equivalent to
709 ui.write(ui.label(s, 'label')).
709 ui.write(ui.label(s, 'label')).
710 '''
710 '''
711 return msg
711 return msg
General Comments 0
You need to be logged in to leave comments. Login now